efipci_root only looks at PCI_SEG when trying to determine the correct I/O root handle for a device but each has a list of descriptors that show which bus numbers it covers. On a system where PCI_SEG is the same across all devices, this always selects the first handle which may not be correct. As a result, reads of PCI config space will fail and NICs will fall back to NII even if they have an appropriate driver available. --- src/interface/efi/efi_pci.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-)
diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index c1f451c9..7d094d1c 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -78,8 +78,10 @@ static int efipci_root ( struct pci_device *pci, EFI_HANDLE *handle, void *interface; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root; } u; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *acpi; EFI_STATUS efirc; UINTN i; + uint16_t bus = PCI_BUS (pci->busdevfn); int rc; /* Enumerate all handles */ @@ -106,9 +108,36 @@ static int efipci_root ( struct pci_device *pci, EFI_HANDLE *handle, continue; } if ( u.root->SegmentNumber == PCI_SEG ( pci->busdevfn ) ) { - *root = u.root; - bs->FreePool ( handles ); - return 0; + ./* + * Just matching PCI_SEG is insufficient + * We need to check the bus ranges in the ACPI address space + * descriptor to determine correct root bridge I/O protocl handle + */ + if ( (efirc = u.root->Configuration (u.root, (void **) &acpi)) != 0) { + rc = -EEFI ( efirc ); + DBGC ( pci, "EFIPCI " PCI_FMT " cannot get address space descriptor %s: %s\n", + PCI_ARGS ( pci ), efi_handle_name ( *handle ), strerror ( rc ) ); + continue; + } + /* if acpi is NULL, Configuration() is not implemented + * and this root bridge covers all buses + */ + if (acpi == NULL) { + *root = u.root; + rc = 0; + goto out; + } else { + while (acpi->Desc != ACPI_END_TAG_DESCRIPTOR) { + if ( (acpi->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) && + (bus >= (uint16_t) acpi->AddrRangeMin) && + (bus <= (uint16_t) acpi->AddrRangeMax)) { + *root = u.root; + rc = 0; + goto out; + } + acpi++; + } + } } bs->CloseProtocol ( *handle, &efi_pci_root_bridge_io_protocol_guid, @@ -117,7 +146,7 @@ static int efipci_root ( struct pci_device *pci, EFI_HANDLE *handle, DBGC ( pci, "EFIPCI " PCI_FMT " found no root bridge\n", PCI_ARGS ( pci ) ); rc = -ENOENT; - + out: bs->FreePool ( handles ); err_locate: return rc; -- 2.20.1 _______________________________________________ ipxe-devel mailing list ipxe-devel@lists.ipxe.org https://lists.ipxe.org/mailman/listinfo/ipxe-devel