summaryrefslogtreecommitdiff
path: root/drivers/usb/cdns3
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@nxp.com>2020-01-07 12:03:57 +0800
committerPeter Chen <peter.chen@nxp.com>2020-01-20 17:26:19 +0800
commitf9e2ca657ff28801410a16aad9cd479b14f85ec4 (patch)
treee07bcdae439185279ba9b0deadd3dd83a8400c70 /drivers/usb/cdns3
parent3e7c6dff3e9ee1d66e6beebad8d9e9f6b739483c (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.c13
-rw-r--r--drivers/usb/cdns3/gadget.h4
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))