/** * Reset the network device * * @v snp SNP interface * @v ext_verify Extended verification required * @ret efirc EFI status code */ static EFI_STATUS EFIAPI efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) { struct efi_snp_device *snpdev = container_of ( snp, struct efi_snp_device, snp ); int rc; DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n", snpdev, ( ext_verify ? "with" : "without" ) ); netdev_close ( snpdev->netdev ); snpdev->mode.State = EfiSimpleNetworkStarted; if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) { DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n", snpdev, snpdev->netdev->name, strerror ( rc ) ); return RC_TO_EFIRC ( rc ); } snpdev->mode.State = EfiSimpleNetworkInitialized; return 0; }
/** * Parse stored options * * @v nvo Non-volatile options block * * Verifies that the options data is valid, and configures the DHCP * options block. If the data is not valid, it is replaced with an * empty options block. */ static void nvo_init_dhcpopts ( struct nvo_block *nvo ) { uint8_t *options_data; size_t options_len; /* Steal one byte for the checksum */ options_data = ( nvo->data + 1 ); options_len = ( nvo->total_len - 1 ); /* If checksum fails, or options data starts with a zero, * assume the whole block is invalid. This should capture the * case of random initial contents. */ if ( ( nvo_checksum ( nvo ) != 0 ) || ( options_data[0] == 0 ) ) { DBGC ( nvo, "NVO %p has checksum %02x and initial byte %02x; " "assuming empty\n", nvo, nvo_checksum ( nvo ), options_data[0] ); memset ( nvo->data, 0, nvo->total_len ); } dhcpopt_init ( &nvo->dhcpopts, options_data, options_len ); }
/** * Wait for admin event queue to be torn down * * @v intelxl Intel device * @ret rc Return status code */ static int intelxlvf_reset_wait_teardown ( struct intelxl_nic *intelxl ) { uint32_t admin_evt_len; unsigned int i; /* Wait for admin event queue to be torn down */ for ( i = 0 ; i < INTELXLVF_RESET_MAX_WAIT_MS ; i++ ) { /* Check admin event queue length register */ admin_evt_len = readl ( intelxl->regs + INTELXLVF_ADMIN + INTELXLVF_ADMIN_EVT_LEN ); if ( ! ( admin_evt_len & INTELXL_ADMIN_LEN_ENABLE ) ) return 0; /* Delay */ mdelay ( 1 ); } DBGC ( intelxl, "INTELXL %p timed out waiting for teardown (%#08x)\n", intelxl, admin_evt_len ); return -ETIMEDOUT; }
/** * Set receive filters * * @v nii NII NIC * @ret rc Return status code */ static int nii_set_rx_filters ( struct nii_nic *nii ) { unsigned int op; int stat; int rc; /* Issue command */ op = NII_OP ( PXE_OPCODE_RECEIVE_FILTERS, ( PXE_OPFLAGS_RECEIVE_FILTER_ENABLE | PXE_OPFLAGS_RECEIVE_FILTER_UNICAST | PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST | PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS | PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST ) ); if ( ( stat = nii_issue ( nii, op ) ) < 0 ) { rc = -EIO_STAT ( stat ); DBGC ( nii, "NII %s could not set receive filters: %s\n", nii->dev.name, strerror ( rc ) ); return rc; } return 0; }
/** * Wait for transmit and receive to become idle * * @v myson Myson device * @ret rc Return status code */ static int myson_wait_idle ( struct myson_nic *myson ) { uint32_t tcr_rcr; unsigned int i; /* Wait for both transmit and receive to be idle */ for ( i = 0 ; i < MYSON_IDLE_MAX_WAIT_MS ; i++ ) { /* If either process is running, delay 1ms and retry */ tcr_rcr = readl ( myson->regs + MYSON_TCR_RCR ); if ( tcr_rcr & ( MYSON_TCR_TXS | MYSON_RCR_RXS ) ) { mdelay ( 1 ); continue; } return 0; } DBGC ( myson, "MYSON %p timed out waiting for idle state (status " "%08x)\n", myson, tcr_rcr ); return -ETIMEDOUT; }
/** * Initialise UNDI * * @v nii NII NIC * @ret rc Return status code */ static int nii_initialise ( struct nii_nic *nii ) { 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, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE ); 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; }
/** * Open all PeerDist discovery sockets * * @ret rc Return status code */ static int peerdisc_socket_open ( void ) { struct peerdisc_socket *socket; int rc; /* Open each socket */ for_each_table_entry ( socket, PEERDISC_SOCKETS ) { if ( ( rc = xfer_open_socket ( &socket->xfer, SOCK_DGRAM, &socket->address.sa, NULL ) ) != 0 ) { DBGC ( socket, "PEERDISC %s could not open socket: " "%s\n", socket->name, strerror ( rc ) ); goto err; } } return 0; err: for_each_table_entry_continue_reverse ( socket, PEERDISC_SOCKETS ) intf_restart ( &socket->xfer, rc ); return rc; }
/** * Probe EFI image * * @v image EFI file * @ret rc Return status code */ static int efi_image_probe ( struct image *image ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_HANDLE handle; EFI_STATUS efirc; /* Attempt loading image */ if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL, user_to_virt ( image->data, 0 ), image->len, &handle ) ) != 0 ) { /* Not an EFI image */ DBGC ( image, "EFIIMAGE %p could not load: %s\n", image, efi_strerror ( efirc ) ); return -ENOEXEC; } /* Unload the image. We can't leave it loaded, because we * have no "unload" operation. */ bs->UnloadImage ( handle ); return 0; }
/** * Enable auto-polling * * @v rhn Rhine device * @ret rc Return status code * * This is voodoo. There seems to be no documentation on exactly what * we are waiting for, or why we have to do anything other than simply * turn the feature on. */ static int rhine_mii_autopoll ( struct rhine_nic *rhn ) { unsigned int timeout = RHINE_TIMEOUT_US; uint8_t addr; /* Initiate auto-polling */ writeb ( MII_BMSR, rhn->regs + RHINE_MII_ADDR ); writeb ( RHINE_MII_CR_AUTOPOLL, rhn->regs + RHINE_MII_CR ); /* Wait for auto-polling to complete */ while ( timeout-- ) { udelay ( 1 ); addr = readb ( rhn->regs + RHINE_MII_ADDR ); if ( ! ( addr & RHINE_MII_ADDR_MDONE ) ) { writeb ( ( MII_BMSR | RHINE_MII_ADDR_MSRCEN ), rhn->regs + RHINE_MII_ADDR ); return 0; } } DBGC ( rhn, "RHINE %p MII auto-poll timeout\n", rhn ); return -ETIMEDOUT; }
/** * Probe PXE image (with rejection of potential EFI images) * * @v image PXE file * @ret rc Return status code */ int pxe_probe_no_mz ( struct image *image ) { uint16_t magic; int rc; /* Probe PXE image */ if ( ( rc = pxe_probe ( image ) ) != 0 ) return rc; /* Reject image with an "MZ" signature which may indicate an * EFI image incorrectly handed out to a BIOS system. */ if ( image->len >= sizeof ( magic ) ) { copy_from_user ( &magic, image->data, 0, sizeof ( magic ) ); if ( magic == cpu_to_le16 ( EFI_IMAGE_DOS_SIGNATURE ) ) { DBGC ( image, "IMAGE %p may be an EFI image\n", image ); return -ENOTTY; } } return 0; }
/** * Poll for received packets * * @v netdev Network device */ static void rhine_poll_rx ( struct net_device *netdev ) { struct rhine_nic *rhn = netdev->priv; struct rhine_descriptor *desc; struct io_buffer *iobuf; unsigned int rx_idx; uint32_t des0; size_t len; /* Check for received packets */ while ( rhn->rx.cons != rhn->rx.prod ) { /* Get next receive descriptor */ rx_idx = ( rhn->rx.cons % RHINE_RXDESC_NUM ); desc = &rhn->rx.desc[rx_idx]; /* Stop if descriptor is still in use */ if ( desc->des0 & cpu_to_le32 ( RHINE_DES0_OWN ) ) return; /* Populate I/O buffer */ iobuf = rhn->rx_iobuf[rx_idx]; rhn->rx_iobuf[rx_idx] = NULL; des0 = le32_to_cpu ( desc->des0 ); len = ( RHINE_DES0_GETSIZE ( des0 ) - 4 /* strip CRC */ ); iob_put ( iobuf, len ); /* Hand off to network stack */ if ( des0 & RHINE_RDES0_RXOK ) { DBGC2 ( rhn, "RHINE %p RX %d complete (length %zd)\n", rhn, rx_idx, len ); netdev_rx ( netdev, iobuf ); } else { DBGC ( rhn, "RHINE %p RX %d error (length %zd, DES0 " "%08x)\n", rhn, rx_idx, len, des0 ); netdev_rx_err ( netdev, iobuf, -EIO ); } rhn->rx.cons++; } }
/** * Get resources * * @v netdev Network device * @ret rc Return status code */ static int intelxlvf_admin_get_resources ( struct net_device *netdev ) { struct intelxl_nic *intelxl = netdev->priv; struct intelxl_admin_descriptor *cmd; struct intelxl_admin_vf_get_resources_buffer *res; int rc; /* Populate descriptor */ cmd = intelxl_admin_command_descriptor ( intelxl ); cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_GET_RESOURCES ); /* Issue command */ if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 ) return rc; /* Parse response */ res = &intelxl->vbuf.res; intelxl->vsi = le16_to_cpu ( res->vsi ); memcpy ( netdev->hw_addr, res->mac, ETH_ALEN ); DBGC ( intelxl, "INTELXL %p VSI %#04x\n", intelxl, intelxl->vsi ); return 0; }
/** * Wait for virtual function to be marked as active * * @v intelxl Intel device * @ret rc Return status code */ static int intelxlvf_reset_wait_active ( struct intelxl_nic *intelxl ) { uint32_t vfgen_rstat; unsigned int vfr_state; unsigned int i; /* Wait for virtual function to be marked as active */ for ( i = 0 ; i < INTELXLVF_RESET_MAX_WAIT_MS ; i++ ) { /* Check status as written by physical function driver */ vfgen_rstat = readl ( intelxl->regs + INTELXLVF_VFGEN_RSTAT ); vfr_state = INTELXLVF_VFGEN_RSTAT_VFR_STATE ( vfgen_rstat ); if ( vfr_state == INTELXLVF_VFGEN_RSTAT_VFR_STATE_ACTIVE ) return 0; /* Delay */ mdelay ( 1 ); } DBGC ( intelxl, "INTELXL %p timed out waiting for activation " "(%#08x)\n", intelxl, vfgen_rstat ); return -ETIMEDOUT; }
/** * Hold off watchdog timer * * @v retry Retry timer * @v over Failure indicator */ static void efi_watchdog_expired ( struct retry_timer *timer, int over __unused ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; static CHAR16 data[] = WATCHDOG_DATA; EFI_STATUS efirc; int rc; DBGC2 ( timer, "EFI holding off watchdog timer\n" ); /* Restart this holdoff timer */ start_timer_fixed ( timer, ( WATCHDOG_HOLDOFF_SECS * TICKS_PER_SEC ) ); /* Reset watchdog timer */ if ( ( efirc = bs->SetWatchdogTimer ( WATCHDOG_TIMEOUT_SECS, WATCHDOG_CODE, sizeof ( data ), data ) ) != 0 ) { rc = -EEFI ( efirc ); DBGC ( timer, "EFI could not set watchdog timer: %s\n", strerror ( rc ) ); return; } }
/** * 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 ) { PXE_CPB_STATION_ADDRESS cpb; int stat; int rc; /* Construct parameter block */ memset ( &cpb, 0, sizeof ( cpb ) ); memcpy ( cpb.StationAddr, netdev->ll_addr, netdev->ll_protocol->ll_addr_len ); /* Issue command */ if ( ( stat = nii_issue_cpb ( nii, PXE_OPCODE_STATION_ADDRESS, &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; }
/** * Transmit packet * * @v netdev Network device * @v iobuf I/O buffer * @ret rc Return status code */ static int netfront_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct netfront_nic *netfront = netdev->priv; struct xen_device *xendev = netfront->xendev; struct netif_tx_request *request; int notify; int rc; /* Check that we have space in the ring */ if ( netfront_ring_is_full ( &netfront->tx ) ) { DBGC ( netfront, "NETFRONT %s out of transmit descriptors\n", xendev->key ); return -ENOBUFS; } /* Add to descriptor ring */ request = RING_GET_REQUEST ( &netfront->tx_fring, netfront->tx_fring.req_prod_pvt ); if ( ( rc = netfront_push ( netfront, &netfront->tx, iobuf, &request->id, &request->gref ) ) != 0 ) { return rc; } request->offset = ( virt_to_phys ( iobuf->data ) & ( PAGE_SIZE - 1 ) ); request->flags = NETTXF_data_validated; request->size = iob_len ( iobuf ); DBGC2 ( netfront, "NETFRONT %s TX id %d ref %d is %#08lx+%zx\n", xendev->key, request->id, request->gref, virt_to_phys ( iobuf->data ), iob_len ( iobuf ) ); /* Consume descriptor */ netfront->tx_fring.req_prod_pvt++; /* Push new descriptor and notify backend if applicable */ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY ( &netfront->tx_fring, notify ); if ( notify ) netfront_send_event ( netfront ); return 0; }
/** * Reload configuration from EEPROM * * @v myson Myson device * @ret rc Return status code */ static int myson_reload_config ( struct myson_nic *myson ) { unsigned int i; /* Initiate reload */ writel ( MYSON_ROM_AUTOLD, myson->regs + MYSON_ROM_MII ); /* Wait for reload to complete */ for ( i = 0 ; i < MYSON_AUTOLD_MAX_WAIT_MS ; i++ ) { /* If reload is not complete, delay 1ms and retry */ if ( readl ( myson->regs + MYSON_ROM_MII ) & MYSON_ROM_AUTOLD ){ mdelay ( 1 ); continue; } return 0; } DBGC ( myson, "MYSON %p timed out waiting for configuration " "reload\n", myson ); return -ETIMEDOUT; }
/** * Poll for received packets * * @v netdev Network device */ static void myson_poll_rx ( struct net_device *netdev ) { struct myson_nic *myson = netdev->priv; struct myson_descriptor *rx; struct io_buffer *iobuf; unsigned int rx_idx; size_t len; /* Check for received packets */ while ( myson->rx.cons != myson->rx.prod ) { /* Get next receive descriptor */ rx_idx = ( myson->rx.cons % MYSON_NUM_RX_DESC ); rx = &myson->rx.desc[rx_idx]; /* Stop if descriptor is still in use */ if ( rx->status & MYSON_RX_STAT_OWN ) return; /* Populate I/O buffer */ iobuf = myson->rx_iobuf[rx_idx]; myson->rx_iobuf[rx_idx] = NULL; len = MYSON_RX_STAT_FLNG ( le32_to_cpu ( rx->status ) ); iob_put ( iobuf, len - 4 /* strip CRC */ ); /* Hand off to network stack */ if ( rx->status & cpu_to_le32 ( MYSON_RX_STAT_ES ) ) { DBGC ( myson, "MYSON %p RX %d error (length %zd, " "status %08x)\n", myson, rx_idx, len, le32_to_cpu ( rx->status ) ); netdev_rx_err ( netdev, iobuf, -EIO ); } else { DBGC2 ( myson, "MYSON %p RX %d complete (length " "%zd)\n", myson, rx_idx, len ); netdev_rx ( netdev, iobuf ); } myson->rx.cons++; } }
/** * 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; }
/** * Open location * * @v intf Data transfer interface * @v type Location type * @v args Remaining arguments depend upon location type * @ret rc Return status code */ int xfer_vopen ( struct interface *intf, int type, va_list args ) { switch ( type ) { case LOCATION_URI_STRING: { const char *uri_string = va_arg ( args, const char * ); return xfer_open_uri_string ( intf, uri_string ); } case LOCATION_URI: { struct uri *uri = va_arg ( args, struct uri * ); return xfer_open_uri ( intf, uri ); } case LOCATION_SOCKET: { int semantics = va_arg ( args, int ); struct sockaddr *peer = va_arg ( args, struct sockaddr * ); struct sockaddr *local = va_arg ( args, struct sockaddr * ); return xfer_open_socket ( intf, semantics, peer, local ); } default: DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " attempted to " "open unsupported location type %d\n", INTF_DBG ( intf ), type ); return -ENOTSUP; } }
/** * Read from MII register * * @v mii MII interface * @v reg Register address * @ret value Data read, or negative error */ static int rhine_mii_read ( struct mii_interface *mii, unsigned int reg ) { struct rhine_nic *rhn = container_of ( mii, struct rhine_nic, mii ); unsigned int timeout = RHINE_TIMEOUT_US; uint8_t cr; DBGC2 ( rhn, "RHINE %p MII read reg %d\n", rhn, reg ); /* Initiate read */ writeb ( reg, rhn->regs + RHINE_MII_ADDR ); cr = readb ( rhn->regs + RHINE_MII_CR ); writeb ( ( cr | RHINE_MII_CR_RDEN ), rhn->regs + RHINE_MII_CR ); /* Wait for read to complete */ while ( timeout-- ) { udelay ( 1 ); cr = readb ( rhn->regs + RHINE_MII_CR ); if ( ! ( cr & RHINE_MII_CR_RDEN ) ) return readw ( rhn->regs + RHINE_MII_RDWR ); } DBGC ( rhn, "RHINE %p MII read timeout\n", rhn ); return -ETIMEDOUT; }
/** * Wait for MII to become idle * * @v smsc95xx SMSC95xx device * @ret rc Return status code */ static int smsc95xx_mii_wait ( struct smsc95xx_device *smsc95xx ) { uint32_t mii_access; unsigned int i; int rc; /* Wait for MIIBZY to become clear */ for ( i = 0 ; i < SMSC95XX_MII_MAX_WAIT_MS ; i++ ) { /* Read MII_ACCESS and check MIIBZY */ if ( ( rc = smsc95xx_readl ( smsc95xx, SMSC95XX_MII_ACCESS, &mii_access ) ) != 0 ) return rc; if ( ! ( mii_access & SMSC95XX_MII_ACCESS_MIIBZY ) ) return 0; /* Delay */ mdelay ( 1 ); } DBGC ( smsc95xx, "SMSC95XX %p timed out waiting for MII\n", smsc95xx ); return -ETIMEDOUT; }
/** * Read block device capacity * * @v control Control interface * @v data Data interface * @ret rc Return status code */ int http_block_read_capacity ( struct http_transaction *http, struct interface *data ) { int rc; /* Start a HEAD request to retrieve the capacity */ if ( ( rc = http_open ( data, &http_head, http->uri, NULL, NULL ) ) != 0 ) goto err_open; /* Insert block device translator */ if ( ( rc = block_translate ( data, UNULL, HTTP_BLKSIZE ) ) != 0 ) { DBGC ( http, "HTTP %p could not insert block translator: %s\n", http, strerror ( rc ) ); goto err_translate; } return 0; err_translate: intf_restart ( data, rc ); err_open: return rc; }
/** * Wait for EEPROM to become idle * * @v smsc95xx SMSC95xx device * @ret rc Return status code */ static int smsc95xx_eeprom_wait ( struct smsc95xx_device *smsc95xx ) { uint32_t e2p_cmd; unsigned int i; int rc; /* Wait for EPC_BSY to become clear */ for ( i = 0 ; i < SMSC95XX_EEPROM_MAX_WAIT_MS ; i++ ) { /* Read E2P_CMD and check EPC_BSY */ if ( ( rc = smsc95xx_readl ( smsc95xx, SMSC95XX_E2P_CMD, &e2p_cmd ) ) != 0 ) return rc; if ( ! ( e2p_cmd & SMSC95XX_E2P_CMD_EPC_BSY ) ) return 0; /* Delay */ mdelay ( 1 ); } DBGC ( smsc95xx, "SMSC95XX %p timed out waiting for EEPROM\n", smsc95xx ); return -ETIMEDOUT; }
/** * Load PXE image into memory * * @v image PXE file * @ret rc Return status code */ int pxe_load ( struct image *image ) { userptr_t buffer = real_to_user ( 0, 0x7c00 ); size_t filesz = image->len; size_t memsz = image->len; int rc; /* Images too large to fit in base memory cannot be PXE * images. We include this check to help prevent unrecognised * images from being marked as PXE images, since PXE images * have no signature we can check against. */ if ( filesz > ( 0xa0000 - 0x7c00 ) ) return -ENOEXEC; /* Rejecting zero-length images is also useful, since these * end up looking to the user like bugs in gPXE. */ if ( ! filesz ) return -ENOEXEC; /* There are no signature checks for PXE; we will accept anything */ if ( ! image->type ) image->type = &pxe_image_type; /* Verify and prepare segment */ if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) { DBGC ( image, "IMAGE %p could not prepare segment: %s\n", image, strerror ( rc ) ); return rc; } /* Copy image to segment */ memcpy_user ( buffer, 0, image->data, 0, filesz ); return 0; }
/** * Open the network device * * @v snp SNP interface * @v extra_rx_bufsize Extra RX buffer size, in bytes * @v extra_tx_bufsize Extra TX buffer size, in bytes * @ret efirc EFI status code */ static EFI_STATUS EFIAPI efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINTN extra_rx_bufsize, UINTN extra_tx_bufsize ) { struct efi_snp_device *snpdev = container_of ( snp, struct efi_snp_device, snp ); int rc; DBGC2 ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n", snpdev, ( ( unsigned long ) extra_rx_bufsize ), ( ( unsigned long ) extra_tx_bufsize ) ); /* Fail if net device is currently claimed for use by iPXE */ if ( efi_snp_claimed ) return EFI_NOT_READY; if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) { DBGC ( snpdev, "SNPDEV %p could not open %s: %s\n", snpdev, snpdev->netdev->name, strerror ( rc ) ); return EFIRC ( rc ); } efi_snp_set_state ( snpdev ); return 0; }
/** * 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; }
/** * Transmit Fibre Channel ELS frame * * @v els Fibre Channel ELS transaction * @v data Data to transmit * @v len Length of data * @ret rc Return status code */ int fc_els_tx ( struct fc_els *els, const void *data, size_t len ) { struct xfer_metadata meta; struct sockaddr_fc dest; int rc; DBGC2 ( els, FCELS_FMT " transmitting:\n", FCELS_ARGS ( els ) ); DBGC2_HDA ( els, 0, data, len ); /* Construct metadata */ memset ( &meta, 0, sizeof ( meta ) ); meta.flags = ( fc_els_is_request ( els ) ? XFER_FL_OVER : ( XFER_FL_RESPONSE | XFER_FL_OUT ) ); meta.dest = fc_fill_sockaddr ( &dest, &els->peer_port_id ); /* Transmit frame */ if ( ( rc = xfer_deliver_raw_meta ( &els->xchg, data, len, &meta ) ) != 0 ) { DBGC ( els, FCELS_FMT " could not deliver frame: %s\n", FCELS_ARGS ( els ), strerror ( rc ) ); return rc; } return 0; }
/** * Start name resolution * * @v resolv Name resolution interface * @v name Name to resolve * @v sa Socket address to complete * @ret rc Return status code */ int resolv ( struct interface *resolv, const char *name, struct sockaddr *sa ) { struct resolv_mux *mux; size_t name_len = ( strlen ( name ) + 1 ); int rc; /* Allocate and initialise structure */ mux = zalloc ( sizeof ( *mux ) + name_len ); if ( ! mux ) return -ENOMEM; ref_init ( &mux->refcnt, NULL ); intf_init ( &mux->parent, &null_intf_desc, &mux->refcnt ); intf_init ( &mux->child, &resmux_child_desc, &mux->refcnt ); mux->resolver = table_start ( RESOLVERS ); if ( sa ) memcpy ( &mux->sa, sa, sizeof ( mux->sa ) ); memcpy ( mux->name, name, name_len ); DBGC ( mux, "RESOLV %p attempting to resolve \"%s\"\n", mux, name ); /* Start first resolver in chain. There will always be at * least one resolver (the numeric resolver), so no need to * check for the zero-resolvers-available case. */ if ( ( rc = resmux_try ( mux ) ) != 0 ) goto err; /* Attach parent interface, mortalise self, and return */ intf_plug_plug ( &mux->parent, resolv ); ref_put ( &mux->refcnt ); return 0; err: ref_put ( &mux->refcnt ); return rc; }
/** * 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; } }