- The loop in dwc3_gadget_set_link_state was using a udelay(500), which is a long time to delay in interrupt context. Change it to udelay(5) and increase the loop count to match. - dwc3_gadget_wakeup was looping on !time_after(jiffies, timeout)) with interrupts disabled, which is wrong. Fix it. - dwc3_gadget_ep_set_wedge and dwc3_gadget_set_selfpowered were modifying dwc->flags/dwc->is_selfpowered without taking the lock. Since those modifications are non-atomic, that could cause other flags to be corrupted. Fix them both to take the lock. - Transfer resource index is cleared in hardware when XFERCOMPLETE event is generated, so clear the driver's res_trans_idx variable immediately after that event is received. The upcoming hibernation patches also need this change. Signed-off-by: Paul Zimmerman <paulz@xxxxxxxxxxxx> --- drivers/usb/dwc3/ep0.c | 1 + drivers/usb/dwc3/gadget.c | 24 +++++++++++++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index c836d42..263c360 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -614,6 +614,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc, struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; dep->flags &= ~DWC3_EP_BUSY; + dep->res_trans_idx = 0; dwc->setup_packet_pending = false; switch (dwc->ep0state) { diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 5577ff8..4702b75 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -95,11 +95,11 @@ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode) * @state: the state to put link into * * Caller should take care of locking. This function will - * return 0 on success or -EINVAL. + * return 0 on success or -ETIMEDOUT. */ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) { - int retries = 100; + int retries = 10000; u32 reg; reg = dwc3_readl(dwc->regs, DWC3_DCTL); @@ -113,11 +113,10 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) while (--retries) { reg = dwc3_readl(dwc->regs, DWC3_DSTS); - /* in HS, means ON */ if (DWC3_DSTS_USBLNKST(reg) == state) return 0; - udelay(500); + udelay(5); } dev_vdbg(dwc->dev, "link state change request timed out\n"); @@ -1173,8 +1172,12 @@ out: static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep) { struct dwc3_ep *dep = to_dwc3_ep(ep); + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + spin_lock_irqsave(&dwc->lock, flags); dep->flags |= DWC3_EP_WEDGE; + spin_unlock_irqrestore(&dwc->lock, flags); return dwc3_gadget_ep_set_halt(ep, 1); } @@ -1277,6 +1280,8 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) /* poll until Link State changes to ON */ timeout = jiffies + msecs_to_jiffies(100); + spin_unlock_irqrestore(&dwc->lock, flags); + while (!time_after(jiffies, timeout)) { reg = dwc3_readl(dwc->regs, DWC3_DSTS); @@ -1285,6 +1290,8 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) break; } + spin_lock_irqsave(&dwc->lock, flags); + if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) { dev_err(dwc->dev, "failed to send remote wakeup\n"); ret = -EINVAL; @@ -1300,8 +1307,11 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g, int is_selfpowered) { struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long flags; + spin_lock_irqsave(&dwc->lock, flags); dwc->is_selfpowered = !!is_selfpowered; + spin_unlock_irqrestore(&dwc->lock, flags); return 0; } @@ -1595,10 +1605,8 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, status = -ECONNRESET; clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status); - if (clean_busy) { + if (clean_busy) dep->flags &= ~DWC3_EP_BUSY; - dep->res_trans_idx = 0; - } /* * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround. @@ -1709,6 +1717,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, switch (event->endpoint_event) { case DWC3_DEPEVT_XFERCOMPLETE: + dep->res_trans_idx = 0; + if (usb_endpoint_xfer_isoc(dep->desc)) { dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n", dep->name); -- 1.7.4.4 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html