From 6a6595318ac2dd169d2931a1d9431a64f4ada75c Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Thu, 19 Nov 2015 13:23:14 -0800 Subject: usb: dwc2: host: Fix missing device insertions If you've got your interrupt signals bouncing a bit as you insert your USB device, you might end up in a state when the device is connected but the driver doesn't know it. Specifically, the observed order is: 1. hardware sees connect 2. hardware sees disconnect 3. hardware sees connect 4. dwc2_port_intr() - clears connect interrupt 5. dwc2_handle_common_intr() - calls dwc2_hcd_disconnect() Now you'll be stuck with the cable plugged in and no further interrupts coming in but the driver will think we're disconnected. We'll fix this by checking for the missing connect interrupt and re-connecting after the disconnect is posted. We don't skip the disconnect because if there is a transitory disconnect we really want to de-enumerate and re-enumerate. Notes: 1. As part of this change we add a "force" parameter to dwc2_hcd_disconnect() so that when we're unloading the module we avoid the new behavior. The need for this was pointed out by John Youn. 2. The bit of code needed at the end of dwc2_hcd_disconnect() is exactly the same bit of code from dwc2_port_intr(). To avoid duplication, we refactor that code out into a new function dwc2_hcd_connect(). Signed-off-by: Douglas Anderson Acked-by: John Youn Tested-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/core_intr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb/dwc2/core_intr.c') diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c index 27daa42788b1..61601d16e233 100644 --- a/drivers/usb/dwc2/core_intr.c +++ b/drivers/usb/dwc2/core_intr.c @@ -239,7 +239,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg) dev_dbg(hsotg->dev, "a_suspend->a_peripheral (%d)\n", hsotg->op_state); spin_unlock(&hsotg->lock); - dwc2_hcd_disconnect(hsotg); + dwc2_hcd_disconnect(hsotg, false); spin_lock(&hsotg->lock); hsotg->op_state = OTG_STATE_A_PERIPHERAL; } else { @@ -401,7 +401,7 @@ static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg) dwc2_op_state_str(hsotg)); if (hsotg->op_state == OTG_STATE_A_HOST) - dwc2_hcd_disconnect(hsotg); + dwc2_hcd_disconnect(hsotg, false); dwc2_writel(GINTSTS_DISCONNINT, hsotg->regs + GINTSTS); } -- cgit v1.2.3