linux-usb.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* dwc3 spin_lock_irq flags
@ 2021-08-10 22:10 Thinh Nguyen
  2021-08-11  1:51 ` Alan Stern
  0 siblings, 1 reply; 3+ messages in thread
From: Thinh Nguyen @ 2021-08-10 22:10 UTC (permalink / raw)
  To: Felipe Balbi, Alan Stern, USB

Hi,

Typically when we use spin_lock_irqsave and spin_unlock_irqrestore,
we save the irq state in the "flags" variable and pass it down to any
function that may need to do spin_unlock_irqrestore and update the flags
again.

I don't see that we're doing it for dwc3 when we give back the requests:

void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
		int status)
{
	struct dwc3			*dwc = dep->dwc;

	dwc3_gadget_del_and_unmap_request(dep, req, status);
	req->status = DWC3_REQUEST_STATUS_COMPLETED;

	spin_unlock(&dwc->lock);
	usb_gadget_giveback_request(&dep->endpoint, &req->request);
	spin_lock(&dwc->lock);
}

Then we would use the stale "flags" to do spin_unlock_irqrestore() at a later
time. Maybe someone can help shed some light on what issue this would cause
(if any). From our hardware testing, there's no obvious failure or performance
impact that we see.

Thanks,
Thinh

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

* Re: dwc3 spin_lock_irq flags
  2021-08-10 22:10 dwc3 spin_lock_irq flags Thinh Nguyen
@ 2021-08-11  1:51 ` Alan Stern
  2021-08-11  2:20   ` Thinh Nguyen
  0 siblings, 1 reply; 3+ messages in thread
From: Alan Stern @ 2021-08-11  1:51 UTC (permalink / raw)
  To: Thinh Nguyen; +Cc: Felipe Balbi, USB

On Tue, Aug 10, 2021 at 10:10:00PM +0000, Thinh Nguyen wrote:
> Hi,
> 
> Typically when we use spin_lock_irqsave and spin_unlock_irqrestore,
> we save the irq state in the "flags" variable and pass it down to any
> function that may need to do spin_unlock_irqrestore and update the flags
> again.
> 
> I don't see that we're doing it for dwc3 when we give back the requests:
> 
> void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
> 		int status)
> {
> 	struct dwc3			*dwc = dep->dwc;
> 
> 	dwc3_gadget_del_and_unmap_request(dep, req, status);
> 	req->status = DWC3_REQUEST_STATUS_COMPLETED;
> 
> 	spin_unlock(&dwc->lock);
> 	usb_gadget_giveback_request(&dep->endpoint, &req->request);
> 	spin_lock(&dwc->lock);
> }
> 
> Then we would use the stale "flags" to do spin_unlock_irqrestore() at a later
> time. Maybe someone can help shed some light on what issue this would cause
> (if any). From our hardware testing, there's no obvious failure or performance
> impact that we see.

There are no issues with this code pattern; it is perfectl valid.  Its 
only effect is that sometimes the request's completion handler will be 
called with interrupts disabled when in theory, it could have been 
called with interrupts enabled.  This won't cause any problem because 
completion handlers are _always_ called with interrupts disabled; this 
is mentioned in the kerneldoc for the @complete member of struct 
usb_request.

When the spin_unlock_irqrestore() call runs later on, its "flags" 
argument won't be stale.  It will accurately reflect whether interrupts 
were enabled when the original spin_lock_irqsave() ran.  By themselves, 
spin_unlock() and spin_lock() don't change the enable state for 
interrupts.

Alan Stern

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

* Re: dwc3 spin_lock_irq flags
  2021-08-11  1:51 ` Alan Stern
@ 2021-08-11  2:20   ` Thinh Nguyen
  0 siblings, 0 replies; 3+ messages in thread
From: Thinh Nguyen @ 2021-08-11  2:20 UTC (permalink / raw)
  To: Alan Stern, Thinh Nguyen; +Cc: Felipe Balbi, USB

Alan Stern wrote:
> On Tue, Aug 10, 2021 at 10:10:00PM +0000, Thinh Nguyen wrote:
>> Hi,
>>
>> Typically when we use spin_lock_irqsave and spin_unlock_irqrestore,
>> we save the irq state in the "flags" variable and pass it down to any
>> function that may need to do spin_unlock_irqrestore and update the flags
>> again.
>>
>> I don't see that we're doing it for dwc3 when we give back the requests:
>>
>> void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
>> 		int status)
>> {
>> 	struct dwc3			*dwc = dep->dwc;
>>
>> 	dwc3_gadget_del_and_unmap_request(dep, req, status);
>> 	req->status = DWC3_REQUEST_STATUS_COMPLETED;
>>
>> 	spin_unlock(&dwc->lock);
>> 	usb_gadget_giveback_request(&dep->endpoint, &req->request);
>> 	spin_lock(&dwc->lock);
>> }
>>
>> Then we would use the stale "flags" to do spin_unlock_irqrestore() at a later
>> time. Maybe someone can help shed some light on what issue this would cause
>> (if any). From our hardware testing, there's no obvious failure or performance
>> impact that we see.
> 
> There are no issues with this code pattern; it is perfectl valid.  Its 
> only effect is that sometimes the request's completion handler will be 
> called with interrupts disabled when in theory, it could have been 
> called with interrupts enabled.  This won't cause any problem because 
> completion handlers are _always_ called with interrupts disabled; this 
> is mentioned in the kerneldoc for the @complete member of struct 
> usb_request.
> 
> When the spin_unlock_irqrestore() call runs later on, its "flags" 
> argument won't be stale.  It will accurately reflect whether interrupts 
> were enabled when the original spin_lock_irqsave() ran.  By themselves, 
> spin_unlock() and spin_lock() don't change the enable state for 
> interrupts.
> 
> Alan Stern
> 

It's clear now. Thanks for the explanation Alan.

BR,
Thinh

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

end of thread, other threads:[~2021-08-11  2:20 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-10 22:10 dwc3 spin_lock_irq flags Thinh Nguyen
2021-08-11  1:51 ` Alan Stern
2021-08-11  2:20   ` Thinh Nguyen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).