lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <1521442253-15906-1-git-send-email-anuragku@xilinx.com>
Date:   Mon, 19 Mar 2018 12:20:53 +0530
From:   Anurag Kumar Vulisha <anurag.kumar.vulisha@...inx.com>
To:     Felipe Balbi <balbi@...nel.org>,
        Greg Kroah-Hartman <gregkh@...uxfoundation.org>
CC:     <v.anuragkumar@...il.com>, <APANDEY@...inx.com>,
        <linux-usb@...r.kernel.org>, <linux-kernel@...r.kernel.org>,
        Anurag Kumar Vulisha <anuragku@...inx.com>
Subject: [PATCH] usb: dwc3: gadget: Correct the logic for queuing sgs

This patch fixes two issues

1. The code logic in dwc3_prepare_one_trb() incorrectly uses the address
and length given in req packet even for scattergather lists. This patch
correct's the code to use sg->address and sg->length when scattergather
lists are present.

2. The present code correctly fetches the req's which were not queued from
the started_list but fails to start from the sg where it previously stopped
queuing because of the unavailable TRB's. This patch correct's the code to
start queuing from the correct sg in sglist.

Signed-off-by: Anurag Kumar Vulisha <anuragku@...inx.com>
---
 drivers/usb/dwc3/core.h   |  4 ++++
 drivers/usb/dwc3/gadget.c | 42 ++++++++++++++++++++++++++++++++++++------
 2 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 860d2bc..2779e58 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -718,7 +718,9 @@ struct dwc3_hwparams {
  * @list: a list_head used for request queueing
  * @dep: struct dwc3_ep owning this request
  * @sg: pointer to first incomplete sg
+ * @sg_to_start: 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
@@ -734,8 +736,10 @@ struct dwc3_request {
        struct list_head        list;
        struct dwc3_ep          *dep;
        struct scatterlist      *sg;
+       struct scatterlist      *sg_to_start;

        unsigned                num_pending_sgs;
+       unsigned int            num_queued_sgs;
        unsigned                remaining;
        u8                      epnum;
        struct dwc3_trb         *trb;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 2bda4eb..1cffed5 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -978,11 +978,20 @@ 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) {
+               /* Use scattergather list address and length */
+               length = sg_dma_len(req->sg_to_start);
+               dma = sg_dma_address(req->sg_to_start);
+       } else {
+               length = req->request.length;
+               dma = req->request.dma;
+       }

        trb = &dep->trb_pool[dep->trb_enqueue];

@@ -1048,11 +1057,14 @@ 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->sg_to_start;
        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;
@@ -1081,6 +1093,16 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
                        dwc3_prepare_one_trb(dep, req, chain, i);
                }

+               /* In the case where not able to queue trbs for all sgs in
+                * request because of trb not available, update sg_to_start
+                * to next sg from which we can start queing trbs once trbs
+                * availbale
+                */
+               if (chain)
+                       req->sg_to_start = sg_next(s);
+
+               req->num_queued_sgs++;
+
                if (!dwc3_calc_trbs_left(dep))
                        break;
        }
@@ -1171,6 +1193,8 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)
                        return;

                req->sg                 = req->request.sg;
+               req->sg_to_start        = req->sg;
+               req->num_queued_sgs     = 0;
                req->num_pending_sgs    = req->request.num_mapped_sgs;

                if (req->num_pending_sgs > 0)
@@ -2327,8 +2351,14 @@ 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 cases where the whole req can't be
+                        * mapped into TRB's available. In that case, we need
+                        * to kick transfer again if (req->num_pending_sgs > 0)
+                        */
+                       if (req->num_pending_sgs)
+                               return __dwc3_gadget_kick_transfer(dep);
+               }

                dwc3_gadget_giveback(dep, req, status);

--
2.1.1

This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ