summaryrefslogtreecommitdiffstats
path: root/drivers/staging/octeon-usb
diff options
context:
space:
mode:
authorAaro Koskinen2015-03-22 16:38:01 +0100
committerGreg Kroah-Hartman2015-03-24 13:47:13 +0100
commit6ad9c95b3a595a2ec516dfcbc677043ea5ac9a76 (patch)
tree5dabb56d9f59231774eadd7e86afaacd0a1217e7 /drivers/staging/octeon-usb
parentstaging: octeon-usb: fail and warn if DMA counters are wrong (diff)
downloadkernel-qcow2-linux-6ad9c95b3a595a2ec516dfcbc677043ea5ac9a76.tar.gz
kernel-qcow2-linux-6ad9c95b3a595a2ec516dfcbc677043ea5ac9a76.tar.xz
kernel-qcow2-linux-6ad9c95b3a595a2ec516dfcbc677043ea5ac9a76.zip
staging: octeon-usb: try to recover from failed hardware reset
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@iki.fi> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/octeon-usb')
-rw-r--r--drivers/staging/octeon-usb/octeon-hcd.c30
1 files changed, 27 insertions, 3 deletions
diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c
index 27acab217d21..d71ae297c36f 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);