diff options
Diffstat (limited to 'src/drivers/net/efi/snpnet.c')
-rw-r--r-- | src/drivers/net/efi/snpnet.c | 70 |
1 files changed, 69 insertions, 1 deletions
diff --git a/src/drivers/net/efi/snpnet.c b/src/drivers/net/efi/snpnet.c index 3b09d491..6ce731d7 100644 --- a/src/drivers/net/efi/snpnet.c +++ b/src/drivers/net/efi/snpnet.c @@ -26,12 +26,14 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/iobuf.h> #include <ipxe/netdevice.h> #include <ipxe/ethernet.h> +#include <ipxe/if_ether.h> #include <ipxe/vsprintf.h> #include <ipxe/timer.h> #include <ipxe/efi/efi.h> #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 @@ -71,6 +73,19 @@ struct snp_nic { /** Delay between each initialisation retry */ #define SNP_INITIALIZE_RETRY_DELAY_MS 10 +/** Additional padding for receive buffers + * + * Some SNP implementations seem to require additional space in the + * allocated receive buffers, otherwise full-length packets will be + * silently dropped. + * + * The EDK2 MnpDxe driver happens to allocate an additional 8 bytes of + * padding (4 for a VLAN tag, 4 for the Ethernet frame checksum). + * Match this behaviour since drivers are very likely to have been + * tested against MnpDxe. + */ +#define SNP_RX_PAD 8 + /** * Format SNP MAC address (for debugging) * @@ -174,6 +189,12 @@ static int snpnet_transmit ( struct net_device *netdev, return 0; } + /* Pad to minimum Ethernet length, to work around underlying + * drivers that do not correctly handle frame padding + * themselves. + */ + iob_pad ( iobuf, ETH_ZLEN ); + /* Transmit packet */ if ( ( efirc = snp->snp->Transmit ( snp->snp, 0, iob_len ( iobuf ), iobuf->data, NULL, NULL, @@ -246,7 +267,7 @@ static void snpnet_poll_rx ( struct net_device *netdev ) { /* Allocate buffer, if required */ if ( ! snp->rxbuf ) { - snp->rxbuf = alloc_iob ( snp->mtu ); + snp->rxbuf = alloc_iob ( snp->mtu + SNP_RX_PAD ); if ( ! snp->rxbuf ) { /* Leave for next poll */ break; @@ -465,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 |