summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Miletich2009-11-08 17:25:39 +0100
committerMarty Connor2009-11-22 13:47:57 +0100
commit2a9688b88057c0e0c0d1472b8782b75a35c34766 (patch)
tree75546eca1ba5a88af67353bdbaf4184ee5406af5
parent[e820mangler] Add missing CLC ins. for success path (diff)
downloadipxe-2a9688b88057c0e0c0d1472b8782b75a35c34766.tar.gz
ipxe-2a9688b88057c0e0c0d1472b8782b75a35c34766.tar.xz
ipxe-2a9688b88057c0e0c0d1472b8782b75a35c34766.zip
[e1000] Implement zero-copy receive
Co-Authored by: Marty Connor <mdc@etherboot.org> Signed-off-by: Marty Connor <mdc@etherboot.org>
-rw-r--r--src/drivers/net/e1000/e1000.c146
1 files changed, 83 insertions, 63 deletions
diff --git a/src/drivers/net/e1000/e1000.c b/src/drivers/net/e1000/e1000.c
index 81e15790..317861d6 100644
--- a/src/drivers/net/e1000/e1000.c
+++ b/src/drivers/net/e1000/e1000.c
@@ -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)
*
@@ -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" );
@@ -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;
}
/**
@@ -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 */
@@ -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