diff options
Diffstat (limited to 'src/drivers/net/efi')
-rw-r--r-- | src/drivers/net/efi/mnp.c | 56 | ||||
-rw-r--r-- | src/drivers/net/efi/mnpnet.c | 504 | ||||
-rw-r--r-- | src/drivers/net/efi/mnpnet.h | 17 | ||||
-rw-r--r-- | src/drivers/net/efi/snp.c | 54 | ||||
-rw-r--r-- | src/drivers/net/efi/snpnet.c | 48 | ||||
-rw-r--r-- | src/drivers/net/efi/snpnet.h | 1 | ||||
-rw-r--r-- | src/drivers/net/efi/snponly.c | 26 |
7 files changed, 654 insertions, 52 deletions
diff --git a/src/drivers/net/efi/mnp.c b/src/drivers/net/efi/mnp.c new file mode 100644 index 00000000..b79fe188 --- /dev/null +++ b/src/drivers/net/efi/mnp.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** @file + * + * MNP driver + * + */ + +#include <errno.h> +#include <ipxe/efi/efi.h> +#include <ipxe/efi/efi_driver.h> +#include "snpnet.h" +#include "mnpnet.h" + +/** + * Check to see if driver supports a device + * + * @v device EFI device handle + * @ret rc Return status code + */ +static int mnp_supported ( EFI_HANDLE device ) { + EFI_GUID *binding = &efi_managed_network_service_binding_protocol_guid; + + return snpnet_supported ( device, binding ); +} + +/** EFI MNP driver */ +struct efi_driver mnp_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { + .name = "MNP", + .supported = mnp_supported, + .start = mnpnet_start, + .stop = mnpnet_stop, +}; diff --git a/src/drivers/net/efi/mnpnet.c b/src/drivers/net/efi/mnpnet.c new file mode 100644 index 00000000..a07eae54 --- /dev/null +++ b/src/drivers/net/efi/mnpnet.c @@ -0,0 +1,504 @@ +/* + * Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** @file + * + * MNP NIC driver + * + */ + +#include <string.h> +#include <errno.h> +#include <ipxe/iobuf.h> +#include <ipxe/netdevice.h> +#include <ipxe/ethernet.h> +#include <ipxe/efi/efi.h> +#include <ipxe/efi/efi_driver.h> +#include <ipxe/efi/efi_service.h> +#include <ipxe/efi/efi_utils.h> +#include <ipxe/efi/Protocol/ManagedNetwork.h> +#include "mnpnet.h" + +/** An MNP transmit or receive token */ +struct mnp_token { + /** MNP completion token */ + EFI_MANAGED_NETWORK_COMPLETION_TOKEN token; + /** Token is owned by MNP */ + int busy; +}; + +/** An MNP NIC */ +struct mnp_nic { + /** EFI device */ + struct efi_device *efidev; + /** Managed network protocol */ + EFI_MANAGED_NETWORK_PROTOCOL *mnp; + /** Generic device */ + struct device dev; + + /** Transmit token */ + struct mnp_token tx; + /** Transmit descriptor */ + EFI_MANAGED_NETWORK_TRANSMIT_DATA txdata; + /** Transmit I/O buffer */ + struct io_buffer *txbuf; + + /** Receive token */ + struct mnp_token rx; +}; + +/** + * Transmit or receive token event + * + * @v event Event + * @v context Event context + */ +static VOID EFIAPI mnpnet_event ( EFI_EVENT event __unused, VOID *context ) { + struct mnp_token *token = context; + + /* Sanity check */ + assert ( token->busy ); + + /* Mark token as no longer owned by MNP */ + token->busy = 0; +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int mnpnet_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ) { + struct mnp_nic *mnp = netdev->priv; + struct ll_protocol *ll_protocol = netdev->ll_protocol; + EFI_STATUS efirc; + int rc; + + /* Do nothing if shutdown is in progress */ + if ( efi_shutdown_in_progress ) + return -ECANCELED; + + /* Defer the packet if there is already a transmission in progress */ + if ( mnp->txbuf ) { + netdev_tx_defer ( netdev, iobuf ); + return 0; + } + + /* Construct transmit token */ + mnp->txdata.DataLength = + ( iob_len ( iobuf ) - ll_protocol->ll_header_len ); + mnp->txdata.HeaderLength = ll_protocol->ll_header_len; + mnp->txdata.FragmentCount = 1; + mnp->txdata.FragmentTable[0].FragmentLength = iob_len ( iobuf ); + mnp->txdata.FragmentTable[0].FragmentBuffer = iobuf->data; + mnp->tx.token.Packet.TxData = &mnp->txdata; + + /* Record as in use */ + mnp->tx.busy = 1; + + /* Transmit packet */ + if ( ( efirc = mnp->mnp->Transmit ( mnp->mnp, &mnp->tx.token ) ) != 0 ){ + rc = -EEFI ( efirc ); + DBGC ( mnp, "MNP %s could not transmit: %s\n", + netdev->name, strerror ( rc ) ); + mnp->tx.busy = 0; + return rc; + } + + /* Record I/O buffer */ + mnp->txbuf = iobuf; + + return 0; +} + +/** + * Refill receive token + * + * @v netdev Network device + */ +static void mnpnet_refill_rx ( struct net_device *netdev ) { + struct mnp_nic *mnp = netdev->priv; + EFI_STATUS efirc; + int rc; + + /* Do nothing if receive token is still in use */ + if ( mnp->rx.busy ) + return; + + /* Mark as in use */ + mnp->rx.busy = 1; + + /* Queue receive token */ + if ( ( efirc = mnp->mnp->Receive ( mnp->mnp, &mnp->rx.token ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( mnp, "MNP %s could not receive: %s\n", + netdev->name, strerror ( rc ) ); + /* Wait for next refill */ + mnp->rx.busy = 0; + return; + } +} + +/** + * Poll for completed packets + * + * @v netdev Network device + */ +static void mnpnet_poll_tx ( struct net_device *netdev ) { + struct mnp_nic *mnp = netdev->priv; + struct io_buffer *iobuf; + EFI_STATUS efirc; + int rc; + + /* Do nothing if transmit token is still in use */ + if ( mnp->tx.busy ) + return; + + /* Do nothing unless we have a completion */ + if ( ! mnp->txbuf ) + return; + + /* Get completion status */ + efirc = mnp->tx.token.Status; + rc = ( efirc ? -EEFI ( efirc ) : 0 ); + + /* Complete transmission */ + iobuf = mnp->txbuf; + mnp->txbuf = NULL; + netdev_tx_complete_err ( netdev, iobuf, rc ); +} + +/** + * Poll for received packets + * + * @v netdev Network device + */ +static void mnpnet_poll_rx ( struct net_device *netdev ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + struct mnp_nic *mnp = netdev->priv; + EFI_MANAGED_NETWORK_RECEIVE_DATA *rxdata; + struct io_buffer *iobuf; + size_t len; + EFI_STATUS efirc; + int rc; + + /* Do nothing unless we have a completion */ + if ( mnp->rx.busy ) + return; + rxdata = mnp->rx.token.Packet.RxData; + + /* Get completion status */ + if ( ( efirc = mnp->rx.token.Status ) != 0 ) { + rc = -EEFI ( efirc ); + netdev_rx_err ( netdev, NULL, rc ); + goto recycle; + } + + /* Allocate and fill I/O buffer */ + len = rxdata->PacketLength; + iobuf = alloc_iob ( len ); + if ( ! iobuf ) { + netdev_rx_err ( netdev, NULL, -ENOMEM ); + goto recycle; + } + memcpy ( iob_put ( iobuf, len ), rxdata->MediaHeader, len ); + + /* Hand off to network stack */ + netdev_rx ( netdev, iobuf ); + + recycle: + /* Recycle token */ + bs->SignalEvent ( rxdata->RecycleEvent ); +} + +/** + * Poll for completed packets + * + * @v netdev Network device + */ +static void mnpnet_poll ( struct net_device *netdev ) { + struct mnp_nic *mnp = netdev->priv; + + /* Do nothing if shutdown is in progress */ + if ( efi_shutdown_in_progress ) + return; + + /* Poll interface */ + mnp->mnp->Poll ( mnp->mnp ); + + /* Process any transmit completions */ + mnpnet_poll_tx ( netdev ); + + /* Process any receive completions */ + mnpnet_poll_rx ( netdev ); + + /* Refill receive token */ + mnpnet_refill_rx ( netdev ); +} + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int mnpnet_open ( struct net_device *netdev ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + static EFI_MANAGED_NETWORK_CONFIG_DATA config = { + .EnableUnicastReceive = TRUE, + .EnableMulticastReceive = TRUE, + .EnableBroadcastReceive = TRUE, + .EnablePromiscuousReceive = TRUE, + .FlushQueuesOnReset = TRUE, + .DisableBackgroundPolling = TRUE, + }; + struct mnp_nic *mnp = netdev->priv; + EFI_STATUS efirc; + int rc; + + /* Create transmit event */ + if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, + mnpnet_event, &mnp->tx, + &mnp->tx.token.Event ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( mnp, "MNP %s could not create TX event: %s\n", + netdev->name, strerror ( rc ) ); + goto err_tx_event; + } + + /* Create receive event */ + if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, + mnpnet_event, &mnp->rx, + &mnp->rx.token.Event ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( mnp, "MNP %s could not create RX event: %s\n", + netdev->name, strerror ( rc ) ); + goto err_rx_event; + } + + /* Configure MNP */ + if ( ( efirc = mnp->mnp->Configure ( mnp->mnp, &config ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( mnp, "MNP %s could not configure: %s\n", + netdev->name, strerror ( rc ) ); + goto err_configure; + } + + /* Refill receive token */ + mnpnet_refill_rx ( netdev ); + + return 0; + + mnp->mnp->Configure ( mnp->mnp, NULL ); + err_configure: + bs->CloseEvent ( mnp->rx.token.Event ); + err_rx_event: + bs->CloseEvent ( mnp->tx.token.Event ); + err_tx_event: + return rc; +} + +/** + * Close network device + * + * @v netdev Network device + */ +static void mnpnet_close ( struct net_device *netdev ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + struct mnp_nic *mnp = netdev->priv; + + /* Reset MNP (unless whole system shutdown is in progress) */ + if ( ! efi_shutdown_in_progress ) + mnp->mnp->Configure ( mnp->mnp, NULL ); + + /* Close events */ + bs->CloseEvent ( mnp->rx.token.Event ); + bs->CloseEvent ( mnp->tx.token.Event ); + + /* Reset tokens */ + mnp->tx.busy = 0; + mnp->rx.busy = 0; + + /* Discard any incomplete I/O buffer */ + if ( mnp->txbuf ) { + netdev_tx_complete_err ( netdev, mnp->txbuf, -ECANCELED ); + mnp->txbuf = NULL; + } +} + +/** MNP network device operations */ +static struct net_device_operations mnpnet_operations = { + .open = mnpnet_open, + .close = mnpnet_close, + .transmit = mnpnet_transmit, + .poll = mnpnet_poll, +}; + +/** + * Attach driver to device + * + * @v efidev EFI device + * @ret rc Return status code + */ +int mnpnet_start ( struct efi_device *efidev ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE device = efidev->device; + EFI_GUID *binding = &efi_managed_network_service_binding_protocol_guid; + EFI_SIMPLE_NETWORK_MODE mode; + union { + EFI_MANAGED_NETWORK_PROTOCOL *mnp; + void *interface; + } u; + struct net_device *netdev; + struct mnp_nic *mnp; + EFI_STATUS efirc; + int rc; + + /* Allocate and initalise structure */ + netdev = alloc_etherdev ( sizeof ( *mnp ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &mnpnet_operations ); + mnp = netdev->priv; + mnp->efidev = efidev; + efidev_set_drvdata ( efidev, netdev ); + + /* Populate underlying device information */ + efi_device_info ( device, "MNP", &mnp->dev ); + mnp->dev.driver_name = "MNP"; + mnp->dev.parent = &efidev->dev; + list_add ( &mnp->dev.siblings, &efidev->dev.children ); + INIT_LIST_HEAD ( &mnp->dev.children ); + netdev->dev = &mnp->dev; + + /* Create MNP child */ + if ( ( rc = efi_service_add ( device, binding, + &efidev->child ) ) != 0 ) { + DBGC ( mnp, "MNP %s could not create child: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + goto err_service; + } + + /* Open MNP protocol */ + if ( ( efirc = bs->OpenProtocol ( efidev->child, + &efi_managed_network_protocol_guid, + &u.interface, efi_image_handle, + efidev->child, + ( EFI_OPEN_PROTOCOL_BY_DRIVER | + EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){ + rc = -EEFI ( efirc ); + DBGC ( mnp, "MNP %s could not open MNP protocol: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + goto err_open; + } + mnp->mnp = u.mnp; + + /* Get configuration */ + efirc = mnp->mnp->GetModeData ( mnp->mnp, NULL, &mode ); + if ( ( efirc != 0 ) && ( efirc != EFI_NOT_STARTED ) ) { + rc = -EEFI ( efirc ); + DBGC ( mnp, "MNP %s could not get mode data: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + goto err_mode; + } + + /* Populate network device parameters */ + if ( mode.HwAddressSize != netdev->ll_protocol->hw_addr_len ) { + DBGC ( device, "MNP %s has invalid hardware address length " + "%d\n", efi_handle_name ( device ), mode.HwAddressSize ); + rc = -ENOTSUP; + goto err_hw_addr_len; + } + memcpy ( netdev->hw_addr, &mode.PermanentAddress, + netdev->ll_protocol->hw_addr_len ); + if ( mode.HwAddressSize != netdev->ll_protocol->ll_addr_len ) { + DBGC ( device, "MNP %s has invalid link-layer address length " + "%d\n", efi_handle_name ( device ), mode.HwAddressSize ); + rc = -ENOTSUP; + goto err_ll_addr_len; + } + memcpy ( netdev->ll_addr, &mode.CurrentAddress, + netdev->ll_protocol->ll_addr_len ); + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register; + DBGC ( mnp, "MNP %s registered as %s\n", + efi_handle_name ( device ), netdev->name ); + + /* Mark as link up: we don't handle link state */ + netdev_link_up ( netdev ); + + return 0; + + unregister_netdev ( netdev ); + err_register: + err_ll_addr_len: + err_hw_addr_len: + err_mode: + bs->CloseProtocol ( efidev->child, &efi_managed_network_protocol_guid, + efi_image_handle, efidev->child ); + err_open: + efi_service_del ( device, binding, efidev->child ); + err_service: + list_del ( &mnp->dev.siblings ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc: + return rc; +} + +/** + * Detach driver from device + * + * @v efidev EFI device + */ +void mnpnet_stop ( struct efi_device *efidev ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_GUID *binding = &efi_managed_network_service_binding_protocol_guid; + struct net_device *netdev = efidev_get_drvdata ( efidev ); + struct mnp_nic *mnp = netdev->priv; + + /* Unregister network device */ + unregister_netdev ( netdev ); + + /* Close MNP protocol */ + bs->CloseProtocol ( efidev->child, &efi_managed_network_protocol_guid, + efi_image_handle, efidev->child ); + + /* Remove MNP child (unless whole system shutdown is in progress) */ + if ( ! efi_shutdown_in_progress ) + efi_service_del ( efidev->device, binding, efidev->child ); + + /* Free network device */ + list_del ( &mnp->dev.siblings ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} diff --git a/src/drivers/net/efi/mnpnet.h b/src/drivers/net/efi/mnpnet.h new file mode 100644 index 00000000..afed62aa --- /dev/null +++ b/src/drivers/net/efi/mnpnet.h @@ -0,0 +1,17 @@ +#ifndef _MNPNET_H +#define _MNPNET_H + +/** @file + * + * MNP NIC driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +struct efi_device; + +extern int mnpnet_start ( struct efi_device *efidev ); +extern void mnpnet_stop ( struct efi_device *efidev ); + +#endif /* _MNPNET_H */ diff --git a/src/drivers/net/efi/snp.c b/src/drivers/net/efi/snp.c index 1920cdbc..cac8b38e 100644 --- a/src/drivers/net/efi/snp.c +++ b/src/drivers/net/efi/snp.c @@ -23,11 +23,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); -#include <errno.h> #include <ipxe/efi/efi.h> #include <ipxe/efi/efi_driver.h> -#include <ipxe/efi/efi_snp.h> -#include <ipxe/efi/efi_utils.h> #include "snpnet.h" #include "nii.h" @@ -41,58 +38,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * Check to see if driver supports a device * * @v device EFI device handle - * @v protocol Protocol GUID - * @ret rc Return status code - */ -static int snp_nii_supported ( EFI_HANDLE device, EFI_GUID *protocol ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - EFI_HANDLE parent; - EFI_STATUS efirc; - int rc; - - /* Check that this is not a device we are providing ourselves */ - if ( find_snpdev ( device ) != NULL ) { - DBGCP ( device, "HANDLE %s is provided by this binary\n", - efi_handle_name ( device ) ); - return -ENOTTY; - } - - /* Test for presence of protocol */ - if ( ( efirc = bs->OpenProtocol ( device, protocol, - NULL, efi_image_handle, device, - EFI_OPEN_PROTOCOL_TEST_PROTOCOL))!=0){ - DBGCP ( device, "HANDLE %s is not a %s device\n", - efi_handle_name ( device ), - efi_guid_ntoa ( protocol ) ); - return -EEFI ( efirc ); - } - - /* Check that there are no instances of this protocol further - * up this device path. - */ - if ( ( rc = efi_locate_device ( device, protocol, - &parent, 1 ) ) == 0 ) { - DBGC2 ( device, "HANDLE %s has %s-supporting parent ", - efi_handle_name ( device ), - efi_guid_ntoa ( protocol ) ); - DBGC2 ( device, "%s\n", efi_handle_name ( parent ) ); - return -ENOTTY; - } - - DBGC ( device, "HANDLE %s is a %s device\n", - efi_handle_name ( device ), efi_guid_ntoa ( protocol ) ); - return 0; -} - -/** - * Check to see if driver supports a device - * - * @v device EFI device handle * @ret rc Return status code */ static int snp_supported ( EFI_HANDLE device ) { - return snp_nii_supported ( device, &efi_simple_network_protocol_guid ); + return snpnet_supported ( device, &efi_simple_network_protocol_guid ); } /** @@ -103,7 +53,7 @@ static int snp_supported ( EFI_HANDLE device ) { */ static int nii_supported ( EFI_HANDLE device ) { - return snp_nii_supported ( device, &efi_nii31_protocol_guid ); + return snpnet_supported ( device, &efi_nii31_protocol_guid ); } /** EFI SNP driver */ diff --git a/src/drivers/net/efi/snpnet.c b/src/drivers/net/efi/snpnet.c index b8bf963e..6ce731d7 100644 --- a/src/drivers/net/efi/snpnet.c +++ b/src/drivers/net/efi/snpnet.c @@ -33,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/efi/Protocol/SimpleNetwork.h> #include <ipxe/efi/efi_driver.h> #include <ipxe/efi/efi_utils.h> +#include <ipxe/efi/efi_snp.h> #include "snpnet.h" /** @file @@ -485,6 +486,53 @@ static struct net_device_operations snpnet_operations = { }; /** + * Check to see if driver supports a device + * + * @v device EFI device handle + * @v protocol Protocol GUID + * @ret rc Return status code + */ +int snpnet_supported ( EFI_HANDLE device, EFI_GUID *protocol ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE parent; + EFI_STATUS efirc; + int rc; + + /* Check that this is not a device we are providing ourselves */ + if ( find_snpdev ( device ) != NULL ) { + DBGCP ( device, "HANDLE %s is provided by this binary\n", + efi_handle_name ( device ) ); + return -ENOTTY; + } + + /* Test for presence of protocol */ + if ( ( efirc = bs->OpenProtocol ( device, protocol, + NULL, efi_image_handle, device, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL))!=0){ + DBGCP ( device, "HANDLE %s is not a %s device\n", + efi_handle_name ( device ), + efi_guid_ntoa ( protocol ) ); + return -EEFI ( efirc ); + } + + /* Check that there are no instances of this protocol further + * up this device path. + */ + if ( ( rc = efi_locate_device ( device, protocol, + &parent, 1 ) ) == 0 ) { + DBGC2 ( device, "HANDLE %s has %s-supporting parent ", + efi_handle_name ( device ), + efi_guid_ntoa ( protocol ) ); + DBGC2 ( device, "%s\n", efi_handle_name ( parent ) ); + return -ENOTTY; + } + + DBGC ( device, "HANDLE %s is a %s device\n", + efi_handle_name ( device ), efi_guid_ntoa ( protocol ) ); + return 0; +} + +/** * Attach driver to device * * @v efidev EFI device diff --git a/src/drivers/net/efi/snpnet.h b/src/drivers/net/efi/snpnet.h index e6d31d5e..4699c789 100644 --- a/src/drivers/net/efi/snpnet.h +++ b/src/drivers/net/efi/snpnet.h @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); struct efi_device; +extern int snpnet_supported ( EFI_HANDLE device, EFI_GUID *protocol ); 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 16370463..6786f3e8 100644 --- a/src/drivers/net/efi/snponly.c +++ b/src/drivers/net/efi/snponly.c @@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/efi/Protocol/SimpleNetwork.h> #include <ipxe/efi/Protocol/NetworkInterfaceIdentifier.h> #include "snpnet.h" +#include "mnpnet.h" #include "nii.h" /** @file @@ -74,6 +75,11 @@ static struct chained_protocol chained_nii = { .protocol = &efi_nii31_protocol_guid, }; +/** Chainloaded MNP protocol */ +static struct chained_protocol chained_mnp = { + .protocol = &efi_managed_network_service_binding_protocol_guid, +}; + /** * Locate chainloaded protocol * @@ -208,6 +214,17 @@ static int niionly_supported ( EFI_HANDLE device ) { return chained_supported ( device, &chained_nii ); } +/** + * Check to see if driver supports a device + * + * @v device EFI device handle + * @ret rc Return status code + */ +static int mnponly_supported ( EFI_HANDLE device ) { + + return chained_supported ( device, &chained_mnp ); +} + /** EFI SNP chainloading-device-only driver */ struct efi_driver snponly_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { .name = "SNPONLY", @@ -224,6 +241,14 @@ struct efi_driver niionly_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { .stop = nii_stop, }; +/** EFI MNP chainloading-device-only driver */ +struct efi_driver mnponly_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { + .name = "MNPONLY", + .supported = mnponly_supported, + .start = mnpnet_start, + .stop = mnpnet_stop, +}; + /** * Initialise EFI chainloaded-device-only driver * @@ -232,6 +257,7 @@ static void chained_init ( void ) { chained_locate ( &chained_snp ); chained_locate ( &chained_nii ); + chained_locate ( &chained_mnp ); } /** EFI chainloaded-device-only initialisation function */ |