diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 4f28122f1bb8..03b444f753aa 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -197,7 +197,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, int ret; spin_lock_irqsave(&dwc->lock, flags); - if (!dep->endpoint.desc || !dwc->pullups_connected) { + if (!dep->endpoint.desc) { dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n", dep->name); ret = -ESHUTDOWN; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 39a9ad12cbbc..a2aaf592a699 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -746,6 +746,8 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) trace_dwc3_gadget_ep_disable(dep); + dwc3_remove_requests(dwc, dep); + /* make sure HW endpoint isn't stalled */ if (dep->flags & DWC3_EP_STALL) __dwc3_gadget_ep_set_halt(dep, 0, false); @@ -754,18 +756,16 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) reg &= ~DWC3_DALEPENA_EP(dep->number); dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); + dep->stream_capable = false; + dep->type = 0; + dep->flags = 0; + /* Clear out the ep descriptors for non-ep0 */ if (dep->number > 1) { dep->endpoint.comp_desc = NULL; dep->endpoint.desc = NULL; } - dwc3_remove_requests(dwc, dep); - - dep->stream_capable = false; - dep->type = 0; - dep->flags = 0; - return 0; } @@ -1511,7 +1511,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) { struct dwc3 *dwc = dep->dwc; - if (!dep->endpoint.desc || !dwc->pullups_connected || !dwc->connected) { + if (!dep->endpoint.desc) { dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n", dep->name); return -ESHUTDOWN; @@ -1931,21 +1931,6 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g, return 0; } -static void dwc3_stop_active_transfers(struct dwc3 *dwc) -{ - u32 epnum; - - for (epnum = 2; epnum < dwc->num_eps; epnum++) { - struct dwc3_ep *dep; - - dep = dwc->eps[epnum]; - if (!dep) - continue; - - dwc3_remove_requests(dwc, dep); - } -} - static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) { u32 reg; @@ -1991,10 +1976,6 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) return 0; } -static void dwc3_gadget_disable_irq(struct dwc3 *dwc); -static void __dwc3_gadget_stop(struct dwc3 *dwc); -static int __dwc3_gadget_start(struct dwc3 *dwc); - static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) { struct dwc3 *dwc = gadget_to_dwc(g); @@ -2012,77 +1993,15 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) ret = wait_for_completion_timeout(&dwc->ep0_in_setup, msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT)); - if (ret == 0) - dev_warn(dwc->dev, "timed out waiting for SETUP phase\n"); + if (ret == 0) { + dev_err(dwc->dev, "timed out waiting for SETUP phase\n"); + return -ETIMEDOUT; + } } - /* - * Avoid issuing a runtime resume if the device is already in the - * suspended state during gadget disconnect. DWC3 gadget was already - * halted/stopped during runtime suspend. - */ - if (!is_on) { - pm_runtime_barrier(dwc->dev); - if (pm_runtime_suspended(dwc->dev)) - return 0; - } - - /* - * Check the return value for successful resume, or error. For a - * successful resume, the DWC3 runtime PM resume routine will handle - * the run stop sequence, so avoid duplicate operations here. - */ - ret = pm_runtime_get_sync(dwc->dev); - if (!ret || ret < 0) { - pm_runtime_put(dwc->dev); - return 0; - } - - /* - * Synchronize and disable any further event handling while controller - * is being enabled/disabled. - */ - disable_irq(dwc->irq_gadget); - spin_lock_irqsave(&dwc->lock, flags); - - if (!is_on) { - u32 count; - - dwc->connected = false; - /* - * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a - * Section 4.1.8 Table 4-7, it states that for a device-initiated - * disconnect, the SW needs to ensure that it sends "a DEPENDXFER - * command for any active transfers" before clearing the RunStop - * bit. - */ - dwc3_stop_active_transfers(dwc); - __dwc3_gadget_stop(dwc); - - /* - * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a - * Section 1.3.4, it mentions that for the DEVCTRLHLT bit, the - * "software needs to acknowledge the events that are generated - * (by writing to GEVNTCOUNTn) while it is waiting for this bit - * to be set to '1'." - */ - count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0)); - count &= DWC3_GEVNTCOUNT_MASK; - if (count > 0) { - dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count); - dwc->ev_buf->lpos = (dwc->ev_buf->lpos + count) % - dwc->ev_buf->length; - } - } else { - __dwc3_gadget_start(dwc); - } - ret = dwc3_gadget_run_stop(dwc, is_on, false); spin_unlock_irqrestore(&dwc->lock, flags); - enable_irq(dwc->irq_gadget); - - pm_runtime_put(dwc->dev); return ret; } @@ -2215,7 +2134,6 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) /* begin to receive SETUP packets */ dwc->ep0state = EP0_SETUP_PHASE; dwc->link_state = DWC3_LINK_STATE_SS_DIS; - dwc->delayed_status = false; dwc3_ep0_out_start(dwc); dwc3_gadget_enable_irq(dwc); @@ -2256,6 +2174,10 @@ static int dwc3_gadget_start(struct usb_gadget *g, } dwc->gadget_driver = driver; + + if (pm_runtime_active(dwc->dev)) + __dwc3_gadget_start(dwc); + spin_unlock_irqrestore(&dwc->lock, flags); return 0; @@ -2281,6 +2203,13 @@ static int dwc3_gadget_stop(struct usb_gadget *g) unsigned long flags; spin_lock_irqsave(&dwc->lock, flags); + + if (pm_runtime_suspended(dwc->dev)) + goto out; + + __dwc3_gadget_stop(dwc); + +out: dwc->gadget_driver = NULL; spin_unlock_irqrestore(&dwc->lock, flags); @@ -3066,6 +2995,8 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) { u32 reg; + dwc->connected = true; + /* * Ideally, dwc3_reset_gadget() would trigger the function * drivers to stop any active transfers through ep disable. @@ -3107,14 +3038,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) } dwc3_reset_gadget(dwc); - /* - * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a - * Section 4.1.2 Table 4-2, it states that during a USB reset, the SW - * needs to ensure that it sends "a DEPENDXFER command for any active - * transfers." - */ - dwc3_stop_active_transfers(dwc); - dwc->connected = true; reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_TSTCTRL_MASK;