aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2023-02-03 16:10:31 +0000
committerMichael Brown <mcb30@ipxe.org>2023-02-03 16:10:31 +0000
commit4e456d992889569e2dbb0426f2438797ab06ca1f (patch)
tree5cab0370a5e6327d1aec3162a114f544b4291839
parentd405a0bd84e34d5c549d71145657add506079fb4 (diff)
downloadipxe-efibridge.zip
ipxe-efibridge.tar.gz
ipxe-efibridge.tar.bz2
[efi] Do not attempt to drive PCI bridge devicesefibridge
The "bridge" driver introduced in 3aa6b79 ("[pci] Add minimal PCI bridge driver") is required only for BIOS builds using the ENA driver, where experimentation shows that we cannot rely on the BIOS to fully assign MMIO addresses. Since the driver is a valid PCI driver, it will end up binding to all PCI bridge devices even on a UEFI platform, where the firmware is likely to have completed MMIO address assignment correctly. This has no impact on most systems since there is generally no UEFI driver for PCI bridges: the enumeration of the whole PCI bus is handled by the PciBusDxe driver bound to the root bridge. Experimentation shows that at least one laptop will freeze at the point that iPXE attempts to bind to the bridge device. No deeper investigation has been carried out to find the root cause. Fix by causing efipci_supported() to return an error unless the configuration space header type indicates a non-bridge device. Reported-by: Marcel Petersen <mp@sbe.de> Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r--src/drivers/bus/pci.c1
-rw-r--r--src/include/ipxe/pci.h2
-rw-r--r--src/interface/efi/efi_pci.c10
3 files changed, 13 insertions, 0 deletions
diff --git a/src/drivers/bus/pci.c b/src/drivers/bus/pci.c
index 7953aae..92b3896 100644
--- a/src/drivers/bus/pci.c
+++ b/src/drivers/bus/pci.c
@@ -205,6 +205,7 @@ int pci_read_config ( struct pci_device *pci ) {
pci_read_config_dword ( pci, PCI_REVISION, &tmp );
pci->class = ( tmp >> 8 );
pci_read_config_byte ( pci, PCI_INTERRUPT_LINE, &pci->irq );
+ pci_read_config_byte ( pci, PCI_HEADER_TYPE, &pci->hdrtype );
pci_read_bases ( pci );
/* Initialise generic device component */
diff --git a/src/include/ipxe/pci.h b/src/include/ipxe/pci.h
index 637b20d..8c6d9e4 100644
--- a/src/include/ipxe/pci.h
+++ b/src/include/ipxe/pci.h
@@ -227,6 +227,8 @@ struct pci_device {
uint32_t class;
/** Interrupt number */
uint8_t irq;
+ /** Header type */
+ uint8_t hdrtype;
/** Segment, bus, device, and function (bus:dev.fn) number */
uint32_t busdevfn;
/** Driver for this device */
diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c
index 4796201..e2eeeb3 100644
--- a/src/interface/efi/efi_pci.c
+++ b/src/interface/efi/efi_pci.c
@@ -785,12 +785,22 @@ int efipci_info ( EFI_HANDLE device, struct efi_pci_device *efipci ) {
*/
static int efipci_supported ( EFI_HANDLE device ) {
struct efi_pci_device efipci;
+ uint8_t hdrtype;
int rc;
/* Get PCI device information */
if ( ( rc = efipci_info ( device, &efipci ) ) != 0 )
return rc;
+ /* Do not attempt to drive bridges */
+ hdrtype = efipci.pci.hdrtype;
+ if ( ( hdrtype & PCI_HEADER_TYPE_MASK ) != PCI_HEADER_TYPE_NORMAL ) {
+ DBGC ( device, "EFIPCI " PCI_FMT " type %02x is not type %02x\n",
+ PCI_ARGS ( &efipci.pci ), hdrtype,
+ PCI_HEADER_TYPE_NORMAL );
+ return -ENOTTY;
+ }
+
/* Look for a driver */
if ( ( rc = pci_find_driver ( &efipci.pci ) ) != 0 ) {
DBGC ( device, "EFIPCI " PCI_FMT " (%04x:%04x class %06x) "