diff options
Diffstat (limited to 'qemu/roms/ipxe/src/drivers/net/efi')
-rw-r--r-- | qemu/roms/ipxe/src/drivers/net/efi/nii.c | 1185 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/drivers/net/efi/nii.h | 17 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/drivers/net/efi/snp.c | 117 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/drivers/net/efi/snpnet.c | 563 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/drivers/net/efi/snpnet.h | 17 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/drivers/net/efi/snponly.c | 212 |
6 files changed, 0 insertions, 2111 deletions
diff --git a/qemu/roms/ipxe/src/drivers/net/efi/nii.c b/qemu/roms/ipxe/src/drivers/net/efi/nii.c deleted file mode 100644 index b91848f5c..000000000 --- a/qemu/roms/ipxe/src/drivers/net/efi/nii.c +++ /dev/null @@ -1,1185 +0,0 @@ -/* - * Copyright (C) 2014 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 ); - -#include <string.h> -#include <strings.h> -#include <unistd.h> -#include <errno.h> -#include <ipxe/netdevice.h> -#include <ipxe/ethernet.h> -#include <ipxe/umalloc.h> -#include <ipxe/efi/efi.h> -#include <ipxe/efi/efi_driver.h> -#include <ipxe/efi/efi_pci.h> -#include <ipxe/efi/efi_utils.h> -#include <ipxe/efi/Protocol/NetworkInterfaceIdentifier.h> -#include <ipxe/efi/IndustryStandard/Acpi10.h> -#include "nii.h" - -/** @file - * - * NII driver - * - */ - -/* Error numbers generated by NII */ -#define EIO_INVALID_CDB __einfo_error ( EINFO_EIO_INVALID_CDB ) -#define EINFO_EIO_INVALID_CDB \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_INVALID_CDB, \ - "Invalid CDB" ) -#define EIO_INVALID_CPB __einfo_error ( EINFO_EIO_INVALID_CPB ) -#define EINFO_EIO_INVALID_CPB \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_INVALID_CPB, \ - "Invalid CPB" ) -#define EIO_BUSY __einfo_error ( EINFO_EIO_BUSY ) -#define EINFO_EIO_BUSY \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_BUSY, \ - "Busy" ) -#define EIO_QUEUE_FULL __einfo_error ( EINFO_EIO_QUEUE_FULL ) -#define EINFO_EIO_QUEUE_FULL \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_QUEUE_FULL, \ - "Queue full" ) -#define EIO_ALREADY_STARTED __einfo_error ( EINFO_EIO_ALREADY_STARTED ) -#define EINFO_EIO_ALREADY_STARTED \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_ALREADY_STARTED, \ - "Already started" ) -#define EIO_NOT_STARTED __einfo_error ( EINFO_EIO_NOT_STARTED ) -#define EINFO_EIO_NOT_STARTED \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_NOT_STARTED, \ - "Not started" ) -#define EIO_NOT_SHUTDOWN __einfo_error ( EINFO_EIO_NOT_SHUTDOWN ) -#define EINFO_EIO_NOT_SHUTDOWN \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_NOT_SHUTDOWN, \ - "Not shutdown" ) -#define EIO_ALREADY_INITIALIZED __einfo_error ( EINFO_EIO_ALREADY_INITIALIZED ) -#define EINFO_EIO_ALREADY_INITIALIZED \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_ALREADY_INITIALIZED, \ - "Already initialized" ) -#define EIO_NOT_INITIALIZED __einfo_error ( EINFO_EIO_NOT_INITIALIZED ) -#define EINFO_EIO_NOT_INITIALIZED \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_NOT_INITIALIZED, \ - "Not initialized" ) -#define EIO_DEVICE_FAILURE __einfo_error ( EINFO_EIO_DEVICE_FAILURE ) -#define EINFO_EIO_DEVICE_FAILURE \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_DEVICE_FAILURE, \ - "Device failure" ) -#define EIO_NVDATA_FAILURE __einfo_error ( EINFO_EIO_NVDATA_FAILURE ) -#define EINFO_EIO_NVDATA_FAILURE \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_NVDATA_FAILURE, \ - "Non-volatile data failure" ) -#define EIO_UNSUPPORTED __einfo_error ( EINFO_EIO_UNSUPPORTED ) -#define EINFO_EIO_UNSUPPORTED \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_UNSUPPORTED, \ - "Unsupported" ) -#define EIO_BUFFER_FULL __einfo_error ( EINFO_EIO_BUFFER_FULL ) -#define EINFO_EIO_BUFFER_FULL \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_BUFFER_FULL, \ - "Buffer full" ) -#define EIO_INVALID_PARAMETER __einfo_error ( EINFO_EIO_INVALID_PARAMETER ) -#define EINFO_EIO_INVALID_PARAMETER \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_INVALID_PARAMETER, \ - "Invalid parameter" ) -#define EIO_INVALID_UNDI __einfo_error ( EINFO_EIO_INVALID_UNDI ) -#define EINFO_EIO_INVALID_UNDI \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_INVALID_UNDI, \ - "Invalid UNDI" ) -#define EIO_IPV4_NOT_SUPPORTED __einfo_error ( EINFO_EIO_IPV4_NOT_SUPPORTED ) -#define EINFO_EIO_IPV4_NOT_SUPPORTED \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_IPV4_NOT_SUPPORTED, \ - "IPv4 not supported" ) -#define EIO_IPV6_NOT_SUPPORTED __einfo_error ( EINFO_EIO_IPV6_NOT_SUPPORTED ) -#define EINFO_EIO_IPV6_NOT_SUPPORTED \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_IPV6_NOT_SUPPORTED, \ - "IPv6 not supported" ) -#define EIO_NOT_ENOUGH_MEMORY __einfo_error ( EINFO_EIO_NOT_ENOUGH_MEMORY ) -#define EINFO_EIO_NOT_ENOUGH_MEMORY \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_NOT_ENOUGH_MEMORY, \ - "Not enough memory" ) -#define EIO_NO_DATA __einfo_error ( EINFO_EIO_NO_DATA ) -#define EINFO_EIO_NO_DATA \ - __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_NO_DATA, \ - "No data" ) -#define EIO_STAT( stat ) \ - EUNIQ ( EINFO_EIO, -(stat), EIO_INVALID_CDB, EIO_INVALID_CPB, \ - EIO_BUSY, EIO_QUEUE_FULL, EIO_ALREADY_STARTED, \ - EIO_NOT_STARTED, EIO_NOT_SHUTDOWN, EIO_ALREADY_INITIALIZED, \ - EIO_NOT_INITIALIZED, EIO_DEVICE_FAILURE, EIO_NVDATA_FAILURE, \ - EIO_UNSUPPORTED, EIO_BUFFER_FULL, EIO_INVALID_PARAMETER, \ - EIO_INVALID_UNDI, EIO_IPV4_NOT_SUPPORTED, \ - EIO_IPV6_NOT_SUPPORTED, EIO_NOT_ENOUGH_MEMORY, EIO_NO_DATA ) - -/** Maximum PCI BAR - * - * This is defined in <ipxe/efi/IndustryStandard/Pci22.h>, but we - * can't #include that since it collides with <ipxe/pci.h>. - */ -#define PCI_MAX_BAR 6 - -/** An NII NIC */ -struct nii_nic { - /** EFI device */ - struct efi_device *efidev; - /** Network interface identifier protocol */ - EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *nii; - /** !PXE structure */ - PXE_SW_UNDI *undi; - /** Entry point */ - EFIAPI VOID ( * issue ) ( UINT64 cdb ); - /** Generic device */ - struct device dev; - - /** PCI device */ - EFI_HANDLE pci_device; - /** PCI I/O protocol */ - EFI_PCI_IO_PROTOCOL *pci_io; - /** Memory BAR */ - unsigned int mem_bar; - /** I/O BAR */ - unsigned int io_bar; - - /** Broadcast address */ - PXE_MAC_ADDR broadcast; - /** Maximum packet length */ - size_t mtu; - - /** Hardware transmit/receive buffer */ - userptr_t buffer; - /** Hardware transmit/receive buffer length */ - size_t buffer_len; - - /** Saved task priority level */ - EFI_TPL saved_tpl; - - /** Media status is supported */ - int media; - - /** Current transmit buffer */ - struct io_buffer *txbuf; - /** Current receive buffer */ - struct io_buffer *rxbuf; -}; - -/** Maximum number of received packets per poll */ -#define NII_RX_QUOTA 4 - -/** - * Open PCI I/O protocol and identify BARs - * - * @v nii NII NIC - * @ret rc Return status code - */ -static int nii_pci_open ( struct nii_nic *nii ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - EFI_HANDLE device = nii->efidev->device; - EFI_HANDLE pci_device; - union { - EFI_PCI_IO_PROTOCOL *pci_io; - void *interface; - } pci_io; - union { - EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *acpi; - void *resource; - } desc; - unsigned int bar; - EFI_STATUS efirc; - int rc; - - /* Locate PCI I/O protocol */ - if ( ( rc = efi_locate_device ( device, &efi_pci_io_protocol_guid, - &pci_device ) ) != 0 ) { - DBGC ( nii, "NII %s could not locate PCI I/O protocol: %s\n", - nii->dev.name, strerror ( rc ) ); - goto err_locate; - } - nii->pci_device = pci_device; - - /* Open PCI I/O protocol */ - if ( ( efirc = bs->OpenProtocol ( pci_device, &efi_pci_io_protocol_guid, - &pci_io.interface, efi_image_handle, - device, - EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ - rc = -EEFI ( efirc ); - DBGC ( nii, "NII %s could not open PCI I/O protocol: %s\n", - nii->dev.name, strerror ( rc ) ); - goto err_open; - } - nii->pci_io = pci_io.pci_io; - - /* Identify memory and I/O BARs */ - nii->mem_bar = PCI_MAX_BAR; - nii->io_bar = PCI_MAX_BAR; - for ( bar = 0 ; bar < PCI_MAX_BAR ; bar++ ) { - efirc = nii->pci_io->GetBarAttributes ( nii->pci_io, bar, NULL, - &desc.resource ); - if ( efirc == EFI_UNSUPPORTED ) { - /* BAR not present; ignore */ - continue; - } - if ( efirc != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( nii, "NII %s could not get BAR %d attributes: " - "%s\n", nii->dev.name, bar, strerror ( rc ) ); - goto err_get_bar_attributes; - } - if ( desc.acpi->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM ) { - nii->mem_bar = bar; - } else if ( desc.acpi->ResType == ACPI_ADDRESS_SPACE_TYPE_IO ) { - nii->io_bar = bar; - } - bs->FreePool ( desc.resource ); - } - DBGC ( nii, "NII %s has ", nii->dev.name ); - if ( nii->mem_bar < PCI_MAX_BAR ) { - DBGC ( nii, "memory BAR %d and ", nii->mem_bar ); - } else { - DBGC ( nii, "no memory BAR and " ); - } - if ( nii->io_bar < PCI_MAX_BAR ) { - DBGC ( nii, "I/O BAR %d\n", nii->io_bar ); - } else { - DBGC ( nii, "no I/O BAR\n" ); - } - - return 0; - - err_get_bar_attributes: - bs->CloseProtocol ( pci_device, &efi_pci_io_protocol_guid, - efi_image_handle, device ); - err_open: - err_locate: - return rc; -} - -/** - * Close PCI I/O protocol - * - * @v nii NII NIC - * @ret rc Return status code - */ -static void nii_pci_close ( struct nii_nic *nii ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - - bs->CloseProtocol ( nii->pci_device, &efi_pci_io_protocol_guid, - efi_image_handle, nii->efidev->device ); -} - -/** - * I/O callback - * - * @v unique_id NII NIC - * @v op Operations - * @v len Length of data - * @v addr Address - * @v data Data buffer - */ -static EFIAPI VOID nii_io ( UINT64 unique_id, UINT8 op, UINT8 len, UINT64 addr, - UINT64 data ) { - struct nii_nic *nii = ( ( void * ) ( intptr_t ) unique_id ); - EFI_PCI_IO_PROTOCOL_ACCESS *access; - EFI_PCI_IO_PROTOCOL_IO_MEM io; - EFI_PCI_IO_PROTOCOL_WIDTH width; - unsigned int bar; - EFI_STATUS efirc; - int rc; - - /* Determine accessor and BAR */ - if ( op & ( PXE_MEM_READ | PXE_MEM_WRITE ) ) { - access = &nii->pci_io->Mem; - bar = nii->mem_bar; - } else { - access = &nii->pci_io->Io; - bar = nii->io_bar; - } - - /* Determine operaton */ - io = ( ( op & ( PXE_IO_WRITE | PXE_MEM_WRITE ) ) ? - access->Write : access->Read ); - - /* Determine width */ - width = ( fls ( len ) - 1 ); - - /* Issue operation */ - if ( ( efirc = io ( nii->pci_io, width, bar, addr, 1, - ( ( void * ) ( intptr_t ) data ) ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( nii, "NII %s I/O operation %#x failed: %s\n", - nii->dev.name, op, strerror ( rc ) ); - /* No way to report failure */ - return; - } -} - -/** - * Delay callback - * - * @v unique_id NII NIC - * @v microseconds Delay in microseconds - */ -static EFIAPI VOID nii_delay ( UINT64 unique_id __unused, UINTN microseconds ) { - - udelay ( microseconds ); -} - -/** - * Block callback - * - * @v unique_id NII NIC - * @v acquire Acquire lock - */ -static EFIAPI VOID nii_block ( UINT64 unique_id, UINT32 acquire ) { - struct nii_nic *nii = ( ( void * ) ( intptr_t ) unique_id ); - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - - /* This functionality (which is copied verbatim from the - * SnpDxe implementation of this function) appears to be - * totally brain-dead, since it produces no actual blocking - * behaviour. - */ - if ( acquire ) { - nii->saved_tpl = bs->RaiseTPL ( TPL_NOTIFY ); - } else { - bs->RestoreTPL ( nii->saved_tpl ); - } -} - -/** - * Construct operation from opcode and flags - * - * @v opcode Opcode - * @v opflags Flags - * @ret op Operation - */ -#define NII_OP( opcode, opflags ) ( (opcode) | ( (opflags) << 16 ) ) - -/** - * Extract opcode from operation - * - * @v op Operation - * @ret opcode Opcode - */ -#define NII_OPCODE( op ) ( (op) & 0xffff ) - -/** - * Extract flags from operation - * - * @v op Operation - * @ret opflags Flags - */ -#define NII_OPFLAGS( op ) ( (op) >> 16 ) - -/** - * Issue command with parameter block and data block - * - * @v nii NII NIC - * @v op Operation - * @v cpb Command parameter block, or NULL - * @v cpb_len Command parameter block length - * @v db Data block, or NULL - * @v db_len Data block length - * @ret stat Status flags, or negative status code - */ -static int nii_issue_cpb_db ( struct nii_nic *nii, unsigned int op, void *cpb, - size_t cpb_len, void *db, size_t db_len ) { - PXE_CDB cdb; - - /* Prepare command descriptor block */ - memset ( &cdb, 0, sizeof ( cdb ) ); - cdb.OpCode = NII_OPCODE ( op ); - cdb.OpFlags = NII_OPFLAGS ( op ); - cdb.CPBaddr = ( ( intptr_t ) cpb ); - cdb.CPBsize = cpb_len; - cdb.DBaddr = ( ( intptr_t ) db ); - cdb.DBsize = db_len; - cdb.IFnum = nii->nii->IfNum; - - /* Issue command */ - DBGC2 ( nii, "NII %s issuing %02x:%04x ifnum %d%s%s\n", - nii->dev.name, cdb.OpCode, cdb.OpFlags, cdb.IFnum, - ( cpb ? " cpb" : "" ), ( db ? " db" : "" ) ); - if ( cpb ) - DBGC2_HD ( nii, cpb, cpb_len ); - if ( db ) - DBGC2_HD ( nii, db, db_len ); - nii->issue ( ( intptr_t ) &cdb ); - - /* Check completion status */ - if ( cdb.StatCode != PXE_STATCODE_SUCCESS ) - return -cdb.StatCode; - - /* Return command-specific status flags */ - return ( cdb.StatFlags & ~PXE_STATFLAGS_STATUS_MASK ); -} - -/** - * Issue command with parameter block - * - * @v nii NII NIC - * @v op Operation - * @v cpb Command parameter block, or NULL - * @v cpb_len Command parameter block length - * @ret stat Status flags, or negative status code - */ -static int nii_issue_cpb ( struct nii_nic *nii, unsigned int op, void *cpb, - size_t cpb_len ) { - - return nii_issue_cpb_db ( nii, op, cpb, cpb_len, NULL, 0 ); -} - -/** - * Issue command with data block - * - * @v nii NII NIC - * @v op Operation - * @v db Data block, or NULL - * @v db_len Data block length - * @ret stat Status flags, or negative status code - */ -static int nii_issue_db ( struct nii_nic *nii, unsigned int op, void *db, - size_t db_len ) { - - return nii_issue_cpb_db ( nii, op, NULL, 0, db, db_len ); -} - -/** - * Issue command - * - * - * @v nii NII NIC - * @v op Operation - * @ret stat Status flags, or negative status code - */ -static int nii_issue ( struct nii_nic *nii, unsigned int op ) { - - return nii_issue_cpb_db ( nii, op, NULL, 0, NULL, 0 ); -} - -/** - * Start UNDI - * - * @v nii NII NIC - * @ret rc Return status code - */ -static int nii_start_undi ( struct nii_nic *nii ) { - PXE_CPB_START_31 cpb; - int stat; - int rc; - - /* Construct parameter block */ - memset ( &cpb, 0, sizeof ( cpb ) ); - cpb.Delay = ( ( intptr_t ) nii_delay ); - cpb.Block = ( ( intptr_t ) nii_block ); - cpb.Mem_IO = ( ( intptr_t ) nii_io ); - cpb.Unique_ID = ( ( intptr_t ) nii ); - - /* Issue command */ - if ( ( stat = nii_issue_cpb ( nii, PXE_OPCODE_START, &cpb, - sizeof ( cpb ) ) ) < 0 ) { - rc = -EIO_STAT ( stat ); - DBGC ( nii, "NII %s could not start: %s\n", - nii->dev.name, strerror ( rc ) ); - return rc; - } - - return 0; -} - -/** - * Stop UNDI - * - * @v nii NII NIC - */ -static void nii_stop_undi ( struct nii_nic *nii ) { - int stat; - int rc; - - /* Issue command */ - if ( ( stat = nii_issue ( nii, PXE_OPCODE_STOP ) ) < 0 ) { - rc = -EIO_STAT ( stat ); - DBGC ( nii, "NII %s could not stop: %s\n", - nii->dev.name, strerror ( rc ) ); - /* Nothing we can do about it */ - return; - } -} - -/** - * Get initialisation information - * - * @v nii NII NIC - * @v netdev Network device to fill in - * @ret rc Return status code - */ -static int nii_get_init_info ( struct nii_nic *nii, - struct net_device *netdev ) { - PXE_DB_GET_INIT_INFO db; - int stat; - int rc; - - /* Issue command */ - if ( ( stat = nii_issue_db ( nii, PXE_OPCODE_GET_INIT_INFO, &db, - sizeof ( db ) ) ) < 0 ) { - rc = -EIO_STAT ( stat ); - DBGC ( nii, "NII %s could not get initialisation info: %s\n", - nii->dev.name, strerror ( rc ) ); - return rc; - } - - /* Determine link layer protocol */ - switch ( db.IFtype ) { - case PXE_IFTYPE_ETHERNET : - netdev->ll_protocol = ðernet_protocol; - break; - default: - DBGC ( nii, "NII %s unknown interface type %#02x\n", - nii->dev.name, db.IFtype ); - return -ENOTSUP; - } - - /* Sanity checks */ - assert ( db.MediaHeaderLen == netdev->ll_protocol->ll_header_len ); - assert ( db.HWaddrLen == netdev->ll_protocol->hw_addr_len ); - assert ( db.HWaddrLen == netdev->ll_protocol->ll_addr_len ); - - /* Extract parameters */ - nii->buffer_len = db.MemoryRequired; - nii->mtu = ( db.FrameDataLen + db.MediaHeaderLen ); - netdev->max_pkt_len = nii->mtu; - nii->media = ( stat & PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED ); - - return 0; -} - -/** - * Initialise UNDI - * - * @v nii NII NIC - * @v flags Flags - * @ret rc Return status code - */ -static int nii_initialise_flags ( struct nii_nic *nii, unsigned int flags ) { - PXE_CPB_INITIALIZE cpb; - PXE_DB_INITIALIZE db; - unsigned int op; - int stat; - int rc; - - /* Allocate memory buffer */ - nii->buffer = umalloc ( nii->buffer_len ); - if ( ! nii->buffer ) { - rc = -ENOMEM; - goto err_alloc; - } - - /* Construct parameter block */ - memset ( &cpb, 0, sizeof ( cpb ) ); - cpb.MemoryAddr = ( ( intptr_t ) nii->buffer ); - cpb.MemoryLength = nii->buffer_len; - - /* Construct data block */ - memset ( &db, 0, sizeof ( db ) ); - - /* Issue command */ - op = NII_OP ( PXE_OPCODE_INITIALIZE, flags ); - if ( ( stat = nii_issue_cpb_db ( nii, op, &cpb, sizeof ( cpb ), - &db, sizeof ( db ) ) ) < 0 ) { - rc = -EIO_STAT ( stat ); - DBGC ( nii, "NII %s could not initialise: %s\n", - nii->dev.name, strerror ( rc ) ); - goto err_initialize; - } - - return 0; - - err_initialize: - ufree ( nii->buffer ); - err_alloc: - return rc; -} - -/** - * Initialise UNDI - * - * @v nii NII NIC - * @ret rc Return status code - */ -static int nii_initialise ( struct nii_nic *nii ) { - unsigned int flags; - - /* Initialise UNDI */ - flags = PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE; - return nii_initialise_flags ( nii, flags ); -} - -/** - * Initialise UNDI and detect cable - * - * @v nii NII NIC - * @ret rc Return status code - */ -static int nii_initialise_and_detect ( struct nii_nic *nii ) { - unsigned int flags; - - /* Initialise UNDI and detect cable. This is required to work - * around bugs in some Emulex NII drivers. - */ - flags = PXE_OPFLAGS_INITIALIZE_DETECT_CABLE; - return nii_initialise_flags ( nii, flags ); -} - -/** - * Shut down UNDI - * - * @v nii NII NIC - */ -static void nii_shutdown ( struct nii_nic *nii ) { - int stat; - int rc; - - /* Issue command */ - if ( ( stat = nii_issue ( nii, PXE_OPCODE_SHUTDOWN ) ) < 0 ) { - rc = -EIO_STAT ( stat ); - DBGC ( nii, "NII %s could not shut down: %s\n", - nii->dev.name, strerror ( rc ) ); - /* Leak memory to avoid corruption */ - return; - } - - /* Free buffer */ - ufree ( nii->buffer ); -} - -/** - * Get station addresses - * - * @v nii NII NIC - * @v netdev Network device to fill in - * @ret rc Return status code - */ -static int nii_get_station_address ( struct nii_nic *nii, - struct net_device *netdev ) { - PXE_DB_STATION_ADDRESS db; - unsigned int op; - int stat; - int rc; - - /* Initialise UNDI */ - if ( ( rc = nii_initialise ( nii ) ) != 0 ) - goto err_initialise; - - /* Issue command */ - op = NII_OP ( PXE_OPCODE_STATION_ADDRESS, - PXE_OPFLAGS_STATION_ADDRESS_READ ); - if ( ( stat = nii_issue_db ( nii, op, &db, sizeof ( db ) ) ) < 0 ) { - rc = -EIO_STAT ( stat ); - DBGC ( nii, "NII %s could not get station address: %s\n", - nii->dev.name, strerror ( rc ) ); - goto err_station_address; - } - - /* Copy MAC addresses */ - memcpy ( netdev->ll_addr, db.StationAddr, - netdev->ll_protocol->ll_addr_len ); - memcpy ( netdev->hw_addr, db.PermanentAddr, - netdev->ll_protocol->hw_addr_len ); - memcpy ( nii->broadcast, db.BroadcastAddr, - sizeof ( nii->broadcast ) ); - - err_station_address: - nii_shutdown ( nii ); - err_initialise: - return rc; -} - -/** - * Set station address - * - * @v nii NII NIC - * @v netdev Network device - * @ret rc Return status code - */ -static int nii_set_station_address ( struct nii_nic *nii, - struct net_device *netdev ) { - uint32_t implementation = nii->undi->Implementation; - PXE_CPB_STATION_ADDRESS cpb; - unsigned int op; - int stat; - int rc; - - /* Fail if setting station address is unsupported */ - if ( ! ( implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE ) ) - return -ENOTSUP; - - /* Construct parameter block */ - memset ( &cpb, 0, sizeof ( cpb ) ); - memcpy ( cpb.StationAddr, netdev->ll_addr, - netdev->ll_protocol->ll_addr_len ); - - /* Issue command */ - op = NII_OP ( PXE_OPCODE_STATION_ADDRESS, - PXE_OPFLAGS_STATION_ADDRESS_WRITE ); - if ( ( stat = nii_issue_cpb ( nii, op, &cpb, sizeof ( cpb ) ) ) < 0 ) { - rc = -EIO_STAT ( stat ); - DBGC ( nii, "NII %s could not set station address: %s\n", - nii->dev.name, strerror ( rc ) ); - return rc; - } - - return 0; -} - -/** - * Set receive filters - * - * @v nii NII NIC - * @ret rc Return status code - */ -static int nii_set_rx_filters ( struct nii_nic *nii ) { - uint32_t implementation = nii->undi->Implementation; - unsigned int flags; - unsigned int op; - int stat; - int rc; - - /* Construct receive filter set */ - flags = ( PXE_OPFLAGS_RECEIVE_FILTER_ENABLE | - PXE_OPFLAGS_RECEIVE_FILTER_UNICAST ); - if ( implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED ) - flags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST; - if ( implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED ) - flags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS; - if ( implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED ) - flags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST; - - /* Issue command */ - op = NII_OP ( PXE_OPCODE_RECEIVE_FILTERS, flags ); - if ( ( stat = nii_issue ( nii, op ) ) < 0 ) { - rc = -EIO_STAT ( stat ); - DBGC ( nii, "NII %s could not set receive filters %#04x: %s\n", - nii->dev.name, flags, strerror ( rc ) ); - return rc; - } - - return 0; -} - -/** - * Transmit packet - * - * @v netdev Network device - * @v iobuf I/O buffer - * @ret rc Return status code - */ -static int nii_transmit ( struct net_device *netdev, - struct io_buffer *iobuf ) { - struct nii_nic *nii = netdev->priv; - PXE_CPB_TRANSMIT cpb; - unsigned int op; - int stat; - int rc; - - /* Defer the packet if there is already a transmission in progress */ - if ( nii->txbuf ) { - netdev_tx_defer ( netdev, iobuf ); - return 0; - } - - /* Construct parameter block */ - memset ( &cpb, 0, sizeof ( cpb ) ); - cpb.FrameAddr = virt_to_bus ( iobuf->data ); - cpb.DataLen = iob_len ( iobuf ); - cpb.MediaheaderLen = netdev->ll_protocol->ll_header_len; - - /* Transmit packet */ - op = NII_OP ( PXE_OPCODE_TRANSMIT, - ( PXE_OPFLAGS_TRANSMIT_WHOLE | - PXE_OPFLAGS_TRANSMIT_DONT_BLOCK ) ); - if ( ( stat = nii_issue_cpb ( nii, op, &cpb, sizeof ( cpb ) ) ) < 0 ) { - rc = -EIO_STAT ( stat ); - DBGC ( nii, "NII %s could not transmit: %s\n", - nii->dev.name, strerror ( rc ) ); - return rc; - } - nii->txbuf = iobuf; - - return 0; -} - -/** - * Poll for completed packets - * - * @v netdev Network device - * @v stat Status flags - */ -static void nii_poll_tx ( struct net_device *netdev, unsigned int stat ) { - struct nii_nic *nii = netdev->priv; - struct io_buffer *iobuf; - - /* Do nothing unless we have a completion */ - if ( stat & PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN ) - return; - - /* Sanity check */ - assert ( nii->txbuf != NULL ); - - /* Complete transmission */ - iobuf = nii->txbuf; - nii->txbuf = NULL; - netdev_tx_complete ( netdev, iobuf ); -} - -/** - * Poll for received packets - * - * @v netdev Network device - */ -static void nii_poll_rx ( struct net_device *netdev ) { - struct nii_nic *nii = netdev->priv; - PXE_CPB_RECEIVE cpb; - PXE_DB_RECEIVE db; - unsigned int quota; - int stat; - int rc; - - /* Retrieve up to NII_RX_QUOTA packets */ - for ( quota = NII_RX_QUOTA ; quota ; quota-- ) { - - /* Allocate buffer, if required */ - if ( ! nii->rxbuf ) { - nii->rxbuf = alloc_iob ( nii->mtu ); - if ( ! nii->rxbuf ) { - /* Leave for next poll */ - break; - } - } - - /* Construct parameter block */ - memset ( &cpb, 0, sizeof ( cpb ) ); - cpb.BufferAddr = virt_to_bus ( nii->rxbuf->data ); - cpb.BufferLen = iob_tailroom ( nii->rxbuf ); - - /* Issue command */ - if ( ( stat = nii_issue_cpb_db ( nii, PXE_OPCODE_RECEIVE, - &cpb, sizeof ( cpb ), - &db, sizeof ( db ) ) ) < 0 ) { - - /* PXE_STATCODE_NO_DATA is just the usual "no packet" - * status indicator; ignore it. - */ - if ( stat == -PXE_STATCODE_NO_DATA ) - break; - - /* Anything else is an error */ - rc = -EIO_STAT ( stat ); - DBGC ( nii, "NII %s could not receive: %s\n", - nii->dev.name, strerror ( rc ) ); - netdev_rx_err ( netdev, NULL, rc ); - break; - } - - /* Hand off to network stack */ - iob_put ( nii->rxbuf, db.FrameLen ); - netdev_rx ( netdev, nii->rxbuf ); - nii->rxbuf = NULL; - } -} - -/** - * Check for link state changes - * - * @v netdev Network device - * @v stat Status flags - */ -static void nii_poll_link ( struct net_device *netdev, unsigned int stat ) { - int no_media = ( stat & PXE_STATFLAGS_GET_STATUS_NO_MEDIA ); - - if ( no_media && netdev_link_ok ( netdev ) ) { - netdev_link_down ( netdev ); - } else if ( ( ! no_media ) && ( ! netdev_link_ok ( netdev ) ) ) { - netdev_link_up ( netdev ); - } -} - -/** - * Poll for completed packets - * - * @v netdev Network device - */ -static void nii_poll ( struct net_device *netdev ) { - struct nii_nic *nii = netdev->priv; - PXE_DB_GET_STATUS db; - unsigned int op; - int stat; - int rc; - - /* Construct data block */ - memset ( &db, 0, sizeof ( db ) ); - - /* Get status */ - op = NII_OP ( PXE_OPCODE_GET_STATUS, - ( PXE_OPFLAGS_GET_INTERRUPT_STATUS | - ( nii->txbuf ? PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS : 0)| - ( nii->media ? PXE_OPFLAGS_GET_MEDIA_STATUS : 0 ) ) ); - if ( ( stat = nii_issue_db ( nii, op, &db, sizeof ( db ) ) ) < 0 ) { - rc = -EIO_STAT ( stat ); - DBGC ( nii, "NII %s could not get status: %s\n", - nii->dev.name, strerror ( rc ) ); - return; - } - - /* Process any TX completions */ - if ( nii->txbuf ) - nii_poll_tx ( netdev, stat ); - - /* Process any RX completions */ - nii_poll_rx ( netdev ); - - /* Check for link state changes */ - if ( nii->media ) - nii_poll_link ( netdev, stat ); -} - -/** - * Open network device - * - * @v netdev Network device - * @ret rc Return status code - */ -static int nii_open ( struct net_device *netdev ) { - struct nii_nic *nii = netdev->priv; - int rc; - - /* Initialise NIC - * - * Some Emulex NII drivers have a bug which prevents packets - * from being sent or received unless we specifically ask it - * to detect cable presence during initialisation. Work - * around these buggy drivers by requesting cable detection at - * this point, even though we don't care about link state here - * (and would prefer to have the NIC initialise even if no - * cable is present, to match the behaviour of all other iPXE - * drivers). - */ - if ( ( rc = nii_initialise_and_detect ( nii ) ) != 0 ) - goto err_initialise; - - /* Attempt to set station address */ - if ( ( rc = nii_set_station_address ( nii, netdev ) ) != 0 ) { - DBGC ( nii, "NII %s could not set station address: %s\n", - nii->dev.name, strerror ( rc ) ); - /* Treat as non-fatal */ - } - - /* Set receive filters */ - if ( ( rc = nii_set_rx_filters ( nii ) ) != 0 ) - goto err_set_rx_filters; - - return 0; - - err_set_rx_filters: - nii_shutdown ( nii ); - err_initialise: - return rc; -} - -/** - * Close network device - * - * @v netdev Network device - */ -static void nii_close ( struct net_device *netdev ) { - struct nii_nic *nii = netdev->priv; - - /* Shut down NIC */ - nii_shutdown ( nii ); - - /* Discard transmit buffer, if applicable */ - if ( nii->txbuf ) { - netdev_tx_complete_err ( netdev, nii->txbuf, -ECANCELED ); - nii->txbuf = NULL; - } - - /* Discard receive buffer, if applicable */ - if ( nii->rxbuf ) { - free_iob ( nii->rxbuf ); - nii->rxbuf = NULL; - } -} - -/** NII network device operations */ -static struct net_device_operations nii_operations = { - .open = nii_open, - .close = nii_close, - .transmit = nii_transmit, - .poll = nii_poll, -}; - -/** - * Attach driver to device - * - * @v efidev EFI device - * @ret rc Return status code - */ -int nii_start ( struct efi_device *efidev ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - EFI_HANDLE device = efidev->device; - struct net_device *netdev; - struct nii_nic *nii; - void *interface; - EFI_STATUS efirc; - int rc; - - /* Allocate and initialise structure */ - netdev = alloc_netdev ( sizeof ( *nii ) ); - if ( ! netdev ) { - rc = -ENOMEM; - goto err_alloc; - } - netdev_init ( netdev, &nii_operations ); - nii = netdev->priv; - nii->efidev = efidev; - netdev->ll_broadcast = nii->broadcast; - efidev_set_drvdata ( efidev, netdev ); - - /* Populate underlying device information */ - efi_device_info ( device, "NII", &nii->dev ); - nii->dev.driver_name = "NII"; - nii->dev.parent = &efidev->dev; - list_add ( &nii->dev.siblings, &efidev->dev.children ); - INIT_LIST_HEAD ( &nii->dev.children ); - netdev->dev = &nii->dev; - - /* Open NII protocol */ - if ( ( efirc = bs->OpenProtocol ( device, &efi_nii31_protocol_guid, - &interface, efi_image_handle, device, - ( EFI_OPEN_PROTOCOL_BY_DRIVER | - EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){ - rc = -EEFI ( efirc ); - DBGC ( nii, "NII %s cannot open NII protocol: %s\n", - nii->dev.name, strerror ( rc ) ); - DBGC_EFI_OPENERS ( device, device, &efi_nii31_protocol_guid ); - goto err_open_protocol; - } - nii->nii = interface; - - /* Locate UNDI and entry point */ - nii->undi = ( ( void * ) ( intptr_t ) nii->nii->Id ); - if ( ! nii->undi ) { - DBGC ( nii, "NII %s has no UNDI\n", nii->dev.name ); - rc = -ENODEV; - goto err_no_undi; - } - if ( nii->undi->Implementation & PXE_ROMID_IMP_HW_UNDI ) { - DBGC ( nii, "NII %s is a mythical hardware UNDI\n", - nii->dev.name ); - rc = -ENOTSUP; - goto err_hw_undi; - } - if ( nii->undi->Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR ) { - nii->issue = ( ( void * ) ( intptr_t ) nii->undi->EntryPoint ); - } else { - nii->issue = ( ( ( void * ) nii->undi ) + - nii->undi->EntryPoint ); - } - DBGC ( nii, "NII %s using UNDI v%x.%x at %p entry %p impl %#08x\n", - nii->dev.name, nii->nii->MajorVer, nii->nii->MinorVer, - nii->undi, nii->issue, nii->undi->Implementation ); - - /* Open PCI I/O protocols and locate BARs */ - if ( ( rc = nii_pci_open ( nii ) ) != 0 ) - goto err_pci_open; - - /* Start UNDI */ - if ( ( rc = nii_start_undi ( nii ) ) != 0 ) - goto err_start_undi; - - /* Get initialisation information */ - if ( ( rc = nii_get_init_info ( nii, netdev ) ) != 0 ) - goto err_get_init_info; - - /* Get MAC addresses */ - if ( ( rc = nii_get_station_address ( nii, netdev ) ) != 0 ) - goto err_get_station_address; - - /* Register network device */ - if ( ( rc = register_netdev ( netdev ) ) != 0 ) - goto err_register_netdev; - DBGC ( nii, "NII %s registered as %s for %p %s\n", nii->dev.name, - netdev->name, device, efi_handle_name ( device ) ); - - /* Set initial link state (if media detection is not supported) */ - if ( ! nii->media ) - netdev_link_up ( netdev ); - - return 0; - - unregister_netdev ( netdev ); - err_register_netdev: - err_get_station_address: - err_get_init_info: - nii_stop_undi ( nii ); - err_start_undi: - nii_pci_close ( nii ); - err_pci_open: - err_hw_undi: - err_no_undi: - bs->CloseProtocol ( device, &efi_nii31_protocol_guid, - efi_image_handle, device ); - err_open_protocol: - list_del ( &nii->dev.siblings ); - netdev_nullify ( netdev ); - netdev_put ( netdev ); - err_alloc: - return rc; -} - -/** - * Detach driver from device - * - * @v efidev EFI device - */ -void nii_stop ( struct efi_device *efidev ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - struct net_device *netdev = efidev_get_drvdata ( efidev ); - struct nii_nic *nii = netdev->priv; - EFI_HANDLE device = efidev->device; - - /* Unregister network device */ - unregister_netdev ( netdev ); - - /* Stop UNDI */ - nii_stop_undi ( nii ); - - /* Close PCI I/O protocols */ - nii_pci_close ( nii ); - - /* Close NII protocol */ - bs->CloseProtocol ( device, &efi_nii31_protocol_guid, - efi_image_handle, device ); - - /* Free network device */ - list_del ( &nii->dev.siblings ); - netdev_nullify ( netdev ); - netdev_put ( netdev ); -} diff --git a/qemu/roms/ipxe/src/drivers/net/efi/nii.h b/qemu/roms/ipxe/src/drivers/net/efi/nii.h deleted file mode 100644 index c10be9db5..000000000 --- a/qemu/roms/ipxe/src/drivers/net/efi/nii.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _NII_H -#define _NII_H - -/** @file - * - * NII driver - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -struct efi_device; - -extern int nii_start ( struct efi_device *efidev ); -extern void nii_stop ( struct efi_device *efidev ); - -#endif /* _NII_H */ diff --git a/qemu/roms/ipxe/src/drivers/net/efi/snp.c b/qemu/roms/ipxe/src/drivers/net/efi/snp.c deleted file mode 100644 index acfcfba9f..000000000 --- a/qemu/roms/ipxe/src/drivers/net/efi/snp.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2014 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 ); - -#include <errno.h> -#include <ipxe/efi/efi.h> -#include <ipxe/efi/efi_driver.h> -#include <ipxe/efi/efi_snp.h> -#include "snpnet.h" -#include "nii.h" - -/** @file - * - * SNP driver - * - */ - -/** - * 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 ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - EFI_STATUS efirc; - - /* Check that this is not a device we are providing ourselves */ - if ( find_snpdev ( device ) != NULL ) { - DBGCP ( device, "SNP %p %s is provided by this binary\n", - device, efi_handle_name ( device ) ); - return -ENOTTY; - } - - /* Test for presence of simple network protocol */ - if ( ( efirc = bs->OpenProtocol ( device, - &efi_simple_network_protocol_guid, - NULL, efi_image_handle, device, - EFI_OPEN_PROTOCOL_TEST_PROTOCOL))!=0){ - DBGCP ( device, "SNP %p %s is not an SNP device\n", - device, efi_handle_name ( device ) ); - return -EEFI ( efirc ); - } - DBGC ( device, "SNP %p %s is an SNP device\n", - device, efi_handle_name ( device ) ); - - return 0; -} - -/** - * Check to see if driver supports a device - * - * @v device EFI device handle - * @ret rc Return status code - */ -static int nii_supported ( EFI_HANDLE device ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - EFI_STATUS efirc; - - /* Check that this is not a device we are providing ourselves */ - if ( find_snpdev ( device ) != NULL ) { - DBGCP ( device, "NII %p %s is provided by this binary\n", - device, efi_handle_name ( device ) ); - return -ENOTTY; - } - - /* Test for presence of NII protocol */ - if ( ( efirc = bs->OpenProtocol ( device, - &efi_nii31_protocol_guid, - NULL, efi_image_handle, device, - EFI_OPEN_PROTOCOL_TEST_PROTOCOL))!=0){ - DBGCP ( device, "NII %p %s is not an NII device\n", - device, efi_handle_name ( device ) ); - return -EEFI ( efirc ); - } - DBGC ( device, "NII %p %s is an NII device\n", - device, efi_handle_name ( device ) ); - - return 0; -} - -/** EFI SNP driver */ -struct efi_driver snp_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { - .name = "SNP", - .supported = snp_supported, - .start = snpnet_start, - .stop = snpnet_stop, -}; - -/** EFI NII driver */ -struct efi_driver nii_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { - .name = "NII", - .supported = nii_supported, - .start = nii_start, - .stop = nii_stop, -}; diff --git a/qemu/roms/ipxe/src/drivers/net/efi/snpnet.c b/qemu/roms/ipxe/src/drivers/net/efi/snpnet.c deleted file mode 100644 index 96642c4ca..000000000 --- a/qemu/roms/ipxe/src/drivers/net/efi/snpnet.c +++ /dev/null @@ -1,563 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <ipxe/iobuf.h> -#include <ipxe/netdevice.h> -#include <ipxe/ethernet.h> -#include <ipxe/vsprintf.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 "snpnet.h" - -/** @file - * - * SNP NIC driver - * - */ - -/** An SNP NIC */ -struct snp_nic { - /** EFI device */ - struct efi_device *efidev; - /** Simple network protocol */ - EFI_SIMPLE_NETWORK_PROTOCOL *snp; - /** Generic device */ - struct device dev; - - /** Maximum packet size - * - * This is calculated as the sum of MediaHeaderSize and - * MaxPacketSize, and may therefore be an overestimate. - */ - size_t mtu; - - /** Current transmit buffer */ - struct io_buffer *txbuf; - /** Current receive buffer */ - struct io_buffer *rxbuf; -}; - -/** Maximum number of received packets per poll */ -#define SNP_RX_QUOTA 4 - -/** - * Format SNP MAC address (for debugging) - * - * @v mac MAC address - * @v len Length of MAC address - * @ret text MAC address as text - */ -static const char * snpnet_mac_text ( EFI_MAC_ADDRESS *mac, size_t len ) { - static char buf[ sizeof ( *mac ) * 3 /* "xx:" or "xx\0" */ ]; - size_t used = 0; - unsigned int i; - - for ( i = 0 ; i < len ; i++ ) { - used += ssnprintf ( &buf[used], ( sizeof ( buf ) - used ), - "%s%02x", ( used ? ":" : "" ), - mac->Addr[i] ); - } - return buf; -} - -/** - * Dump SNP mode information (for debugging) - * - * @v netdev Network device - */ -static void snpnet_dump_mode ( struct net_device *netdev ) { - struct snp_nic *snp = netdev_priv ( netdev ); - EFI_SIMPLE_NETWORK_MODE *mode = snp->snp->Mode; - size_t mac_len = mode->HwAddressSize; - unsigned int i; - - /* Do nothing unless debugging is enabled */ - if ( ! DBG_EXTRA ) - return; - - DBGC2 ( snp, "SNP %s st %d type %d hdr %d pkt %d rxflt %#x/%#x%s " - "nvram %d acc %d mcast %d/%d\n", netdev->name, mode->State, - mode->IfType, mode->MediaHeaderSize, mode->MaxPacketSize, - mode->ReceiveFilterSetting, mode->ReceiveFilterMask, - ( mode->MultipleTxSupported ? " multitx" : "" ), - mode->NvRamSize, mode->NvRamAccessSize, - mode->MCastFilterCount, mode->MaxMCastFilterCount ); - DBGC2 ( snp, "SNP %s hw %s", netdev->name, - snpnet_mac_text ( &mode->PermanentAddress, mac_len ) ); - DBGC2 ( snp, " addr %s%s", - snpnet_mac_text ( &mode->CurrentAddress, mac_len ), - ( mode->MacAddressChangeable ? "" : "(f)" ) ); - DBGC2 ( snp, " bcast %s\n", - snpnet_mac_text ( &mode->BroadcastAddress, mac_len ) ); - for ( i = 0 ; i < mode->MCastFilterCount ; i++ ) { - DBGC2 ( snp, "SNP %s mcast %s\n", netdev->name, - snpnet_mac_text ( &mode->MCastFilter[i], mac_len ) ); - } - DBGC2 ( snp, "SNP %s media %s\n", netdev->name, - ( mode->MediaPresentSupported ? - ( mode->MediaPresent ? "present" : "not present" ) : - "presence not supported" ) ); -} - -/** - * Check link state - * - * @v netdev Network device - */ -static void snpnet_check_link ( struct net_device *netdev ) { - struct snp_nic *snp = netdev_priv ( netdev ); - EFI_SIMPLE_NETWORK_MODE *mode = snp->snp->Mode; - - /* Do nothing unless media presence detection is supported */ - if ( ! mode->MediaPresentSupported ) - return; - - /* Report any link status change */ - if ( mode->MediaPresent && ( ! netdev_link_ok ( netdev ) ) ) { - netdev_link_up ( netdev ); - } else if ( ( ! mode->MediaPresent ) && netdev_link_ok ( netdev ) ) { - netdev_link_down ( netdev ); - } -} - -/** - * Transmit packet - * - * @v netdev Network device - * @v iobuf I/O buffer - * @ret rc Return status code - */ -static int snpnet_transmit ( struct net_device *netdev, - struct io_buffer *iobuf ) { - struct snp_nic *snp = netdev_priv ( netdev ); - EFI_STATUS efirc; - int rc; - - /* Defer the packet if there is already a transmission in progress */ - if ( snp->txbuf ) { - netdev_tx_defer ( netdev, iobuf ); - return 0; - } - - /* Transmit packet */ - if ( ( efirc = snp->snp->Transmit ( snp->snp, 0, iob_len ( iobuf ), - iobuf->data, NULL, NULL, - NULL ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( snp, "SNP %s could not transmit: %s\n", - netdev->name, strerror ( rc ) ); - return rc; - } - snp->txbuf = iobuf; - - return 0; -} - -/** - * Poll for completed packets - * - * @v netdev Network device - */ -static void snpnet_poll_tx ( struct net_device *netdev ) { - struct snp_nic *snp = netdev->priv; - struct io_buffer *iobuf; - UINT32 irq; - VOID *txbuf; - EFI_STATUS efirc; - int rc; - - /* Get status */ - if ( ( efirc = snp->snp->GetStatus ( snp->snp, &irq, &txbuf ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( snp, "SNP %s could not get status: %s\n", - netdev->name, strerror ( rc ) ); - netdev_rx_err ( netdev, NULL, rc ); - return; - } - - /* Do nothing unless we have a completion */ - if ( ! txbuf ) - return; - - /* Sanity check */ - if ( ! snp->txbuf ) { - DBGC ( snp, "SNP %s reported spurious TX completion\n", - netdev->name ); - netdev_tx_err ( netdev, NULL, -EPIPE ); - return; - } - - /* Complete transmission */ - iobuf = snp->txbuf; - snp->txbuf = NULL; - netdev_tx_complete ( netdev, iobuf ); -} - -/** - * Poll for received packets - * - * @v netdev Network device - */ -static void snpnet_poll_rx ( struct net_device *netdev ) { - struct snp_nic *snp = netdev->priv; - UINTN len; - unsigned int quota; - EFI_STATUS efirc; - int rc; - - /* Retrieve up to SNP_RX_QUOTA packets */ - for ( quota = SNP_RX_QUOTA ; quota ; quota-- ) { - - /* Allocate buffer, if required */ - if ( ! snp->rxbuf ) { - snp->rxbuf = alloc_iob ( snp->mtu ); - if ( ! snp->rxbuf ) { - /* Leave for next poll */ - break; - } - } - - /* Receive packet */ - len = iob_tailroom ( snp->rxbuf ); - if ( ( efirc = snp->snp->Receive ( snp->snp, NULL, &len, - snp->rxbuf->data, NULL, - NULL, NULL ) ) != 0 ) { - - /* EFI_NOT_READY is just the usual "no packet" - * status indication; ignore it. - */ - if ( efirc == EFI_NOT_READY ) - break; - - /* Anything else is an error */ - rc = -EEFI ( efirc ); - DBGC ( snp, "SNP %s could not receive: %s\n", - netdev->name, strerror ( rc ) ); - netdev_rx_err ( netdev, NULL, rc ); - break; - } - - /* Hand off to network stack */ - iob_put ( snp->rxbuf, len ); - netdev_rx ( netdev, snp->rxbuf ); - snp->rxbuf = NULL; - } -} - -/** - * Poll for completed packets - * - * @v netdev Network device - */ -static void snpnet_poll ( struct net_device *netdev ) { - - /* Process any TX completions */ - snpnet_poll_tx ( netdev ); - - /* Process any RX completions */ - snpnet_poll_rx ( netdev ); - - /* Check for link state changes */ - snpnet_check_link ( netdev ); -} - -/** - * Set receive filters - * - * @v netdev Network device - * @ret rc Return status code - */ -static int snpnet_rx_filters ( struct net_device *netdev ) { - struct snp_nic *snp = netdev->priv; - UINT32 filters[] = { - snp->snp->Mode->ReceiveFilterMask, - ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | - EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | - EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST ), - ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | - EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST ), - ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST ), - }; - unsigned int i; - EFI_STATUS efirc; - int rc; - - /* Try possible receive filters in turn */ - for ( i = 0; i < ( sizeof ( filters ) / sizeof ( filters[0] ) ); i++ ) { - efirc = snp->snp->ReceiveFilters ( snp->snp, filters[i], - 0, TRUE, 0, NULL ); - if ( efirc == 0 ) - return 0; - rc = -EEFI ( efirc ); - DBGC ( snp, "SNP %s could not set receive filters %#02x (have " - "%#02x): %s\n", netdev->name, filters[i], - snp->snp->Mode->ReceiveFilterSetting, strerror ( rc ) ); - } - - return rc; -} - -/** - * Open network device - * - * @v netdev Network device - * @ret rc Return status code - */ -static int snpnet_open ( struct net_device *netdev ) { - struct snp_nic *snp = netdev->priv; - EFI_MAC_ADDRESS *mac = ( ( void * ) netdev->ll_addr ); - EFI_STATUS efirc; - int rc; - - /* Try setting MAC address (before initialising) */ - if ( ( efirc = snp->snp->StationAddress ( snp->snp, FALSE, mac ) ) !=0){ - rc = -EEFI ( efirc ); - DBGC ( snp, "SNP %s could not set station address before " - "initialising: %s\n", netdev->name, strerror ( rc ) ); - /* Ignore error */ - } - - /* Initialise NIC */ - if ( ( efirc = snp->snp->Initialize ( snp->snp, 0, 0 ) ) != 0 ) { - rc = -EEFI ( efirc ); - snpnet_dump_mode ( netdev ); - DBGC ( snp, "SNP %s could not initialise: %s\n", - netdev->name, strerror ( rc ) ); - return rc; - } - - /* Try setting MAC address (after initialising) */ - if ( ( efirc = snp->snp->StationAddress ( snp->snp, FALSE, mac ) ) !=0){ - rc = -EEFI ( efirc ); - DBGC ( snp, "SNP %s could not set station address after " - "initialising: %s\n", netdev->name, strerror ( rc ) ); - /* Ignore error */ - } - - /* Set receive filters */ - if ( ( rc = snpnet_rx_filters ( netdev ) ) != 0 ) { - /* Ignore error */ - } - - /* Dump mode information (for debugging) */ - snpnet_dump_mode ( netdev ); - - return 0; -} - -/** - * Close network device - * - * @v netdev Network device - */ -static void snpnet_close ( struct net_device *netdev ) { - struct snp_nic *snp = netdev->priv; - EFI_STATUS efirc; - int rc; - - /* Shut down NIC */ - if ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( snp, "SNP %s could not shut down: %s\n", - netdev->name, strerror ( rc ) ); - /* Nothing we can do about this */ - } - - /* Discard transmit buffer, if applicable */ - if ( snp->txbuf ) { - netdev_tx_complete_err ( netdev, snp->txbuf, -ECANCELED ); - snp->txbuf = NULL; - } - - /* Discard receive buffer, if applicable */ - if ( snp->rxbuf ) { - free_iob ( snp->rxbuf ); - snp->rxbuf = NULL; - } -} - -/** SNP network device operations */ -static struct net_device_operations snpnet_operations = { - .open = snpnet_open, - .close = snpnet_close, - .transmit = snpnet_transmit, - .poll = snpnet_poll, -}; - -/** - * Attach driver to device - * - * @v efidev EFI device - * @ret rc Return status code - */ -int snpnet_start ( struct efi_device *efidev ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - EFI_HANDLE device = efidev->device; - EFI_SIMPLE_NETWORK_MODE *mode; - struct net_device *netdev; - struct snp_nic *snp; - void *interface; - EFI_STATUS efirc; - int rc; - - /* Open SNP protocol */ - if ( ( efirc = bs->OpenProtocol ( device, - &efi_simple_network_protocol_guid, - &interface, efi_image_handle, device, - ( EFI_OPEN_PROTOCOL_BY_DRIVER | - EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){ - rc = -EEFI ( efirc ); - DBGC ( device, "SNP %p %s cannot open SNP protocol: %s\n", - device, efi_handle_name ( device ), strerror ( rc ) ); - DBGC_EFI_OPENERS ( device, device, - &efi_simple_network_protocol_guid ); - goto err_open_protocol; - } - - /* Allocate and initialise structure */ - netdev = alloc_etherdev ( sizeof ( *snp ) ); - if ( ! netdev ) { - rc = -ENOMEM; - goto err_alloc; - } - netdev_init ( netdev, &snpnet_operations ); - snp = netdev->priv; - snp->efidev = efidev; - snp->snp = interface; - mode = snp->snp->Mode; - efidev_set_drvdata ( efidev, netdev ); - - /* Populate underlying device information */ - efi_device_info ( device, "SNP", &snp->dev ); - snp->dev.driver_name = "SNP"; - snp->dev.parent = &efidev->dev; - list_add ( &snp->dev.siblings, &efidev->dev.children ); - INIT_LIST_HEAD ( &snp->dev.children ); - netdev->dev = &snp->dev; - - /* Bring to the Started state */ - if ( ( mode->State == EfiSimpleNetworkStopped ) && - ( ( efirc = snp->snp->Start ( snp->snp ) ) != 0 ) ) { - rc = -EEFI ( efirc ); - DBGC ( device, "SNP %p %s could not start: %s\n", device, - efi_handle_name ( device ), strerror ( rc ) ); - goto err_start; - } - if ( ( mode->State == EfiSimpleNetworkInitialized ) && - ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) { - rc = -EEFI ( efirc ); - DBGC ( device, "SNP %p %s could not shut down: %s\n", device, - efi_handle_name ( device ), strerror ( rc ) ); - goto err_shutdown; - } - - /* Populate network device parameters */ - if ( mode->HwAddressSize != netdev->ll_protocol->hw_addr_len ) { - DBGC ( device, "SNP %p %s has invalid hardware address " - "length %d\n", device, 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, "SNP %p %s has invalid link-layer address " - "length %d\n", device, 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 ); - snp->mtu = ( snp->snp->Mode->MaxPacketSize + - snp->snp->Mode->MediaHeaderSize ); - - /* Register network device */ - if ( ( rc = register_netdev ( netdev ) ) != 0 ) - goto err_register_netdev; - DBGC ( device, "SNP %p %s registered as %s\n", - device, efi_handle_name ( device ), netdev->name ); - - /* Set initial link state */ - if ( snp->snp->Mode->MediaPresentSupported ) { - snpnet_check_link ( netdev ); - } else { - netdev_link_up ( netdev ); - } - - return 0; - - unregister_netdev ( netdev ); - err_register_netdev: - err_ll_addr_len: - err_hw_addr_len: - err_shutdown: - err_start: - list_del ( &snp->dev.siblings ); - netdev_nullify ( netdev ); - netdev_put ( netdev ); - err_alloc: - bs->CloseProtocol ( device, &efi_simple_network_protocol_guid, - efi_image_handle, device ); - err_open_protocol: - return rc; -} - -/** - * Detach driver from device - * - * @v efidev EFI device - */ -void snpnet_stop ( struct efi_device *efidev ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - struct net_device *netdev = efidev_get_drvdata ( efidev ); - struct snp_nic *snp = netdev->priv; - EFI_HANDLE device = efidev->device; - EFI_STATUS efirc; - int rc; - - /* Unregister network device */ - unregister_netdev ( netdev ); - - /* Stop SNP protocol */ - if ( ( efirc = snp->snp->Stop ( snp->snp ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( device, "SNP %p %s could not stop: %s\n", device, - efi_handle_name ( device ), strerror ( rc ) ); - /* Nothing we can do about this */ - } - - /* Free network device */ - list_del ( &snp->dev.siblings ); - netdev_nullify ( netdev ); - netdev_put ( netdev ); - - /* Close SNP protocol */ - bs->CloseProtocol ( device, &efi_simple_network_protocol_guid, - efi_image_handle, device ); -} diff --git a/qemu/roms/ipxe/src/drivers/net/efi/snpnet.h b/qemu/roms/ipxe/src/drivers/net/efi/snpnet.h deleted file mode 100644 index e6d31d5e4..000000000 --- a/qemu/roms/ipxe/src/drivers/net/efi/snpnet.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _SNPNET_H -#define _SNPNET_H - -/** @file - * - * SNP NIC driver - * - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -struct efi_device; - -extern int snpnet_start ( struct efi_device *efidev ); -extern void snpnet_stop ( struct efi_device *efidev ); - -#endif /* _SNPNET_H */ diff --git a/qemu/roms/ipxe/src/drivers/net/efi/snponly.c b/qemu/roms/ipxe/src/drivers/net/efi/snponly.c deleted file mode 100644 index 73abfdbf4..000000000 --- a/qemu/roms/ipxe/src/drivers/net/efi/snponly.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (C) 2014 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 ); - -#include <string.h> -#include <errno.h> -#include <ipxe/init.h> -#include <ipxe/efi/efi.h> -#include <ipxe/efi/efi_driver.h> -#include <ipxe/efi/efi_utils.h> -#include <ipxe/efi/Protocol/SimpleNetwork.h> -#include <ipxe/efi/Protocol/NetworkInterfaceIdentifier.h> -#include "snpnet.h" -#include "nii.h" - -/** @file - * - * EFI chainloaded-device-only driver - * - */ - -/** A chainloaded protocol */ -struct chained_protocol { - /** Protocol GUID */ - EFI_GUID *protocol; - /** - * Protocol instance installed on the loaded image's device handle - * - * We match against the protocol instance (rather than simply - * matching against the device handle itself) because some - * systems load us via a child of the underlying device, with - * a duplicate protocol installed on the child handle. - */ - void *interface; -}; - -/** Chainloaded SNP protocol */ -static struct chained_protocol chained_snp = { - .protocol = &efi_simple_network_protocol_guid, -}; - -/** Chainloaded NII protocol */ -static struct chained_protocol chained_nii = { - .protocol = &efi_nii31_protocol_guid, -}; - -/** - * Locate chainloaded protocol instance - * - * @v chained Chainloaded protocol - * @ret rc Return status code - */ -static int chained_locate ( struct chained_protocol *chained ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - EFI_HANDLE device = efi_loaded_image->DeviceHandle; - EFI_HANDLE parent; - EFI_STATUS efirc; - int rc; - - /* Locate handle supporting this protocol */ - if ( ( rc = efi_locate_device ( device, chained->protocol, - &parent ) ) != 0 ) { - DBGC ( device, "CHAINED %p %s does not support %s: %s\n", - device, efi_handle_name ( device ), - efi_guid_ntoa ( chained->protocol ), strerror ( rc ) ); - goto err_locate_device; - } - DBGC ( device, "CHAINED %p %s found %s on ", device, - efi_handle_name ( device ), efi_guid_ntoa ( chained->protocol )); - DBGC ( device, "%p %s\n", parent, efi_handle_name ( parent ) ); - - /* Get protocol instance */ - if ( ( efirc = bs->OpenProtocol ( parent, chained->protocol, - &chained->interface, efi_image_handle, - device, - EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ - rc = -EEFI ( efirc ); - DBGC ( device, "CHAINED %p %s could not open %s on ", - device, efi_handle_name ( device ), - efi_guid_ntoa ( chained->protocol ) ); - DBGC ( device, "%p %s: %s\n", - parent, efi_handle_name ( parent ), strerror ( rc ) ); - goto err_open_protocol; - } - - err_locate_device: - bs->CloseProtocol ( parent, chained->protocol, efi_image_handle, - device ); - err_open_protocol: - return rc; -} - -/** - * Check to see if driver supports a device - * - * @v device EFI device handle - * @v chained Chainloaded protocol - * @ret rc Return status code - */ -static int chained_supported ( EFI_HANDLE device, - struct chained_protocol *chained ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - EFI_STATUS efirc; - void *interface; - int rc; - - /* Get protocol */ - if ( ( efirc = bs->OpenProtocol ( device, chained->protocol, &interface, - efi_image_handle, device, - EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ - rc = -EEFI ( efirc ); - DBGCP ( device, "CHAINED %p %s is not a %s device\n", - device, efi_handle_name ( device ), - efi_guid_ntoa ( chained->protocol ) ); - goto err_open_protocol; - } - - /* Test for a match against the chainloading device */ - if ( interface != chained->interface ) { - DBGC ( device, "CHAINED %p %s %p is not the chainloaded " - "%s\n", device, efi_handle_name ( device ), - interface, efi_guid_ntoa ( chained->protocol ) ); - rc = -ENOTTY; - goto err_no_match; - } - - /* Success */ - rc = 0; - DBGC ( device, "CHAINED %p %s %p is the chainloaded %s\n", - device, efi_handle_name ( device ), interface, - efi_guid_ntoa ( chained->protocol ) ); - - err_no_match: - bs->CloseProtocol ( device, chained->protocol, efi_image_handle, - device ); - err_open_protocol: - return rc; -} - -/** - * Check to see if driver supports a device - * - * @v device EFI device handle - * @ret rc Return status code - */ -static int snponly_supported ( EFI_HANDLE device ) { - - return chained_supported ( device, &chained_snp ); -} - -/** - * Check to see if driver supports a device - * - * @v device EFI device handle - * @ret rc Return status code - */ -static int niionly_supported ( EFI_HANDLE device ) { - - return chained_supported ( device, &chained_nii ); -} - -/** EFI SNP chainloading-device-only driver */ -struct efi_driver snponly_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { - .name = "SNPONLY", - .supported = snponly_supported, - .start = snpnet_start, - .stop = snpnet_stop, -}; - -/** EFI NII chainloading-device-only driver */ -struct efi_driver niionly_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { - .name = "NIIONLY", - .supported = niionly_supported, - .start = nii_start, - .stop = nii_stop, -}; - -/** - * Initialise EFI chainloaded-device-only driver - * - */ -static void chained_init ( void ) { - - chained_locate ( &chained_snp ); - chained_locate ( &chained_nii ); -} - -/** EFI chainloaded-device-only initialisation function */ -struct init_fn chained_init_fn __init_fn ( INIT_LATE ) = { - .initialise = chained_init, -}; |