diff options
Diffstat (limited to 'drivers/usb/dwc3/gadget.c')
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 101 |
1 files changed, 54 insertions, 47 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index c2813c2b005a..c9e729a4bf65 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -434,15 +434,25 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep) static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, const struct usb_endpoint_descriptor *desc, - const struct usb_ss_ep_comp_descriptor *comp_desc) + const struct usb_ss_ep_comp_descriptor *comp_desc, + bool ignore) { struct dwc3_gadget_ep_cmd_params params; memset(¶ms, 0x00, sizeof(params)); params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc)) - | DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc)) - | DWC3_DEPCFG_BURST_SIZE(dep->endpoint.maxburst - 1); + | DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc)); + + /* Burst size is only needed in SuperSpeed mode */ + if (dwc->gadget.speed == USB_SPEED_SUPER) { + u32 burst = dep->endpoint.maxburst - 1; + + params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst); + } + + if (ignore) + params.param0 |= DWC3_DEPCFG_IGN_SEQ_NUM; params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN | DWC3_DEPCFG_XFER_NOT_READY_EN; @@ -501,7 +511,8 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep) */ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, const struct usb_endpoint_descriptor *desc, - const struct usb_ss_ep_comp_descriptor *comp_desc) + const struct usb_ss_ep_comp_descriptor *comp_desc, + bool ignore) { struct dwc3 *dwc = dep->dwc; u32 reg; @@ -513,7 +524,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, return ret; } - ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc); + ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore); if (ret) return ret; @@ -561,27 +572,7 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) if (!list_empty(&dep->req_queued)) { dwc3_stop_active_transfer(dwc, dep->number); - /* - * NOTICE: We are violating what the Databook says about the - * EndTransfer command. Ideally we would _always_ wait for the - * EndTransfer Command Completion IRQ, but that's causing too - * much trouble synchronizing between us and gadget driver. - * - * We have discussed this with the IP Provider and it was - * suggested to giveback all requests here, but give HW some - * extra time to synchronize with the interconnect. We're using - * an arbitraty 100us delay for that. - * - * Note also that a similar handling was tested by Synopsys - * (thanks a lot Paul) and nothing bad has come out of it. - * In short, what we're doing is: - * - * - Issue EndTransfer WITH CMDIOC bit set - * - Wait 100us - * - giveback all requests to gadget driver - */ - udelay(100); - + /* - giveback all requests to gadget driver */ while (!list_empty(&dep->req_queued)) { req = next_request(&dep->req_queued); @@ -660,6 +651,12 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, dep = to_dwc3_ep(ep); dwc = dep->dwc; + if (dep->flags & DWC3_EP_ENABLED) { + dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n", + dep->name); + return 0; + } + switch (usb_endpoint_type(desc)) { case USB_ENDPOINT_XFER_CONTROL: strlcat(dep->name, "-control", sizeof(dep->name)); @@ -677,16 +674,10 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, dev_err(dwc->dev, "invalid endpoint transfer type\n"); } - if (dep->flags & DWC3_EP_ENABLED) { - dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n", - dep->name); - return 0; - } - dev_vdbg(dwc->dev, "Enabling %s\n", dep->name); spin_lock_irqsave(&dwc->lock, flags); - ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc); + ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false); spin_unlock_irqrestore(&dwc->lock, flags); return ret; @@ -1105,12 +1096,9 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) } ret = __dwc3_gadget_kick_transfer(dep, 0, true); - if (ret && ret != -EBUSY) { - struct dwc3 *dwc = dep->dwc; - + if (ret && ret != -EBUSY) dev_dbg(dwc->dev, "%s: failed to kick transfers\n", dep->name); - } } /* @@ -1119,16 +1107,14 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) * core may not see the modified TRB(s). */ if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && - (dep->flags & DWC3_EP_BUSY)) { + (dep->flags & DWC3_EP_BUSY) && + !(dep->flags & DWC3_EP_MISSED_ISOC)) { WARN_ON_ONCE(!dep->resource_index); ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index, false); - if (ret && ret != -EBUSY) { - struct dwc3 *dwc = dep->dwc; - + if (ret && ret != -EBUSY) dev_dbg(dwc->dev, "%s: failed to kick transfers\n", dep->name); - } } /* @@ -1533,14 +1519,14 @@ static int dwc3_gadget_start(struct usb_gadget *g, dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); dep = dwc->eps[0]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); + ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); goto err0; } dep = dwc->eps[1]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); + ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); goto err1; @@ -1765,7 +1751,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, int i; for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) { - struct dwc3_ep *dep = dwc->eps[i]; + dep = dwc->eps[i]; if (!(dep->flags & DWC3_EP_ENABLED)) continue; @@ -1892,6 +1878,25 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum) if (!dep->resource_index) return; + /* + * NOTICE: We are violating what the Databook says about the + * EndTransfer command. Ideally we would _always_ wait for the + * EndTransfer Command Completion IRQ, but that's causing too + * much trouble synchronizing between us and gadget driver. + * + * We have discussed this with the IP Provider and it was + * suggested to giveback all requests here, but give HW some + * extra time to synchronize with the interconnect. We're using + * an arbitraty 100us delay for that. + * + * Note also that a similar handling was tested by Synopsys + * (thanks a lot Paul) and nothing bad has come out of it. + * In short, what we're doing is: + * + * - Issue EndTransfer WITH CMDIOC bit set + * - Wait 100us + */ + cmd = DWC3_DEPCMD_ENDTRANSFER; cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC; cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); @@ -1899,6 +1904,8 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum) ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); WARN_ON_ONCE(ret); dep->resource_index = 0; + + udelay(100); } static void dwc3_stop_active_transfers(struct dwc3 *dwc) @@ -2156,14 +2163,14 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) } dep = dwc->eps[0]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); + ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); return; } dep = dwc->eps[1]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); + ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); return; |