Commit d1912009 authored by Chiqijun's avatar Chiqijun Committed by Yang Yingliang
Browse files

net/hinic: Fix VF has a low probability of network failure on the virtual machine



driver inclusion
category: bugfix
bugzilla: 4472

-----------------------------------------------------------------------

VF does not switch interrupts on the virtual machine. If the hardware
sends the entire tx queue packets between tx_poll processed all the
packets and calling napi_complete, it will cause the hardware to no
longer report the interrupt, napi will not be called again, and driver
unable free up tx resources. Eventually, the queue is full and packets
cannot be sent.

By calling tx_poll again before napi_complete, to ensure that the queue
resources can be released in time.

When clearing queue resources during ifconfig down processing, determine
whether the packet has been sent more accurately by judging hardware CI
and software PI.

Signed-off-by: default avatarChiqijun <chiqijun@huawei.com>
Reviewed-by: default avatarZengweiliang <zengweiliang.zengweiliang@huawei.com>
Signed-off-by: default avatarYang Yingliang <yangyingliang@huawei.com>
parent cce4abf9
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -468,7 +468,8 @@ static int hinic_poll(struct napi_struct *napi, int budget)

	set_bit(HINIC_RESEND_ON, &irq_cfg->intr_flag);
	rx_pkts += hinic_rx_poll(irq_cfg->rxq, budget - rx_pkts);
	if (rx_pkts >= budget) {
	tx_pkts += hinic_tx_poll(irq_cfg->txq, budget - tx_pkts);
	if (rx_pkts >= budget || tx_pkts >= budget) {
		clear_bit(HINIC_RESEND_ON, &irq_cfg->intr_flag);
		return budget;
	}
+15 −11
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@
#include "hinic_nic_dev.h"
#include "hinic_qp.h"
#include "hinic_tx.h"
#include "hinic_dbg.h"

#define MIN_SKB_LEN        32
#define MAX_PAYLOAD_OFFSET 221
@@ -1291,17 +1292,25 @@ void hinic_free_txqs(struct net_device *netdev)
/* should stop transmit any packets before calling this function */
#define HINIC_FLUSH_QUEUE_TIMEOUT	1000

static bool hinic_get_hw_handle_status(void *hwdev, u16 q_id)
{
	u16 sw_pi = 0, hw_ci = 0;

	sw_pi = hinic_dbg_get_sq_pi(hwdev, q_id);
	hw_ci = hinic_get_sq_hw_ci(hwdev, q_id);

	return sw_pi == hw_ci;
}

int hinic_stop_sq(struct hinic_txq *txq)
{
	struct hinic_nic_dev *nic_dev = netdev_priv(txq->netdev);
	unsigned long timeout;
	int free_wqebbs, err;
	int err;

	timeout = msecs_to_jiffies(HINIC_FLUSH_QUEUE_TIMEOUT) + jiffies;
	do {
		free_wqebbs = hinic_get_sq_free_wqebbs(nic_dev->hwdev,
						       txq->q_id) + 1;
		if (free_wqebbs == txq->q_depth)
		if (hinic_get_hw_handle_status(nic_dev->hwdev, txq->q_id))
			return 0;

		usleep_range(900, 1000);
@@ -1310,9 +1319,7 @@ int hinic_stop_sq(struct hinic_txq *txq)
	/* force hardware to drop packets */
	timeout = msecs_to_jiffies(HINIC_FLUSH_QUEUE_TIMEOUT) + jiffies;
	do {
		free_wqebbs = hinic_get_sq_free_wqebbs(nic_dev->hwdev,
						       txq->q_id) + 1;
		if (free_wqebbs == txq->q_depth)
		if (hinic_get_hw_handle_status(nic_dev->hwdev, txq->q_id))
			return 0;

		err = hinic_force_drop_tx_pkt(nic_dev->hwdev);
@@ -1323,8 +1330,7 @@ int hinic_stop_sq(struct hinic_txq *txq)
	} while (time_before(jiffies, timeout));

	/* Avoid msleep takes too long and get a fake result */
	free_wqebbs = hinic_get_sq_free_wqebbs(nic_dev->hwdev, txq->q_id) + 1;
	if (free_wqebbs == txq->q_depth)
	if (hinic_get_hw_handle_status(nic_dev->hwdev, txq->q_id))
		return 0;

	return -EFAULT;
@@ -1342,6 +1348,4 @@ void hinic_flush_txqs(struct net_device *netdev)
			nicif_err(nic_dev, drv, netdev,
				  "Failed to stop sq%d\n", qid);
	}

	return;
} /*lint -e766*/