Commit 92710f36 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[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.
parent bae6e21c
...@@ -30,6 +30,15 @@ ...@@ -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 static int __devinit
ohci_pci_start (struct usb_hcd *hcd) ohci_pci_start (struct usb_hcd *hcd)
{ {
...@@ -89,12 +98,6 @@ ohci_pci_start (struct usb_hcd *hcd) ...@@ -89,12 +98,6 @@ ohci_pci_start (struct usb_hcd *hcd)
ohci_stop (hcd); ohci_stop (hcd);
return ret; return ret;
} }
ohci->regs = hcd->regs;
if (hc_reset (ohci) < 0) {
ohci_stop (hcd);
return -ENODEV;
}
if (hc_start (ohci) < 0) { if (hc_start (ohci) < 0) {
ohci_err (ohci, "can't start\n"); ohci_err (ohci, "can't start\n");
...@@ -315,6 +318,7 @@ static const struct hc_driver ohci_pci_hc_driver = { ...@@ -315,6 +318,7 @@ static const struct hc_driver ohci_pci_hc_driver = {
/* /*
* basic lifecycle operations * basic lifecycle operations
*/ */
.reset = ohci_pci_reset,
.start = ohci_pci_start, .start = ohci_pci_start,
#ifdef CONFIG_PM #ifdef CONFIG_PM
.suspend = ohci_pci_suspend, .suspend = ohci_pci_suspend,
......
...@@ -1013,10 +1013,22 @@ dl_done_list (struct ohci_hcd *ohci, struct td *td, struct pt_regs *regs) ...@@ -1013,10 +1013,22 @@ dl_done_list (struct ohci_hcd *ohci, struct td *td, struct pt_regs *regs)
if (list_empty (&ed->td_list)) if (list_empty (&ed->td_list))
ed_deschedule (ohci, ed); ed_deschedule (ohci, ed);
/* ... reenabling halted EDs only after fault cleanup */ /* ... 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); 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; 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; td = td_next;
......
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