[PATCH 4/4] net: e1000: make use of multiple rx packets

Christian Gmeiner christian.gmeiner at gmail.com
Fri Mar 3 21:48:44 CET 2023


When facing a very busy network, the single rx packet
buffer was oftentimes overwritten before a desired
response packet (e.g. a Ping reply) could have been
processed. This change improves resistance to this
by utilising multiple buffers.

Signed-off-by: Christian Gmeiner <christian.gmeiner at gmail.com>
---
 drivers/net/e1000.c | 30 ++++++++++++++++++++++--------
 drivers/net/e1000.h |  2 +-
 2 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c
index ea9ca76917..86300898af 100644
--- a/drivers/net/e1000.c
+++ b/drivers/net/e1000.c
@@ -5086,7 +5086,7 @@ e1000_sw_init(struct e1000_hw *hw)
 void
 fill_rx(struct e1000_hw *hw)
 {
-	unsigned char *packet = hw->rx_packet;
+	unsigned char *packet = hw->rx_packet[hw->rx_tail];
 	struct e1000_rx_desc *rd;
 	unsigned long flush_start, flush_end;
 
@@ -5284,6 +5284,9 @@ e1000_configure_rx(struct e1000_hw *hw)
 		mdelay(20);
 	}
 
+	for (int i = 0; i < NUM_RX_DESC; i++)
+		memset(&hw->rx_base[i], 0, 16);
+
 	E1000_WRITE_REG(hw, RCTL, rctl);
 
 	fill_rx(hw);
@@ -5295,9 +5298,9 @@ POLL - Wait for a frame
 static int
 _e1000_poll(struct e1000_hw *hw)
 {
-	unsigned char *packet = hw->rx_packet;
 	struct e1000_rx_desc *rd;
 	unsigned long inval_start, inval_end;
+	unsigned char *packet;
 	uint32_t len;
 
 	/* return true if there's an ethernet packet ready to read */
@@ -5310,6 +5313,9 @@ _e1000_poll(struct e1000_hw *hw)
 
 	if (!(rd->status & E1000_RXD_STAT_DD))
 		return 0;
+
+	packet = (unsigned char *)rd->buffer_addr;
+
 	/* DEBUGOUT("recv: packet len=%d\n", rd->length); */
 	/* Packet received, make sure the data are re-loaded from RAM. */
 	len = le16_to_cpu(rd->length);
@@ -5403,8 +5409,8 @@ _e1000_init(struct e1000_hw *hw, unsigned char enetaddr[6])
 		return ret_val;
 	}
 	e1000_configure_tx(hw);
-	e1000_setup_rctl(hw);
 	e1000_configure_rx(hw);
+	e1000_setup_rctl(hw);
 	return 0;
 }
 
@@ -5474,12 +5480,14 @@ static int e1000_init_one(struct e1000_hw *hw, int cardnum,
 	}
 
 	hw->rx_base = e1000_alloc(NUM_RX_DESC * sizeof(struct e1000_rx_desc));
-	hw->rx_packet = e1000_alloc(4096);
 
-	if (!hw->rx_base || !hw->rx_packet) {
-		free(hw->rx_base);
-		free(hw->rx_packet);
+	if (!hw->rx_base)
 		return -ENOMEM;
+
+	for (int i = 0; i < NUM_RX_DESC; i++) {
+		hw->rx_packet[i] = e1000_alloc(4096);
+		if (!hw->rx_packet[i])
+			goto out_alloc_fail;
 	}
 
 	/* Are these variables needed? */
@@ -5529,6 +5537,12 @@ static int e1000_init_one(struct e1000_hw *hw, int cardnum,
 #endif
 
 	return 0;
+
+out_alloc_fail:
+	for (int i = 0; i < NUM_RX_DESC; i++)
+		free(hw->rx_packet[i]);
+
+	return -ENOMEM;
 }
 
 /* Put the name of a device in a string */
@@ -5676,7 +5690,7 @@ static int e1000_eth_recv(struct udevice *dev, int flags, uchar **packetp)
 
 	len = _e1000_poll(hw);
 	if (len)
-		*packetp = hw->rx_packet;
+		*packetp = hw->rx_packet[hw->rx_last];
 
 	return len ? len : -EAGAIN;
 }
diff --git a/drivers/net/e1000.h b/drivers/net/e1000.h
index f83e3a0b33..be3fce4bb6 100644
--- a/drivers/net/e1000.h
+++ b/drivers/net/e1000.h
@@ -1136,7 +1136,7 @@ struct e1000_hw {
 	e1000_dsp_config	dsp_config_state;
 
 	struct e1000_rx_desc *rx_base;
-	unsigned char *rx_packet;
+	unsigned char *rx_packet[NUM_RX_DESC];
 	int rx_tail;
 	int rx_last;
 };
-- 
2.39.2



More information about the U-Boot mailing list