[ipxe-devel] [PATCH] efcpci_root doesn't account for bus ranges

Thomas Walker Thomas.Walker at twosigma.com
Tue May 12 18:45:20 UTC 2020


>From 0f5310780426f6009fbd538110e939f4bc66f51f Mon Sep 17 00:00:00 2001
From: Thomas Walker <twalker at twosigma.com>
Date: Tue, 12 May 2020 11:29:06 -0400
Subject: [PATCH] efcpci_root doesn't account for bus ranges

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.

v2: match comment style
---
 src/interface/efi/efi_pci.c | 38 +++++++++++++++++++++++++++++++++----
 1 file changed, 34 insertions(+), 4 deletions(-)

diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c
index c1f451c9..aa0368b4 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,37 @@ 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 +147,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

-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-efcpci_root-doesn-t-account-for-bus-ranges.patch
Type: text/x-diff
Size: 2851 bytes
Desc: not available
URL: <http://lists.ipxe.org/pipermail/ipxe-devel/attachments/20200512/b9ddde8f/attachment.bin>


More information about the ipxe-devel mailing list