]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
usb: dwc3: gadget: Correct the logic for queuing sgs
authorAnurag Kumar Vulisha <anuragku@xilinx.com>
Tue, 27 Mar 2018 11:05:21 +0000 (16:35 +0530)
committerFelipe Balbi <felipe.balbi@linux.intel.com>
Mon, 21 May 2018 07:00:47 +0000 (10:00 +0300)
The present code correctly fetches the req which were previously not
queued from the started_list but fails to continue queuing from the sg
where it previously stopped queuing (because of the unavailable TRB's).
This patch correct's the code to continue queuing from the correct sg
present in the sglist.

For example, consider 5 sgs in req. Because of limited TRB's among the
5 sgs only 3 got queued. This patch corrects the code to start queuing
from correct sg i.e 4th sg when the TRBs are available.

Signed-off-by: Anurag Kumar Vulisha <anuragku@xilinx.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
drivers/usb/dwc3/core.h
drivers/usb/dwc3/gadget.c

index b6ca898a65d0045d2c55f1356a89b4ba06824a3a..ab93d22b69656663a6af068959669c7292503625 100644 (file)
@@ -834,6 +834,7 @@ struct dwc3_hwparams {
  * @sg: pointer to first incomplete sg
  * @start_sg: pointer to the sg which should be queued next
  * @num_pending_sgs: counter to pending sgs
+ * @num_queued_sgs: counter to the number of sgs which already got queued
  * @remaining: amount of data remaining
  * @epnum: endpoint number to which this request refers
  * @trb: pointer to struct dwc3_trb
@@ -852,6 +853,7 @@ struct dwc3_request {
        struct scatterlist      *start_sg;
 
        unsigned                num_pending_sgs;
+       unsigned int            num_queued_sgs;
        unsigned                remaining;
        u8                      epnum;
        struct dwc3_trb         *trb;
index 56ca1666b35fe8b20459a3a849597bddcb84924c..43cbc363c72fe92b072ce06a3ac8e8045719a84e 100644 (file)
@@ -1067,7 +1067,10 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
        struct scatterlist *s;
        int             i;
 
-       for_each_sg(sg, s, req->num_pending_sgs, i) {
+       unsigned int remaining = req->request.num_mapped_sgs
+               - req->num_queued_sgs;
+
+       for_each_sg(sg, s, remaining, i) {
                unsigned int length = req->request.length;
                unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
                unsigned int rem = length % maxp;
@@ -1106,6 +1109,8 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
                if (chain)
                        req->start_sg = sg_next(s);
 
+               req->num_queued_sgs++;
+
                if (!dwc3_calc_trbs_left(dep))
                        break;
        }
@@ -1197,6 +1202,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)
 
                req->sg                 = req->request.sg;
                req->start_sg           = req->sg;
+               req->num_queued_sgs     = 0;
                req->num_pending_sgs    = req->request.num_mapped_sgs;
 
                if (req->num_pending_sgs > 0)
@@ -2380,8 +2386,19 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
 
                req->request.actual = length - req->remaining;
 
-               if ((req->request.actual < length) && req->num_pending_sgs)
-                       return __dwc3_gadget_kick_transfer(dep);
+               if (req->request.actual < length || req->num_pending_sgs) {
+                       /*
+                        * There could be a scenario where the whole req can't
+                        * be mapped into available TRB's. In that case, we need
+                        * to kick transfer again if (req->num_pending_sgs > 0)
+                        */
+                       if (req->num_pending_sgs) {
+                               dev_WARN_ONCE(dwc->dev,
+                                             (req->request.actual == length),
+                                             "There are some pending sg's that needs to be queued again\n");
+                               return __dwc3_gadget_kick_transfer(dep);
+                       }
+               }
 
                dwc3_gadget_giveback(dep, req, status);