diff --git a/src/drivers/net/efi/nii.c b/src/drivers/net/efi/nii.c index 81f1838a4..6381fb2dd 100644 --- a/src/drivers/net/efi/nii.c +++ b/src/drivers/net/efi/nii.c @@ -1257,6 +1257,26 @@ static struct net_device_operations nii_operations = { .poll = nii_poll, }; +/** + * Exclude existing drivers + * + * @v device EFI device handle + * @ret rc Return status code + */ +int nii_exclude ( EFI_HANDLE device ) { + EFI_GUID *protocol = &efi_nii31_protocol_guid; + int rc; + + /* Exclude existing NII protocol drivers */ + if ( ( rc = efi_driver_exclude ( device, protocol ) ) != 0 ) { + DBGC ( device, "NII %s could not exclude drivers: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + return rc; + } + + return 0; +} + /** * Attach driver to device * diff --git a/src/drivers/net/efi/nii.h b/src/drivers/net/efi/nii.h index c10be9db5..df7ab7dbe 100644 --- a/src/drivers/net/efi/nii.h +++ b/src/drivers/net/efi/nii.h @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); struct efi_device; +extern int nii_exclude ( EFI_HANDLE device ); extern int nii_start ( struct efi_device *efidev ); extern void nii_stop ( struct efi_device *efidev ); diff --git a/src/drivers/net/efi/snp.c b/src/drivers/net/efi/snp.c index 7c4123677..2e0d9df3a 100644 --- a/src/drivers/net/efi/snp.c +++ b/src/drivers/net/efi/snp.c @@ -59,8 +59,8 @@ static int nii_supported ( EFI_HANDLE device ) { /** EFI SNP driver */ struct efi_driver snp_driver __efi_driver ( EFI_DRIVER_SNP ) = { .name = "SNP", - .exclude = &efi_simple_network_protocol_guid, .supported = snp_supported, + .exclude = snpnet_exclude, .start = snpnet_start, .stop = snpnet_stop, }; @@ -68,8 +68,8 @@ struct efi_driver snp_driver __efi_driver ( EFI_DRIVER_SNP ) = { /** EFI NII driver */ struct efi_driver nii_driver __efi_driver ( EFI_DRIVER_NII ) = { .name = "NII", - .exclude = &efi_nii31_protocol_guid, .supported = nii_supported, + .exclude = nii_exclude, .start = nii_start, .stop = nii_stop, }; diff --git a/src/drivers/net/efi/snpnet.c b/src/drivers/net/efi/snpnet.c index c8e2f2f68..c4062a5a7 100644 --- a/src/drivers/net/efi/snpnet.c +++ b/src/drivers/net/efi/snpnet.c @@ -528,6 +528,26 @@ int snpnet_supported ( EFI_HANDLE device, EFI_GUID *protocol ) { return 0; } +/** + * Exclude existing drivers + * + * @v device EFI device handle + * @ret rc Return status code + */ +int snpnet_exclude ( EFI_HANDLE device ) { + EFI_GUID *protocol = &efi_simple_network_protocol_guid; + int rc; + + /* Exclude existing SNP drivers */ + if ( ( rc = efi_driver_exclude ( device, protocol ) ) != 0 ) { + DBGC ( device, "SNP %s could not exclude drivers: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + return rc; + } + + return 0; +} + /** * Attach driver to device * diff --git a/src/drivers/net/efi/snpnet.h b/src/drivers/net/efi/snpnet.h index 4699c7892..d3602a589 100644 --- a/src/drivers/net/efi/snpnet.h +++ b/src/drivers/net/efi/snpnet.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); struct efi_device; extern int snpnet_supported ( EFI_HANDLE device, EFI_GUID *protocol ); +extern int snpnet_exclude ( EFI_HANDLE device ); extern int snpnet_start ( struct efi_device *efidev ); extern void snpnet_stop ( struct efi_device *efidev ); diff --git a/src/drivers/net/efi/snponly.c b/src/drivers/net/efi/snponly.c index 267572e34..88c74ed42 100644 --- a/src/drivers/net/efi/snponly.c +++ b/src/drivers/net/efi/snponly.c @@ -209,8 +209,8 @@ static int mnponly_supported ( EFI_HANDLE device ) { /** EFI SNP chainloading-device-only driver */ struct efi_driver snponly_driver __efi_driver ( EFI_DRIVER_SNP ) = { .name = "SNPONLY", - .exclude = &efi_simple_network_protocol_guid, .supported = snponly_supported, + .exclude = snpnet_exclude, .start = snpnet_start, .stop = snpnet_stop, }; @@ -218,8 +218,8 @@ struct efi_driver snponly_driver __efi_driver ( EFI_DRIVER_SNP ) = { /** EFI NII chainloading-device-only driver */ struct efi_driver niionly_driver __efi_driver ( EFI_DRIVER_NII ) = { .name = "NIIONLY", - .exclude = &efi_nii31_protocol_guid, .supported = niionly_supported, + .exclude = nii_exclude, .start = nii_start, .stop = nii_stop, }; diff --git a/src/drivers/usb/usbio.c b/src/drivers/usb/usbio.c index 991b290ad..97860a281 100644 --- a/src/drivers/usb/usbio.c +++ b/src/drivers/usb/usbio.c @@ -1542,6 +1542,26 @@ static int usbio_interfaces ( struct usbio_device *usbio ) { return rc; } +/** + * Exclude existing drivers + * + * @v device EFI device handle + * @ret rc Return status code + */ +static int usbio_exclude ( EFI_HANDLE device ) { + EFI_GUID *protocol = &efi_usb_io_protocol_guid; + int rc; + + /* Exclude existing USB I/O protocol drivers */ + if ( ( rc = efi_driver_exclude ( device, protocol ) ) != 0 ) { + DBGC ( device, "USBIO %s could not exclude drivers: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + return rc; + } + + return 0; +} + /** * Attach driver to device * @@ -1651,8 +1671,8 @@ static void usbio_stop ( struct efi_device *efidev ) { /** EFI USB I/O driver */ struct efi_driver usbio_driver __efi_driver ( EFI_DRIVER_HARDWARE ) = { .name = "USBIO", - .exclude = &efi_usb_io_protocol_guid, .supported = usbio_supported, + .exclude = usbio_exclude, .start = usbio_start, .stop = usbio_stop, }; diff --git a/src/include/ipxe/efi/efi_driver.h b/src/include/ipxe/efi/efi_driver.h index 4c2148919..5ab2d011a 100644 --- a/src/include/ipxe/efi/efi_driver.h +++ b/src/include/ipxe/efi/efi_driver.h @@ -33,8 +33,13 @@ struct efi_device { struct efi_driver { /** Name */ const char *name; - /** Protocol to which exclusive access is required, if any */ - EFI_GUID *exclude; + /** + * Exclude existing drivers + * + * @v device EFI device handle + * @ret rc Return status code + */ + int ( * exclude ) ( EFI_HANDLE device ); /** * Check if driver supports device * @@ -95,6 +100,7 @@ extern void efidev_free ( struct efi_device *efidev ); extern struct efi_device * efidev_parent ( struct device *dev ); extern int efi_driver_install ( void ); extern void efi_driver_uninstall ( void ); +extern int efi_driver_exclude ( EFI_HANDLE device, EFI_GUID *protocol ); extern int efi_driver_connect_all ( void ); extern void efi_driver_disconnect_all ( void ); extern void efi_driver_reconnect_all ( void ); diff --git a/src/interface/efi/efi_driver.c b/src/interface/efi/efi_driver.c index 8c5e00bfb..ce1db228d 100644 --- a/src/interface/efi/efi_driver.c +++ b/src/interface/efi/efi_driver.c @@ -448,7 +448,7 @@ void efi_driver_uninstall ( void ) { * @v protocol Protocol GUID * @ret rc Return status code */ -static int efi_driver_exclude ( EFI_HANDLE device, EFI_GUID *protocol ) { +int efi_driver_exclude ( EFI_HANDLE device, EFI_GUID *protocol ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *openers; EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *opener; @@ -479,6 +479,8 @@ static int efi_driver_exclude ( EFI_HANDLE device, EFI_GUID *protocol ) { } /* Try to disconnect driver */ + DBGC ( device, "EFIDRV %s disconnecting %s drivers\n", + efi_handle_name ( device ), efi_guid_ntoa ( protocol ) ); if ( driver ) { DBGC ( device, "EFIDRV %s disconnecting %s driver ", efi_handle_name ( device ), efi_guid_ntoa ( protocol ) ); @@ -514,7 +516,6 @@ static int efi_driver_connect ( EFI_HANDLE device ) { EFI_HANDLE drivers[2] = { efi_driver_binding.DriverBindingHandle, NULL }; struct efi_driver *efidrv; - EFI_GUID *exclude; EFI_STATUS efirc; int rc; @@ -533,17 +534,14 @@ static int efi_driver_connect ( EFI_HANDLE device ) { efi_handle_name ( device ) ); efi_driver_disconnecting = 1; for_each_table_entry_reverse ( efidrv, EFI_DRIVERS ) { - exclude = efidrv->exclude; - if ( ! exclude ) + if ( ! efidrv->exclude ) continue; if ( ( rc = efidrv->supported ( device ) ) != 0 ) continue; - DBGC ( device, "EFIDRV %s disconnecting %s drivers\n", - efi_handle_name ( device ), efi_guid_ntoa ( exclude ) ); - if ( ( rc = efi_driver_exclude ( device, exclude ) ) != 0 ) { - DBGC ( device, "EFIDRV %s could not disconnect %s " + if ( ( rc = efidrv->exclude ( device ) ) != 0 ) { + DBGC ( device, "EFIDRV %s could not disconnect " "drivers: %s\n", efi_handle_name ( device ), - efi_guid_ntoa ( exclude ), strerror ( rc ) ); + strerror ( rc ) ); /* Ignore the error and attempt to connect anyway */ } } diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index f98794c27..dd11dd342 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -829,6 +829,26 @@ static int efipci_supported ( EFI_HANDLE device ) { return 0; } +/** + * Exclude existing drivers + * + * @v device EFI device handle + * @ret rc Return status code + */ +static int efipci_exclude ( EFI_HANDLE device ) { + EFI_GUID *protocol = &efi_pci_io_protocol_guid; + int rc; + + /* Exclude existing PCI I/O protocol drivers */ + if ( ( rc = efi_driver_exclude ( device, protocol ) ) != 0 ) { + DBGC ( device, "EFIPCI %s could not exclude drivers: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + return rc; + } + + return 0; +} + /** * Attach driver to device * @@ -916,8 +936,8 @@ static void efipci_stop ( struct efi_device *efidev ) { /** EFI PCI driver */ struct efi_driver efipci_driver __efi_driver ( EFI_DRIVER_HARDWARE ) = { .name = "PCI", - .exclude = &efi_pci_io_protocol_guid, .supported = efipci_supported, + .exclude = efipci_exclude, .start = efipci_start, .stop = efipci_stop, };