From: Peter Chen peter.chen@nxp.com
commit 4bf2dd65135a2d7fe202f7c10d65b51bcf645ac6 upstream.
If there are TRBs pending during reset endpoint operation, the DMA will advance after reset operation, but it isn't expected, since the data is not yet available (For OUT, the data is not yet available). After the data is ready, there won't be any interrupt since the EP_TRADDR already points to next TRB entry and doorbell is not set.
To fix it, it toggles cycle bit before reset operation, and restores it after reset, it could avoid unexpected DMA advance due to cycle bit is for software during the endpoint reset operation.
Fixes: 7733f6c32e36 ("usb: cdns3: Add Cadence USB3 DRD Driver") Signed-off-by: Peter Chen peter.chen@nxp.com Cc: stable stable@vger.kernel.org Link: https://lore.kernel.org/r/20200219141455.23257-3-peter.chen@nxp.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/usb/cdns3/gadget.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-)
--- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -2152,11 +2152,21 @@ int __cdns3_gadget_ep_clear_halt(struct { 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 ^ TRB_CYCLE; + } + writel(EP_CMD_CSTALL | EP_CMD_EPRST, &priv_dev->regs->ep_cmd);
/* wait for EPRST cleared */ @@ -2167,10 +2177,11 @@ int __cdns3_gadget_ep_clear_halt(struct
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 ^ TRB_CYCLE; cdns3_rearm_transfer(priv_ep, 1); + }
cdns3_start_all_request(priv_dev, priv_ep); return ret;