[ipxe-devel] [PATCH] efcpci_root doesn't account for bus ranges
Thomas Walker
Thomas.Walker at twosigma.com
Tue May 12 18:36:03 UTC 2020
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
More information about the ipxe-devel
mailing list