From 1af9284225993de505c89d128d5bcf77c636637a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 16 May 2012 19:04:33 +0100 Subject: [PATCH] [efi] Work around platforms which choke on EFI_PCI_DEVICE_ENABLE EFI_PCI_DEVICE_ENABLE is a list of the standard attributes that must be enabled for a PCI device to function: I/O cycles, memory cycles, and bus-mastering. We currently call EFI_PCI_IO_PROTOCOL::Attribute() with the parameter EFI_PCI_DEVICE_ENABLE to enable a PCI device. This should translate to a single write to PCI configuration space. Simplicity is not a virtue within the UEFI world. Some platforms will 'helpfully' report an error if EFI_PCI_DEVICE_ENABLE is used on a device that doesn't actually support all three of the relevant attributes. For example, if a PCI device provides only memory-mapped accesses (and so hardwires the I/O enable bit to zero), then using EFI_PCI_DEVICE_ENABLE on such a platform will result in an EFI_UNSUPPORTED error. There is no plausible use case in which it is useful for the platform to return an error in this way, and doing so makes it impossible to distinguish genuine errors from noise. Work around this broken behaviour by attempting to enable the three attributes individually, and ignoring any errors. Signed-off-by: Michael Brown --- src/interface/efi/efi_pci.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index fa71e7d8..0a2da2e4 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -216,17 +216,19 @@ struct efi_pci_device * efipci_create ( struct efi_driver *efidrv, */ EFI_STATUS efipci_enable ( struct efi_pci_device *efipci ) { EFI_PCI_IO_PROTOCOL *pci_io = efipci->pci_io; - EFI_STATUS efirc; - /* Enable device */ - if ( ( efirc = pci_io->Attributes ( pci_io, - EfiPciIoAttributeOperationSet, - EFI_PCI_DEVICE_ENABLE, - NULL ) ) != 0 ) { - DBGC ( efipci, "EFIPCI " PCI_FMT " could not be enabled: %s\n", - PCI_ARGS ( &efipci->pci ), efi_strerror ( efirc ) ); - return efirc; - } + /* Try to enable I/O cycles, memory cycles, and bus mastering. + * Some platforms will 'helpfully' report errors if these bits + * can't be enabled (for example, if the card doesn't actually + * support I/O cycles). Work around any such platforms by + * enabling bits individually and simply ignoring any errors. + */ + pci_io->Attributes ( pci_io, EfiPciIoAttributeOperationEnable, + EFI_PCI_IO_ATTRIBUTE_IO, NULL ); + pci_io->Attributes ( pci_io, EfiPciIoAttributeOperationEnable, + EFI_PCI_IO_ATTRIBUTE_MEMORY, NULL ); + pci_io->Attributes ( pci_io, EfiPciIoAttributeOperationEnable, + EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, NULL ); return 0; }