USB: OHCI: make URB completions single-threaded
URBs for a particular endpoint should complete sequentially. That is, we shouldn't call the completion handler for one URB until the handler for the previous URB has returned. When the OHCI watchdog routine is added, there will be two paths for completing URBs: interrupt handler and watchdog routine. Their activities have to be synchronized so that completions don't occur in multiple threads concurrently. For that purpose, this patch creates an ohci_work() routine which will be responsible for calling process_done_list() and finish_unlinks(), the two routines that detect when an URB is complete. Everything will funnel through ohci_work(), and it will be careful not to run in more than one thread at a time. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

vanhempi
c6fcb85ea2
commit
cdb4dd15e6
@@ -316,7 +316,7 @@ static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
|
||||
|
||||
if (ohci->rh_state != OHCI_RH_RUNNING) {
|
||||
/* With HC dead, we can clean up right away */
|
||||
finish_unlinks(ohci, 0);
|
||||
ohci_work(ohci);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore (&ohci->lock, flags);
|
||||
@@ -349,7 +349,7 @@ rescan:
|
||||
if (ohci->rh_state != OHCI_RH_RUNNING) {
|
||||
sanitize:
|
||||
ed->state = ED_IDLE;
|
||||
finish_unlinks (ohci, 0);
|
||||
ohci_work(ohci);
|
||||
}
|
||||
|
||||
switch (ed->state) {
|
||||
@@ -789,9 +789,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
|
||||
/* handle any pending URB/ED unlinks, leaving INTR_SF enabled
|
||||
* when there's still unlinking to be done (next frame).
|
||||
*/
|
||||
process_done_list(ohci);
|
||||
if (ohci->ed_rm_list)
|
||||
finish_unlinks (ohci, ohci_frame_no(ohci));
|
||||
ohci_work(ohci);
|
||||
if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
|
||||
&& ohci->rh_state == OHCI_RH_RUNNING)
|
||||
ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable);
|
||||
@@ -879,7 +877,7 @@ int ohci_restart(struct ohci_hcd *ohci)
|
||||
if (!urb->unlinked)
|
||||
urb->unlinked = -ESHUTDOWN;
|
||||
}
|
||||
finish_unlinks (ohci, 0);
|
||||
ohci_work(ohci);
|
||||
spin_unlock_irq(&ohci->lock);
|
||||
|
||||
/* paranoia, in case that didn't work: */
|
||||
|
Viittaa uudesa ongelmassa
Block a user