ChangeSet 1.1276.1.54, 2003/08/27 17:32:14-07:00, david-b@pacbell.net

[PATCH] USB: ohci -- reset, fault recovery

This fixes two small and unrelated bugs in the current OHCI code:

  - Certain initialization sequences had problems with IRQs.
    Fixed last month in EHCI, but this ohci patch didn't seem
    needed back then.  OK, so now I saw the same bug in OHCI.
    (I could believe UHCI needs it too, sigh.)

  - When restarting endpoint i/o after a queue fault, the HC
    needs to be told the control (or bulk) list filled (CLF/BLF).
    Likely this wasn't common (usbtest test10 subcase7 fault
    recovery reproduced it nicely).

Please merge.  Lack of the first one might make trouble for
some people.


 drivers/usb/host/ohci-pci.c |   16 ++++++++++------
 drivers/usb/host/ohci-q.c   |   16 ++++++++++++++--
 2 files changed, 24 insertions(+), 8 deletions(-)


diff -Nru a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
--- a/drivers/usb/host/ohci-pci.c	Tue Sep  2 12:43:11 2003
+++ b/drivers/usb/host/ohci-pci.c	Tue Sep  2 12:43:11 2003
@@ -30,6 +30,15 @@
 
 /*-------------------------------------------------------------------------*/
 
+static int
+ohci_pci_reset (struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+
+	ohci->regs = hcd->regs;
+	return hc_reset (ohci);
+}
+
 static int __devinit
 ohci_pci_start (struct usb_hcd *hcd)
 {
@@ -89,12 +98,6 @@
 		ohci_stop (hcd);
 		return ret;
 	}
-	ohci->regs = hcd->regs;
-
-	if (hc_reset (ohci) < 0) {
-		ohci_stop (hcd);
-		return -ENODEV;
-	}
 
 	if (hc_start (ohci) < 0) {
 		ohci_err (ohci, "can't start\n");
@@ -315,6 +318,7 @@
 	/*
 	 * basic lifecycle operations
 	 */
+	.reset =		ohci_pci_reset,
 	.start =		ohci_pci_start,
 #ifdef	CONFIG_PM
 	.suspend =		ohci_pci_suspend,
diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
--- a/drivers/usb/host/ohci-q.c	Tue Sep  2 12:43:11 2003
+++ b/drivers/usb/host/ohci-q.c	Tue Sep  2 12:43:11 2003
@@ -1013,10 +1013,22 @@
 		if (list_empty (&ed->td_list))
 			ed_deschedule (ohci, ed);
 		/* ... reenabling halted EDs only after fault cleanup */
-		else if (!(ed->hwINFO & ED_DEQUEUE)) {
+		else if ((ed->hwINFO & (ED_SKIP | ED_DEQUEUE)) == ED_SKIP) {
 			td = list_entry (ed->td_list.next, struct td, td_list);
-			if (!(td->hwINFO & TD_DONE))
+			if (!(td->hwINFO & TD_DONE)) {
 				ed->hwINFO &= ~ED_SKIP;
+				/* ... hc may need waking-up */
+				switch (ed->type) {
+				case PIPE_CONTROL:
+					writel (OHCI_CLF,
+						&ohci->regs->cmdstatus);   
+					break;
+				case PIPE_BULK:
+					writel (OHCI_BLF,
+						&ohci->regs->cmdstatus);   
+					break;
+				}
+			}
 		}
 
     		td = td_next;
