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;