Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f8fa222c authored by Lipeng's avatar Lipeng Committed by David S. Miller
Browse files

net: hns3: Add timeout process in hns3_enet



This patch add timeout handler in hns3_enet.c to handle
TX side timeout event, when TX timeout event occur, it will triger
NIC driver into reset process.

Signed-off-by: default avatarqumingguang <qumingguang@huawei.com>
Signed-off-by: default avatarLipeng <lipeng321@huawei.com>
Signed-off-by: default avatarYunsheng Lin <linyunsheng@huawei.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4ed340ab
Loading
Loading
Loading
Loading
+86 −0
Original line number Diff line number Diff line
@@ -258,6 +258,7 @@ static int hns3_nic_net_up(struct net_device *netdev)

static int hns3_nic_net_open(struct net_device *netdev)
{
	struct hns3_nic_priv *priv = netdev_priv(netdev);
	int ret;

	netif_carrier_off(netdev);
@@ -273,6 +274,7 @@ static int hns3_nic_net_open(struct net_device *netdev)
		return ret;
	}

	priv->last_reset_time = jiffies;
	return 0;
}

@@ -1322,10 +1324,91 @@ static int hns3_nic_change_mtu(struct net_device *netdev, int new_mtu)
	return ret;
}

static bool hns3_get_tx_timeo_queue_info(struct net_device *ndev)
{
	struct hns3_nic_priv *priv = netdev_priv(ndev);
	struct hns3_enet_ring *tx_ring = NULL;
	int timeout_queue = 0;
	int hw_head, hw_tail;
	int i;

	/* Find the stopped queue the same way the stack does */
	for (i = 0; i < ndev->real_num_tx_queues; i++) {
		struct netdev_queue *q;
		unsigned long trans_start;

		q = netdev_get_tx_queue(ndev, i);
		trans_start = q->trans_start;
		if (netif_xmit_stopped(q) &&
		    time_after(jiffies,
			       (trans_start + ndev->watchdog_timeo))) {
			timeout_queue = i;
			break;
		}
	}

	if (i == ndev->num_tx_queues) {
		netdev_info(ndev,
			    "no netdev TX timeout queue found, timeout count: %llu\n",
			    priv->tx_timeout_count);
		return false;
	}

	tx_ring = priv->ring_data[timeout_queue].ring;

	hw_head = readl_relaxed(tx_ring->tqp->io_base +
				HNS3_RING_TX_RING_HEAD_REG);
	hw_tail = readl_relaxed(tx_ring->tqp->io_base +
				HNS3_RING_TX_RING_TAIL_REG);
	netdev_info(ndev,
		    "tx_timeout count: %llu, queue id: %d, SW_NTU: 0x%x, SW_NTC: 0x%x, HW_HEAD: 0x%x, HW_TAIL: 0x%x, INT: 0x%x\n",
		    priv->tx_timeout_count,
		    timeout_queue,
		    tx_ring->next_to_use,
		    tx_ring->next_to_clean,
		    hw_head,
		    hw_tail,
		    readl(tx_ring->tqp_vector->mask_addr));

	return true;
}

static void hns3_nic_net_timeout(struct net_device *ndev)
{
	struct hns3_nic_priv *priv = netdev_priv(ndev);
	unsigned long last_reset_time = priv->last_reset_time;
	struct hnae3_handle *h = priv->ae_handle;

	if (!hns3_get_tx_timeo_queue_info(ndev))
		return;

	priv->tx_timeout_count++;

	/* This timeout is far away enough from last timeout,
	 * if timeout again,set the reset type to PF reset
	 */
	if (time_after(jiffies, (last_reset_time + 20 * HZ)))
		priv->reset_level = HNAE3_FUNC_RESET;

	/* Don't do any new action before the next timeout */
	else if (time_before(jiffies, (last_reset_time + ndev->watchdog_timeo)))
		return;

	priv->last_reset_time = jiffies;

	if (h->ae_algo->ops->reset_event)
		h->ae_algo->ops->reset_event(h, priv->reset_level);

	priv->reset_level++;
	if (priv->reset_level > HNAE3_GLOBAL_RESET)
		priv->reset_level = HNAE3_GLOBAL_RESET;
}

static const struct net_device_ops hns3_nic_netdev_ops = {
	.ndo_open		= hns3_nic_net_open,
	.ndo_stop		= hns3_nic_net_stop,
	.ndo_start_xmit		= hns3_nic_net_xmit,
	.ndo_tx_timeout		= hns3_nic_net_timeout,
	.ndo_set_mac_address	= hns3_nic_net_set_mac_address,
	.ndo_change_mtu		= hns3_nic_change_mtu,
	.ndo_set_features	= hns3_nic_set_features,
@@ -2763,6 +2846,9 @@ static int hns3_client_init(struct hnae3_handle *handle)
	priv->dev = &pdev->dev;
	priv->netdev = netdev;
	priv->ae_handle = handle;
	priv->last_reset_time = jiffies;
	priv->reset_level = HNAE3_FUNC_RESET;
	priv->tx_timeout_count = 0;

	handle->kinfo.netdev = netdev;
	handle->priv = (void *)priv;
+2 −0
Original line number Diff line number Diff line
@@ -518,6 +518,8 @@ struct hns3_nic_priv {
	/* The most recently read link state */
	int link;
	u64 tx_timeout_count;
	enum hnae3_reset_type reset_level;
	unsigned long last_reset_time;

	unsigned long state;