libpayload: Handle multifunction bridge devices better.
This change modifies the code in libpayload that scans the PCI hierarchy for
USB controllers. Previously, if a devices primary function (function 0) was a
bridge, then none of the other functions, if any, would be looked at. If one
of the other functions was a bridge, that wouldn't be handled either. The new
version looks at each function that's present no matter what, and if it
discovers that it's a bridge it scans the other side.
Change-Id: I37f269a4fe505fd32d9594e2daf17ddd78609c15
Signed-off-by: Gabe Black <gabeblack@google.com>
Reviewed-on: http://review.coreboot.org/2517
Reviewed-by: Marc Jones <marc.jones@se-eng.com>
Tested-by: build bot (Jenkins)
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
diff --git a/payloads/libpayload/drivers/usb/usbinit.c b/payloads/libpayload/drivers/usb/usbinit.c
index 74358bb..76653ff 100644
--- a/payloads/libpayload/drivers/usb/usbinit.c
+++ b/payloads/libpayload/drivers/usb/usbinit.c
@@ -47,12 +47,12 @@
u32 class;
u32 devclass;
u32 prog_if;
- pcidev_t addr;
+ pcidev_t pci_device;
u32 pciid;
- addr = PCI_DEV (bus, dev, func);
- class = pci_read_config32(addr, 8);
- pciid = pci_read_config32(addr, 0);
+ pci_device = PCI_DEV (bus, dev, func);
+ class = pci_read_config32(pci_device, 8);
+ pciid = pci_read_config32(pci_device, 0);
devclass = class >> 16;
prog_if = (class >> 8) & 0xff;
@@ -63,9 +63,9 @@
if (devclass == 0xc03) {
u32 pci_command;
- pci_command = pci_read_config32(addr, PCI_COMMAND);
+ pci_command = pci_read_config32(pci_device, PCI_COMMAND);
pci_command |= PCI_COMMAND_MASTER;
- pci_write_config32(addr, PCI_COMMAND, pci_command);
+ pci_write_config32(pci_device, PCI_COMMAND, pci_command);
usb_debug("%02x:%02x.%x %04x:%04x.%d ", bus, dev, func,
pciid >> 16, pciid & 0xFFFF, func);
@@ -73,7 +73,7 @@
case 0x00:
#ifdef CONFIG_USB_UHCI
usb_debug("UHCI controller\n");
- uhci_init (addr);
+ uhci_init (pci_device);
#else
usb_debug("UHCI controller (not supported)\n");
#endif
@@ -82,7 +82,7 @@
case 0x10:
#ifdef CONFIG_USB_OHCI
usb_debug("OHCI controller\n");
- ohci_init(addr);
+ ohci_init(pci_device);
#else
usb_debug("OHCI controller (not supported)\n");
#endif
@@ -91,7 +91,7 @@
case 0x20:
#ifdef CONFIG_USB_EHCI
usb_debug("EHCI controller\n");
- ehci_init(addr);
+ ehci_init(pci_device);
#else
usb_debug("EHCI controller (not supported)\n");
#endif
@@ -100,7 +100,7 @@
case 0x30:
#ifdef CONFIG_USB_XHCI
usb_debug("xHCI controller\n");
- xhci_init(addr);
+ xhci_init(pci_device);
#else
usb_debug("xHCI controller (not supported)\n");
#endif
@@ -121,31 +121,37 @@
int dev, func;
for (dev = 0; dev < 32; dev++) {
u8 header_type;
- pcidev_t addr = PCI_DEV(bus, dev, 0);
+ pcidev_t pci_device = PCI_DEV(bus, dev, 0);
+
/* Check if there's a device here at all. */
- if (pci_read_config32(addr, REG_VENDOR_ID) == 0xffffffff)
+ if (pci_read_config32(pci_device, REG_VENDOR_ID) == 0xffffffff)
continue;
- header_type = pci_read_config8(addr, REG_HEADER_TYPE);
- /* If this is a bridge, scan the bus on the other side. */
- if ((header_type & ~HEADER_TYPE_MULTIFUNCTION) ==
- HEADER_TYPE_BRIDGE) {
- int sub_bus =
- pci_read_config8(addr, REG_SECONDARY_BUS);
- usb_scan_pci_bus(sub_bus);
- continue;
- }
+
/*
* EHCI is defined by standards to be at a higher function
* than the USB1 controllers. We don't want to init USB1 +
* devices just to "steal" those for USB2, so make sure USB2
- * comes first.
+ * comes first by scanning multifunction devices from 7 to 0.
*/
+
/* Check for a multifunction device. */
+ header_type = pci_read_config8(pci_device, REG_HEADER_TYPE);
if (header_type & HEADER_TYPE_MULTIFUNCTION)
- for (func = 7; func > 0; func--)
+ func = 7;
+ else
+ func = 0;
+
+ for (; func >= 0; func--) {
+ pci_device = PCI_DEV(bus, dev, func);
+ header_type = pci_read_config8(pci_device, REG_HEADER_TYPE);
+ /* If this is a bridge, scan the other side. */
+ if ((header_type & ~HEADER_TYPE_MULTIFUNCTION) ==
+ HEADER_TYPE_BRIDGE)
+ usb_scan_pci_bus(pci_read_config8(pci_device,
+ REG_SECONDARY_BUS));
+ else
usb_controller_initialize(bus, dev, func);
- /* Initialize function 0. */
- usb_controller_initialize(bus, dev, 0);
+ }
}
}