]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[efi] Do not attempt to drive PCI bridge devices 878/head
authorMichael Brown <mcb30@ipxe.org>
Fri, 3 Feb 2023 16:10:31 +0000 (16:10 +0000)
committerMichael Brown <mcb30@ipxe.org>
Fri, 3 Feb 2023 16:10:31 +0000 (16:10 +0000)
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>
src/drivers/bus/pci.c
src/include/ipxe/pci.h
src/interface/efi/efi_pci.c

index 7953aaedd763dec4cf0980f1b7f4026c8ada3ac7..92b389641d81ebe39f9727cae694cf080ea8f406 100644 (file)
@@ -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 */
index 637b20d60f8b5652db55139a3501a7180fad3ceb..8c6d9e4e28744d75c5bbeecdec322bbadc0b3352 100644 (file)
@@ -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 */
index 4796201e92be6b942b23d8ba8575ff41f68d1849..e2eeeb34465f520f3e55a3b90163f83bf96560c4 100644 (file)
@@ -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) "