summaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3/gadget.c
diff options
context:
space:
mode:
authorLinus Torvalds2018-04-05 02:55:35 +0200
committerLinus Torvalds2018-04-05 02:55:35 +0200
commitac9053d2dcb9e8c3fa35ce458dfca8fddc141680 (patch)
tree3ffa30d58dac22ee0a80e2dd32f41b71da91132b /drivers/usb/dwc3/gadget.c
parentMerge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net (diff)
parentRevert "USB: serial: ftdi_sio: add Id for Physik Instrumente E-870" (diff)
downloadkernel-qcow2-linux-ac9053d2dcb9e8c3fa35ce458dfca8fddc141680.tar.gz
kernel-qcow2-linux-ac9053d2dcb9e8c3fa35ce458dfca8fddc141680.tar.xz
kernel-qcow2-linux-ac9053d2dcb9e8c3fa35ce458dfca8fddc141680.zip
Merge tag 'usb-4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB/PHY updates from Greg KH: "Here is the big set of USB and PHY driver patches for 4.17-rc1. Lots of USB typeC work happened this round, with code moving from the staging directory into the "real" part of the kernel, as well as new infrastructure being added to be able to handle the different types of "roles" that typeC requires. There is also the normal huge set of USB gadget controller and driver updates, along with XHCI changes, and a raft of other tiny fixes all over the USB tree. And the PHY driver updates are merged in here as well as they interacted with the USB drivers in some places. All of these have been in linux-next for a while with no reported issues" * tag 'usb-4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (250 commits) Revert "USB: serial: ftdi_sio: add Id for Physik Instrumente E-870" usb: musb: gadget: misplaced out of bounds check usb: chipidea: imx: Fix ULPI on imx53 usb: chipidea: imx: Cleanup ci_hdrc_imx_platform_flag usb: chipidea: usbmisc: small clean up usb: chipidea: usbmisc: evdo can be set e/o reset usb: chipidea: usbmisc: evdo is only specific to OTG port USB: serial: ftdi_sio: add Id for Physik Instrumente E-870 usb: dwc3: gadget: never call ->complete() from ->ep_queue() usb: gadget: udc: core: update usb_ep_queue() documentation usb: host: Remove the deprecated ATH79 USB host config options usb: roles: Fix return value check in intel_xhci_usb_probe() USB: gadget: f_midi: fixing a possible double-free in f_midi usb: core: Add USB_QUIRK_DELAY_CTRL_MSG to usbcore quirks usb: core: Copy parameter string correctly and remove superfluous null check USB: announce bcdDevice as well as idVendor, idProduct. USB:fix USB3 devices behind USB3 hubs not resuming at hibernate thaw usb: hub: Reduce warning to notice on power loss USB: serial: ftdi_sio: add support for Harman FirmwareHubEmulator USB: serial: cp210x: add ELDAT Easywave RX09 id ...
Diffstat (limited to 'drivers/usb/dwc3/gadget.c')
-rw-r--r--drivers/usb/dwc3/gadget.c82
1 files changed, 58 insertions, 24 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 2bda4eb1e9ac..8796a5ee9bb9 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -166,18 +166,8 @@ static void dwc3_ep_inc_deq(struct dwc3_ep *dep)
dwc3_ep_inc_trb(&dep->trb_dequeue);
}
-/**
- * dwc3_gadget_giveback - call struct usb_request's ->complete callback
- * @dep: The endpoint to whom the request belongs to
- * @req: The request we're giving back
- * @status: completion code for the request
- *
- * Must be called with controller's lock held and interrupts disabled. This
- * function will unmap @req and call its ->complete() callback to notify upper
- * layers that it has completed.
- */
-void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
- int status)
+void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep,
+ struct dwc3_request *req, int status)
{
struct dwc3 *dwc = dep->dwc;
@@ -190,18 +180,35 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
if (req->trb)
usb_gadget_unmap_request_by_dev(dwc->sysdev,
- &req->request, req->direction);
+ &req->request, req->direction);
req->trb = NULL;
-
trace_dwc3_gadget_giveback(req);
+ if (dep->number > 1)
+ pm_runtime_put(dwc->dev);
+}
+
+/**
+ * dwc3_gadget_giveback - call struct usb_request's ->complete callback
+ * @dep: The endpoint to whom the request belongs to
+ * @req: The request we're giving back
+ * @status: completion code for the request
+ *
+ * Must be called with controller's lock held and interrupts disabled. This
+ * function will unmap @req and call its ->complete() callback to notify upper
+ * layers that it has completed.
+ */
+void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
+ int status)
+{
+ struct dwc3 *dwc = dep->dwc;
+
+ dwc3_gadget_del_and_unmap_request(dep, req, status);
+
spin_unlock(&dwc->lock);
usb_gadget_giveback_request(&dep->endpoint, &req->request);
spin_lock(&dwc->lock);
-
- if (dep->number > 1)
- pm_runtime_put(dwc->dev);
}
/**
@@ -1227,7 +1234,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep)
if (req->trb)
memset(req->trb, 0, sizeof(struct dwc3_trb));
dep->queued_requests--;
- dwc3_gadget_giveback(dep, req, ret);
+ dwc3_gadget_del_and_unmap_request(dep, req, ret);
return ret;
}
@@ -1858,7 +1865,11 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
* bursts of data without going through any sort of endpoint throttling.
*/
reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG);
- reg &= ~DWC3_GRXTHRCFG_PKTCNTSEL;
+ if (dwc3_is_usb31(dwc))
+ reg &= ~DWC31_GRXTHRCFG_PKTCNTSEL;
+ else
+ reg &= ~DWC3_GRXTHRCFG_PKTCNTSEL;
+
dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);
dwc3_gadget_setup_nump(dwc);
@@ -1950,6 +1961,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
int epnum;
+ u32 tmo_eps = 0;
spin_lock_irqsave(&dwc->lock, flags);
@@ -1960,6 +1972,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
struct dwc3_ep *dep = dwc->eps[epnum];
+ int ret;
if (!dep)
continue;
@@ -1967,9 +1980,24 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING))
continue;
- wait_event_lock_irq(dep->wait_end_transfer,
- !(dep->flags & DWC3_EP_END_TRANSFER_PENDING),
- dwc->lock);
+ ret = wait_event_interruptible_lock_irq_timeout(dep->wait_end_transfer,
+ !(dep->flags & DWC3_EP_END_TRANSFER_PENDING),
+ dwc->lock, msecs_to_jiffies(5));
+
+ if (ret <= 0) {
+ /* Timed out or interrupted! There's nothing much
+ * we can do so we just log here and print which
+ * endpoints timed out at the end.
+ */
+ tmo_eps |= 1 << epnum;
+ dep->flags &= DWC3_EP_END_TRANSFER_PENDING;
+ }
+ }
+
+ if (tmo_eps) {
+ dev_err(dwc->dev,
+ "end transfer timed out on endpoints 0x%x [bitmap]\n",
+ tmo_eps);
}
out:
@@ -2023,7 +2051,10 @@ static void dwc3_gadget_set_speed(struct usb_gadget *g,
reg |= DWC3_DCFG_SUPERSPEED;
break;
case USB_SPEED_SUPER_PLUS:
- reg |= DWC3_DCFG_SUPERSPEED_PLUS;
+ if (dwc3_is_usb31(dwc))
+ reg |= DWC3_DCFG_SUPERSPEED_PLUS;
+ else
+ reg |= DWC3_DCFG_SUPERSPEED;
break;
default:
dev_err(dwc->dev, "invalid speed (%d)\n", speed);
@@ -2101,7 +2132,10 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc, u8 total)
mdwidth /= 8;
size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(num));
- size = DWC3_GTXFIFOSIZ_TXFDEF(size);
+ if (dwc3_is_usb31(dwc))
+ size = DWC31_GTXFIFOSIZ_TXFDEF(size);
+ else
+ size = DWC3_GTXFIFOSIZ_TXFDEF(size);
/* FIFO Depth is in MDWDITH bytes. Multiply */
size *= mdwidth;