aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/pci-quirks.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2011-11-17 16:41:45 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-11-18 14:18:45 -0500
commitc61875977458637226ab093a35d200f2d5789787 (patch)
tree8599601ac6abc0532f11858d572119d260d9925c /drivers/usb/host/pci-quirks.c
parent46b5a277ed90317a4d17e936c16037e76011b219 (diff)
OHCI: final fix for NVIDIA problems (I hope)
Problems with NVIDIA's OHCI host controllers persist. After looking carefully through the spec, I finally realized that when a controller is reset it then automatically goes into a SUSPEND state in which it is completely quiescent (no DMA and no IRQs) and from which it will not awaken until the system puts it into the OPERATIONAL state. Therefore there's no need to worry about controllers being in the RESET state for extended periods, or remaining in the OPERATIONAL state during system shutdown. The proper action for device initialization is to put the controller into the RESET state (if it's not there already) and then to issue a software reset. Similarly, the proper action for device shutdown is simply to do a software reset. This patch (as1499) implements such an approach. It simplifies initialization and shutdown, and allows the NVIDIA shutdown-quirk code to be removed. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Tested-by: Andre "Osku" Schmidt <andre.osku.schmidt@googlemail.com> Tested-by: Arno Augustin <Arno.Augustin@web.de> Cc: stable <stable@vger.kernel.org> [after tested in 3.2 for a while] Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/pci-quirks.c')
-rw-r--r--drivers/usb/host/pci-quirks.c50
1 files changed, 22 insertions, 28 deletions
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index c7fd6ce11904..caf87428ca43 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -37,6 +37,7 @@
37#define OHCI_INTRENABLE 0x10 37#define OHCI_INTRENABLE 0x10
38#define OHCI_INTRDISABLE 0x14 38#define OHCI_INTRDISABLE 0x14
39#define OHCI_FMINTERVAL 0x34 39#define OHCI_FMINTERVAL 0x34
40#define OHCI_HCFS (3 << 6) /* hc functional state */
40#define OHCI_HCR (1 << 0) /* host controller reset */ 41#define OHCI_HCR (1 << 0) /* host controller reset */
41#define OHCI_OCR (1 << 3) /* ownership change request */ 42#define OHCI_OCR (1 << 3) /* ownership change request */
42#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ 43#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
@@ -466,6 +467,8 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
466{ 467{
467 void __iomem *base; 468 void __iomem *base;
468 u32 control; 469 u32 control;
470 u32 fminterval;
471 int cnt;
469 472
470 if (!mmio_resource_enabled(pdev, 0)) 473 if (!mmio_resource_enabled(pdev, 0))
471 return; 474 return;
@@ -498,41 +501,32 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
498 } 501 }
499#endif 502#endif
500 503
501 /* reset controller, preserving RWC (and possibly IR) */ 504 /* disable interrupts */
502 writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); 505 writel((u32) ~0, base + OHCI_INTRDISABLE);
503 readl(base + OHCI_CONTROL);
504 506
505 /* Some NVIDIA controllers stop working if kept in RESET for too long */ 507 /* Reset the USB bus, if the controller isn't already in RESET */
506 if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) { 508 if (control & OHCI_HCFS) {
507 u32 fminterval; 509 /* Go into RESET, preserving RWC (and possibly IR) */
508 int cnt; 510 writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
511 readl(base + OHCI_CONTROL);
509 512
510 /* drive reset for at least 50 ms (7.1.7.5) */ 513 /* drive bus reset for at least 50 ms (7.1.7.5) */
511 msleep(50); 514 msleep(50);
515 }
512 516
513 /* software reset of the controller, preserving HcFmInterval */ 517 /* software reset of the controller, preserving HcFmInterval */
514 fminterval = readl(base + OHCI_FMINTERVAL); 518 fminterval = readl(base + OHCI_FMINTERVAL);
515 writel(OHCI_HCR, base + OHCI_CMDSTATUS); 519 writel(OHCI_HCR, base + OHCI_CMDSTATUS);
516 520
517 /* reset requires max 10 us delay */ 521 /* reset requires max 10 us delay */
518 for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */ 522 for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */
519 if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) 523 if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0)
520 break; 524 break;
521 udelay(1); 525 udelay(1);
522 }
523 writel(fminterval, base + OHCI_FMINTERVAL);
524
525 /* Now we're in the SUSPEND state with all devices reset
526 * and wakeups and interrupts disabled
527 */
528 } 526 }
527 writel(fminterval, base + OHCI_FMINTERVAL);
529 528
530 /* 529 /* Now the controller is safely in SUSPEND and nothing can wake it up */
531 * disable interrupts
532 */
533 writel(~(u32)0, base + OHCI_INTRDISABLE);
534 writel(~(u32)0, base + OHCI_INTRSTATUS);
535
536 iounmap(base); 530 iounmap(base);
537} 531}
538 532