73 lines
2.7 KiB
Diff
73 lines
2.7 KiB
Diff
commit 2656a9abcf1ec8dd5fee6a75d6997a0f2fa0094e
|
|
Author: Alan Stern <stern@rowland.harvard.edu>
|
|
Date: Thu Nov 8 10:17:01 2012 -0500
|
|
|
|
USB: EHCI: bugfix: urb->hcpriv should not be NULL
|
|
|
|
This patch (as1632b) fixes a bug in ehci-hcd. The USB core uses
|
|
urb->hcpriv to determine whether or not an URB is active; host
|
|
controller drivers are supposed to set this pointer to a non-NULL
|
|
value when an URB is queued. However ehci-hcd sets it to NULL for
|
|
isochronous URBs, which defeats the check in usbcore.
|
|
|
|
In itself this isn't a big deal. But people have recently found that
|
|
certain sequences of actions will cause the snd-usb-audio driver to
|
|
reuse URBs without waiting for them to complete. In the absence of
|
|
proper checking by usbcore, the URBs get added to their endpoint list
|
|
twice. This leads to list corruption and a system freeze.
|
|
|
|
The patch makes ehci-hcd assign a meaningful value to urb->hcpriv for
|
|
isochronous URBs. Improving robustness always helps.
|
|
|
|
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
|
|
Reported-by: Artem S. Tashkinov <t.artem@lycos.com>
|
|
Reported-by: Christof Meerwald <cmeerw@cmeerw.org>
|
|
CC: <stable@vger.kernel.org>
|
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
|
|
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
|
|
index 4b66374..3d98902 100644
|
|
--- a/drivers/usb/host/ehci-q.c
|
|
+++ b/drivers/usb/host/ehci-q.c
|
|
@@ -264,15 +264,9 @@ ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
|
|
__releases(ehci->lock)
|
|
__acquires(ehci->lock)
|
|
{
|
|
- if (likely (urb->hcpriv != NULL)) {
|
|
- struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv;
|
|
-
|
|
- /* S-mask in a QH means it's an interrupt urb */
|
|
- if ((qh->hw->hw_info2 & cpu_to_hc32(ehci, QH_SMASK)) != 0) {
|
|
-
|
|
- /* ... update hc-wide periodic stats (for usbfs) */
|
|
- ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
|
|
- }
|
|
+ if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
|
|
+ /* ... update hc-wide periodic stats */
|
|
+ ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
|
|
}
|
|
|
|
if (unlikely(urb->unlinked)) {
|
|
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
|
|
index 2e14714..69ebee7 100644
|
|
--- a/drivers/usb/host/ehci-sched.c
|
|
+++ b/drivers/usb/host/ehci-sched.c
|
|
@@ -1630,7 +1630,7 @@ static void itd_link_urb(
|
|
|
|
/* don't need that schedule data any more */
|
|
iso_sched_free (stream, iso_sched);
|
|
- urb->hcpriv = NULL;
|
|
+ urb->hcpriv = stream;
|
|
|
|
++ehci->isoc_count;
|
|
enable_periodic(ehci);
|
|
@@ -2029,7 +2029,7 @@ static void sitd_link_urb(
|
|
|
|
/* don't need that schedule data any more */
|
|
iso_sched_free (stream, sched);
|
|
- urb->hcpriv = NULL;
|
|
+ urb->hcpriv = stream;
|
|
|
|
++ehci->isoc_count;
|
|
enable_periodic(ehci);
|