usb: cdns3: gadget: fix new urb never complete if ep cancel previous requests
commit 387c2b6ba197c6df28e75359f7d892f7c8dec204 upstream. This issue was found at android12 MTP. 1. MTP submit many out urb request. 2. Cancel left requests (>20) when enough data get from host 3. Send ACK by IN endpoint. 4. MTP submit new out urb request. 5. 4's urb never complete. TRACE LOG: MtpServer-2157 [000] d..3 1287.150391: cdns3_ep_dequeue: ep1out: req: 00000000299e6836, req buff 000000009df42287, length: 0/16384 zsi, status: -115, trb: [start:87, end:87: virt addr 0x80004000ffd50420], flags:1 SID: 0 MtpServer-2157 [000] d..3 1287.150410: cdns3_gadget_giveback: ep1out: req: 00000000299e6836, req buff 000000009df42287, length: 0/16384 zsi, status: -104, trb: [start:87, end:87: virt addr 0x80004000ffd50420], flags:0 SID: 0 MtpServer-2157 [000] d..3 1287.150433: cdns3_ep_dequeue: ep1out: req: 0000000080b7bde6, req buff 000000009ed5c556, length: 0/16384 zsi, status: -115, trb: [start:88, end:88: virt addr 0x80004000ffd5042c], flags:1 SID: 0 MtpServer-2157 [000] d..3 1287.150446: cdns3_gadget_giveback: ep1out: req: 0000000080b7bde6, req buff 000000009ed5c556, length: 0/16384 zsi, status: -104, trb: [start:88, end:88: virt addr 0x80004000ffd5042c], flags:0 SID: 0 .... MtpServer-2157 [000] d..1 1293.630410: cdns3_alloc_request: ep1out: req: 00000000afbccb7d, req buff 0000000000000000, length: 0/0 zsi, status: 0, trb: [start:0, end:0: virt addr (null)], flags:0 SID: 0 MtpServer-2157 [000] d..2 1293.630421: cdns3_ep_queue: ep1out: req: 00000000afbccb7d, req buff 00000000871caf90, length: 0/512 zsi, status: -115, trb: [start:0, end:0: virt addr (null)], flags:0 SID: 0 MtpServer-2157 [000] d..2 1293.630445: cdns3_wa1: WA1: ep1out set guard MtpServer-2157 [000] d..2 1293.630450: cdns3_wa1: WA1: ep1out restore cycle bit MtpServer-2157 [000] d..2 1293.630453: cdns3_prepare_trb: ep1out: trb 000000007317b3ee, dma buf: 0xffd5bc00, size: 512, burst: 128 ctrl: 0x00000424 (C=0, T=0, ISP, IOC, Normal) SID:0 LAST_SID:0 MtpServer-2157 [000] d..2 1293.630460: cdns3_doorbell_epx: ep1out, ep_trbaddr ffd50414 .... irq/241-5b13000-2154 [000] d..1 1293.680849: cdns3_epx_irq: IRQ for ep1out: 01000408 ISP , ep_traddr: ffd508ac ep_last_sid: 00000000 use_streams: 0 irq/241-5b13000-2154 [000] d..1 1293.680858: cdns3_complete_trb: ep1out: trb 0000000021a11b54, dma buf: 0xffd50420, size: 16384, burst: 128 ctrl: 0x00001810 (C=0, T=0, CHAIN, LINK) SID:0 LAST_SID:0 irq/241-5b13000-2154 [000] d..1 1293.680865: cdns3_request_handled: Req: 00000000afbccb7d not handled, DMA pos: 185, ep deq: 88, ep enq: 185, start trb: 184, end trb: 184 Actually DMA pos already bigger than previous submit request afbccb7d's TRB (184-184). The reason of (not handled) is that deq position is wrong. The TRB link is below when irq happen. DEQ LINK LINK LINK LINK LINK .... TRB(afbccb7d):START DMA(EP_TRADDR). Original code check LINK TRB, but DEQ just move one step. LINK DEQ LINK LINK LINK LINK .... TRB(afbccb7d):START DMA(EP_TRADDR). This patch skip all LINK TRB and sync DEQ to trb's start. LINK LINK LINK LINK LINK .... DEQ = TRB(afbccb7d):START DMA(EP_TRADDR). Acked-by: Peter Chen <peter.chen@kernel.org> Cc: stable <stable@vger.kernel.org> Signed-off-by: Frank Li <Frank.Li@nxp.com> Signed-off-by: Jun Li <jun.li@nxp.com> Link: https://lore.kernel.org/r/20211130154239.8029-1-Frank.Li@nxp.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
cfdb7032a4
commit
f4f77594cc
@ -337,19 +337,6 @@ static void cdns3_ep_inc_deq(struct cdns3_endpoint *priv_ep)
|
||||
cdns3_ep_inc_trb(&priv_ep->dequeue, &priv_ep->ccs, priv_ep->num_trbs);
|
||||
}
|
||||
|
||||
static void cdns3_move_deq_to_next_trb(struct cdns3_request *priv_req)
|
||||
{
|
||||
struct cdns3_endpoint *priv_ep = priv_req->priv_ep;
|
||||
int current_trb = priv_req->start_trb;
|
||||
|
||||
while (current_trb != priv_req->end_trb) {
|
||||
cdns3_ep_inc_deq(priv_ep);
|
||||
current_trb = priv_ep->dequeue;
|
||||
}
|
||||
|
||||
cdns3_ep_inc_deq(priv_ep);
|
||||
}
|
||||
|
||||
/**
|
||||
* cdns3_allow_enable_l1 - enable/disable permits to transition to L1.
|
||||
* @priv_dev: Extended gadget object
|
||||
@ -1517,10 +1504,11 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev,
|
||||
|
||||
trb = priv_ep->trb_pool + priv_ep->dequeue;
|
||||
|
||||
/* Request was dequeued and TRB was changed to TRB_LINK. */
|
||||
if (TRB_FIELD_TO_TYPE(le32_to_cpu(trb->control)) == TRB_LINK) {
|
||||
/* The TRB was changed as link TRB, and the request was handled at ep_dequeue */
|
||||
while (TRB_FIELD_TO_TYPE(le32_to_cpu(trb->control)) == TRB_LINK) {
|
||||
trace_cdns3_complete_trb(priv_ep, trb);
|
||||
cdns3_move_deq_to_next_trb(priv_req);
|
||||
cdns3_ep_inc_deq(priv_ep);
|
||||
trb = priv_ep->trb_pool + priv_ep->dequeue;
|
||||
}
|
||||
|
||||
if (!request->stream_id) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user