From: Aaro Koskinen Date: Sun, 22 Mar 2015 15:38:01 +0000 (+0200) Subject: staging: octeon-usb: try to recover from failed hardware reset X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=6ad9c95b3a595a2ec516dfcbc677043ea5ac9a76;p=openwrt%2Fstaging%2Fblogic.git 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 Signed-off-by: Greg Kroah-Hartman --- 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);