[PATCH net-next v02 1/5] hinic3: Solve an stall issue in hinic3_rx_poll()

From: Fan Gong

Date: Tue Nov 10 2026 - 23:18:00 EST


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 <wudi234@xxxxxxxxxx>
Signed-off-by: Wu Di <wudi234@xxxxxxxxxx>
Co-developed-by: Teng Peisen <tengpeisen@xxxxxxxxxx>
Signed-off-by: Teng Peisen <tengpeisen@xxxxxxxxxx>
Signed-off-by: Fan Gong <gongfan1@xxxxxxxxxx>
---
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