diff options
author | Michael Brown <mcb30@ipxe.org> | 2014-08-05 20:49:42 +0100 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2014-08-05 23:10:33 +0100 |
commit | 7b3cc18462425ab816348103f1bfa2546d248d37 (patch) | |
tree | ed3c38e2d663c51e74d81f7638b2ead8afd4aaaf /src/drivers/net/efi/snpnet.c | |
parent | 3b42ed477f21ee3f5851dc2993ea670e9edc10f7 (diff) | |
download | ipxe-7b3cc18462425ab816348103f1bfa2546d248d37.tar.gz |
[efi] Open device path protocol only at point of use
Some EFI 1.10 systems (observed on an Apple iMac) do not allow us to
open the device path protocol with an attribute of
EFI_OPEN_PROTOCOL_BY_DRIVER and so we cannot maintain a safe,
long-lived pointer to the device path. Work around this by instead
opening the device path protocol with an attribute of
EFI_OPEN_PROTOCOL_GET_PROTOCOL whenever we need to use it.
Debugged-by: Curtis Larsen <larsen@dixie.edu>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers/net/efi/snpnet.c')
-rw-r--r-- | src/drivers/net/efi/snpnet.c | 31 |
1 files changed, 27 insertions, 4 deletions
diff --git a/src/drivers/net/efi/snpnet.c b/src/drivers/net/efi/snpnet.c index 75574526f..79b4946c4 100644 --- a/src/drivers/net/efi/snpnet.c +++ b/src/drivers/net/efi/snpnet.c @@ -389,33 +389,56 @@ static struct net_device_operations snpnet_operations = { */ static int snpnet_pci_info ( struct efi_device *efidev, struct device *dev ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - EFI_DEVICE_PATH_PROTOCOL *devpath = efidev->path; EFI_HANDLE device = efidev->device; + union { + EFI_DEVICE_PATH_PROTOCOL *path; + void *interface; + } path; + EFI_DEVICE_PATH_PROTOCOL *devpath; struct pci_device pci; EFI_HANDLE pci_device; EFI_STATUS efirc; int rc; + /* Get device path */ + if ( ( efirc = bs->OpenProtocol ( device, + &efi_device_path_protocol_guid, + &path.interface, + efi_image_handle, device, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ + rc = -EEFI ( efirc ); + DBGC ( device, "SNP %p %s cannot open device path: %s\n", + device, efi_handle_name ( device ), strerror ( rc ) ); + goto err_open_device_path; + } + devpath = path.path; + /* Check for presence of PCI I/O protocol */ if ( ( efirc = bs->LocateDevicePath ( &efi_pci_io_protocol_guid, &devpath, &pci_device ) ) != 0 ) { + rc = -EEFI ( efirc ); DBGC ( device, "SNP %p %s is not a PCI device\n", device, efi_handle_name ( device ) ); - return -EEFI ( efirc ); + goto err_locate_pci_io; } /* Get PCI device information */ if ( ( rc = efipci_info ( pci_device, &pci ) ) != 0 ) { DBGC ( device, "SNP %p %s could not get PCI information: %s\n", device, efi_handle_name ( device ), strerror ( rc ) ); - return rc; + goto err_efipci_info; } /* Populate SNP device information */ memcpy ( &dev->desc, &pci.dev.desc, sizeof ( dev->desc ) ); snprintf ( dev->name, sizeof ( dev->name ), "SNP-%s", pci.dev.name ); - return 0; + err_efipci_info: + err_locate_pci_io: + bs->CloseProtocol ( device, &efi_device_path_protocol_guid, + efi_image_handle, device ); + err_open_device_path: + return rc; } /** |