mirror of https://github.com/ipxe/ipxe.git
[e1000] Implement zero-copy receive
Co-Authored by: Marty Connor <mdc@etherboot.org> Signed-off-by: Marty Connor <mdc@etherboot.org>pull/1/head
parent
ec7e97f458
commit
2a9688b880
|
@ -290,6 +290,65 @@ e1000_configure_tx ( struct e1000_adapter *adapter )
|
||||||
E1000_WRITE_FLUSH ( hw );
|
E1000_WRITE_FLUSH ( hw );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
e1000_free_rx_resources ( struct e1000_adapter *adapter )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
DBG ( "e1000_free_rx_resources\n" );
|
||||||
|
|
||||||
|
free_dma ( adapter->rx_base, adapter->rx_ring_size );
|
||||||
|
|
||||||
|
for ( i = 0; i < NUM_RX_DESC; i++ ) {
|
||||||
|
free_iob ( adapter->rx_iobuf[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* e1000_refill_rx_ring - allocate Rx io_buffers
|
||||||
|
*
|
||||||
|
* @v adapter e1000 private structure
|
||||||
|
*
|
||||||
|
* @ret rc Returns 0 on success, negative on failure
|
||||||
|
**/
|
||||||
|
int e1000_refill_rx_ring ( struct e1000_adapter *adapter )
|
||||||
|
{
|
||||||
|
int i, rx_curr;
|
||||||
|
int rc = 0;
|
||||||
|
struct e1000_rx_desc *rx_curr_desc;
|
||||||
|
struct e1000_hw *hw = &adapter->hw;
|
||||||
|
struct io_buffer *iob;
|
||||||
|
|
||||||
|
DBG ("e1000_refill_rx_ring\n");
|
||||||
|
|
||||||
|
for ( i = 0; i < NUM_RX_DESC; i++ ) {
|
||||||
|
rx_curr = ( ( adapter->rx_curr + i ) % NUM_RX_DESC );
|
||||||
|
rx_curr_desc = adapter->rx_base + rx_curr;
|
||||||
|
|
||||||
|
if ( rx_curr_desc->status & E1000_RXD_STAT_DD )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ( adapter->rx_iobuf[rx_curr] != NULL )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
DBG2 ( "Refilling rx desc %d\n", rx_curr );
|
||||||
|
|
||||||
|
iob = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE );
|
||||||
|
adapter->rx_iobuf[rx_curr] = iob;
|
||||||
|
|
||||||
|
if ( ! iob ) {
|
||||||
|
DBG ( "alloc_iob failed\n" );
|
||||||
|
rc = -ENOMEM;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
rx_curr_desc->buffer_addr = virt_to_bus ( iob->data );
|
||||||
|
|
||||||
|
E1000_WRITE_REG ( hw, RDT, rx_curr );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* e1000_setup_rx_resources - allocate Rx resources (Descriptors)
|
* e1000_setup_rx_resources - allocate Rx resources (Descriptors)
|
||||||
*
|
*
|
||||||
|
@ -300,8 +359,7 @@ e1000_configure_tx ( struct e1000_adapter *adapter )
|
||||||
static int
|
static int
|
||||||
e1000_setup_rx_resources ( struct e1000_adapter *adapter )
|
e1000_setup_rx_resources ( struct e1000_adapter *adapter )
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, rc = 0;
|
||||||
struct e1000_rx_desc *rx_curr_desc;
|
|
||||||
|
|
||||||
DBG ( "e1000_setup_rx_resources\n" );
|
DBG ( "e1000_setup_rx_resources\n" );
|
||||||
|
|
||||||
|
@ -318,43 +376,16 @@ e1000_setup_rx_resources ( struct e1000_adapter *adapter )
|
||||||
memset ( adapter->rx_base, 0, adapter->rx_ring_size );
|
memset ( adapter->rx_base, 0, adapter->rx_ring_size );
|
||||||
|
|
||||||
for ( i = 0; i < NUM_RX_DESC; i++ ) {
|
for ( i = 0; i < NUM_RX_DESC; i++ ) {
|
||||||
|
/* let e1000_refill_rx_ring() io_buffer allocations */
|
||||||
adapter->rx_iobuf[i] = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE );
|
adapter->rx_iobuf[i] = NULL;
|
||||||
|
|
||||||
/* If unable to allocate all iobufs, free any that
|
|
||||||
* were successfully allocated, and return an error
|
|
||||||
*/
|
|
||||||
if ( ! adapter->rx_iobuf[i] ) {
|
|
||||||
for ( j = 0; j < i; j++ ) {
|
|
||||||
free_iob ( adapter->rx_iobuf[j] );
|
|
||||||
}
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rx_curr_desc = ( void * ) ( adapter->rx_base ) +
|
/* allocate io_buffers */
|
||||||
( i * sizeof ( *adapter->rx_base ) );
|
rc = e1000_refill_rx_ring ( adapter );
|
||||||
|
if ( rc < 0 )
|
||||||
|
e1000_free_rx_resources ( adapter );
|
||||||
|
|
||||||
rx_curr_desc->buffer_addr = virt_to_bus ( adapter->rx_iobuf[i]->data );
|
return rc;
|
||||||
|
|
||||||
DBG ( "i = %d rx_curr_desc->buffer_addr = %#16llx\n",
|
|
||||||
i, rx_curr_desc->buffer_addr );
|
|
||||||
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
e1000_free_rx_resources ( struct e1000_adapter *adapter )
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
DBG ( "e1000_free_rx_resources\n" );
|
|
||||||
|
|
||||||
free_dma ( adapter->rx_base, adapter->rx_ring_size );
|
|
||||||
|
|
||||||
for ( i = 0; i < NUM_RX_DESC; i++ ) {
|
|
||||||
free_iob ( adapter->rx_iobuf[i] );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -676,11 +707,9 @@ e1000_poll ( struct net_device *netdev )
|
||||||
uint32_t rx_status;
|
uint32_t rx_status;
|
||||||
uint32_t rx_len;
|
uint32_t rx_len;
|
||||||
uint32_t rx_err;
|
uint32_t rx_err;
|
||||||
struct io_buffer *rx_iob;
|
|
||||||
struct e1000_tx_desc *tx_curr_desc;
|
struct e1000_tx_desc *tx_curr_desc;
|
||||||
struct e1000_rx_desc *rx_curr_desc;
|
struct e1000_rx_desc *rx_curr_desc;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint64_t tmp_buffer_addr;
|
|
||||||
|
|
||||||
DBGP ( "e1000_poll\n" );
|
DBGP ( "e1000_poll\n" );
|
||||||
|
|
||||||
|
@ -741,6 +770,9 @@ e1000_poll ( struct net_device *netdev )
|
||||||
if ( ! ( rx_status & E1000_RXD_STAT_DD ) )
|
if ( ! ( rx_status & E1000_RXD_STAT_DD ) )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if ( adapter->rx_iobuf[i] == NULL )
|
||||||
|
break;
|
||||||
|
|
||||||
DBG ( "RCTL = %#08x\n", E1000_READ_REG ( &adapter->hw, RCTL ) );
|
DBG ( "RCTL = %#08x\n", E1000_READ_REG ( &adapter->hw, RCTL ) );
|
||||||
|
|
||||||
rx_len = rx_curr_desc->length;
|
rx_len = rx_curr_desc->length;
|
||||||
|
@ -750,36 +782,24 @@ e1000_poll ( struct net_device *netdev )
|
||||||
|
|
||||||
rx_err = rx_curr_desc->errors;
|
rx_err = rx_curr_desc->errors;
|
||||||
|
|
||||||
|
iob_put ( adapter->rx_iobuf[i], rx_len );
|
||||||
|
|
||||||
if ( rx_err & E1000_RXD_ERR_FRAME_ERR_MASK ) {
|
if ( rx_err & E1000_RXD_ERR_FRAME_ERR_MASK ) {
|
||||||
|
|
||||||
netdev_rx_err ( netdev, NULL, -EINVAL );
|
netdev_rx_err ( netdev, adapter->rx_iobuf[i], -EINVAL );
|
||||||
DBG ( "e1000_poll: Corrupted packet received!"
|
DBG ( "e1000_poll: Corrupted packet received!"
|
||||||
" rx_err: %#08x\n", rx_err );
|
" rx_err: %#08x\n", rx_err );
|
||||||
} else {
|
} else {
|
||||||
|
/* Add this packet to the receive queue. */
|
||||||
/* If unable allocate space for this packet,
|
netdev_rx ( netdev, adapter->rx_iobuf[i] );
|
||||||
* try again next poll
|
|
||||||
*/
|
|
||||||
rx_iob = alloc_iob ( rx_len );
|
|
||||||
if ( ! rx_iob )
|
|
||||||
break;
|
|
||||||
|
|
||||||
memcpy ( iob_put ( rx_iob, rx_len ),
|
|
||||||
adapter->rx_iobuf[i]->data, rx_len );
|
|
||||||
|
|
||||||
/* Add this packet to the receive queue.
|
|
||||||
*/
|
|
||||||
netdev_rx ( netdev, rx_iob );
|
|
||||||
}
|
}
|
||||||
|
adapter->rx_iobuf[i] = NULL;
|
||||||
|
|
||||||
tmp_buffer_addr = rx_curr_desc->buffer_addr;
|
|
||||||
memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );
|
memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );
|
||||||
rx_curr_desc->buffer_addr = tmp_buffer_addr;
|
|
||||||
|
|
||||||
E1000_WRITE_REG ( hw, RDT, adapter->rx_curr );
|
|
||||||
|
|
||||||
adapter->rx_curr = ( adapter->rx_curr + 1 ) % NUM_RX_DESC;
|
adapter->rx_curr = ( adapter->rx_curr + 1 ) % NUM_RX_DESC;
|
||||||
}
|
}
|
||||||
|
e1000_refill_rx_ring(adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue