Hi Alan, I applied it by hand to my ubuntu natty backport kernel after reverting to the original versions. For me it works fine and I didn't notice any problem. Thanks for the patches. Arno Am 03.11.2011 21:03, schrieb Alan Stern: > Pail, Arno, and Andre: > > I think I have found a permanent solution to the problem of starting up > and shutting down NVIDIA OHCI controllers. In order to test over the > widest range of controllers, I'd appreciate it if you could all try the > patch below. It's meant to apply to the 3.1 kernel, but adapting it to > other kernel versions should be pretty easy. (Arno, you should first > revert the test patch I sent you earlier.) > > The patch should even fix the problem some of you have seen when you > unload ohci-hcd and then load it back again. > > Please let me know how well it works for each of you. > > Thanks, > > Alan Stern > > > > Index: usb-3.2/drivers/usb/host/pci-quirks.c > =================================================================== > --- usb-3.2.orig/drivers/usb/host/pci-quirks.c > +++ usb-3.2/drivers/usb/host/pci-quirks.c > @@ -36,6 +36,7 @@ > #define OHCI_INTRENABLE 0x10 > #define OHCI_INTRDISABLE 0x14 > #define OHCI_FMINTERVAL 0x34 > +#define OHCI_HCFS (3 << 6) /* hc functional state */ > #define OHCI_HCR (1 << 0) /* host controller reset */ > #define OHCI_OCR (1 << 3) /* ownership change request */ > #define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ > @@ -465,6 +466,8 @@ static void __devinit quirk_usb_handoff_ > { > void __iomem *base; > u32 control; > + u32 fminterval; > + int cnt; > > if (!mmio_resource_enabled(pdev, 0)) > return; > @@ -497,41 +500,32 @@ static void __devinit quirk_usb_handoff_ > } > #endif > > - /* reset controller, preserving RWC (and possibly IR) */ > - writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); > - readl(base + OHCI_CONTROL); > - > - /* Some NVIDIA controllers stop working if kept in RESET for too long */ > - if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) { > - u32 fminterval; > - int cnt; > + /* disable interrupts */ > + writel((u32) ~0, base + OHCI_INTRDISABLE); > > - /* drive reset for at least 50 ms (7.1.7.5) */ > - msleep(50); > + /* Reset the USB bus, if the controller isn't already in RESET */ > + if (control & OHCI_HCFS) { > + /* Go into RESET, preserving RWC (and possibly IR) */ > + writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); > + readl(base + OHCI_CONTROL); > > - /* software reset of the controller, preserving HcFmInterval */ > - fminterval = readl(base + OHCI_FMINTERVAL); > - writel(OHCI_HCR, base + OHCI_CMDSTATUS); > - > - /* reset requires max 10 us delay */ > - for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */ > - if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) > - break; > - udelay(1); > - } > - writel(fminterval, base + OHCI_FMINTERVAL); > - > - /* Now we're in the SUSPEND state with all devices reset > - * and wakeups and interrupts disabled > - */ > + /* drive bus reset for at least 50 ms (7.1.7.5) */ > + msleep(50); > } > > - /* > - * disable interrupts > - */ > - writel(~(u32)0, base + OHCI_INTRDISABLE); > - writel(~(u32)0, base + OHCI_INTRSTATUS); > + /* software reset of the controller, preserving HcFmInterval */ > + fminterval = readl(base + OHCI_FMINTERVAL); > + writel(OHCI_HCR, base + OHCI_CMDSTATUS); > + > + /* reset requires max 10 us delay */ > + for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */ > + if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) > + break; > + udelay(1); > + } > + writel(fminterval, base + OHCI_FMINTERVAL); > > + /* Now the controller is safely in SUSPEND and nothing can wake it up */ > iounmap(base); > } > > Index: usb-3.2/drivers/usb/host/ohci.h > =================================================================== > --- usb-3.2.orig/drivers/usb/host/ohci.h > +++ usb-3.2/drivers/usb/host/ohci.h > @@ -403,7 +403,6 @@ struct ohci_hcd { > #define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */ > #define OHCI_QUIRK_AMD_PLL 0x200 /* AMD PLL quirk*/ > #define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */ > -#define OHCI_QUIRK_SHUTDOWN 0x800 /* nVidia power bug */ > // there are also chip quirks/bugs in init logic > > struct work_struct nec_work; /* Worker for NEC quirk */ > Index: usb-3.2/drivers/usb/host/ohci-pci.c > =================================================================== > --- usb-3.2.orig/drivers/usb/host/ohci-pci.c > +++ usb-3.2/drivers/usb/host/ohci-pci.c > @@ -175,28 +175,6 @@ static int ohci_quirk_amd700(struct usb_ > return 0; > } > > -/* nVidia controllers continue to drive Reset signalling on the bus > - * even after system shutdown, wasting power. This flag tells the > - * shutdown routine to leave the controller OPERATIONAL instead of RESET. > - */ > -static int ohci_quirk_nvidia_shutdown(struct usb_hcd *hcd) > -{ > - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); > - struct ohci_hcd *ohci = hcd_to_ohci(hcd); > - > - /* Evidently nVidia fixed their later hardware; this is a guess at > - * the changeover point. > - */ > -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB 0x026d > - > - if (pdev->device < PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB) { > - ohci->flags |= OHCI_QUIRK_SHUTDOWN; > - ohci_dbg(ohci, "enabled nVidia shutdown quirk\n"); > - } > - > - return 0; > -} > - > static void sb800_prefetch(struct ohci_hcd *ohci, int on) > { > struct pci_dev *pdev; > @@ -260,10 +238,6 @@ static const struct pci_device_id ohci_p > PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399), > .driver_data = (unsigned long)ohci_quirk_amd700, > }, > - { > - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), > - .driver_data = (unsigned long) ohci_quirk_nvidia_shutdown, > - }, > > /* FIXME for some of the early AMD 760 southbridges, OHCI > * won't work at all. blacklist them. > Index: usb-3.2/drivers/usb/host/ohci-hcd.c > =================================================================== > --- usb-3.2.orig/drivers/usb/host/ohci-hcd.c > +++ usb-3.2/drivers/usb/host/ohci-hcd.c > @@ -389,17 +389,14 @@ ohci_shutdown (struct usb_hcd *hcd) > struct ohci_hcd *ohci; > > ohci = hcd_to_ohci (hcd); > - ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); > - ohci->hc_control = ohci_readl(ohci, &ohci->regs->control); > + ohci_writel(ohci, (u32) ~0, &ohci->regs->intrdisable); > > - /* If the SHUTDOWN quirk is set, don't put the controller in RESET */ > - ohci->hc_control &= (ohci->flags & OHCI_QUIRK_SHUTDOWN ? > - OHCI_CTRL_RWC | OHCI_CTRL_HCFS : > - OHCI_CTRL_RWC); > - ohci_writel(ohci, ohci->hc_control, &ohci->regs->control); > + /* Software reset, after which the controller goes into SUSPEND */ > + ohci_writel(ohci, OHCI_HCR, &ohci->regs->cmdstatus); > + ohci_readl(ohci, &ohci->regs->cmdstatus); /* flush the writes */ > + udelay(10); > > - /* flush the writes */ > - (void) ohci_readl (ohci, &ohci->regs->control); > + ohci_writel(ohci, ohci->fminterval, &ohci->regs->fminterval); > } > > static int check_ed(struct ohci_hcd *ohci, struct ed *ed) > -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html