Commit 65e2da7e authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] ohci-hcd, queue fault recovery + rm DEBUG

This USB patch updates the OHCI driver:

  - converts to relying on td_list shadowing the hardware's
    schedule; only collecting the donelist needs dma_to_td(),
    and td list handling works much like EHCI or UHCI.

  - leaves faulted endpoint queues (bulk/intr) disabled until
    the relevant drivers had a chance to clean up.

  - fixes minor bugs (unreported) in the affected code:
      * byteswap problem when unlinking urbs ... symptom would
        be data toggle confusion (since 2.4.2x) on big-endian cpus
      * latent bug if folk unlinked queue in LIFO order, not FIFO

  - removes unnecessary debug code; mostly de-BUG()ged

The interesting fix is the "leave queues halted" one.  As
discussed on email a while back, this HCD fault handling
policy (also followed by EHCI) is sufficient to let device
drivers implement the two key fault handling policies that
seem to be necessary:

    (a) Datagram style, where issues on one I/O won't affect
        the next unless the device halted the endpoint.  The
        device driver can ignore most errors other than -EPIPE.

    (b) Stream style, where for example it'd be wrong to ever
        let block N+1 overwrite block N on the disk.  Once
        the first URB fails, the rest would just be unlinked
        in the completion handler.

As a consequence of using the td_list, you can now see urb
queuing in action in the driverfs 'async' file.  At least, if
you look at the right time, or use drivers (networking, etc)
that queue (bulk) reads for a long time.
parent f20bf018
...@@ -108,7 +108,7 @@ ...@@ -108,7 +108,7 @@
* - lots more testing!! * - lots more testing!!
*/ */
#define DRIVER_VERSION "2002-Sep-03" #define DRIVER_VERSION "2002-Sep-17"
#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell" #define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver" #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
...@@ -318,9 +318,6 @@ ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev) ...@@ -318,9 +318,6 @@ ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
struct hcd_dev *dev = (struct hcd_dev *) udev->hcpriv; struct hcd_dev *dev = (struct hcd_dev *) udev->hcpriv;
int i; int i;
unsigned long flags; unsigned long flags;
#ifdef DEBUG
int rescans = 0;
#endif
rescan: rescan:
/* free any eds, and dummy tds, still hanging around */ /* free any eds, and dummy tds, still hanging around */
...@@ -340,16 +337,18 @@ ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev) ...@@ -340,16 +337,18 @@ ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
td_free (ohci, ed->dummy); td_free (ohci, ed->dummy);
break; break;
default: default:
#ifdef DEBUG err ("%s-%s ed %p (#%d) not unlinked; disconnect() bug? %d",
err ("illegal ED %d state in free_config, %d", ohci->hcd.self.bus_name, udev->devpath, ed,
i, ed->state); i, ed->state);
#endif
/* ED_OPER: some driver disconnect() is broken, /* ED_OPER: some driver disconnect() is broken,
* it didn't even start its unlinks much less wait * it didn't even start its unlinks much less wait
* for their completions. * for their completions.
* OTHERWISE: hcd bug, ed is garbage * OTHERWISE: hcd bug, ed is garbage
*
* ... we can't recycle this memory in either case,
* so just leak it to avoid oopsing.
*/ */
BUG (); continue;
} }
ed_free (ohci, ed); ed_free (ohci, ed);
} }
...@@ -360,13 +359,9 @@ ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev) ...@@ -360,13 +359,9 @@ ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
#ifdef DEBUG #ifdef DEBUG
/* a driver->disconnect() returned before its unlinks completed? */ /* a driver->disconnect() returned before its unlinks completed? */
if (in_interrupt ()) { if (in_interrupt ()) {
dbg ("WARNING: spin in interrupt; driver->disconnect() bug"); warn ("disconnect() bug for dev usb-%s-%s ep 0x%x",
dbg ("dev usb-%s-%s ep 0x%x",
ohci->hcd.self.bus_name, udev->devpath, i); ohci->hcd.self.bus_name, udev->devpath, i);
} }
BUG_ON (!(readl (&ohci->regs->intrenable) & OHCI_INTR_SF));
BUG_ON (rescans >= 2); /* HWBUG */
rescans++;
#endif #endif
spin_unlock_irqrestore (&ohci->lock, flags); spin_unlock_irqrestore (&ohci->lock, flags);
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment