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