diff options
author | Peter Chen <peter.chen@nxp.com> | 2020-01-07 12:03:57 +0800 |
---|---|---|
committer | Peter Chen <peter.chen@nxp.com> | 2020-01-20 17:26:19 +0800 |
commit | f9e2ca657ff28801410a16aad9cd479b14f85ec4 (patch) | |
tree | e07bcdae439185279ba9b0deadd3dd83a8400c70 /drivers/usb/cdns3 | |
parent | 3e7c6dff3e9ee1d66e6beebad8d9e9f6b739483c (diff) |
MLK-23181-3 usb: cdns3: gadget: handle multiple trb request properly
We use polling EP_TRADDR to judge if the trb has finished, so for
request which includes multiple trb, we may quit the trb judgement
in the middle of request, in that case, we can't giveback the
request. We should only giveback the request when all the TRB in
this request has finished.
Reviewed-by: Jun Li <jun.li@nxp.com>
Signed-off-by: Peter Chen <peter.chen@nxp.com>
Diffstat (limited to 'drivers/usb/cdns3')
-rw-r--r-- | drivers/usb/cdns3/gadget.c | 13 | ||||
-rw-r--r-- | drivers/usb/cdns3/gadget.h | 4 |
2 files changed, 13 insertions, 4 deletions
diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index c7b163700bd4..b8c1a3e00cc1 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -451,6 +451,8 @@ void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep, request->length); priv_req->flags &= ~(REQUEST_PENDING | REQUEST_UNALIGNED); + /* All TRBs have finished, clear the flag */ + priv_req->finished_trb = 0; trace_cdns3_gadget_giveback(priv_req); /* WA2: */ @@ -700,6 +702,7 @@ int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, trb = priv_req->trb; priv_req->flags |= REQUEST_PENDING; + priv_req->num_of_trb = num_trb; /* give the TD to the consumer*/ if (sg_iter == 1) @@ -884,7 +887,7 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev, struct cdns3_request *priv_req; struct usb_request *request; struct cdns3_trb *trb; - bool trb_handled = false; + bool request_handled = false; while (!list_empty(&priv_ep->pending_req_list)) { request = cdns3_next_request(&priv_ep->pending_req_list); @@ -896,7 +899,9 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev, cdns3_select_ep(priv_dev, priv_ep->endpoint.address); while (cdns3_request_handled(priv_ep, priv_req)) { - trb_handled = true; + priv_req->finished_trb++; + if (priv_req->finished_trb >= priv_req->num_of_trb) + request_handled = true; trb = priv_ep->trb_pool + priv_ep->dequeue; trace_cdns3_complete_trb(priv_ep, trb); @@ -904,9 +909,9 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev, cdns3_ep_inc_deq(priv_ep); } - if (trb_handled) { + if (request_handled) { cdns3_gadget_giveback(priv_ep, priv_req, 0); - trb_handled = false; + request_handled = false; } else { return; } diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h index bd470afa25ce..0c9c94f5de19 100644 --- a/drivers/usb/cdns3/gadget.h +++ b/drivers/usb/cdns3/gadget.h @@ -1125,6 +1125,8 @@ struct cdns3_aligned_buf { * this endpoint * @flags: flag specifying special usage of request * @list: used by internally allocated request to add to descmiss_req_list. + * @finished_trb: number of trb has already finished per request + * @num_of_trb: how many trbs in this request */ struct cdns3_request { struct usb_request request; @@ -1140,6 +1142,8 @@ struct cdns3_request { #define REQUEST_UNALIGNED BIT(4) u32 flags; struct list_head list; + int finished_trb; + int num_of_trb; }; #define to_cdns3_request(r) (container_of(r, struct cdns3_request, request)) |