diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2014-07-18 16:25:59 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-07-18 16:30:46 -0700 |
commit | c6fcb85ea22889527ee44aba42c3e3b479fd2d92 (patch) | |
tree | 37ef7947b0b0aa53aa49bf6c5cbc7fca3204b1ea /drivers/usb/host/ohci-hcd.c | |
parent | 8b3ab0edaf6acd281243bf974fac7e01c9574d08 (diff) | |
download | op-kernel-dev-c6fcb85ea22889527ee44aba42c3e3b479fd2d92.zip op-kernel-dev-c6fcb85ea22889527ee44aba42c3e3b479fd2d92.tar.gz |
USB: OHCI: redesign the TD done list
This patch changes the way ohci-hcd handles the TD done list. In
addition to relying on the TD pointers stored by the controller
hardware, we need to handle TDs that the hardware has forgotten about.
This means the list has to exist even while the dl_done_list() routine
isn't running. That function essentially gets split in two:
update_done_list() reads the TD pointers stored by the hardware and
adds the TDs to the done list, and process_done_list() scans through
the list to handle URB completions. When we detect a TD that the
hardware forgot about, we will be able to add it to the done list
manually and then process it normally.
Since the list is really a queue, and because there can be a lot of
TDs, keep the existing singly linked implementation. To insure that
URBs are given back in order of submission, whenever a TD is added to
the done list, all the preceding TDs for the same endpoint must be
added as well (going back to the first one that isn't already on the
done list).
The done list manipulations must all be protected by the private
lock. The scope of the lock is expanded in preparation for the
watchdog routine to be added in a later patch.
We have to be more careful about giving back unlinked URBs. Since TDs
may be added to the done list by the watchdog routine and not in
response to a controller interrupt, we have to check explicitly to
make sure all the URB's TDs that were added to the done list have been
processed before giving back the URB.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host/ohci-hcd.c')
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 12 |
1 files changed, 5 insertions, 7 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 5282927..3112799 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -780,24 +780,21 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) usb_hcd_resume_root_hub(hcd); } - if (ints & OHCI_INTR_WDH) { - spin_lock (&ohci->lock); - dl_done_list (ohci); - spin_unlock (&ohci->lock); - } + spin_lock(&ohci->lock); + if (ints & OHCI_INTR_WDH) + update_done_list(ohci); /* could track INTR_SO to reduce available PCI/... bandwidth */ /* handle any pending URB/ED unlinks, leaving INTR_SF enabled * when there's still unlinking to be done (next frame). */ - spin_lock (&ohci->lock); + process_done_list(ohci); if (ohci->ed_rm_list) finish_unlinks (ohci, ohci_frame_no(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); - spin_unlock (&ohci->lock); if (ohci->rh_state == OHCI_RH_RUNNING) { ohci_writel (ohci, ints, ®s->intrstatus); @@ -805,6 +802,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) // flush those writes (void) ohci_readl (ohci, &ohci->regs->control); } + spin_unlock(&ohci->lock); return IRQ_HANDLED; } |