From: Arthur Kiyanovski akiyano@amazon.com
stable inclusion from stable-v5.10.91 commit e7f5480978fd245762380d40fed03930ee21ccea bugzilla: 186187 https://gitee.com/openeuler/kernel/issues/I4SI2C
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
commit c255a34e02efb1393d23ffb205ba1a11320aeffb upstream.
ena_com_tx_comp_req_id_get() checks the req_id of a received completion, and if it is out of bounds returns -EINVAL. This is a sign that something is wrong with the device and it needs to be reset.
The current code does not reset the device in this case, which leaves the driver in an undefined state, where this completion is not properly handled.
This commit adds a call to handle_invalid_req_id() in ena_clean_tx_irq() and ena_clean_xdp_irq() which resets the device to fix the issue.
This commit also removes unnecessary request id checks from validate_tx_req_id() and validate_xdp_req_id(). This check is unneeded because it was already performed in ena_com_tx_comp_req_id_get(), which is called right before these functions.
Fixes: 548c4940b9f1 ("net: ena: Implement XDP_TX action") Signed-off-by: Shay Agroskin shayagr@amazon.com Signed-off-by: Arthur Kiyanovski akiyano@amazon.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Chen Jun chenjun102@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 34 ++++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-)
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index df1884d57d1a..dc15db154853 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -1199,26 +1199,22 @@ static int handle_invalid_req_id(struct ena_ring *ring, u16 req_id,
static int validate_tx_req_id(struct ena_ring *tx_ring, u16 req_id) { - struct ena_tx_buffer *tx_info = NULL; + struct ena_tx_buffer *tx_info;
- if (likely(req_id < tx_ring->ring_size)) { - tx_info = &tx_ring->tx_buffer_info[req_id]; - if (likely(tx_info->skb)) - return 0; - } + tx_info = &tx_ring->tx_buffer_info[req_id]; + if (likely(tx_info->skb)) + return 0;
return handle_invalid_req_id(tx_ring, req_id, tx_info, false); }
static int validate_xdp_req_id(struct ena_ring *xdp_ring, u16 req_id) { - struct ena_tx_buffer *tx_info = NULL; + struct ena_tx_buffer *tx_info;
- if (likely(req_id < xdp_ring->ring_size)) { - tx_info = &xdp_ring->tx_buffer_info[req_id]; - if (likely(tx_info->xdpf)) - return 0; - } + tx_info = &xdp_ring->tx_buffer_info[req_id]; + if (likely(tx_info->xdpf)) + return 0;
return handle_invalid_req_id(xdp_ring, req_id, tx_info, true); } @@ -1243,9 +1239,14 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget)
rc = ena_com_tx_comp_req_id_get(tx_ring->ena_com_io_cq, &req_id); - if (rc) + if (rc) { + if (unlikely(rc == -EINVAL)) + handle_invalid_req_id(tx_ring, req_id, NULL, + false); break; + }
+ /* validate that the request id points to a valid skb */ rc = validate_tx_req_id(tx_ring, req_id); if (rc) break; @@ -1801,9 +1802,14 @@ static int ena_clean_xdp_irq(struct ena_ring *xdp_ring, u32 budget)
rc = ena_com_tx_comp_req_id_get(xdp_ring->ena_com_io_cq, &req_id); - if (rc) + if (rc) { + if (unlikely(rc == -EINVAL)) + handle_invalid_req_id(xdp_ring, req_id, NULL, + true); break; + }
+ /* validate that the request id points to a valid xdp_frame */ rc = validate_xdp_req_id(xdp_ring, req_id); if (rc) break;