aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3/ep0.c
diff options
context:
space:
mode:
authorFelipe Balbi <felipe.balbi@linux.intel.com>2017-04-07 16:34:38 +0300
committerFelipe Balbi <felipe.balbi@linux.intel.com>2017-04-11 10:58:29 +0300
commitd6e5a549cc4dba504a62855d9613836f76950790 (patch)
tree1804ea4768e2e880ae475f31ba3bf8b26c3c7dc3 /drivers/usb/dwc3/ep0.c
parentusb: dwc3: ep0: improve handling of unaligned OUT requests (diff)
downloadlinux-dev-d6e5a549cc4dba504a62855d9613836f76950790.tar.xz
linux-dev-d6e5a549cc4dba504a62855d9613836f76950790.zip
usb: dwc3: simplify ZLP handling
It's much simpler to just add one extra TRB chained to previous TRB to handle ZLP. This helps us reduce pointless allocations and simplifies the code a little bit. Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Diffstat (limited to 'drivers/usb/dwc3/ep0.c')
-rw-r--r--drivers/usb/dwc3/ep0.c49
1 files changed, 29 insertions, 20 deletions
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 04249243e4d3..a78c78e7a8c3 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -873,34 +873,19 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
transferred = ur->length - length;
ur->actual += transferred;
- if (dwc->ep0_bounced) {
+ if ((IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) &&
+ ur->length && ur->zero) || dwc->ep0_bounced) {
trb++;
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
+ trace_dwc3_complete_trb(ep0, trb);
ep0->trb_enqueue = 0;
dwc->ep0_bounced = false;
}
- if ((epnum & 1) && ur->actual < ur->length) {
- /* for some reason we did not get everything out */
-
+ if ((epnum & 1) && ur->actual < ur->length)
dwc3_ep0_stall_and_restart(dwc);
- } else {
+ else
dwc3_gadget_giveback(ep0, r, 0);
-
- if (IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) &&
- ur->length && ur->zero) {
- struct dwc3_ep *dep;
- int ret;
-
- dwc->ep0_next_event = DWC3_EP0_COMPLETE;
-
- dep = dwc->eps[epnum];
- dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr,
- 0, DWC3_TRBCTL_CONTROL_DATA, false);
- ret = dwc3_ep0_start_trans(dep);
- WARN_ON(ret < 0);
- }
- }
}
static void dwc3_ep0_complete_status(struct dwc3 *dwc,
@@ -1005,6 +990,30 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
DWC3_TRBCTL_CONTROL_DATA,
false);
ret = dwc3_ep0_start_trans(dep);
+ } else if (IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) &&
+ req->request.length && req->request.zero) {
+ u32 maxpacket;
+ u32 rem;
+
+ ret = usb_gadget_map_request_by_dev(dwc->sysdev,
+ &req->request, dep->number);
+ if (ret)
+ return;
+
+ maxpacket = dep->endpoint.maxpacket;
+ rem = req->request.length % maxpacket;
+
+ /* prepare normal TRB */
+ dwc3_ep0_prepare_one_trb(dep, req->request.dma,
+ req->request.length,
+ DWC3_TRBCTL_CONTROL_DATA,
+ true);
+
+ /* Now prepare one extra TRB to align transfer size */
+ dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
+ 0, DWC3_TRBCTL_CONTROL_DATA,
+ false);
+ ret = dwc3_ep0_start_trans(dep);
} else {
ret = usb_gadget_map_request_by_dev(dwc->sysdev,
&req->request, dep->number);