[PATCH 17/18] staging: octeon-usb: try to recover from failed hardware reset

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On some hardware the USB fails to initialize to sane state after
cold boot. We can detect this based on some unexpected interrupt bits,
and recover by re-initializing.

Signed-off-by: Aaro Koskinen <aaro.koskinen@xxxxxx>
---
 drivers/staging/octeon-usb/octeon-hcd.c | 30 +++++++++++++++++++++++++++---
 1 file changed, 27 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c
index 54c23c4..7981c93 100644
--- a/drivers/staging/octeon-usb/octeon-hcd.c
+++ b/drivers/staging/octeon-usb/octeon-hcd.c
@@ -697,15 +697,20 @@ static int cvmx_usb_shutdown(struct cvmx_usb_state *usb)
  * other access to the Octeon USB port is made. The port starts
  * off in the disabled state.
  *
+ * @dev:	 Pointer to struct device for logging purposes.
  * @usb:	 Pointer to struct cvmx_usb_state.
  *
  * Returns: 0 or a negative error code.
  */
-static int cvmx_usb_initialize(struct cvmx_usb_state *usb)
+static int cvmx_usb_initialize(struct device *dev,
+			       struct cvmx_usb_state *usb)
 {
+	int retries = 0;
 	union cvmx_usbnx_clk_ctl usbn_clk_ctl;
+	union cvmx_usbcx_gintsts usbc_gintsts;
 	union cvmx_usbnx_usbp_ctl_status usbn_usbp_ctl_status;
 
+retry:
 	/*
 	 * Power On Reset and PHY Initialization
 	 *
@@ -952,7 +957,26 @@ static int cvmx_usb_initialize(struct cvmx_usb_state *usb)
 
 	cvmx_fifo_setup(usb);
 
-	return 0;
+	/*
+	 * If the controller is getting port events right after the reset, it
+	 * means the initialization failed. Try resetting the controller again
+	 * in such case. This is seen to happen after cold boot on DSR-1000N.
+	 */
+	usbc_gintsts.u32 = cvmx_usb_read_csr32(usb,
+					       CVMX_USBCX_GINTSTS(usb->index));
+	cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index),
+			     usbc_gintsts.u32);
+	dev_dbg(dev, "gintsts after reset: 0x%x\n", (int)usbc_gintsts.u32);
+	if (!usbc_gintsts.s.disconnint && !usbc_gintsts.s.prtint)
+		return 0;
+	if (retries++ >= 5)
+		return -EAGAIN;
+	dev_info(dev, "controller reset failed (gintsts=0x%x) - retrying\n",
+		 (int)usbc_gintsts.u32);
+	msleep(50);
+	cvmx_usb_shutdown(usb);
+	msleep(50);
+	goto retry;
 }
 
 /**
@@ -3690,7 +3714,7 @@ static int octeon_usb_probe(struct platform_device *pdev)
 		priv->usb.idle_hardware_channels = 0xff;
 	}
 
-	status = cvmx_usb_initialize(&priv->usb);
+	status = cvmx_usb_initialize(dev, &priv->usb);
 	if (status) {
 		dev_dbg(dev, "USB initialization failed with %d\n", status);
 		kfree(hcd);
-- 
2.2.0

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel




[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux