From 4199c5f8bccd7ff6923c32af0f8ef0224eeaa651 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 7 Apr 2017 14:09:13 +0300 Subject: [PATCH] usb: dwc3: ep0: improve handling of unaligned OUT requests Just like we did for all other endpoint types, let's rely on a chained TRB pointing to ep0_bounce_addr in order to align transfer size. This will make the code simpler. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 6 +--- drivers/usb/dwc3/ep0.c | 65 +++++++++++---------------------------- drivers/usb/dwc3/gadget.c | 50 ++++++------------------------ 3 files changed, 29 insertions(+), 92 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index bbb7c3f6749e..8dc416daa85c 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -42,7 +42,7 @@ #define DWC3_PULL_UP_TIMEOUT 500 /* ms */ #define DWC3_ZLP_BUF_SIZE 1024 /* size of a superspeed bulk */ #define DWC3_BOUNCE_SIZE 1024 /* size of a superspeed bulk */ -#define DWC3_EP0_BOUNCE_SIZE 512 +#define DWC3_EP0_SETUP_SIZE 512 #define DWC3_ENDPOINTS_NUM 32 #define DWC3_XHCI_RESOURCES_NUM 2 @@ -761,12 +761,10 @@ struct dwc3_scratchpad_array { /** * struct dwc3 - representation of our controller * @ep0_trb: trb which is used for the ctrl_req - * @ep0_bounce: bounce buffer for ep0 * @zlp_buf: used when request->zero is set * @setup_buf: used while precessing STD USB requests * @ep0_trb: dma address of ep0_trb * @ep0_usb_req: dummy req used while handling STD USB requests - * @ep0_bounce_addr: dma address of ep0_bounce * @scratch_addr: dma address of scratchbuf * @ep0_in_setup: one control transfer is completed and enter setup phase * @lock: for synchronizing @@ -859,13 +857,11 @@ struct dwc3_scratchpad_array { struct dwc3 { struct dwc3_trb *ep0_trb; void *bounce; - void *ep0_bounce; void *zlp_buf; void *scratchbuf; u8 *setup_buf; dma_addr_t ep0_trb_addr; dma_addr_t bounce_addr; - dma_addr_t ep0_bounce_addr; dma_addr_t scratch_addr; struct dwc3_request ep0_usb_req; struct completion ep0_in_setup; diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 3ba2309c837f..04249243e4d3 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -836,7 +836,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, struct usb_request *ur; struct dwc3_trb *trb; struct dwc3_ep *ep0; - unsigned transfer_size = 0; unsigned maxp; unsigned remaining_ur_length; void *buf; @@ -849,9 +848,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, ep0 = dwc->eps[0]; dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS; - trb = dwc->ep0_trb; - trace_dwc3_complete_trb(ep0, trb); r = next_request(&ep0->pending_list); @@ -872,39 +869,17 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, remaining_ur_length = ur->length; length = trb->size & DWC3_TRB_SIZE_MASK; - maxp = ep0->endpoint.maxpacket; + transferred = ur->length - length; + ur->actual += transferred; if (dwc->ep0_bounced) { - /* - * Handle the first TRB before handling the bounce buffer if - * the request length is greater than the bounce buffer size - */ - if (ur->length > DWC3_EP0_BOUNCE_SIZE) { - transfer_size = ALIGN(ur->length - maxp, maxp); - transferred = transfer_size - length; - buf = (u8 *)buf + transferred; - ur->actual += transferred; - remaining_ur_length -= transferred; - - trb++; - length = trb->size & DWC3_TRB_SIZE_MASK; - - ep0->trb_enqueue = 0; - } - - transfer_size = roundup((ur->length - transfer_size), - maxp); - - transferred = min_t(u32, remaining_ur_length, - transfer_size - length); - memcpy(buf, dwc->ep0_bounce, transferred); - } else { - transferred = ur->length - length; + trb++; + trb->ctrl &= ~DWC3_TRB_CTRL_HWO; + ep0->trb_enqueue = 0; + dwc->ep0_bounced = false; } - ur->actual += transferred; - if ((epnum & 1) && ur->actual < ur->length) { /* for some reason we did not get everything out */ @@ -1006,8 +981,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, ret = dwc3_ep0_start_trans(dep); } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) && (dep->number == 0)) { - u32 transfer_size = 0; u32 maxpacket; + u32 rem; ret = usb_gadget_map_request_by_dev(dwc->sysdev, &req->request, dep->number); @@ -1015,23 +990,19 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, return; maxpacket = dep->endpoint.maxpacket; - - if (req->request.length > DWC3_EP0_BOUNCE_SIZE) { - transfer_size = ALIGN(req->request.length - maxpacket, - maxpacket); - dwc3_ep0_prepare_one_trb(dep, req->request.dma, - transfer_size, - DWC3_TRBCTL_CONTROL_DATA, - true); - } - - transfer_size = roundup((req->request.length - transfer_size), - maxpacket); - + rem = req->request.length % maxpacket; dwc->ep0_bounced = true; - dwc3_ep0_prepare_one_trb(dep, dwc->ep0_bounce_addr, - transfer_size, DWC3_TRBCTL_CONTROL_DATA, + /* 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, + maxpacket - rem, + DWC3_TRBCTL_CONTROL_DATA, false); ret = dwc3_ep0_start_trans(dep); } else { diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 4787d6f449fa..4dc80729ae11 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -171,7 +171,6 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, int status) { struct dwc3 *dwc = dep->dwc; - unsigned int unmap_after_complete = false; req->started = false; list_del(&req->list); @@ -181,19 +180,8 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, if (req->request.status == -EINPROGRESS) req->request.status = status; - /* - * NOTICE we don't want to unmap before calling ->complete() if we're - * dealing with a bounced ep0 request. If we unmap it here, we would end - * up overwritting the contents of req->buf and this could confuse the - * gadget driver. - */ - if (dwc->ep0_bounced && dep->number <= 1) { - dwc->ep0_bounced = false; - unmap_after_complete = true; - } else { - usb_gadget_unmap_request_by_dev(dwc->sysdev, - &req->request, req->direction); - } + usb_gadget_unmap_request_by_dev(dwc->sysdev, + &req->request, req->direction); trace_dwc3_gadget_giveback(req); @@ -201,10 +189,6 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, usb_gadget_giveback_request(&dep->endpoint, &req->request); spin_lock(&dwc->lock); - if (unmap_after_complete) - usb_gadget_unmap_request_by_dev(dwc->sysdev, - &req->request, req->direction); - if (dep->number > 1) pm_runtime_put(dwc->dev); } @@ -3153,32 +3137,23 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err0; } - dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL); + dwc->setup_buf = kzalloc(DWC3_EP0_SETUP_SIZE, GFP_KERNEL); if (!dwc->setup_buf) { ret = -ENOMEM; goto err1; } - dwc->ep0_bounce = dma_alloc_coherent(dwc->sysdev, - DWC3_EP0_BOUNCE_SIZE, &dwc->ep0_bounce_addr, - GFP_KERNEL); - if (!dwc->ep0_bounce) { - dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n"); - ret = -ENOMEM; - goto err2; - } - dwc->zlp_buf = kzalloc(DWC3_ZLP_BUF_SIZE, GFP_KERNEL); if (!dwc->zlp_buf) { ret = -ENOMEM; - goto err3; + goto err2; } dwc->bounce = dma_alloc_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, &dwc->bounce_addr, GFP_KERNEL); if (!dwc->bounce) { ret = -ENOMEM; - goto err4; + goto err3; } init_completion(&dwc->ep0_in_setup); @@ -3218,7 +3193,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) ret = dwc3_gadget_init_endpoints(dwc, dwc->num_eps); if (ret) - goto err5; + goto err4; ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget); if (ret) { @@ -3228,16 +3203,14 @@ int dwc3_gadget_init(struct dwc3 *dwc) return 0; err5: - dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce, - dwc->bounce_addr); + dwc3_gadget_free_endpoints(dwc); err4: - kfree(dwc->zlp_buf); + dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce, + dwc->bounce_addr); err3: - dwc3_gadget_free_endpoints(dwc); - dma_free_coherent(dwc->sysdev, DWC3_EP0_BOUNCE_SIZE, - dwc->ep0_bounce, dwc->ep0_bounce_addr); + kfree(dwc->zlp_buf); err2: kfree(dwc->setup_buf); @@ -3260,9 +3233,6 @@ void dwc3_gadget_exit(struct dwc3 *dwc) dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce, dwc->bounce_addr); - dma_free_coherent(dwc->sysdev, DWC3_EP0_BOUNCE_SIZE, - dwc->ep0_bounce, dwc->ep0_bounce_addr); - kfree(dwc->setup_buf); kfree(dwc->zlp_buf); -- 2.39.5