Linux-USB Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH] usb: cdns3: Fix dequeue implementation.
@ 2019-10-07 12:06 Pawel Laszczak
  2019-10-08  7:34 ` Peter Chen
  0 siblings, 1 reply; 4+ messages in thread
From: Pawel Laszczak @ 2019-10-07 12:06 UTC (permalink / raw)
  To: felipe.balbi
  Cc: gregkh, linux-usb, rogerq, linux-kernel, jbergsagel, nsekhar, nm,
	sureshp, peter.chen, kurahul, Pawel Laszczak

Dequeuing implementation in cdns3_gadget_ep_dequeu gets first request from
deferred_req_list and changed TRB associated with it to LINK TRB.
This approach is incorrect because deferred_req_list contains requests
that have not been placed on hardware RING.  In this case driver should
just giveback this request to gadget driver.

The patch implements new approach that first checks where dequeuing
request is located and only when it's on Transfer Ring then changes TRB
associated with it to LINK TRB.
During processing completed transfers such LINK TRB will be ignored.

Reported-by: Peter Chen <peter.chen@nxp.com>
Signed-off-by: Pawel Laszczak <pawell@cadence.com>
Fixes: 7733f6c32e36 ("usb: cdns3: Add Cadence USB3 DRD Driver")
---
 drivers/usb/cdns3/gadget.c | 35 ++++++++++++++++++++---------------
 1 file changed, 20 insertions(+), 15 deletions(-)

diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c
index 2ca280f4c054..9050b380ab83 100644
--- a/drivers/usb/cdns3/gadget.c
+++ b/drivers/usb/cdns3/gadget.c
@@ -1145,6 +1145,14 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev,
 		request = cdns3_next_request(&priv_ep->pending_req_list);
 		priv_req = to_cdns3_request(request);
 
+		trb = priv_ep->trb_pool + priv_ep->dequeue;
+
+		/* Request was dequeued and TRB was changed to TRB_LINK. */
+		if (TRB_FIELD_TO_TYPE(trb->control) == TRB_LINK) {
+			trace_cdns3_complete_trb(priv_ep, trb);
+			cdns3_move_deq_to_next_trb(priv_req);
+		}
+
 		/* Re-select endpoint. It could be changed by other CPU during
 		 * handling usb_gadget_giveback_request.
 		 */
@@ -2067,6 +2075,7 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
 	struct usb_request *req, *req_temp;
 	struct cdns3_request *priv_req;
 	struct cdns3_trb *link_trb;
+	u8 req_on_hw_ring = 0;
 	unsigned long flags;
 	int ret = 0;
 
@@ -2083,8 +2092,10 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
 
 	list_for_each_entry_safe(req, req_temp, &priv_ep->pending_req_list,
 				 list) {
-		if (request == req)
+		if (request == req) {
+			req_on_hw_ring = 1;
 			goto found;
+		}
 	}
 
 	list_for_each_entry_safe(req, req_temp, &priv_ep->deferred_req_list,
@@ -2096,27 +2107,21 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
 	goto not_found;
 
 found:
-
-	if (priv_ep->wa1_trb == priv_req->trb)
-		cdns3_wa1_restore_cycle_bit(priv_ep);
-
 	link_trb = priv_req->trb;
-	cdns3_move_deq_to_next_trb(priv_req);
-	cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET);
-
-	/* Update ring */
-	request = cdns3_next_request(&priv_ep->deferred_req_list);
-	if (request) {
-		priv_req = to_cdns3_request(request);
 
+	/* Update ring only if removed request is on pending_req_list list */
+	if (req_on_hw_ring) {
 		link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma +
 					      (priv_req->start_trb * TRB_SIZE));
 		link_trb->control = (link_trb->control & TRB_CYCLE) |
-				    TRB_TYPE(TRB_LINK) | TRB_CHAIN | TRB_TOGGLE;
-	} else {
-		priv_ep->flags |= EP_UPDATE_EP_TRBADDR;
+				    TRB_TYPE(TRB_LINK) | TRB_CHAIN;
+
+		if (priv_ep->wa1_trb == priv_req->trb)
+			cdns3_wa1_restore_cycle_bit(priv_ep);
 	}
 
+	cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET);
+
 not_found:
 	spin_unlock_irqrestore(&priv_dev->lock, flags);
 	return ret;
-- 
2.17.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] usb: cdns3: Fix dequeue implementation.
  2019-10-07 12:06 [PATCH] usb: cdns3: Fix dequeue implementation Pawel Laszczak
@ 2019-10-08  7:34 ` Peter Chen
  2019-10-08  8:01   ` Pawel Laszczak
  0 siblings, 1 reply; 4+ messages in thread
From: Peter Chen @ 2019-10-08  7:34 UTC (permalink / raw)
  To: Pawel Laszczak
  Cc: felipe.balbi, gregkh, linux-usb, rogerq, linux-kernel,
	jbergsagel, nsekhar, nm, sureshp, kurahul

On 19-10-07 13:06:18, Pawel Laszczak wrote:
> Dequeuing implementation in cdns3_gadget_ep_dequeu gets first request from

%s/cdns3_gadget_ep_dequeu/cdns3_gadget_ep_dequeue

> deferred_req_list and changed TRB associated with it to LINK TRB.
> This approach is incorrect because deferred_req_list contains requests
> that have not been placed on hardware RING.  In this case driver should
> just giveback this request to gadget driver.
> 
> The patch implements new approach that first checks where dequeuing
> request is located and only when it's on Transfer Ring then changes TRB
> associated with it to LINK TRB.
> During processing completed transfers such LINK TRB will be ignored.
> 
> Reported-by: Peter Chen <peter.chen@nxp.com>
> Signed-off-by: Pawel Laszczak <pawell@cadence.com>
> Fixes: 7733f6c32e36 ("usb: cdns3: Add Cadence USB3 DRD Driver")
> ---
>  drivers/usb/cdns3/gadget.c | 35 ++++++++++++++++++++---------------
>  1 file changed, 20 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c
> index 2ca280f4c054..9050b380ab83 100644
> --- a/drivers/usb/cdns3/gadget.c
> +++ b/drivers/usb/cdns3/gadget.c
> @@ -1145,6 +1145,14 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev,
>  		request = cdns3_next_request(&priv_ep->pending_req_list);
>  		priv_req = to_cdns3_request(request);
>  
> +		trb = priv_ep->trb_pool + priv_ep->dequeue;
> +
> +		/* Request was dequeued and TRB was changed to TRB_LINK. */
> +		if (TRB_FIELD_TO_TYPE(trb->control) == TRB_LINK) {
> +			trace_cdns3_complete_trb(priv_ep, trb);
> +			cdns3_move_deq_to_next_trb(priv_req);
> +		}

If the request was dequeued, it should not be at request list, isn't it?

Peter
> +
>  		/* Re-select endpoint. It could be changed by other CPU during
>  		 * handling usb_gadget_giveback_request.
>  		 */
> @@ -2067,6 +2075,7 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
>  	struct usb_request *req, *req_temp;
>  	struct cdns3_request *priv_req;
>  	struct cdns3_trb *link_trb;
> +	u8 req_on_hw_ring = 0;
>  	unsigned long flags;
>  	int ret = 0;
>  
> @@ -2083,8 +2092,10 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
>  
>  	list_for_each_entry_safe(req, req_temp, &priv_ep->pending_req_list,
>  				 list) {
> -		if (request == req)
> +		if (request == req) {
> +			req_on_hw_ring = 1;
>  			goto found;
> +		}
>  	}
>  
>  	list_for_each_entry_safe(req, req_temp, &priv_ep->deferred_req_list,
> @@ -2096,27 +2107,21 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
>  	goto not_found;
>  
>  found:
> -
> -	if (priv_ep->wa1_trb == priv_req->trb)
> -		cdns3_wa1_restore_cycle_bit(priv_ep);
> -
>  	link_trb = priv_req->trb;
> -	cdns3_move_deq_to_next_trb(priv_req);
> -	cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET);
> -
> -	/* Update ring */
> -	request = cdns3_next_request(&priv_ep->deferred_req_list);
> -	if (request) {
> -		priv_req = to_cdns3_request(request);
>  
> +	/* Update ring only if removed request is on pending_req_list list */
> +	if (req_on_hw_ring) {
>  		link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma +
>  					      (priv_req->start_trb * TRB_SIZE));
>  		link_trb->control = (link_trb->control & TRB_CYCLE) |
> -				    TRB_TYPE(TRB_LINK) | TRB_CHAIN | TRB_TOGGLE;
> -	} else {
> -		priv_ep->flags |= EP_UPDATE_EP_TRBADDR;
> +				    TRB_TYPE(TRB_LINK) | TRB_CHAIN;
> +
> +		if (priv_ep->wa1_trb == priv_req->trb)
> +			cdns3_wa1_restore_cycle_bit(priv_ep);
>  	}
>  
> +	cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET);
> +
>  not_found:
>  	spin_unlock_irqrestore(&priv_dev->lock, flags);
>  	return ret;

-- 

Thanks,
Peter Chen

^ permalink raw reply	[flat|nested] 4+ messages in thread

* RE: [PATCH] usb: cdns3: Fix dequeue implementation.
  2019-10-08  7:34 ` Peter Chen
@ 2019-10-08  8:01   ` Pawel Laszczak
  2019-10-09  2:31     ` Peter Chen
  0 siblings, 1 reply; 4+ messages in thread
From: Pawel Laszczak @ 2019-10-08  8:01 UTC (permalink / raw)
  To: Peter Chen
  Cc: felipe.balbi, gregkh, linux-usb, rogerq, linux-kernel,
	jbergsagel, nsekhar, nm, Suresh Punnoose, Rahul Kumar



>-----Original Message-----
>From: Peter Chen <peter.chen@nxp.com>
>Sent: Tuesday, October 8, 2019 9:34 AM
>To: Pawel Laszczak <pawell@cadence.com>
>Cc: felipe.balbi@linux.intel.com; gregkh@linuxfoundation.org; linux-usb@vger.kernel.org; rogerq@ti.com; linux-
>kernel@vger.kernel.org; jbergsagel@ti.com; nsekhar@ti.com; nm@ti.com; Suresh Punnoose <sureshp@cadence.com>; Rahul Kumar
><kurahul@cadence.com>
>Subject: Re: [PATCH] usb: cdns3: Fix dequeue implementation.
>
>EXTERNAL MAIL
>
>
>On 19-10-07 13:06:18, Pawel Laszczak wrote:
>> Dequeuing implementation in cdns3_gadget_ep_dequeu gets first request from
>
>%s/cdns3_gadget_ep_dequeu/cdns3_gadget_ep_dequeue
>
>> deferred_req_list and changed TRB associated with it to LINK TRB.
>> This approach is incorrect because deferred_req_list contains requests
>> that have not been placed on hardware RING.  In this case driver should
>> just giveback this request to gadget driver.
>>
>> The patch implements new approach that first checks where dequeuing
>> request is located and only when it's on Transfer Ring then changes TRB
>> associated with it to LINK TRB.
>> During processing completed transfers such LINK TRB will be ignored.
>>
>> Reported-by: Peter Chen <peter.chen@nxp.com>
>> Signed-off-by: Pawel Laszczak <pawell@cadence.com>
>> Fixes: 7733f6c32e36 ("usb: cdns3: Add Cadence USB3 DRD Driver")
>> ---
>>  drivers/usb/cdns3/gadget.c | 35 ++++++++++++++++++++---------------
>>  1 file changed, 20 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c
>> index 2ca280f4c054..9050b380ab83 100644
>> --- a/drivers/usb/cdns3/gadget.c
>> +++ b/drivers/usb/cdns3/gadget.c
>> @@ -1145,6 +1145,14 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev,
>>  		request = cdns3_next_request(&priv_ep->pending_req_list);
>>  		priv_req = to_cdns3_request(request);
>>
>> +		trb = priv_ep->trb_pool + priv_ep->dequeue;
>> +
>> +		/* Request was dequeued and TRB was changed to TRB_LINK. */
>> +		if (TRB_FIELD_TO_TYPE(trb->control) == TRB_LINK) {
>> +			trace_cdns3_complete_trb(priv_ep, trb);
>> +			cdns3_move_deq_to_next_trb(priv_req);
>> +		}
>
>If the request was dequeued, it should not be at request list, isn't it?

Yes
The dequeued request was removed from pending list but TRB associated with it 
was changed to Link TRB so it should be ignored in cdns3_transfer_completed function. 

Pawel

>
>Peter
>> +
>>  		/* Re-select endpoint. It could be changed by other CPU during
>>  		 * handling usb_gadget_giveback_request.
>>  		 */
>> @@ -2067,6 +2075,7 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
>>  	struct usb_request *req, *req_temp;
>>  	struct cdns3_request *priv_req;
>>  	struct cdns3_trb *link_trb;
>> +	u8 req_on_hw_ring = 0;
>>  	unsigned long flags;
>>  	int ret = 0;
>>
>> @@ -2083,8 +2092,10 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
>>
>>  	list_for_each_entry_safe(req, req_temp, &priv_ep->pending_req_list,
>>  				 list) {
>> -		if (request == req)
>> +		if (request == req) {
>> +			req_on_hw_ring = 1;
>>  			goto found;
>> +		}
>>  	}
>>
>>  	list_for_each_entry_safe(req, req_temp, &priv_ep->deferred_req_list,
>> @@ -2096,27 +2107,21 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
>>  	goto not_found;
>>
>>  found:
>> -
>> -	if (priv_ep->wa1_trb == priv_req->trb)
>> -		cdns3_wa1_restore_cycle_bit(priv_ep);
>> -
>>  	link_trb = priv_req->trb;
>> -	cdns3_move_deq_to_next_trb(priv_req);
>> -	cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET);
>> -
>> -	/* Update ring */
>> -	request = cdns3_next_request(&priv_ep->deferred_req_list);
>> -	if (request) {
>> -		priv_req = to_cdns3_request(request);
>>
>> +	/* Update ring only if removed request is on pending_req_list list */
>> +	if (req_on_hw_ring) {
>>  		link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma +
>>  					      (priv_req->start_trb * TRB_SIZE));
>>  		link_trb->control = (link_trb->control & TRB_CYCLE) |
>> -				    TRB_TYPE(TRB_LINK) | TRB_CHAIN | TRB_TOGGLE;
>> -	} else {
>> -		priv_ep->flags |= EP_UPDATE_EP_TRBADDR;
>> +				    TRB_TYPE(TRB_LINK) | TRB_CHAIN;
>> +
>> +		if (priv_ep->wa1_trb == priv_req->trb)
>> +			cdns3_wa1_restore_cycle_bit(priv_ep);
>>  	}
>>
>> +	cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET);
>> +
>>  not_found:
>>  	spin_unlock_irqrestore(&priv_dev->lock, flags);
>>  	return ret;
>
>--
>
>Thanks,
>Peter Chen

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] usb: cdns3: Fix dequeue implementation.
  2019-10-08  8:01   ` Pawel Laszczak
@ 2019-10-09  2:31     ` Peter Chen
  0 siblings, 0 replies; 4+ messages in thread
From: Peter Chen @ 2019-10-09  2:31 UTC (permalink / raw)
  To: Pawel Laszczak
  Cc: felipe.balbi, gregkh, linux-usb, rogerq, linux-kernel,
	jbergsagel, nsekhar, nm, Suresh Punnoose, Rahul Kumar

On 19-10-08 08:01:19, Pawel Laszczak wrote:
> >>
> >> diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c
> >> index 2ca280f4c054..9050b380ab83 100644
> >> --- a/drivers/usb/cdns3/gadget.c
> >> +++ b/drivers/usb/cdns3/gadget.c
> >> @@ -1145,6 +1145,14 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev,
> >>  		request = cdns3_next_request(&priv_ep->pending_req_list);
> >>  		priv_req = to_cdns3_request(request);
> >>
> >> +		trb = priv_ep->trb_pool + priv_ep->dequeue;
> >> +
> >> +		/* Request was dequeued and TRB was changed to TRB_LINK. */
> >> +		if (TRB_FIELD_TO_TYPE(trb->control) == TRB_LINK) {
> >> +			trace_cdns3_complete_trb(priv_ep, trb);
> >> +			cdns3_move_deq_to_next_trb(priv_req);
> >> +		}
> >
> >If the request was dequeued, it should not be at request list, isn't it?
> 
> Yes
> The dequeued request was removed from pending list but TRB associated with it 
> was changed to Link TRB so it should be ignored in cdns3_transfer_completed function. 
> 

I see, you are right. Except for the typo, otherwise:

Reviewed-by: Peter Chen <peter.chen@nxp.com>

Peter


> Pawel
> 
> >
> >Peter
> >> +
> >>  		/* Re-select endpoint. It could be changed by other CPU during
> >>  		 * handling usb_gadget_giveback_request.
> >>  		 */
> >> @@ -2067,6 +2075,7 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
> >>  	struct usb_request *req, *req_temp;
> >>  	struct cdns3_request *priv_req;
> >>  	struct cdns3_trb *link_trb;
> >> +	u8 req_on_hw_ring = 0;
> >>  	unsigned long flags;
> >>  	int ret = 0;
> >>
> >> @@ -2083,8 +2092,10 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
> >>
> >>  	list_for_each_entry_safe(req, req_temp, &priv_ep->pending_req_list,
> >>  				 list) {
> >> -		if (request == req)
> >> +		if (request == req) {
> >> +			req_on_hw_ring = 1;
> >>  			goto found;
> >> +		}
> >>  	}
> >>
> >>  	list_for_each_entry_safe(req, req_temp, &priv_ep->deferred_req_list,
> >> @@ -2096,27 +2107,21 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
> >>  	goto not_found;
> >>
> >>  found:
> >> -
> >> -	if (priv_ep->wa1_trb == priv_req->trb)
> >> -		cdns3_wa1_restore_cycle_bit(priv_ep);
> >> -
> >>  	link_trb = priv_req->trb;
> >> -	cdns3_move_deq_to_next_trb(priv_req);
> >> -	cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET);
> >> -
> >> -	/* Update ring */
> >> -	request = cdns3_next_request(&priv_ep->deferred_req_list);
> >> -	if (request) {
> >> -		priv_req = to_cdns3_request(request);
> >>
> >> +	/* Update ring only if removed request is on pending_req_list list */
> >> +	if (req_on_hw_ring) {
> >>  		link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma +
> >>  					      (priv_req->start_trb * TRB_SIZE));
> >>  		link_trb->control = (link_trb->control & TRB_CYCLE) |
> >> -				    TRB_TYPE(TRB_LINK) | TRB_CHAIN | TRB_TOGGLE;
> >> -	} else {
> >> -		priv_ep->flags |= EP_UPDATE_EP_TRBADDR;
> >> +				    TRB_TYPE(TRB_LINK) | TRB_CHAIN;
> >> +
> >> +		if (priv_ep->wa1_trb == priv_req->trb)
> >> +			cdns3_wa1_restore_cycle_bit(priv_ep);
> >>  	}
> >>
> >> +	cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET);
> >> +
> >>  not_found:
> >>  	spin_unlock_irqrestore(&priv_dev->lock, flags);
> >>  	return ret;
> >
> >--
> >
> >Thanks,
> >Peter Chen

-- 

Thanks,
Peter Chen

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, back to index

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-07 12:06 [PATCH] usb: cdns3: Fix dequeue implementation Pawel Laszczak
2019-10-08  7:34 ` Peter Chen
2019-10-08  8:01   ` Pawel Laszczak
2019-10-09  2:31     ` Peter Chen

Linux-USB Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-usb/0 linux-usb/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-usb linux-usb/ https://lore.kernel.org/linux-usb \
		linux-usb@vger.kernel.org
	public-inbox-index linux-usb

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-usb


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git