summaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3/gadget.c
diff options
context:
space:
mode:
authorAnurag Kumar Vulisha <anuragku@xilinx.com>2018-03-27 16:35:21 +0530
committerFelipe Balbi <felipe.balbi@linux.intel.com>2018-05-21 10:00:47 +0300
commitc96e6725db9d6a04ac1bee881e3034b636d9f71c (patch)
tree2c0e37dc8365e01f1cb8dfdf41c172b68e2fbef3 /drivers/usb/dwc3/gadget.c
parenta31e63b608ff78c77d8e033347239431d522fe5d (diff)
downloadop-kernel-dev-c96e6725db9d6a04ac1bee881e3034b636d9f71c.zip
op-kernel-dev-c96e6725db9d6a04ac1bee881e3034b636d9f71c.tar.gz
usb: dwc3: gadget: Correct the logic for queuing sgs
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>
Diffstat (limited to 'drivers/usb/dwc3/gadget.c')
-rw-r--r--drivers/usb/dwc3/gadget.c23
1 files changed, 20 insertions, 3 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 56ca166..43cbc36 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -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);
OpenPOWER on IntegriCloud