> >If there are TRBs pending during clear stall and reset endpoint, the >DMA will advance after reset operation, but it doesn't be expected, >since the data has still not be ready (For OUT, the data has still >not received). After the data is ready, there isn't any interrupt >since the EP_TRADDR has already points to next TRB entry. > >To fix it, it toggles cyclt bit before reset operation, and restore >it after reset, it could keep DMA stopping. > >Fixes: 7733f6c32e36 ("usb: cdns3: Add Cadence USB3 DRD Driver") >Signed-off-by: Peter Chen <peter.chen@xxxxxxx> >--- > drivers/usb/cdns3/gadget.c | 17 ++++++++++++++--- > 1 file changed, 14 insertions(+), 3 deletions(-) > >diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c >index 1d8a2af35bb0..7b6bb96b91d1 100644 >--- a/drivers/usb/cdns3/gadget.c >+++ b/drivers/usb/cdns3/gadget.c >@@ -2595,11 +2595,21 @@ int __cdns3_gadget_ep_clear_halt(struct cdns3_endpoint *priv_ep) > { > struct cdns3_device *priv_dev = priv_ep->cdns3_dev; > struct usb_request *request; >+ struct cdns3_request *priv_req; >+ struct cdns3_trb *trb = NULL; > int ret; > int val; > > trace_cdns3_halt(priv_ep, 0, 0); > >+ request = cdns3_next_request(&priv_ep->pending_req_list); >+ if (request) { >+ priv_req = to_cdns3_request(request); >+ trb = priv_req->trb; >+ if (trb) >+ trb->control = trb->control ^ 1; >+ } >+ What about doing simple read/write on ep_traddr register: u32 ep_traddr; ep_traddr = readl(&priv_dev->regs->ep_traddr); > writel(EP_CMD_CSTALL | EP_CMD_EPRST, &priv_dev->regs->ep_cmd); writel(&priv_dev->regs->ep_traddr, ep_traddr); It should work in the same way but is simpler. And maybe we could add some comment because this code look little strange. Something like: When endpoint is armed during endpoint reset the controller can advance TRADDR to next TD, so driver need to restore the previous value. > > /* wait for EPRST cleared */ >@@ -2610,10 +2620,11 @@ int __cdns3_gadget_ep_clear_halt(struct cdns3_endpoint *priv_ep) > > priv_ep->flags &= ~(EP_STALLED | EP_STALL_PENDING); > >- request = cdns3_next_request(&priv_ep->pending_req_list); >- >- if (request) >+ if (request) { >+ if (trb) >+ trb->control = trb->control ^ 1; > cdns3_rearm_transfer(priv_ep, 1); >+ } > > cdns3_start_all_request(priv_dev, priv_ep); > return ret; >-- >2.17.1