Skip to content

Commit cf3113d

Browse files
author
Felipe Balbi
committed
usb: dwc3: gadget: properly increment dequeue pointer on ep_dequeue
If request was already started, this means we had to stop the transfer. With that we also need to ignore all TRBs used by the request, however TRBs can only be modified after completion of END_TRANSFER command. So what we have to do here is wait for END_TRANSFER completion and only after that jump over TRBs by clearing HWO and incrementing dequeue pointer. Note that we have 2 possible types of transfers here: i) Linear buffer request ii) SG-list based request SG-list based requests will have r->num_pending_sgs set to a valid number (> 0). Linear requests, normally use a single TRB. For each of these two cases, if r->unaligned flag is set, one extra TRB has been used to align transfer size to wMaxPacketSize. All of these cases need to be taken into consideration so we don't mess up our TRB ring pointers. Tested-by: Janusz Dziedzic <[email protected]> Signed-off-by: Felipe Balbi <[email protected]>
1 parent 2bfa071 commit cf3113d

File tree

1 file changed

+63
-0
lines changed

1 file changed

+63
-0
lines changed

drivers/usb/dwc3/gadget.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,6 +1342,68 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
13421342
if (r == req) {
13431343
/* wait until it is processed */
13441344
dwc3_stop_active_transfer(dwc, dep->number, true);
1345+
1346+
/*
1347+
* If request was already started, this means we had to
1348+
* stop the transfer. With that we also need to ignore
1349+
* all TRBs used by the request, however TRBs can only
1350+
* be modified after completion of END_TRANSFER
1351+
* command. So what we do here is that we wait for
1352+
* END_TRANSFER completion and only after that, we jump
1353+
* over TRBs by clearing HWO and incrementing dequeue
1354+
* pointer.
1355+
*
1356+
* Note that we have 2 possible types of transfers here:
1357+
*
1358+
* i) Linear buffer request
1359+
* ii) SG-list based request
1360+
*
1361+
* SG-list based requests will have r->num_pending_sgs
1362+
* set to a valid number (> 0). Linear requests,
1363+
* normally use a single TRB.
1364+
*
1365+
* For each of these two cases, if r->unaligned flag is
1366+
* set, one extra TRB has been used to align transfer
1367+
* size to wMaxPacketSize.
1368+
*
1369+
* All of these cases need to be taken into
1370+
* consideration so we don't mess up our TRB ring
1371+
* pointers.
1372+
*/
1373+
wait_event_lock_irq(dep->wait_end_transfer,
1374+
!(dep->flags & DWC3_EP_END_TRANSFER_PENDING),
1375+
dwc->lock);
1376+
1377+
if (!r->trb)
1378+
goto out1;
1379+
1380+
if (r->num_pending_sgs) {
1381+
struct dwc3_trb *trb;
1382+
int i = 0;
1383+
1384+
for (i = 0; i < r->num_pending_sgs; i++) {
1385+
trb = r->trb + i;
1386+
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
1387+
dwc3_ep_inc_deq(dep);
1388+
}
1389+
1390+
if (r->unaligned) {
1391+
trb = r->trb + r->num_pending_sgs + 1;
1392+
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
1393+
dwc3_ep_inc_deq(dep);
1394+
}
1395+
} else {
1396+
struct dwc3_trb *trb = r->trb;
1397+
1398+
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
1399+
dwc3_ep_inc_deq(dep);
1400+
1401+
if (r->unaligned) {
1402+
trb = r->trb + 1;
1403+
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
1404+
dwc3_ep_inc_deq(dep);
1405+
}
1406+
}
13451407
goto out1;
13461408
}
13471409
dev_err(dwc->dev, "request %p was not queued to %s\n",
@@ -1352,6 +1414,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
13521414

13531415
out1:
13541416
/* giveback the request */
1417+
dep->queued_requests--;
13551418
dwc3_gadget_giveback(dep, req, -ECONNRESET);
13561419

13571420
out0:

0 commit comments

Comments
 (0)