When Large Receive Offload (LRO) packets are large, such as 32KB, each packet consumes 16 Work Queue Elements (WQEs). If multiple large LRO packets occur at this time, it will cause rapid consumption of WQEs in the RQ and WQEs cannot be replenished in time. The chip will drop packets due to lack of WQEs, causing the RQ to be unable to receive packets. Furthermore, the NAPI instance will not be polled again, resulting in residual packets in the RQ. When napi_alloc_skb() fails inside recv_one_pkt(), hinic3_rx_poll() breaks out of the loop without advancing rxq->cons_idx or clearing rx_cqe->status, and returns nr_pkts (< budget). hinic3_poll() then calls napi_complete_done() and re-enables the edge-triggered MSI-X interrupt while the unprocessed CQE remains at the head of the ring, stalling the receive queue until a new packet arrives to trigger another interrupt. Fixes: 17fcb3dc12bb ("hinic3: module initialization and tx/rx logic") Co-developed-by: Wu Di Signed-off-by: Wu Di Co-developed-by: Teng Peisen Signed-off-by: Teng Peisen Signed-off-by: Fan Gong --- drivers/net/ethernet/huawei/hinic3/hinic3_rx.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_rx.c b/drivers/net/ethernet/huawei/hinic3/hinic3_rx.c index 309ab5901379..f2262cdd6628 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_rx.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_rx.c @@ -555,6 +555,7 @@ int hinic3_rx_poll(struct hinic3_rxq *rxq, int budget) struct hinic3_nic_dev *nic_dev = netdev_priv(rxq->netdev); u32 sw_ci, status, pkt_len, vlan_len; struct hinic3_rq_cqe *rx_cqe; + bool poll_again = false; u32 num_wqe = 0; int nr_pkts = 0; u16 num_lro; @@ -571,8 +572,10 @@ int hinic3_rx_poll(struct hinic3_rxq *rxq, int budget) vlan_len = le32_to_cpu(rx_cqe->vlan_len); pkt_len = RQ_CQE_SGE_GET(vlan_len, LEN); - if (recv_one_pkt(rxq, rx_cqe, pkt_len, vlan_len, status)) + if (recv_one_pkt(rxq, rx_cqe, pkt_len, vlan_len, status)) { + poll_again = true; break; + } nr_pkts++; num_lro = RQ_CQE_STATUS_GET(status, NUM_LRO); @@ -581,12 +584,14 @@ int hinic3_rx_poll(struct hinic3_rxq *rxq, int budget) rx_cqe->status = 0; - if (num_wqe >= nic_dev->lro_replenish_thld) + if (num_wqe >= nic_dev->lro_replenish_thld) { + poll_again = true; break; + } } if (rxq->delta >= HINIC3_RX_BUFFER_WRITE) hinic3_rx_fill_buffers(rxq); - return nr_pkts; + return poll_again ? budget : nr_pkts; } -- 2.43.0