aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2011-07-15 17:22:15 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-07-16 05:34:44 -0400
commit6ea12a04d295235ed67010a09fdea58c949e3eb0 (patch)
tree0404a9aed3c147e2a0f4ec03eefb40572a9505b8 /drivers/usb/host
parent18fbb93fbec3cfd6acf46f60990f7ab21c4221dd (diff)
USB: OHCI: fix another regression for NVIDIA controllers
The NVIDIA series of OHCI controllers continues to be troublesome. A few people using the MCP67 chipset have reported that even with the most recent kernels, the OHCI controller fails to handle new connections and spams the system log with "unable to enumerate USB port" messages. This is different from the other problems previously reported for NVIDIA OHCI controllers, although it is probably related. It turns out that the MCP67 controller does not like to be kept in the RESET state very long. After only a few seconds, it decides not to work any more. This patch (as1479) changes the PCI initialization quirk code so that NVIDIA controllers are switched into the SUSPEND state after 50 ms of RESET. With no interrupts enabled and all the downstream devices reset, and thus unable to send wakeup requests, this should be perfectly safe (even for non-NVIDIA hardware). The removal code in ohci-hcd hasn't been changed; it will still leave the controller in the RESET state. As a result, if someone unloads ohci-hcd and then reloads it, the controller won't work again until the system is rebooted. If anybody complains about this, the removal code can be updated similarly. This fixes Bugzilla #22052. Tested-by: Larry Finger <Larry.Finger@lwfinger.net> Cc: stable <stable@kernel.org> Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/pci-quirks.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index b5a7304fcbef..a9d315906e3d 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -35,6 +35,8 @@
35#define OHCI_INTRSTATUS 0x0c 35#define OHCI_INTRSTATUS 0x0c
36#define OHCI_INTRENABLE 0x10 36#define OHCI_INTRENABLE 0x10
37#define OHCI_INTRDISABLE 0x14 37#define OHCI_INTRDISABLE 0x14
38#define OHCI_FMINTERVAL 0x34
39#define OHCI_HCR (1 << 0) /* host controller reset */
38#define OHCI_OCR (1 << 3) /* ownership change request */ 40#define OHCI_OCR (1 << 3) /* ownership change request */
39#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ 41#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
40#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ 42#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
@@ -497,6 +499,32 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
497 499
498 /* reset controller, preserving RWC (and possibly IR) */ 500 /* reset controller, preserving RWC (and possibly IR) */
499 writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); 501 writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
502 readl(base + OHCI_CONTROL);
503
504 /* Some NVIDIA controllers stop working if kept in RESET for too long */
505 if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) {
506 u32 fminterval;
507 int cnt;
508
509 /* drive reset for at least 50 ms (7.1.7.5) */
510 msleep(50);
511
512 /* software reset of the controller, preserving HcFmInterval */
513 fminterval = readl(base + OHCI_FMINTERVAL);
514 writel(OHCI_HCR, base + OHCI_CMDSTATUS);
515
516 /* reset requires max 10 us delay */
517 for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */
518 if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0)
519 break;
520 udelay(1);
521 }
522 writel(fminterval, base + OHCI_FMINTERVAL);
523
524 /* Now we're in the SUSPEND state with all devices reset
525 * and wakeups and interrupts disabled
526 */
527 }
500 528
501 /* 529 /*
502 * disable interrupts 530 * disable interrupts