]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/commitdiff
usb: dwc3: gadget: Correct handling of scattergather lists
authorAnurag Kumar Vulisha <anuragku@xilinx.com>
Tue, 27 Mar 2018 11:05:20 +0000 (16:35 +0530)
committerFelipe Balbi <felipe.balbi@linux.intel.com>
Mon, 21 May 2018 07:00:47 +0000 (10:00 +0300)
The code logic in dwc3_prepare_one_trb() incorrectly uses the address
and length fields present in req packet for mapping TRB's instead of
using the address and length fields of scattergather lists. This patch
correct's the code to use sg->address and sg->length when scattergather
lists are present.

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 1765e014aa081eb2080ca5f488cd3829fd2f4325..b6ca898a65d0045d2c55f1356a89b4ba06824a3a 100644 (file)
@@ -832,6 +832,7 @@ struct dwc3_hwparams {
  * @list: a list_head used for request queueing
  * @dep: struct dwc3_ep owning this request
  * @sg: pointer to first incomplete sg
+ * @start_sg: pointer to the sg which should be queued next
  * @num_pending_sgs: counter to pending sgs
  * @remaining: amount of data remaining
  * @epnum: endpoint number to which this request refers
@@ -848,6 +849,7 @@ struct dwc3_request {
        struct list_head        list;
        struct dwc3_ep          *dep;
        struct scatterlist      *sg;
+       struct scatterlist      *start_sg;
 
        unsigned                num_pending_sgs;
        unsigned                remaining;
index 8796a5ee9bb95fe2e9e0b0455d3ae55614ca9bef..56ca1666b35fe8b20459a3a849597bddcb84924c 100644 (file)
@@ -985,11 +985,19 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
                struct dwc3_request *req, unsigned chain, unsigned node)
 {
        struct dwc3_trb         *trb;
-       unsigned                length = req->request.length;
+       unsigned int            length;
+       dma_addr_t              dma;
        unsigned                stream_id = req->request.stream_id;
        unsigned                short_not_ok = req->request.short_not_ok;
        unsigned                no_interrupt = req->request.no_interrupt;
-       dma_addr_t              dma = req->request.dma;
+
+       if (req->request.num_sgs > 0) {
+               length = sg_dma_len(req->start_sg);
+               dma = sg_dma_address(req->start_sg);
+       } else {
+               length = req->request.length;
+               dma = req->request.dma;
+       }
 
        trb = &dep->trb_pool[dep->trb_enqueue];
 
@@ -1055,7 +1063,7 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep)
 static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
                struct dwc3_request *req)
 {
-       struct scatterlist *sg = req->sg;
+       struct scatterlist *sg = req->start_sg;
        struct scatterlist *s;
        int             i;
 
@@ -1088,6 +1096,16 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
                        dwc3_prepare_one_trb(dep, req, chain, i);
                }
 
+               /*
+                * There can be a situation where all sgs in sglist are not
+                * queued because of insufficient trb number. To handle this
+                * case, update start_sg to next sg to be queued, so that
+                * we have free trbs we can continue queuing from where we
+                * previously stopped
+                */
+               if (chain)
+                       req->start_sg = sg_next(s);
+
                if (!dwc3_calc_trbs_left(dep))
                        break;
        }
@@ -1178,6 +1196,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)
                        return;
 
                req->sg                 = req->request.sg;
+               req->start_sg           = req->sg;
                req->num_pending_sgs    = req->request.num_mapped_sgs;
 
                if (req->num_pending_sgs > 0)