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.gmei...@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

Reply via email to