Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[e1000] Implement zero-copy receive
Co-Authored by: Marty Connor <mdc@etherboot.org>
Signed-off-by: Marty Connor <mdc@etherboot.org>
  • Loading branch information
thomil authored and Marty Connor committed Nov 22, 2009
1 parent ec7e97f commit 2a9688b
Showing 1 changed file with 83 additions and 63 deletions.
146 changes: 83 additions & 63 deletions src/drivers/net/e1000/e1000.c
Expand Up @@ -290,6 +290,65 @@ e1000_configure_tx ( struct e1000_adapter *adapter )
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)
*
Expand All @@ -300,8 +359,7 @@ e1000_configure_tx ( struct e1000_adapter *adapter )
static int
e1000_setup_rx_resources ( struct e1000_adapter *adapter )
{
int i, j;
struct e1000_rx_desc *rx_curr_desc;
int i, rc = 0;

DBG ( "e1000_setup_rx_resources\n" );

Expand All @@ -311,50 +369,23 @@ e1000_setup_rx_resources ( struct e1000_adapter *adapter )

adapter->rx_base =
malloc_dma ( adapter->rx_ring_size, adapter->rx_ring_size );

if ( ! adapter->rx_base ) {
return -ENOMEM;
}
memset ( adapter->rx_base, 0, adapter->rx_ring_size );

for ( i = 0; i < NUM_RX_DESC; i++ ) {

adapter->rx_iobuf[i] = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE );

/* 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 ) +
( i * sizeof ( *adapter->rx_base ) );

rx_curr_desc->buffer_addr = virt_to_bus ( adapter->rx_iobuf[i]->data );

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" );
/* let e1000_refill_rx_ring() io_buffer allocations */
adapter->rx_iobuf[i] = NULL;
}

free_dma ( adapter->rx_base, adapter->rx_ring_size );
/* allocate io_buffers */
rc = e1000_refill_rx_ring ( adapter );
if ( rc < 0 )
e1000_free_rx_resources ( adapter );

for ( i = 0; i < NUM_RX_DESC; i++ ) {
free_iob ( adapter->rx_iobuf[i] );
}
return rc;
}

/**
Expand Down Expand Up @@ -676,12 +707,10 @@ e1000_poll ( struct net_device *netdev )
uint32_t rx_status;
uint32_t rx_len;
uint32_t rx_err;
struct io_buffer *rx_iob;
struct e1000_tx_desc *tx_curr_desc;
struct e1000_rx_desc *rx_curr_desc;
uint32_t i;
uint64_t tmp_buffer_addr;


DBGP ( "e1000_poll\n" );

/* Acknowledge interrupts */
Expand Down Expand Up @@ -741,46 +770,37 @@ e1000_poll ( struct net_device *netdev )
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, NULL, -EINVAL );
netdev_rx_err ( netdev, adapter->rx_iobuf[i], -EINVAL );
DBG ( "e1000_poll: Corrupted packet received!"
" rx_err: %#08x\n", rx_err );
} else {

/* If unable allocate space for this packet,
* 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 );
/* Add this packet to the receive queue. */
netdev_rx ( netdev, adapter->rx_iobuf[i] );
}
adapter->rx_iobuf[i] = NULL;

tmp_buffer_addr = rx_curr_desc->buffer_addr;
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;
}
}
e1000_refill_rx_ring(adapter);
}

/**
* e1000_irq - enable or Disable interrupts
Expand Down

0 comments on commit 2a9688b

Please sign in to comment.