diff options
-rw-r--r-- | drivers/usb/core/hcd-pci.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 9 | ||||
-rw-r--r-- | drivers/usb/host/ohci-pci.c | 18 | ||||
-rw-r--r-- | drivers/usb/host/ohci.h | 1 | ||||
-rw-r--r-- | drivers/usb/host/pci-quirks.c | 18 |
5 files changed, 41 insertions, 9 deletions
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index c3f98543caaf..3799573bd385 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c | |||
@@ -329,8 +329,10 @@ void usb_hcd_pci_shutdown(struct pci_dev *dev) | |||
329 | return; | 329 | return; |
330 | 330 | ||
331 | if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) && | 331 | if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) && |
332 | hcd->driver->shutdown) | 332 | hcd->driver->shutdown) { |
333 | hcd->driver->shutdown(hcd); | 333 | hcd->driver->shutdown(hcd); |
334 | pci_disable_device(dev); | ||
335 | } | ||
334 | } | 336 | } |
335 | EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown); | 337 | EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown); |
336 | 338 | ||
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index c3b4ccc7337b..8ef3c1944364 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c | |||
@@ -398,7 +398,14 @@ ohci_shutdown (struct usb_hcd *hcd) | |||
398 | 398 | ||
399 | ohci = hcd_to_ohci (hcd); | 399 | ohci = hcd_to_ohci (hcd); |
400 | ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); | 400 | ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); |
401 | ohci_usb_reset (ohci); | 401 | ohci->hc_control = ohci_readl(ohci, &ohci->regs->control); |
402 | |||
403 | /* If the SHUTDOWN quirk is set, don't put the controller in RESET */ | ||
404 | ohci->hc_control &= (ohci->flags & OHCI_QUIRK_SHUTDOWN ? | ||
405 | OHCI_CTRL_RWC | OHCI_CTRL_HCFS : | ||
406 | OHCI_CTRL_RWC); | ||
407 | ohci_writel(ohci, ohci->hc_control, &ohci->regs->control); | ||
408 | |||
402 | /* flush the writes */ | 409 | /* flush the writes */ |
403 | (void) ohci_readl (ohci, &ohci->regs->control); | 410 | (void) ohci_readl (ohci, &ohci->regs->control); |
404 | } | 411 | } |
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 6bdc8b25a6a1..36ee9a666e93 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c | |||
@@ -201,6 +201,20 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd) | |||
201 | return 0; | 201 | return 0; |
202 | } | 202 | } |
203 | 203 | ||
204 | /* nVidia controllers continue to drive Reset signalling on the bus | ||
205 | * even after system shutdown, wasting power. This flag tells the | ||
206 | * shutdown routine to leave the controller OPERATIONAL instead of RESET. | ||
207 | */ | ||
208 | static int ohci_quirk_nvidia_shutdown(struct usb_hcd *hcd) | ||
209 | { | ||
210 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); | ||
211 | |||
212 | ohci->flags |= OHCI_QUIRK_SHUTDOWN; | ||
213 | ohci_dbg(ohci, "enabled nVidia shutdown quirk\n"); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
204 | /* | 218 | /* |
205 | * The hardware normally enables the A-link power management feature, which | 219 | * The hardware normally enables the A-link power management feature, which |
206 | * lets the system lower the power consumption in idle states. | 220 | * lets the system lower the power consumption in idle states. |
@@ -332,6 +346,10 @@ static const struct pci_device_id ohci_pci_quirks[] = { | |||
332 | PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399), | 346 | PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399), |
333 | .driver_data = (unsigned long)ohci_quirk_amd700, | 347 | .driver_data = (unsigned long)ohci_quirk_amd700, |
334 | }, | 348 | }, |
349 | { | ||
350 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), | ||
351 | .driver_data = (unsigned long) ohci_quirk_nvidia_shutdown, | ||
352 | }, | ||
335 | 353 | ||
336 | /* FIXME for some of the early AMD 760 southbridges, OHCI | 354 | /* FIXME for some of the early AMD 760 southbridges, OHCI |
337 | * won't work at all. blacklist them. | 355 | * won't work at all. blacklist them. |
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 5bf15fed0d9f..51facb985c84 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h | |||
@@ -403,6 +403,7 @@ struct ohci_hcd { | |||
403 | #define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */ | 403 | #define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */ |
404 | #define OHCI_QUIRK_AMD_ISO 0x200 /* ISO transfers*/ | 404 | #define OHCI_QUIRK_AMD_ISO 0x200 /* ISO transfers*/ |
405 | #define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */ | 405 | #define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */ |
406 | #define OHCI_QUIRK_SHUTDOWN 0x800 /* nVidia power bug */ | ||
406 | // there are also chip quirks/bugs in init logic | 407 | // there are also chip quirks/bugs in init logic |
407 | 408 | ||
408 | struct work_struct nec_work; /* Worker for NEC quirk */ | 409 | struct work_struct nec_work; /* Worker for NEC quirk */ |
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 83b5f9cea85a..464ed977b45d 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c | |||
@@ -169,6 +169,7 @@ static int __devinit mmio_resource_enabled(struct pci_dev *pdev, int idx) | |||
169 | static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) | 169 | static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) |
170 | { | 170 | { |
171 | void __iomem *base; | 171 | void __iomem *base; |
172 | u32 control; | ||
172 | 173 | ||
173 | if (!mmio_resource_enabled(pdev, 0)) | 174 | if (!mmio_resource_enabled(pdev, 0)) |
174 | return; | 175 | return; |
@@ -177,10 +178,14 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) | |||
177 | if (base == NULL) | 178 | if (base == NULL) |
178 | return; | 179 | return; |
179 | 180 | ||
181 | control = readl(base + OHCI_CONTROL); | ||
182 | |||
180 | /* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */ | 183 | /* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */ |
181 | #ifndef __hppa__ | 184 | #ifdef __hppa__ |
182 | { | 185 | #define OHCI_CTRL_MASK (OHCI_CTRL_RWC | OHCI_CTRL_IR) |
183 | u32 control = readl(base + OHCI_CONTROL); | 186 | #else |
187 | #define OHCI_CTRL_MASK OHCI_CTRL_RWC | ||
188 | |||
184 | if (control & OHCI_CTRL_IR) { | 189 | if (control & OHCI_CTRL_IR) { |
185 | int wait_time = 500; /* arbitrary; 5 seconds */ | 190 | int wait_time = 500; /* arbitrary; 5 seconds */ |
186 | writel(OHCI_INTR_OC, base + OHCI_INTRENABLE); | 191 | writel(OHCI_INTR_OC, base + OHCI_INTRENABLE); |
@@ -194,13 +199,12 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) | |||
194 | dev_warn(&pdev->dev, "OHCI: BIOS handoff failed" | 199 | dev_warn(&pdev->dev, "OHCI: BIOS handoff failed" |
195 | " (BIOS bug?) %08x\n", | 200 | " (BIOS bug?) %08x\n", |
196 | readl(base + OHCI_CONTROL)); | 201 | readl(base + OHCI_CONTROL)); |
197 | |||
198 | /* reset controller, preserving RWC */ | ||
199 | writel(control & OHCI_CTRL_RWC, base + OHCI_CONTROL); | ||
200 | } | 202 | } |
201 | } | ||
202 | #endif | 203 | #endif |
203 | 204 | ||
205 | /* reset controller, preserving RWC (and possibly IR) */ | ||
206 | writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); | ||
207 | |||
204 | /* | 208 | /* |
205 | * disable interrupts | 209 | * disable interrupts |
206 | */ | 210 | */ |