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 Within the while loop of hinic3_get_stats64(), the counters between u64_stats_fetch_retry and u64_stats_fetch_begin are incremented by +=. This operation will cause repeated counting of the counters on a 32-bit system. Therefore, change += to + and the counters are incremented out side the wile loop. csum_errors and other_errors are not the same things. csum_errors will go to csum_bad in netdev netlink qstats. Remove unnecessary checks for the nic_dev->txqs and nic_dev->rxqs. Remove dead stores before the loop. Fixes: f47872bed40f ("hinic3: Add .ndo_tx_timeout and .ndo_get_stats64") 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 --- .../huawei/hinic3/hinic3_netdev_ops.c | 42 +++++++------------ 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c index da73811641a9..d1fd91d97ccf 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c @@ -791,49 +791,35 @@ static void hinic3_get_stats64(struct net_device *netdev, unsigned int start; int i; - bytes = 0; - packets = 0; - dropped = 0; for (i = 0; i < nic_dev->max_qps; i++) { - if (!nic_dev->txqs) - break; - txq = &nic_dev->txqs[i]; txq_stats = &txq->txq_stats; do { start = u64_stats_fetch_begin(&txq_stats->syncp); - bytes += txq_stats->bytes; - packets += txq_stats->packets; - dropped += txq_stats->dropped; + bytes = txq_stats->bytes; + packets = txq_stats->packets; + dropped = txq_stats->dropped; } while (u64_stats_fetch_retry(&txq_stats->syncp, start)); + stats->tx_packets += packets; + stats->tx_bytes += bytes; + stats->tx_dropped += dropped; } - stats->tx_packets = packets; - stats->tx_bytes = bytes; - stats->tx_dropped = dropped; - bytes = 0; - packets = 0; - errors = 0; - dropped = 0; for (i = 0; i < nic_dev->max_qps; i++) { - if (!nic_dev->rxqs) - break; - rxq = &nic_dev->rxqs[i]; rxq_stats = &rxq->rxq_stats; do { start = u64_stats_fetch_begin(&rxq_stats->syncp); - bytes += rxq_stats->bytes; - packets += rxq_stats->packets; - errors += rxq_stats->csum_errors + - rxq_stats->other_errors; - dropped += rxq_stats->dropped; + bytes = rxq_stats->bytes; + packets = rxq_stats->packets; + errors = rxq_stats->other_errors; + dropped = rxq_stats->dropped; } while (u64_stats_fetch_retry(&rxq_stats->syncp, start)); + stats->rx_packets += packets; + stats->rx_bytes += bytes; + stats->rx_errors += errors; + stats->rx_dropped += dropped; } - stats->rx_packets = packets; - stats->rx_bytes = bytes; - stats->rx_errors = errors; - stats->rx_dropped = dropped; } static void hinic3_nic_set_rx_mode(struct net_device *netdev) -- 2.43.0 Cleanup checkpatchs of lines exceeding 80 columns. 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 --- .../huawei/hinic3/hinic3_netdev_ops.c | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c index d1fd91d97ccf..621d8b12e247 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c @@ -121,8 +121,9 @@ static void hinic3_destroy_num_qps(struct net_device *netdev) kfree(nic_dev->qps_msix_entries); } -static int hinic3_alloc_txrxq_resources(struct net_device *netdev, - struct hinic3_dyna_txrxq_params *q_params) +static int +hinic3_alloc_txrxq_resources(struct net_device *netdev, + struct hinic3_dyna_txrxq_params *q_params) { int err; @@ -176,8 +177,9 @@ static int hinic3_alloc_txrxq_resources(struct net_device *netdev, return err; } -static void hinic3_free_txrxq_resources(struct net_device *netdev, - struct hinic3_dyna_txrxq_params *q_params) +static void +hinic3_free_txrxq_resources(struct net_device *netdev, + struct hinic3_dyna_txrxq_params *q_params) { hinic3_free_rxqs_res(netdev, q_params->num_qps, q_params->rq_depth, q_params->rxqs_res); @@ -251,16 +253,17 @@ static void hinic3_remove_configure(struct net_device *netdev) hinic3_rss_uninit(netdev); } -static int hinic3_alloc_channel_resources(struct net_device *netdev, - struct hinic3_dyna_qp_params *qp_params, - struct hinic3_dyna_txrxq_params *trxq_params) +static int +hinic3_alloc_channel_resources(struct net_device *netdev, + struct hinic3_dyna_qp_params *qp_params, + struct hinic3_dyna_txrxq_params *q_params) { struct hinic3_nic_dev *nic_dev = netdev_priv(netdev); int err; - qp_params->num_qps = trxq_params->num_qps; - qp_params->sq_depth = trxq_params->sq_depth; - qp_params->rq_depth = trxq_params->rq_depth; + qp_params->num_qps = q_params->num_qps; + qp_params->sq_depth = q_params->sq_depth; + qp_params->rq_depth = q_params->rq_depth; err = hinic3_alloc_qps(nic_dev, qp_params); if (err) { @@ -268,7 +271,7 @@ static int hinic3_alloc_channel_resources(struct net_device *netdev, return err; } - err = hinic3_alloc_txrxq_resources(netdev, trxq_params); + err = hinic3_alloc_txrxq_resources(netdev, q_params); if (err) { netdev_err(netdev, "Failed to alloc txrxq resources\n"); hinic3_free_qps(nic_dev, qp_params); @@ -278,13 +281,14 @@ static int hinic3_alloc_channel_resources(struct net_device *netdev, return 0; } -static void hinic3_free_channel_resources(struct net_device *netdev, - struct hinic3_dyna_qp_params *qp_params, - struct hinic3_dyna_txrxq_params *trxq_params) +static void +hinic3_free_channel_resources(struct net_device *netdev, + struct hinic3_dyna_qp_params *qp_params, + struct hinic3_dyna_txrxq_params *q_params) { struct hinic3_nic_dev *nic_dev = netdev_priv(netdev); - hinic3_free_txrxq_resources(netdev, trxq_params); + hinic3_free_txrxq_resources(netdev, q_params); hinic3_free_qps(nic_dev, qp_params); } -- 2.43.0 nic_dev->max_qps is used to allocate hardware resources. Therefore, it is assigned the value 1 only when its value is abnormal. In other scenarios, the value cannot be changed. However, the value of nic_dev->q_params.num_qps can be dynamically changed. Fixes: 1f3838b84a63 ("hinic3: Add Rss function") 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_rss.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_rss.c b/drivers/net/ethernet/huawei/hinic3/hinic3_rss.c index 25db74d8c7dd..75dc0c044071 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_rss.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_rss.c @@ -307,15 +307,13 @@ void hinic3_try_to_enable_rss(struct net_device *netdev) int err; nic_dev->max_qps = hinic3_func_max_qnum(hwdev); - if (nic_dev->max_qps <= 1 || + if (nic_dev->max_qps == 1 || !hinic3_test_support(nic_dev, HINIC3_NIC_F_RSS)) goto err_reset_q_params; err = alloc_rss_resource(netdev); - if (err) { - nic_dev->max_qps = 1; + if (err) goto err_reset_q_params; - } set_bit(HINIC3_RSS_ENABLE, &nic_dev->flags); decide_num_qps(netdev); @@ -324,7 +322,6 @@ void hinic3_try_to_enable_rss(struct net_device *netdev) if (err) { dev_err(hwdev->dev, "Failed to set hardware rss parameters\n"); hinic3_clear_rss_config(netdev); - nic_dev->max_qps = 1; goto err_reset_q_params; } @@ -332,5 +329,5 @@ void hinic3_try_to_enable_rss(struct net_device *netdev) err_reset_q_params: clear_bit(HINIC3_RSS_ENABLE, &nic_dev->flags); - nic_dev->q_params.num_qps = nic_dev->max_qps; + nic_dev->q_params.num_qps = 1; } -- 2.43.0