summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2012-02-07 15:11:46 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-03-04 09:49:21 -0800
commitaddf2e1999cc01c2d4c46a70aba505f9504c8719 (patch)
treeb0b8904d8542c514b6dfc1aab9d904c4a0131c8b
parentc807095470574a9aa1ef0b2bac9593aaf13837a9 (diff)
USB: Fix handoff when BIOS disables host PCI device.
commit cab928ee1f221c9cc48d6615070fefe2e444384a upstream. On some systems with an Intel Panther Point xHCI host controller, the BIOS disables the xHCI PCI device during boot, and switches the xHCI ports over to EHCI. This allows the BIOS to access USB devices without having xHCI support. The downside is that the xHCI BIOS handoff mechanism will fail because memory mapped I/O is not enabled for the disabled PCI device. Jesse Barnes says this is expected behavior. The PCI core will enable BARs before quirks run, but it will leave it in an undefined state, and it may not have memory mapped I/O enabled. Make the generic USB quirk handler call pci_enable_device() to re-enable MMIO, and call pci_disable_device() once the host-specific BIOS handoff is finished. This will balance the ref counts in the PCI core. When the PCI probe function is called, usb_hcd_pci_probe() will call pci_enable_device() again. This should be back ported to kernels as old as 2.6.31. That was the first kernel with xHCI support, and no one has complained about BIOS handoffs failing due to memory mapped I/O being disabled on other hosts (EHCI, UHCI, or OHCI). Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Acked-by: Oliver Neukum <oneukum@suse.de> Cc: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/host/pci-quirks.c11
1 files changed, 11 insertions, 0 deletions
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 8213f793d3d9..0ff157a40a34 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -503,7 +503,17 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
*/
if (pdev->vendor == 0x184e) /* vendor Netlogic */
return;
+ if (pdev->class != PCI_CLASS_SERIAL_USB_UHCI &&
+ pdev->class != PCI_CLASS_SERIAL_USB_OHCI &&
+ pdev->class != PCI_CLASS_SERIAL_USB_EHCI &&
+ pdev->class != PCI_CLASS_SERIAL_USB_XHCI)
+ return;
+ if (pci_enable_device(pdev) < 0) {
+ dev_warn(&pdev->dev, "Can't enable PCI device, "
+ "BIOS handoff failed.\n");
+ return;
+ }
if (pdev->class == PCI_CLASS_SERIAL_USB_UHCI)
quirk_usb_handoff_uhci(pdev);
else if (pdev->class == PCI_CLASS_SERIAL_USB_OHCI)
@@ -512,5 +522,6 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
quirk_usb_disable_ehci(pdev);
else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI)
quirk_usb_handoff_xhci(pdev);
+ pci_disable_device(pdev);
}
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);