aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ohci-pci.c
diff options
context:
space:
mode:
authorMike Nuss <mike@terascala.com>2007-08-01 16:24:30 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-10-12 17:54:59 -0400
commit89a0fd18a96eb1f8732714b575073f8a8d69c009 (patch)
tree166d14fc49ad7fd646e1e7aa7decf6b3bea6d381 /drivers/usb/host/ohci-pci.c
parente8fa0ce65c58dbb60be279c4e33534650dcacc31 (diff)
USB: OHCI handles more ZFMicro quirks
The ZF Micro OHCI controller exhibits unexpected behavior that seems to be related to high load. Under certain conditions, the controller will complete a TD, remove it from the endpoint's queue, and fail to add it to the donelist. This causes the endpoint to appear to stop responding. Worse, if the device is removed while in that state, OHCI will hang while waiting for the orphaned TD to complete. The situation is not recoverable without rebooting. This fix enhances the scope of the existing OHCI_QUIRK_ZFMICRO flag: 1. A watchdog routine periodically scans the OHCI structures to check for orphaned TDs. In these cases the TD is taken back from the controller and completed normally. 2. If a device is removed while the endpoint is hung but before the watchdog catches the situation, any outstanding TDs are taken back from the controller in the 'sanitize' phase. The ohci-hcd driver used to print "INTR_SF lossage" in this situation; this changes it to the universally accurate "ED unlink timeout". Other instances of this message presumably have different root causes. Both this Compaq quirk and a NEC quirk are now properly compiled out for non-PCI builds of this driver. Signed-off-by: Mike Nuss <mike@terascala.com> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ohci-pci.c')
-rw-r--r--drivers/usb/host/ohci-pci.c22
1 files changed, 21 insertions, 1 deletions
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index a5e2eb85d073..d0360f65ebd9 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -84,7 +84,7 @@ static int ohci_quirk_zfmicro(struct usb_hcd *hcd)
84 struct ohci_hcd *ohci = hcd_to_ohci (hcd); 84 struct ohci_hcd *ohci = hcd_to_ohci (hcd);
85 85
86 ohci->flags |= OHCI_QUIRK_ZFMICRO; 86 ohci->flags |= OHCI_QUIRK_ZFMICRO;
87 ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n"); 87 ohci_dbg(ohci, "enabled Compaq ZFMicro chipset quirks\n");
88 88
89 return 0; 89 return 0;
90} 90}
@@ -113,11 +113,31 @@ static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
113 113
114/* Check for NEC chip and apply quirk for allegedly lost interrupts. 114/* Check for NEC chip and apply quirk for allegedly lost interrupts.
115 */ 115 */
116
117static void ohci_quirk_nec_worker(struct work_struct *work)
118{
119 struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
120 int status;
121
122 status = ohci_init(ohci);
123 if (status != 0) {
124 ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
125 "ohci_init", status);
126 return;
127 }
128
129 status = ohci_restart(ohci);
130 if (status != 0)
131 ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
132 "ohci_restart", status);
133}
134
116static int ohci_quirk_nec(struct usb_hcd *hcd) 135static int ohci_quirk_nec(struct usb_hcd *hcd)
117{ 136{
118 struct ohci_hcd *ohci = hcd_to_ohci (hcd); 137 struct ohci_hcd *ohci = hcd_to_ohci (hcd);
119 138
120 ohci->flags |= OHCI_QUIRK_NEC; 139 ohci->flags |= OHCI_QUIRK_NEC;
140 INIT_WORK(&ohci->nec_work, ohci_quirk_nec_worker);
121 ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n"); 141 ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n");
122 142
123 return 0; 143 return 0;