diff options
author | Gabe Black <gabeblack@google.com> | 2012-11-08 19:31:23 -0800 |
---|---|---|
committer | Stefan Reinauer <stefan.reinauer@coreboot.org> | 2013-04-08 20:27:46 +0200 |
commit | 9e8af58263b7c84ee276354b97c19ad31992c8e9 (patch) | |
tree | 307b3e8324e541a9d0146492a82d57c84a23e02e /payloads | |
parent | 6d0fe9cad003d752af3214ae9a91d7411d582950 (diff) |
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>
Diffstat (limited to 'payloads')
-rw-r--r-- | payloads/libpayload/drivers/usb/usbinit.c | 56 |
1 files changed, 31 insertions, 25 deletions
diff --git a/payloads/libpayload/drivers/usb/usbinit.c b/payloads/libpayload/drivers/usb/usbinit.c index 74358bb20f..76653ff0d0 100644 --- a/payloads/libpayload/drivers/usb/usbinit.c +++ b/payloads/libpayload/drivers/usb/usbinit.c @@ -47,12 +47,12 @@ static int usb_controller_initialize(int bus, int dev, int func) 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 @@ static int usb_controller_initialize(int bus, int dev, int func) 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 @@ static int usb_controller_initialize(int bus, int dev, int func) 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 @@ static int usb_controller_initialize(int bus, int dev, int func) 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 @@ static int usb_controller_initialize(int bus, int dev, int func) 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 @@ static int usb_controller_initialize(int bus, int dev, int func) 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 @@ static void usb_scan_pci_bus(int bus) 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) - 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); + if (pci_read_config32(pci_device, REG_VENDOR_ID) == 0xffffffff) 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); + } } } |