/** * 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 ); }
/** * Transmit an ethernet packet. * * The packet can be written to the socket and marked as complete immediately. */ static int af_packet_nic_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct af_packet_nic * nic = netdev->priv; struct sockaddr_ll socket_address; const struct ethhdr * eh; int rc; memset(&socket_address, 0, sizeof(socket_address)); socket_address.sll_family = LINUX_AF_PACKET; socket_address.sll_ifindex = nic->ifindex; socket_address.sll_halen = ETH_ALEN; eh = iobuf->data; memcpy(socket_address.sll_addr, eh->h_dest, ETH_ALEN); rc = linux_sendto(nic->fd, iobuf->data, iobuf->tail - iobuf->data, 0, (struct sockaddr *)&socket_address, sizeof(socket_address)); DBGC2(nic, "af_packet %p wrote %d bytes\n", nic, rc); netdev_tx_complete(netdev, iobuf); return 0; }
/* * vxge_xmit_compl * * If an interrupt was raised to indicate DMA complete of the Tx packet, * this function is called. It identifies the last TxD whose buffer was * freed and frees all skbs whose data have already DMA'ed into the NICs * internal memory. */ enum vxge_hw_status vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, struct vxge_hw_fifo_txd *txdp, enum vxge_hw_fifo_tcode tcode) { struct net_device *netdev; struct io_buffer *tx_iob = NULL; vxge_trace(); netdev = fifo_hw->vpathh->hldev->ndev; tx_iob = (struct io_buffer *)(intptr_t)txdp->host_control; if (tcode == VXGE_HW_FIFO_T_CODE_OK) { netdev_tx_complete(netdev, tx_iob); } else { netdev_tx_complete_err(netdev, tx_iob, -EINVAL); vxge_debug(VXGE_ERR, "%s: transmit failed, tcode %d\n", netdev->name, tcode); } memset(txdp, 0, sizeof(struct vxge_hw_fifo_txd)); return VXGE_HW_OK; }
/** * Poll for completed packets * * @v netdev Network device */ static void netfront_poll_tx ( struct net_device *netdev ) { struct netfront_nic *netfront = netdev->priv; struct xen_device *xendev = netfront->xendev; struct netif_tx_response *response; struct io_buffer *iobuf; unsigned int status; int rc; /* Consume any unconsumed responses */ while ( RING_HAS_UNCONSUMED_RESPONSES ( &netfront->tx_fring ) ) { /* Get next response */ response = RING_GET_RESPONSE ( &netfront->tx_fring, netfront->tx_fring.rsp_cons++ ); /* Retrieve from descriptor ring */ iobuf = netfront_pull ( netfront, &netfront->tx, response->id ); status = response->status; if ( status == NETIF_RSP_OKAY ) { DBGC2 ( netfront, "NETFRONT %s TX id %d complete\n", xendev->key, response->id ); netdev_tx_complete ( netdev, iobuf ); } else { rc = -EIO_NETIF_RSP ( status ); DBGC2 ( netfront, "NETFRONT %s TX id %d error %d: %s\n", xendev->key, response->id, status, strerror ( rc ) ); netdev_tx_complete_err ( netdev, iobuf, rc ); } } }
static int legacy_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct nic *nic = netdev->priv; struct ethhdr *ethhdr; DBG ( "Transmitting %zd bytes\n", iob_len ( iobuf ) ); iob_pad ( iobuf, ETH_ZLEN ); ethhdr = iobuf->data; iob_pull ( iobuf, sizeof ( *ethhdr ) ); nic->nic_op->transmit ( nic, ( const char * ) ethhdr->h_dest, ntohs ( ethhdr->h_protocol ), iob_len ( iobuf ), iobuf->data ); netdev_tx_complete ( netdev, iobuf ); return 0; }
/** * e1000_process_tx_packets - process transmitted packets * * @v netdev network interface device structure **/ static void e1000e_process_tx_packets ( struct net_device *netdev ) { struct e1000_adapter *adapter = netdev_priv ( netdev ); uint32_t i; uint32_t tx_status; struct e1000_tx_desc *tx_curr_desc; /* Check status of transmitted packets */ DBG ( "process_tx_packets: tx_head = %d, tx_tail = %d\n", adapter->tx_head, adapter->tx_tail ); while ( ( i = adapter->tx_head ) != adapter->tx_tail ) { tx_curr_desc = ( void * ) ( adapter->tx_base ) + ( i * sizeof ( *adapter->tx_base ) ); tx_status = tx_curr_desc->upper.data; DBG ( " tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) ); DBG ( " tx_status = %#08x\n", tx_status ); /* if the packet at tx_head is not owned by hardware it is for us */ if ( ! ( tx_status & E1000_TXD_STAT_DD ) ) break; DBG ( "Sent packet. tx_head: %d tx_tail: %d tx_status: %#08x\n", adapter->tx_head, adapter->tx_tail, tx_status ); if ( tx_status & ( E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | E1000_TXD_STAT_TU ) ) { netdev_tx_complete_err ( netdev, adapter->tx_iobuf[i], -EINVAL ); DBG ( "Error transmitting packet, tx_status: %#08x\n", tx_status ); } else { netdev_tx_complete ( netdev, adapter->tx_iobuf[i] ); DBG ( "Success transmitting packet, tx_status: %#08x\n", tx_status ); } /* Decrement count of used descriptors, clear this descriptor */ adapter->tx_fill_ctr--; memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) ); adapter->tx_head = ( adapter->tx_head + 1 ) % NUM_TX_DESC; } }
/** * 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 ); }
/** Recycles sent TX descriptors and notifies network stack * * @v bp Driver state */ static void b44_tx_complete(struct b44_private *bp) { u32 cur, i; cur = pending_tx_index(bp); for (i = bp->tx_dirty; i != cur; i = ring_next(i)) { /* Free finished frame */ netdev_tx_complete(bp->netdev, bp->tx_iobuf[i]); bp->tx_iobuf[i] = NULL; /* Clear TX descriptor */ bp->tx[i].ctrl = 0; bp->tx[i].addr = 0; } bp->tx_dirty = cur; }
/** * Transmit packet * * @v netdev Network device * @v iobuf I/O buffer * @ret rc Return status code */ static int undinet_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct s_PXENV_UNDI_TRANSMIT undi_transmit; size_t len = iob_len ( iobuf ); int rc; /* Technically, we ought to make sure that the previous * transmission has completed before we re-use the buffer. * However, many PXE stacks (including at least some Intel PXE * stacks and Etherboot 5.4) fail to generate TX completions. * In practice this won't be a problem, since our TX datapath * has a very low packet volume and we can get away with * assuming that a TX will be complete by the time we want to * transmit the next packet. */ /* Copy packet to UNDI I/O buffer */ if ( len > sizeof ( basemem_packet ) ) len = sizeof ( basemem_packet ); memcpy ( &basemem_packet, iobuf->data, len ); /* Create PXENV_UNDI_TRANSMIT data structure */ memset ( &undi_transmit, 0, sizeof ( undi_transmit ) ); undi_transmit.DestAddr.segment = rm_ds; undi_transmit.DestAddr.offset = __from_data16 ( &undinet_tbd ); undi_transmit.TBD.segment = rm_ds; undi_transmit.TBD.offset = __from_data16 ( &undinet_tbd ); /* Create PXENV_UNDI_TBD data structure */ undinet_tbd.ImmedLength = len; undinet_tbd.Xmit.segment = rm_ds; undinet_tbd.Xmit.offset = __from_data16 ( basemem_packet ); /* Issue PXE API call */ if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_TRANSMIT, &undi_transmit, sizeof ( undi_transmit ) ) ) != 0 ) goto done; /* Free I/O buffer */ netdev_tx_complete ( netdev, iobuf ); done: return rc; }
/** * e1000_poll - Poll for received packets * * @v netdev Network device */ static void e1000_poll ( struct net_device *netdev ) { struct e1000_adapter *adapter = netdev_priv( netdev ); struct e1000_hw *hw = &adapter->hw; uint32_t icr; uint32_t tx_status; uint32_t rx_status; uint32_t rx_len; uint32_t rx_err; struct e1000_tx_desc *tx_curr_desc; struct e1000_rx_desc *rx_curr_desc; uint32_t i; DBGP ( "e1000_poll\n" ); /* Acknowledge interrupts */ icr = E1000_READ_REG ( hw, ICR ); if ( ! icr ) return; DBG ( "e1000_poll: intr_status = %#08x\n", icr ); /* Check status of transmitted packets */ while ( ( i = adapter->tx_head ) != adapter->tx_tail ) { tx_curr_desc = ( void * ) ( adapter->tx_base ) + ( i * sizeof ( *adapter->tx_base ) ); tx_status = tx_curr_desc->upper.data; /* if the packet at tx_head is not owned by hardware it is for us */ if ( ! ( tx_status & E1000_TXD_STAT_DD ) ) break; DBG ( "Sent packet. tx_head: %d tx_tail: %d tx_status: %#08x\n", adapter->tx_head, adapter->tx_tail, tx_status ); if ( tx_status & ( E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | E1000_TXD_STAT_TU ) ) { netdev_tx_complete_err ( netdev, adapter->tx_iobuf[i], -EINVAL ); DBG ( "Error transmitting packet, tx_status: %#08x\n", tx_status ); } else { netdev_tx_complete ( netdev, adapter->tx_iobuf[i] ); DBG ( "Success transmitting packet, tx_status: %#08x\n", tx_status ); } /* Decrement count of used descriptors, clear this descriptor */ adapter->tx_fill_ctr--; memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) ); adapter->tx_head = ( adapter->tx_head + 1 ) % NUM_TX_DESC; } /* Process received packets */ while ( 1 ) { i = adapter->rx_curr; rx_curr_desc = ( void * ) ( adapter->rx_base ) + ( i * sizeof ( *adapter->rx_base ) ); rx_status = rx_curr_desc->status; DBG2 ( "Before DD Check RX_status: %#08x\n", rx_status ); if ( ! ( rx_status & E1000_RXD_STAT_DD ) ) break; if ( adapter->rx_iobuf[i] == NULL ) break; DBG ( "RCTL = %#08x\n", E1000_READ_REG ( &adapter->hw, RCTL ) ); rx_len = rx_curr_desc->length; DBG ( "Received packet, rx_curr: %d rx_status: %#08x rx_len: %d\n", i, rx_status, rx_len ); rx_err = rx_curr_desc->errors; iob_put ( adapter->rx_iobuf[i], rx_len ); if ( rx_err & E1000_RXD_ERR_FRAME_ERR_MASK ) { netdev_rx_err ( netdev, adapter->rx_iobuf[i], -EINVAL ); DBG ( "e1000_poll: Corrupted packet received!" " rx_err: %#08x\n", rx_err ); } else { /* Add this packet to the receive queue. */ netdev_rx ( netdev, adapter->rx_iobuf[i] ); } adapter->rx_iobuf[i] = NULL; memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) ); adapter->rx_curr = ( adapter->rx_curr + 1 ) % NUM_RX_DESC; } e1000_refill_rx_ring(adapter); }