usb: dwc3: ep0: improve handling of unaligned OUT requests
authorFelipe Balbi <felipe.balbi@linux.intel.com>
Fri, 7 Apr 2017 11:09:13 +0000 (14:09 +0300)
committerFelipe Balbi <felipe.balbi@linux.intel.com>
Tue, 11 Apr 2017 07:58:28 +0000 (10:58 +0300)
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 <felipe.balbi@linux.intel.com>
drivers/usb/dwc3/core.h
drivers/usb/dwc3/ep0.c
drivers/usb/dwc3/gadget.c

index bbb7c3f6749e6263e3b40a28815a3e0e7d001762..8dc416daa85c7b02329803371ff907ee613ebe51 100644 (file)
@@ -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;
index 3ba2309c837f9075095e772615ad596a48632aee..04249243e4d3ed53dd6dd799a1b317b141980f57 100644 (file)
@@ -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 {
index 4787d6f449fa05d055f6fdce3858e19a56588200..4dc80729ae11c3a7877a5ce1fa9632d0ff34d9d7 100644 (file)
@@ -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);