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 @@
* - lots more testing!!
*/
#define DRIVER_VERSION "2002-Sep-03"
#define DRIVER_VERSION "2002-Sep-17"
#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
#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)
struct hcd_dev *dev = (struct hcd_dev *) udev->hcpriv;
int i;
unsigned long flags;
#ifdef DEBUG
int rescans = 0;
#endif
rescan:
/* free any eds, and dummy tds, still hanging around */
......@@ -340,16 +337,18 @@ ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
td_free (ohci, ed->dummy);
break;
default:
#ifdef DEBUG
err ("illegal ED %d state in free_config, %d",
err ("%s-%s ed %p (#%d) not unlinked; disconnect() bug? %d",
ohci->hcd.self.bus_name, udev->devpath, ed,
i, ed->state);
#endif
/* ED_OPER: some driver disconnect() is broken,
* it didn't even start its unlinks much less wait
* for their completions.
* 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);
}
......@@ -360,13 +359,9 @@ ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
#ifdef DEBUG
/* a driver->disconnect() returned before its unlinks completed? */
if (in_interrupt ()) {
dbg ("WARNING: spin in interrupt; driver->disconnect() bug");
dbg ("dev usb-%s-%s ep 0x%x",
warn ("disconnect() bug for dev usb-%s-%s ep 0x%x",
ohci->hcd.self.bus_name, udev->devpath, i);
}
BUG_ON (!(readl (&ohci->regs->intrenable) & OHCI_INTR_SF));
BUG_ON (rescans >= 2); /* HWBUG */
rescans++;
#endif
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