162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci// Copyright (c) 2016-2017 Hisilicon Limited.
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/etherdevice.h>
562306a36Sopenharmony_ci#include <linux/string.h>
662306a36Sopenharmony_ci#include <linux/phy.h>
762306a36Sopenharmony_ci#include <linux/sfp.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "hns3_enet.h"
1062306a36Sopenharmony_ci#include "hns3_ethtool.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/* tqp related stats */
1362306a36Sopenharmony_ci#define HNS3_TQP_STAT(_string, _member)	{			\
1462306a36Sopenharmony_ci	.stats_string = _string,				\
1562306a36Sopenharmony_ci	.stats_offset = offsetof(struct hns3_enet_ring, stats) +\
1662306a36Sopenharmony_ci			offsetof(struct ring_stats, _member),   \
1762306a36Sopenharmony_ci}
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic const struct hns3_stats hns3_txq_stats[] = {
2062306a36Sopenharmony_ci	/* Tx per-queue statistics */
2162306a36Sopenharmony_ci	HNS3_TQP_STAT("dropped", sw_err_cnt),
2262306a36Sopenharmony_ci	HNS3_TQP_STAT("seg_pkt_cnt", seg_pkt_cnt),
2362306a36Sopenharmony_ci	HNS3_TQP_STAT("packets", tx_pkts),
2462306a36Sopenharmony_ci	HNS3_TQP_STAT("bytes", tx_bytes),
2562306a36Sopenharmony_ci	HNS3_TQP_STAT("more", tx_more),
2662306a36Sopenharmony_ci	HNS3_TQP_STAT("push", tx_push),
2762306a36Sopenharmony_ci	HNS3_TQP_STAT("mem_doorbell", tx_mem_doorbell),
2862306a36Sopenharmony_ci	HNS3_TQP_STAT("wake", restart_queue),
2962306a36Sopenharmony_ci	HNS3_TQP_STAT("busy", tx_busy),
3062306a36Sopenharmony_ci	HNS3_TQP_STAT("copy", tx_copy),
3162306a36Sopenharmony_ci	HNS3_TQP_STAT("vlan_err", tx_vlan_err),
3262306a36Sopenharmony_ci	HNS3_TQP_STAT("l4_proto_err", tx_l4_proto_err),
3362306a36Sopenharmony_ci	HNS3_TQP_STAT("l2l3l4_err", tx_l2l3l4_err),
3462306a36Sopenharmony_ci	HNS3_TQP_STAT("tso_err", tx_tso_err),
3562306a36Sopenharmony_ci	HNS3_TQP_STAT("over_max_recursion", over_max_recursion),
3662306a36Sopenharmony_ci	HNS3_TQP_STAT("hw_limitation", hw_limitation),
3762306a36Sopenharmony_ci	HNS3_TQP_STAT("bounce", tx_bounce),
3862306a36Sopenharmony_ci	HNS3_TQP_STAT("spare_full", tx_spare_full),
3962306a36Sopenharmony_ci	HNS3_TQP_STAT("copy_bits_err", copy_bits_err),
4062306a36Sopenharmony_ci	HNS3_TQP_STAT("sgl", tx_sgl),
4162306a36Sopenharmony_ci	HNS3_TQP_STAT("skb2sgl_err", skb2sgl_err),
4262306a36Sopenharmony_ci	HNS3_TQP_STAT("map_sg_err", map_sg_err),
4362306a36Sopenharmony_ci};
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define HNS3_TXQ_STATS_COUNT ARRAY_SIZE(hns3_txq_stats)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic const struct hns3_stats hns3_rxq_stats[] = {
4862306a36Sopenharmony_ci	/* Rx per-queue statistics */
4962306a36Sopenharmony_ci	HNS3_TQP_STAT("dropped", sw_err_cnt),
5062306a36Sopenharmony_ci	HNS3_TQP_STAT("seg_pkt_cnt", seg_pkt_cnt),
5162306a36Sopenharmony_ci	HNS3_TQP_STAT("packets", rx_pkts),
5262306a36Sopenharmony_ci	HNS3_TQP_STAT("bytes", rx_bytes),
5362306a36Sopenharmony_ci	HNS3_TQP_STAT("errors", rx_err_cnt),
5462306a36Sopenharmony_ci	HNS3_TQP_STAT("reuse_pg_cnt", reuse_pg_cnt),
5562306a36Sopenharmony_ci	HNS3_TQP_STAT("err_pkt_len", err_pkt_len),
5662306a36Sopenharmony_ci	HNS3_TQP_STAT("err_bd_num", err_bd_num),
5762306a36Sopenharmony_ci	HNS3_TQP_STAT("l2_err", l2_err),
5862306a36Sopenharmony_ci	HNS3_TQP_STAT("l3l4_csum_err", l3l4_csum_err),
5962306a36Sopenharmony_ci	HNS3_TQP_STAT("csum_complete", csum_complete),
6062306a36Sopenharmony_ci	HNS3_TQP_STAT("multicast", rx_multicast),
6162306a36Sopenharmony_ci	HNS3_TQP_STAT("non_reuse_pg", non_reuse_pg),
6262306a36Sopenharmony_ci	HNS3_TQP_STAT("frag_alloc_err", frag_alloc_err),
6362306a36Sopenharmony_ci	HNS3_TQP_STAT("frag_alloc", frag_alloc),
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define HNS3_PRIV_FLAGS_LEN ARRAY_SIZE(hns3_priv_flags)
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define HNS3_RXQ_STATS_COUNT ARRAY_SIZE(hns3_rxq_stats)
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#define HNS3_TQP_STATS_COUNT (HNS3_TXQ_STATS_COUNT + HNS3_RXQ_STATS_COUNT)
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#define HNS3_NIC_LB_TEST_PKT_NUM	1
7362306a36Sopenharmony_ci#define HNS3_NIC_LB_TEST_RING_ID	0
7462306a36Sopenharmony_ci#define HNS3_NIC_LB_TEST_PACKET_SIZE	128
7562306a36Sopenharmony_ci#define HNS3_NIC_LB_SETUP_USEC		10000
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/* Nic loopback test err  */
7862306a36Sopenharmony_ci#define HNS3_NIC_LB_TEST_NO_MEM_ERR	1
7962306a36Sopenharmony_ci#define HNS3_NIC_LB_TEST_TX_CNT_ERR	2
8062306a36Sopenharmony_ci#define HNS3_NIC_LB_TEST_RX_CNT_ERR	3
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(ndev);
8562306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
8662306a36Sopenharmony_ci	int ret;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	if (!h->ae_algo->ops->set_loopback ||
8962306a36Sopenharmony_ci	    !h->ae_algo->ops->set_promisc_mode)
9062306a36Sopenharmony_ci		return -EOPNOTSUPP;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	switch (loop) {
9362306a36Sopenharmony_ci	case HNAE3_LOOP_SERIAL_SERDES:
9462306a36Sopenharmony_ci	case HNAE3_LOOP_PARALLEL_SERDES:
9562306a36Sopenharmony_ci	case HNAE3_LOOP_APP:
9662306a36Sopenharmony_ci	case HNAE3_LOOP_PHY:
9762306a36Sopenharmony_ci	case HNAE3_LOOP_EXTERNAL:
9862306a36Sopenharmony_ci		ret = h->ae_algo->ops->set_loopback(h, loop, en);
9962306a36Sopenharmony_ci		break;
10062306a36Sopenharmony_ci	default:
10162306a36Sopenharmony_ci		ret = -ENOTSUPP;
10262306a36Sopenharmony_ci		break;
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (ret || ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2)
10662306a36Sopenharmony_ci		return ret;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (en)
10962306a36Sopenharmony_ci		h->ae_algo->ops->set_promisc_mode(h, true, true);
11062306a36Sopenharmony_ci	else
11162306a36Sopenharmony_ci		/* recover promisc mode before loopback test */
11262306a36Sopenharmony_ci		hns3_request_update_promisc_mode(h);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	return ret;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic int hns3_lp_up(struct net_device *ndev, enum hnae3_loop loop_mode)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(ndev);
12062306a36Sopenharmony_ci	int ret;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	ret = hns3_nic_reset_all_ring(h);
12362306a36Sopenharmony_ci	if (ret)
12462306a36Sopenharmony_ci		return ret;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	ret = hns3_lp_setup(ndev, loop_mode, true);
12762306a36Sopenharmony_ci	usleep_range(HNS3_NIC_LB_SETUP_USEC, HNS3_NIC_LB_SETUP_USEC * 2);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	return ret;
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic int hns3_lp_down(struct net_device *ndev, enum hnae3_loop loop_mode)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	int ret;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	ret = hns3_lp_setup(ndev, loop_mode, false);
13762306a36Sopenharmony_ci	if (ret) {
13862306a36Sopenharmony_ci		netdev_err(ndev, "lb_setup return error: %d\n", ret);
13962306a36Sopenharmony_ci		return ret;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	usleep_range(HNS3_NIC_LB_SETUP_USEC, HNS3_NIC_LB_SETUP_USEC * 2);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	return 0;
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic void hns3_lp_setup_skb(struct sk_buff *skb)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci#define	HNS3_NIC_LB_DST_MAC_ADDR	0x1f
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	struct net_device *ndev = skb->dev;
15262306a36Sopenharmony_ci	struct hnae3_handle *handle;
15362306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev;
15462306a36Sopenharmony_ci	unsigned char *packet;
15562306a36Sopenharmony_ci	struct ethhdr *ethh;
15662306a36Sopenharmony_ci	unsigned int i;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	skb_reserve(skb, NET_IP_ALIGN);
15962306a36Sopenharmony_ci	ethh = skb_put(skb, sizeof(struct ethhdr));
16062306a36Sopenharmony_ci	packet = skb_put(skb, HNS3_NIC_LB_TEST_PACKET_SIZE);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	memcpy(ethh->h_dest, ndev->dev_addr, ETH_ALEN);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	/* The dst mac addr of loopback packet is the same as the host'
16562306a36Sopenharmony_ci	 * mac addr, the SSU component may loop back the packet to host
16662306a36Sopenharmony_ci	 * before the packet reaches mac or serdes, which will defect
16762306a36Sopenharmony_ci	 * the purpose of mac or serdes selftest.
16862306a36Sopenharmony_ci	 */
16962306a36Sopenharmony_ci	handle = hns3_get_handle(ndev);
17062306a36Sopenharmony_ci	ae_dev = pci_get_drvdata(handle->pdev);
17162306a36Sopenharmony_ci	if (ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2)
17262306a36Sopenharmony_ci		ethh->h_dest[5] += HNS3_NIC_LB_DST_MAC_ADDR;
17362306a36Sopenharmony_ci	eth_zero_addr(ethh->h_source);
17462306a36Sopenharmony_ci	ethh->h_proto = htons(ETH_P_ARP);
17562306a36Sopenharmony_ci	skb_reset_mac_header(skb);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	for (i = 0; i < HNS3_NIC_LB_TEST_PACKET_SIZE; i++)
17862306a36Sopenharmony_ci		packet[i] = (unsigned char)(i & 0xff);
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic void hns3_lb_check_skb_data(struct hns3_enet_ring *ring,
18262306a36Sopenharmony_ci				   struct sk_buff *skb)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	struct hns3_enet_tqp_vector *tqp_vector = ring->tqp_vector;
18562306a36Sopenharmony_ci	unsigned char *packet = skb->data;
18662306a36Sopenharmony_ci	u32 len = skb_headlen(skb);
18762306a36Sopenharmony_ci	u32 i;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	len = min_t(u32, len, HNS3_NIC_LB_TEST_PACKET_SIZE);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	for (i = 0; i < len; i++)
19262306a36Sopenharmony_ci		if (packet[i] != (unsigned char)(i & 0xff))
19362306a36Sopenharmony_ci			break;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	/* The packet is correctly received */
19662306a36Sopenharmony_ci	if (i == HNS3_NIC_LB_TEST_PACKET_SIZE)
19762306a36Sopenharmony_ci		tqp_vector->rx_group.total_packets++;
19862306a36Sopenharmony_ci	else
19962306a36Sopenharmony_ci		print_hex_dump(KERN_ERR, "selftest:", DUMP_PREFIX_OFFSET, 16, 1,
20062306a36Sopenharmony_ci			       skb->data, len, true);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	dev_kfree_skb_any(skb);
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic u32 hns3_lb_check_rx_ring(struct hns3_nic_priv *priv, u32 budget)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	struct hnae3_handle *h = priv->ae_handle;
20862306a36Sopenharmony_ci	struct hnae3_knic_private_info *kinfo;
20962306a36Sopenharmony_ci	u32 i, rcv_good_pkt_total = 0;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	kinfo = &h->kinfo;
21262306a36Sopenharmony_ci	for (i = kinfo->num_tqps; i < kinfo->num_tqps * 2; i++) {
21362306a36Sopenharmony_ci		struct hns3_enet_ring *ring = &priv->ring[i];
21462306a36Sopenharmony_ci		struct hns3_enet_ring_group *rx_group;
21562306a36Sopenharmony_ci		u64 pre_rx_pkt;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		rx_group = &ring->tqp_vector->rx_group;
21862306a36Sopenharmony_ci		pre_rx_pkt = rx_group->total_packets;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci		preempt_disable();
22162306a36Sopenharmony_ci		hns3_clean_rx_ring(ring, budget, hns3_lb_check_skb_data);
22262306a36Sopenharmony_ci		preempt_enable();
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci		rcv_good_pkt_total += (rx_group->total_packets - pre_rx_pkt);
22562306a36Sopenharmony_ci		rx_group->total_packets = pre_rx_pkt;
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci	return rcv_good_pkt_total;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic void hns3_lb_clear_tx_ring(struct hns3_nic_priv *priv, u32 start_ringid,
23162306a36Sopenharmony_ci				  u32 end_ringid)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	u32 i;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	for (i = start_ringid; i <= end_ringid; i++) {
23662306a36Sopenharmony_ci		struct hns3_enet_ring *ring = &priv->ring[i];
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci		hns3_clean_tx_ring(ring, 0);
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci/**
24362306a36Sopenharmony_ci * hns3_lp_run_test - run loopback test
24462306a36Sopenharmony_ci * @ndev: net device
24562306a36Sopenharmony_ci * @mode: loopback type
24662306a36Sopenharmony_ci *
24762306a36Sopenharmony_ci * Return: %0 for success or a NIC loopback test error code on failure
24862306a36Sopenharmony_ci */
24962306a36Sopenharmony_cistatic int hns3_lp_run_test(struct net_device *ndev, enum hnae3_loop mode)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	struct hns3_nic_priv *priv = netdev_priv(ndev);
25262306a36Sopenharmony_ci	struct sk_buff *skb;
25362306a36Sopenharmony_ci	u32 i, good_cnt;
25462306a36Sopenharmony_ci	int ret_val = 0;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	skb = alloc_skb(HNS3_NIC_LB_TEST_PACKET_SIZE + ETH_HLEN + NET_IP_ALIGN,
25762306a36Sopenharmony_ci			GFP_KERNEL);
25862306a36Sopenharmony_ci	if (!skb)
25962306a36Sopenharmony_ci		return HNS3_NIC_LB_TEST_NO_MEM_ERR;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	skb->dev = ndev;
26262306a36Sopenharmony_ci	hns3_lp_setup_skb(skb);
26362306a36Sopenharmony_ci	skb->queue_mapping = HNS3_NIC_LB_TEST_RING_ID;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	good_cnt = 0;
26662306a36Sopenharmony_ci	for (i = 0; i < HNS3_NIC_LB_TEST_PKT_NUM; i++) {
26762306a36Sopenharmony_ci		netdev_tx_t tx_ret;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci		skb_get(skb);
27062306a36Sopenharmony_ci		tx_ret = hns3_nic_net_xmit(skb, ndev);
27162306a36Sopenharmony_ci		if (tx_ret == NETDEV_TX_OK) {
27262306a36Sopenharmony_ci			good_cnt++;
27362306a36Sopenharmony_ci		} else {
27462306a36Sopenharmony_ci			kfree_skb(skb);
27562306a36Sopenharmony_ci			netdev_err(ndev, "hns3_lb_run_test xmit failed: %d\n",
27662306a36Sopenharmony_ci				   tx_ret);
27762306a36Sopenharmony_ci		}
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci	if (good_cnt != HNS3_NIC_LB_TEST_PKT_NUM) {
28062306a36Sopenharmony_ci		ret_val = HNS3_NIC_LB_TEST_TX_CNT_ERR;
28162306a36Sopenharmony_ci		netdev_err(ndev, "mode %d sent fail, cnt=0x%x, budget=0x%x\n",
28262306a36Sopenharmony_ci			   mode, good_cnt, HNS3_NIC_LB_TEST_PKT_NUM);
28362306a36Sopenharmony_ci		goto out;
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/* Allow 200 milliseconds for packets to go from Tx to Rx */
28762306a36Sopenharmony_ci	msleep(200);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	good_cnt = hns3_lb_check_rx_ring(priv, HNS3_NIC_LB_TEST_PKT_NUM);
29062306a36Sopenharmony_ci	if (good_cnt != HNS3_NIC_LB_TEST_PKT_NUM) {
29162306a36Sopenharmony_ci		ret_val = HNS3_NIC_LB_TEST_RX_CNT_ERR;
29262306a36Sopenharmony_ci		netdev_err(ndev, "mode %d recv fail, cnt=0x%x, budget=0x%x\n",
29362306a36Sopenharmony_ci			   mode, good_cnt, HNS3_NIC_LB_TEST_PKT_NUM);
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ciout:
29762306a36Sopenharmony_ci	hns3_lb_clear_tx_ring(priv, HNS3_NIC_LB_TEST_RING_ID,
29862306a36Sopenharmony_ci			      HNS3_NIC_LB_TEST_RING_ID);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	kfree_skb(skb);
30162306a36Sopenharmony_ci	return ret_val;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic void hns3_set_selftest_param(struct hnae3_handle *h, int (*st_param)[2])
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	st_param[HNAE3_LOOP_EXTERNAL][0] = HNAE3_LOOP_EXTERNAL;
30762306a36Sopenharmony_ci	st_param[HNAE3_LOOP_EXTERNAL][1] =
30862306a36Sopenharmony_ci			h->flags & HNAE3_SUPPORT_EXTERNAL_LOOPBACK;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	st_param[HNAE3_LOOP_APP][0] = HNAE3_LOOP_APP;
31162306a36Sopenharmony_ci	st_param[HNAE3_LOOP_APP][1] =
31262306a36Sopenharmony_ci			h->flags & HNAE3_SUPPORT_APP_LOOPBACK;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	st_param[HNAE3_LOOP_SERIAL_SERDES][0] = HNAE3_LOOP_SERIAL_SERDES;
31562306a36Sopenharmony_ci	st_param[HNAE3_LOOP_SERIAL_SERDES][1] =
31662306a36Sopenharmony_ci			h->flags & HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	st_param[HNAE3_LOOP_PARALLEL_SERDES][0] =
31962306a36Sopenharmony_ci			HNAE3_LOOP_PARALLEL_SERDES;
32062306a36Sopenharmony_ci	st_param[HNAE3_LOOP_PARALLEL_SERDES][1] =
32162306a36Sopenharmony_ci			h->flags & HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	st_param[HNAE3_LOOP_PHY][0] = HNAE3_LOOP_PHY;
32462306a36Sopenharmony_ci	st_param[HNAE3_LOOP_PHY][1] =
32562306a36Sopenharmony_ci			h->flags & HNAE3_SUPPORT_PHY_LOOPBACK;
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic void hns3_selftest_prepare(struct net_device *ndev, bool if_running)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	struct hns3_nic_priv *priv = netdev_priv(ndev);
33162306a36Sopenharmony_ci	struct hnae3_handle *h = priv->ae_handle;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	if (if_running)
33462306a36Sopenharmony_ci		ndev->netdev_ops->ndo_stop(ndev);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_VLAN_8021Q)
33762306a36Sopenharmony_ci	/* Disable the vlan filter for selftest does not support it */
33862306a36Sopenharmony_ci	if (h->ae_algo->ops->enable_vlan_filter &&
33962306a36Sopenharmony_ci	    ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
34062306a36Sopenharmony_ci		h->ae_algo->ops->enable_vlan_filter(h, false);
34162306a36Sopenharmony_ci#endif
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	/* Tell firmware to stop mac autoneg before loopback test start,
34462306a36Sopenharmony_ci	 * otherwise loopback test may be failed when the port is still
34562306a36Sopenharmony_ci	 * negotiating.
34662306a36Sopenharmony_ci	 */
34762306a36Sopenharmony_ci	if (h->ae_algo->ops->halt_autoneg)
34862306a36Sopenharmony_ci		h->ae_algo->ops->halt_autoneg(h, true);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	set_bit(HNS3_NIC_STATE_TESTING, &priv->state);
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic void hns3_selftest_restore(struct net_device *ndev, bool if_running)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	struct hns3_nic_priv *priv = netdev_priv(ndev);
35662306a36Sopenharmony_ci	struct hnae3_handle *h = priv->ae_handle;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	clear_bit(HNS3_NIC_STATE_TESTING, &priv->state);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	if (h->ae_algo->ops->halt_autoneg)
36162306a36Sopenharmony_ci		h->ae_algo->ops->halt_autoneg(h, false);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_VLAN_8021Q)
36462306a36Sopenharmony_ci	if (h->ae_algo->ops->enable_vlan_filter &&
36562306a36Sopenharmony_ci	    ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
36662306a36Sopenharmony_ci		h->ae_algo->ops->enable_vlan_filter(h, true);
36762306a36Sopenharmony_ci#endif
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	if (if_running)
37062306a36Sopenharmony_ci		ndev->netdev_ops->ndo_open(ndev);
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic void hns3_do_selftest(struct net_device *ndev, int (*st_param)[2],
37462306a36Sopenharmony_ci			     struct ethtool_test *eth_test, u64 *data)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	int test_index = HNAE3_LOOP_APP;
37762306a36Sopenharmony_ci	u32 i;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	for (i = HNAE3_LOOP_APP; i < HNAE3_LOOP_NONE; i++) {
38062306a36Sopenharmony_ci		enum hnae3_loop loop_type = (enum hnae3_loop)st_param[i][0];
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci		if (!st_param[i][1])
38362306a36Sopenharmony_ci			continue;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci		data[test_index] = hns3_lp_up(ndev, loop_type);
38662306a36Sopenharmony_ci		if (!data[test_index])
38762306a36Sopenharmony_ci			data[test_index] = hns3_lp_run_test(ndev, loop_type);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci		hns3_lp_down(ndev, loop_type);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci		if (data[test_index])
39262306a36Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci		test_index++;
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic void hns3_do_external_lb(struct net_device *ndev,
39962306a36Sopenharmony_ci				struct ethtool_test *eth_test, u64 *data)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	data[HNAE3_LOOP_EXTERNAL] = hns3_lp_up(ndev, HNAE3_LOOP_EXTERNAL);
40262306a36Sopenharmony_ci	if (!data[HNAE3_LOOP_EXTERNAL])
40362306a36Sopenharmony_ci		data[HNAE3_LOOP_EXTERNAL] = hns3_lp_run_test(ndev, HNAE3_LOOP_EXTERNAL);
40462306a36Sopenharmony_ci	hns3_lp_down(ndev, HNAE3_LOOP_EXTERNAL);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	if (data[HNAE3_LOOP_EXTERNAL])
40762306a36Sopenharmony_ci		eth_test->flags |= ETH_TEST_FL_FAILED;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci/**
41362306a36Sopenharmony_ci * hns3_self_test - self test
41462306a36Sopenharmony_ci * @ndev: net device
41562306a36Sopenharmony_ci * @eth_test: test cmd
41662306a36Sopenharmony_ci * @data: test result
41762306a36Sopenharmony_ci */
41862306a36Sopenharmony_cistatic void hns3_self_test(struct net_device *ndev,
41962306a36Sopenharmony_ci			   struct ethtool_test *eth_test, u64 *data)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	struct hns3_nic_priv *priv = netdev_priv(ndev);
42262306a36Sopenharmony_ci	struct hnae3_handle *h = priv->ae_handle;
42362306a36Sopenharmony_ci	int st_param[HNAE3_LOOP_NONE][2];
42462306a36Sopenharmony_ci	bool if_running = netif_running(ndev);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (hns3_nic_resetting(ndev)) {
42762306a36Sopenharmony_ci		netdev_err(ndev, "dev resetting!");
42862306a36Sopenharmony_ci		return;
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	if (!(eth_test->flags & ETH_TEST_FL_OFFLINE))
43262306a36Sopenharmony_ci		return;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	if (netif_msg_ifdown(h))
43562306a36Sopenharmony_ci		netdev_info(ndev, "self test start\n");
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	hns3_set_selftest_param(h, st_param);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	/* external loopback test requires that the link is up and the duplex is
44062306a36Sopenharmony_ci	 * full, do external test first to reduce the whole test time
44162306a36Sopenharmony_ci	 */
44262306a36Sopenharmony_ci	if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) {
44362306a36Sopenharmony_ci		hns3_external_lb_prepare(ndev, if_running);
44462306a36Sopenharmony_ci		hns3_do_external_lb(ndev, eth_test, data);
44562306a36Sopenharmony_ci		hns3_external_lb_restore(ndev, if_running);
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	hns3_selftest_prepare(ndev, if_running);
44962306a36Sopenharmony_ci	hns3_do_selftest(ndev, st_param, eth_test, data);
45062306a36Sopenharmony_ci	hns3_selftest_restore(ndev, if_running);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if (netif_msg_ifdown(h))
45362306a36Sopenharmony_ci		netdev_info(ndev, "self test end\n");
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic void hns3_update_limit_promisc_mode(struct net_device *netdev,
45762306a36Sopenharmony_ci					   bool enable)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	struct hnae3_handle *handle = hns3_get_handle(netdev);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	if (enable)
46262306a36Sopenharmony_ci		set_bit(HNAE3_PFLAG_LIMIT_PROMISC, &handle->priv_flags);
46362306a36Sopenharmony_ci	else
46462306a36Sopenharmony_ci		clear_bit(HNAE3_PFLAG_LIMIT_PROMISC, &handle->priv_flags);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	hns3_request_update_promisc_mode(handle);
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic const struct hns3_pflag_desc hns3_priv_flags[HNAE3_PFLAG_MAX] = {
47062306a36Sopenharmony_ci	{ "limit_promisc",	hns3_update_limit_promisc_mode }
47162306a36Sopenharmony_ci};
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic int hns3_get_sset_count(struct net_device *netdev, int stringset)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
47662306a36Sopenharmony_ci	const struct hnae3_ae_ops *ops = h->ae_algo->ops;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	if (!ops->get_sset_count)
47962306a36Sopenharmony_ci		return -EOPNOTSUPP;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	switch (stringset) {
48262306a36Sopenharmony_ci	case ETH_SS_STATS:
48362306a36Sopenharmony_ci		return ((HNS3_TQP_STATS_COUNT * h->kinfo.num_tqps) +
48462306a36Sopenharmony_ci			ops->get_sset_count(h, stringset));
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	case ETH_SS_TEST:
48762306a36Sopenharmony_ci		return ops->get_sset_count(h, stringset);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	case ETH_SS_PRIV_FLAGS:
49062306a36Sopenharmony_ci		return HNAE3_PFLAG_MAX;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	default:
49362306a36Sopenharmony_ci		return -EOPNOTSUPP;
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_cistatic void *hns3_update_strings(u8 *data, const struct hns3_stats *stats,
49862306a36Sopenharmony_ci		u32 stat_count, u32 num_tqps, const char *prefix)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci#define MAX_PREFIX_SIZE (6 + 4)
50162306a36Sopenharmony_ci	u32 size_left;
50262306a36Sopenharmony_ci	u32 i, j;
50362306a36Sopenharmony_ci	u32 n1;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	for (i = 0; i < num_tqps; i++) {
50662306a36Sopenharmony_ci		for (j = 0; j < stat_count; j++) {
50762306a36Sopenharmony_ci			data[ETH_GSTRING_LEN - 1] = '\0';
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci			/* first, prepend the prefix string */
51062306a36Sopenharmony_ci			n1 = scnprintf(data, MAX_PREFIX_SIZE, "%s%u_",
51162306a36Sopenharmony_ci				       prefix, i);
51262306a36Sopenharmony_ci			size_left = (ETH_GSTRING_LEN - 1) - n1;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci			/* now, concatenate the stats string to it */
51562306a36Sopenharmony_ci			strncat(data, stats[j].stats_string, size_left);
51662306a36Sopenharmony_ci			data += ETH_GSTRING_LEN;
51762306a36Sopenharmony_ci		}
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	return data;
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic u8 *hns3_get_strings_tqps(struct hnae3_handle *handle, u8 *data)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	struct hnae3_knic_private_info *kinfo = &handle->kinfo;
52662306a36Sopenharmony_ci	const char tx_prefix[] = "txq";
52762306a36Sopenharmony_ci	const char rx_prefix[] = "rxq";
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	/* get strings for Tx */
53062306a36Sopenharmony_ci	data = hns3_update_strings(data, hns3_txq_stats, HNS3_TXQ_STATS_COUNT,
53162306a36Sopenharmony_ci				   kinfo->num_tqps, tx_prefix);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	/* get strings for Rx */
53462306a36Sopenharmony_ci	data = hns3_update_strings(data, hns3_rxq_stats, HNS3_RXQ_STATS_COUNT,
53562306a36Sopenharmony_ci				   kinfo->num_tqps, rx_prefix);
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	return data;
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cistatic void hns3_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
54362306a36Sopenharmony_ci	const struct hnae3_ae_ops *ops = h->ae_algo->ops;
54462306a36Sopenharmony_ci	char *buff = (char *)data;
54562306a36Sopenharmony_ci	int i;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	if (!ops->get_strings)
54862306a36Sopenharmony_ci		return;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	switch (stringset) {
55162306a36Sopenharmony_ci	case ETH_SS_STATS:
55262306a36Sopenharmony_ci		buff = hns3_get_strings_tqps(h, buff);
55362306a36Sopenharmony_ci		ops->get_strings(h, stringset, (u8 *)buff);
55462306a36Sopenharmony_ci		break;
55562306a36Sopenharmony_ci	case ETH_SS_TEST:
55662306a36Sopenharmony_ci		ops->get_strings(h, stringset, data);
55762306a36Sopenharmony_ci		break;
55862306a36Sopenharmony_ci	case ETH_SS_PRIV_FLAGS:
55962306a36Sopenharmony_ci		for (i = 0; i < HNS3_PRIV_FLAGS_LEN; i++) {
56062306a36Sopenharmony_ci			snprintf(buff, ETH_GSTRING_LEN, "%s",
56162306a36Sopenharmony_ci				 hns3_priv_flags[i].name);
56262306a36Sopenharmony_ci			buff += ETH_GSTRING_LEN;
56362306a36Sopenharmony_ci		}
56462306a36Sopenharmony_ci		break;
56562306a36Sopenharmony_ci	default:
56662306a36Sopenharmony_ci		break;
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic u64 *hns3_get_stats_tqps(struct hnae3_handle *handle, u64 *data)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	struct hnae3_knic_private_info *kinfo = &handle->kinfo;
57362306a36Sopenharmony_ci	struct hns3_nic_priv *nic_priv = handle->priv;
57462306a36Sopenharmony_ci	struct hns3_enet_ring *ring;
57562306a36Sopenharmony_ci	u8 *stat;
57662306a36Sopenharmony_ci	int i, j;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	/* get stats for Tx */
57962306a36Sopenharmony_ci	for (i = 0; i < kinfo->num_tqps; i++) {
58062306a36Sopenharmony_ci		ring = &nic_priv->ring[i];
58162306a36Sopenharmony_ci		for (j = 0; j < HNS3_TXQ_STATS_COUNT; j++) {
58262306a36Sopenharmony_ci			stat = (u8 *)ring + hns3_txq_stats[j].stats_offset;
58362306a36Sopenharmony_ci			*data++ = *(u64 *)stat;
58462306a36Sopenharmony_ci		}
58562306a36Sopenharmony_ci	}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	/* get stats for Rx */
58862306a36Sopenharmony_ci	for (i = 0; i < kinfo->num_tqps; i++) {
58962306a36Sopenharmony_ci		ring = &nic_priv->ring[i + kinfo->num_tqps];
59062306a36Sopenharmony_ci		for (j = 0; j < HNS3_RXQ_STATS_COUNT; j++) {
59162306a36Sopenharmony_ci			stat = (u8 *)ring + hns3_rxq_stats[j].stats_offset;
59262306a36Sopenharmony_ci			*data++ = *(u64 *)stat;
59362306a36Sopenharmony_ci		}
59462306a36Sopenharmony_ci	}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	return data;
59762306a36Sopenharmony_ci}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci/* hns3_get_stats - get detail statistics.
60062306a36Sopenharmony_ci * @netdev: net device
60162306a36Sopenharmony_ci * @stats: statistics info.
60262306a36Sopenharmony_ci * @data: statistics data.
60362306a36Sopenharmony_ci */
60462306a36Sopenharmony_cistatic void hns3_get_stats(struct net_device *netdev,
60562306a36Sopenharmony_ci			   struct ethtool_stats *stats, u64 *data)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
60862306a36Sopenharmony_ci	u64 *p = data;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	if (hns3_nic_resetting(netdev)) {
61162306a36Sopenharmony_ci		netdev_err(netdev, "dev resetting, could not get stats\n");
61262306a36Sopenharmony_ci		return;
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	if (!h->ae_algo->ops->get_stats || !h->ae_algo->ops->update_stats) {
61662306a36Sopenharmony_ci		netdev_err(netdev, "could not get any statistics\n");
61762306a36Sopenharmony_ci		return;
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	h->ae_algo->ops->update_stats(h);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	/* get per-queue stats */
62362306a36Sopenharmony_ci	p = hns3_get_stats_tqps(h, p);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	/* get MAC & other misc hardware stats */
62662306a36Sopenharmony_ci	h->ae_algo->ops->get_stats(h, p);
62762306a36Sopenharmony_ci}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_cistatic void hns3_get_drvinfo(struct net_device *netdev,
63062306a36Sopenharmony_ci			     struct ethtool_drvinfo *drvinfo)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	struct hns3_nic_priv *priv = netdev_priv(netdev);
63362306a36Sopenharmony_ci	struct hnae3_handle *h = priv->ae_handle;
63462306a36Sopenharmony_ci	u32 fw_version;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	if (!h->ae_algo->ops->get_fw_version) {
63762306a36Sopenharmony_ci		netdev_err(netdev, "could not get fw version!\n");
63862306a36Sopenharmony_ci		return;
63962306a36Sopenharmony_ci	}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	strscpy(drvinfo->driver, dev_driver_string(&h->pdev->dev),
64262306a36Sopenharmony_ci		sizeof(drvinfo->driver));
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	strscpy(drvinfo->bus_info, pci_name(h->pdev),
64562306a36Sopenharmony_ci		sizeof(drvinfo->bus_info));
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	fw_version = priv->ae_handle->ae_algo->ops->get_fw_version(h);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
65062306a36Sopenharmony_ci		 "%lu.%lu.%lu.%lu",
65162306a36Sopenharmony_ci		 hnae3_get_field(fw_version, HNAE3_FW_VERSION_BYTE3_MASK,
65262306a36Sopenharmony_ci				 HNAE3_FW_VERSION_BYTE3_SHIFT),
65362306a36Sopenharmony_ci		 hnae3_get_field(fw_version, HNAE3_FW_VERSION_BYTE2_MASK,
65462306a36Sopenharmony_ci				 HNAE3_FW_VERSION_BYTE2_SHIFT),
65562306a36Sopenharmony_ci		 hnae3_get_field(fw_version, HNAE3_FW_VERSION_BYTE1_MASK,
65662306a36Sopenharmony_ci				 HNAE3_FW_VERSION_BYTE1_SHIFT),
65762306a36Sopenharmony_ci		 hnae3_get_field(fw_version, HNAE3_FW_VERSION_BYTE0_MASK,
65862306a36Sopenharmony_ci				 HNAE3_FW_VERSION_BYTE0_SHIFT));
65962306a36Sopenharmony_ci}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic u32 hns3_get_link(struct net_device *netdev)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	if (h->ae_algo->ops->get_status)
66662306a36Sopenharmony_ci		return h->ae_algo->ops->get_status(h);
66762306a36Sopenharmony_ci	else
66862306a36Sopenharmony_ci		return 0;
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_cistatic void hns3_get_ringparam(struct net_device *netdev,
67262306a36Sopenharmony_ci			       struct ethtool_ringparam *param,
67362306a36Sopenharmony_ci			       struct kernel_ethtool_ringparam *kernel_param,
67462306a36Sopenharmony_ci			       struct netlink_ext_ack *extack)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	struct hns3_nic_priv *priv = netdev_priv(netdev);
67762306a36Sopenharmony_ci	struct hnae3_handle *h = priv->ae_handle;
67862306a36Sopenharmony_ci	int rx_queue_index = h->kinfo.num_tqps;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (hns3_nic_resetting(netdev) || !priv->ring) {
68162306a36Sopenharmony_ci		netdev_err(netdev, "failed to get ringparam value, due to dev resetting or uninited\n");
68262306a36Sopenharmony_ci		return;
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	param->tx_max_pending = HNS3_RING_MAX_PENDING;
68662306a36Sopenharmony_ci	param->rx_max_pending = HNS3_RING_MAX_PENDING;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	param->tx_pending = priv->ring[0].desc_num;
68962306a36Sopenharmony_ci	param->rx_pending = priv->ring[rx_queue_index].desc_num;
69062306a36Sopenharmony_ci	kernel_param->rx_buf_len = priv->ring[rx_queue_index].buf_size;
69162306a36Sopenharmony_ci	kernel_param->tx_push = test_bit(HNS3_NIC_STATE_TX_PUSH_ENABLE,
69262306a36Sopenharmony_ci					 &priv->state);
69362306a36Sopenharmony_ci}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_cistatic void hns3_get_pauseparam(struct net_device *netdev,
69662306a36Sopenharmony_ci				struct ethtool_pauseparam *param)
69762306a36Sopenharmony_ci{
69862306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
69962306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	if (!test_bit(HNAE3_DEV_SUPPORT_PAUSE_B, ae_dev->caps))
70262306a36Sopenharmony_ci		return;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	if (h->ae_algo->ops->get_pauseparam)
70562306a36Sopenharmony_ci		h->ae_algo->ops->get_pauseparam(h, &param->autoneg,
70662306a36Sopenharmony_ci			&param->rx_pause, &param->tx_pause);
70762306a36Sopenharmony_ci}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_cistatic int hns3_set_pauseparam(struct net_device *netdev,
71062306a36Sopenharmony_ci			       struct ethtool_pauseparam *param)
71162306a36Sopenharmony_ci{
71262306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
71362306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	if (!test_bit(HNAE3_DEV_SUPPORT_PAUSE_B, ae_dev->caps))
71662306a36Sopenharmony_ci		return -EOPNOTSUPP;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	netif_dbg(h, drv, netdev,
71962306a36Sopenharmony_ci		  "set pauseparam: autoneg=%u, rx:%u, tx:%u\n",
72062306a36Sopenharmony_ci		  param->autoneg, param->rx_pause, param->tx_pause);
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	if (h->ae_algo->ops->set_pauseparam)
72362306a36Sopenharmony_ci		return h->ae_algo->ops->set_pauseparam(h, param->autoneg,
72462306a36Sopenharmony_ci						       param->rx_pause,
72562306a36Sopenharmony_ci						       param->tx_pause);
72662306a36Sopenharmony_ci	return -EOPNOTSUPP;
72762306a36Sopenharmony_ci}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_cistatic void hns3_get_ksettings(struct hnae3_handle *h,
73062306a36Sopenharmony_ci			       struct ethtool_link_ksettings *cmd)
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	const struct hnae3_ae_ops *ops = h->ae_algo->ops;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	/* 1.auto_neg & speed & duplex from cmd */
73562306a36Sopenharmony_ci	if (ops->get_ksettings_an_result)
73662306a36Sopenharmony_ci		ops->get_ksettings_an_result(h,
73762306a36Sopenharmony_ci					     &cmd->base.autoneg,
73862306a36Sopenharmony_ci					     &cmd->base.speed,
73962306a36Sopenharmony_ci					     &cmd->base.duplex,
74062306a36Sopenharmony_ci					     &cmd->lanes);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	/* 2.get link mode */
74362306a36Sopenharmony_ci	if (ops->get_link_mode)
74462306a36Sopenharmony_ci		ops->get_link_mode(h,
74562306a36Sopenharmony_ci				   cmd->link_modes.supported,
74662306a36Sopenharmony_ci				   cmd->link_modes.advertising);
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	/* 3.mdix_ctrl&mdix get from phy reg */
74962306a36Sopenharmony_ci	if (ops->get_mdix_mode)
75062306a36Sopenharmony_ci		ops->get_mdix_mode(h, &cmd->base.eth_tp_mdix_ctrl,
75162306a36Sopenharmony_ci				   &cmd->base.eth_tp_mdix);
75262306a36Sopenharmony_ci}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_cistatic int hns3_get_link_ksettings(struct net_device *netdev,
75562306a36Sopenharmony_ci				   struct ethtool_link_ksettings *cmd)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
75862306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
75962306a36Sopenharmony_ci	const struct hnae3_ae_ops *ops;
76062306a36Sopenharmony_ci	u8 module_type;
76162306a36Sopenharmony_ci	u8 media_type;
76262306a36Sopenharmony_ci	u8 link_stat;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	ops = h->ae_algo->ops;
76562306a36Sopenharmony_ci	if (ops->get_media_type)
76662306a36Sopenharmony_ci		ops->get_media_type(h, &media_type, &module_type);
76762306a36Sopenharmony_ci	else
76862306a36Sopenharmony_ci		return -EOPNOTSUPP;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	switch (media_type) {
77162306a36Sopenharmony_ci	case HNAE3_MEDIA_TYPE_NONE:
77262306a36Sopenharmony_ci		cmd->base.port = PORT_NONE;
77362306a36Sopenharmony_ci		hns3_get_ksettings(h, cmd);
77462306a36Sopenharmony_ci		break;
77562306a36Sopenharmony_ci	case HNAE3_MEDIA_TYPE_FIBER:
77662306a36Sopenharmony_ci		if (module_type == HNAE3_MODULE_TYPE_UNKNOWN)
77762306a36Sopenharmony_ci			cmd->base.port = PORT_OTHER;
77862306a36Sopenharmony_ci		else if (module_type == HNAE3_MODULE_TYPE_CR)
77962306a36Sopenharmony_ci			cmd->base.port = PORT_DA;
78062306a36Sopenharmony_ci		else
78162306a36Sopenharmony_ci			cmd->base.port = PORT_FIBRE;
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci		hns3_get_ksettings(h, cmd);
78462306a36Sopenharmony_ci		break;
78562306a36Sopenharmony_ci	case HNAE3_MEDIA_TYPE_BACKPLANE:
78662306a36Sopenharmony_ci		cmd->base.port = PORT_NONE;
78762306a36Sopenharmony_ci		hns3_get_ksettings(h, cmd);
78862306a36Sopenharmony_ci		break;
78962306a36Sopenharmony_ci	case HNAE3_MEDIA_TYPE_COPPER:
79062306a36Sopenharmony_ci		cmd->base.port = PORT_TP;
79162306a36Sopenharmony_ci		if (test_bit(HNAE3_DEV_SUPPORT_PHY_IMP_B, ae_dev->caps) &&
79262306a36Sopenharmony_ci		    ops->get_phy_link_ksettings)
79362306a36Sopenharmony_ci			ops->get_phy_link_ksettings(h, cmd);
79462306a36Sopenharmony_ci		else if (!netdev->phydev)
79562306a36Sopenharmony_ci			hns3_get_ksettings(h, cmd);
79662306a36Sopenharmony_ci		else
79762306a36Sopenharmony_ci			phy_ethtool_ksettings_get(netdev->phydev, cmd);
79862306a36Sopenharmony_ci		break;
79962306a36Sopenharmony_ci	default:
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci		netdev_warn(netdev, "Unknown media type");
80262306a36Sopenharmony_ci		return 0;
80362306a36Sopenharmony_ci	}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	/* mdio_support */
80662306a36Sopenharmony_ci	cmd->base.mdio_support = ETH_MDIO_SUPPORTS_C22;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	link_stat = hns3_get_link(netdev);
80962306a36Sopenharmony_ci	if (!link_stat) {
81062306a36Sopenharmony_ci		cmd->base.speed = SPEED_UNKNOWN;
81162306a36Sopenharmony_ci		cmd->base.duplex = DUPLEX_UNKNOWN;
81262306a36Sopenharmony_ci	}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	return 0;
81562306a36Sopenharmony_ci}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_cistatic int hns3_check_ksettings_param(const struct net_device *netdev,
81862306a36Sopenharmony_ci				      const struct ethtool_link_ksettings *cmd)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	struct hnae3_handle *handle = hns3_get_handle(netdev);
82162306a36Sopenharmony_ci	const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
82262306a36Sopenharmony_ci	u8 module_type = HNAE3_MODULE_TYPE_UNKNOWN;
82362306a36Sopenharmony_ci	u8 media_type = HNAE3_MEDIA_TYPE_UNKNOWN;
82462306a36Sopenharmony_ci	u32 lane_num;
82562306a36Sopenharmony_ci	u8 autoneg;
82662306a36Sopenharmony_ci	u32 speed;
82762306a36Sopenharmony_ci	u8 duplex;
82862306a36Sopenharmony_ci	int ret;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	/* hw doesn't support use specified speed and duplex to negotiate,
83162306a36Sopenharmony_ci	 * unnecessary to check them when autoneg on.
83262306a36Sopenharmony_ci	 */
83362306a36Sopenharmony_ci	if (cmd->base.autoneg)
83462306a36Sopenharmony_ci		return 0;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	if (ops->get_ksettings_an_result) {
83762306a36Sopenharmony_ci		ops->get_ksettings_an_result(handle, &autoneg, &speed, &duplex, &lane_num);
83862306a36Sopenharmony_ci		if (cmd->base.autoneg == autoneg && cmd->base.speed == speed &&
83962306a36Sopenharmony_ci		    cmd->base.duplex == duplex && cmd->lanes == lane_num)
84062306a36Sopenharmony_ci			return 0;
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	if (ops->get_media_type)
84462306a36Sopenharmony_ci		ops->get_media_type(handle, &media_type, &module_type);
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	if (cmd->base.duplex == DUPLEX_HALF &&
84762306a36Sopenharmony_ci	    media_type != HNAE3_MEDIA_TYPE_COPPER) {
84862306a36Sopenharmony_ci		netdev_err(netdev,
84962306a36Sopenharmony_ci			   "only copper port supports half duplex!");
85062306a36Sopenharmony_ci		return -EINVAL;
85162306a36Sopenharmony_ci	}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	if (ops->check_port_speed) {
85462306a36Sopenharmony_ci		ret = ops->check_port_speed(handle, cmd->base.speed);
85562306a36Sopenharmony_ci		if (ret) {
85662306a36Sopenharmony_ci			netdev_err(netdev, "unsupported speed\n");
85762306a36Sopenharmony_ci			return ret;
85862306a36Sopenharmony_ci		}
85962306a36Sopenharmony_ci	}
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	return 0;
86262306a36Sopenharmony_ci}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_cistatic int hns3_set_link_ksettings(struct net_device *netdev,
86562306a36Sopenharmony_ci				   const struct ethtool_link_ksettings *cmd)
86662306a36Sopenharmony_ci{
86762306a36Sopenharmony_ci	struct hnae3_handle *handle = hns3_get_handle(netdev);
86862306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev);
86962306a36Sopenharmony_ci	const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
87062306a36Sopenharmony_ci	int ret;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	/* Chip don't support this mode. */
87362306a36Sopenharmony_ci	if (cmd->base.speed == SPEED_1000 && cmd->base.duplex == DUPLEX_HALF)
87462306a36Sopenharmony_ci		return -EINVAL;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	if (cmd->lanes && !hnae3_ae_dev_lane_num_supported(ae_dev))
87762306a36Sopenharmony_ci		return -EOPNOTSUPP;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	netif_dbg(handle, drv, netdev,
88062306a36Sopenharmony_ci		  "set link(%s): autoneg=%u, speed=%u, duplex=%u, lanes=%u\n",
88162306a36Sopenharmony_ci		  netdev->phydev ? "phy" : "mac",
88262306a36Sopenharmony_ci		  cmd->base.autoneg, cmd->base.speed, cmd->base.duplex,
88362306a36Sopenharmony_ci		  cmd->lanes);
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	/* Only support ksettings_set for netdev with phy attached for now */
88662306a36Sopenharmony_ci	if (netdev->phydev) {
88762306a36Sopenharmony_ci		if (cmd->base.speed == SPEED_1000 &&
88862306a36Sopenharmony_ci		    cmd->base.autoneg == AUTONEG_DISABLE)
88962306a36Sopenharmony_ci			return -EINVAL;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci		return phy_ethtool_ksettings_set(netdev->phydev, cmd);
89262306a36Sopenharmony_ci	} else if (test_bit(HNAE3_DEV_SUPPORT_PHY_IMP_B, ae_dev->caps) &&
89362306a36Sopenharmony_ci		   ops->set_phy_link_ksettings) {
89462306a36Sopenharmony_ci		return ops->set_phy_link_ksettings(handle, cmd);
89562306a36Sopenharmony_ci	}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	if (ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2)
89862306a36Sopenharmony_ci		return -EOPNOTSUPP;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	ret = hns3_check_ksettings_param(netdev, cmd);
90162306a36Sopenharmony_ci	if (ret)
90262306a36Sopenharmony_ci		return ret;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	if (ops->set_autoneg) {
90562306a36Sopenharmony_ci		ret = ops->set_autoneg(handle, cmd->base.autoneg);
90662306a36Sopenharmony_ci		if (ret)
90762306a36Sopenharmony_ci			return ret;
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	/* hw doesn't support use specified speed and duplex to negotiate,
91162306a36Sopenharmony_ci	 * ignore them when autoneg on.
91262306a36Sopenharmony_ci	 */
91362306a36Sopenharmony_ci	if (cmd->base.autoneg) {
91462306a36Sopenharmony_ci		netdev_info(netdev,
91562306a36Sopenharmony_ci			    "autoneg is on, ignore the speed and duplex\n");
91662306a36Sopenharmony_ci		return 0;
91762306a36Sopenharmony_ci	}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	if (ops->cfg_mac_speed_dup_h)
92062306a36Sopenharmony_ci		ret = ops->cfg_mac_speed_dup_h(handle, cmd->base.speed,
92162306a36Sopenharmony_ci					       cmd->base.duplex, (u8)(cmd->lanes));
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	return ret;
92462306a36Sopenharmony_ci}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_cistatic u32 hns3_get_rss_key_size(struct net_device *netdev)
92762306a36Sopenharmony_ci{
92862306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	if (!h->ae_algo->ops->get_rss_key_size)
93162306a36Sopenharmony_ci		return 0;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	return h->ae_algo->ops->get_rss_key_size(h);
93462306a36Sopenharmony_ci}
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_cistatic u32 hns3_get_rss_indir_size(struct net_device *netdev)
93762306a36Sopenharmony_ci{
93862306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
93962306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	return ae_dev->dev_specs.rss_ind_tbl_size;
94262306a36Sopenharmony_ci}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_cistatic int hns3_get_rss(struct net_device *netdev, u32 *indir, u8 *key,
94562306a36Sopenharmony_ci			u8 *hfunc)
94662306a36Sopenharmony_ci{
94762306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	if (!h->ae_algo->ops->get_rss)
95062306a36Sopenharmony_ci		return -EOPNOTSUPP;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	return h->ae_algo->ops->get_rss(h, indir, key, hfunc);
95362306a36Sopenharmony_ci}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_cistatic int hns3_set_rss(struct net_device *netdev, const u32 *indir,
95662306a36Sopenharmony_ci			const u8 *key, const u8 hfunc)
95762306a36Sopenharmony_ci{
95862306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
95962306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	if (!h->ae_algo->ops->set_rss)
96262306a36Sopenharmony_ci		return -EOPNOTSUPP;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	if ((ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2 &&
96562306a36Sopenharmony_ci	     hfunc != ETH_RSS_HASH_TOP) || (hfunc != ETH_RSS_HASH_NO_CHANGE &&
96662306a36Sopenharmony_ci	     hfunc != ETH_RSS_HASH_TOP && hfunc != ETH_RSS_HASH_XOR)) {
96762306a36Sopenharmony_ci		netdev_err(netdev, "hash func not supported\n");
96862306a36Sopenharmony_ci		return -EOPNOTSUPP;
96962306a36Sopenharmony_ci	}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	if (!indir) {
97262306a36Sopenharmony_ci		netdev_err(netdev,
97362306a36Sopenharmony_ci			   "set rss failed for indir is empty\n");
97462306a36Sopenharmony_ci		return -EOPNOTSUPP;
97562306a36Sopenharmony_ci	}
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	return h->ae_algo->ops->set_rss(h, indir, key, hfunc);
97862306a36Sopenharmony_ci}
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_cistatic int hns3_get_rxnfc(struct net_device *netdev,
98162306a36Sopenharmony_ci			  struct ethtool_rxnfc *cmd,
98262306a36Sopenharmony_ci			  u32 *rule_locs)
98362306a36Sopenharmony_ci{
98462306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	switch (cmd->cmd) {
98762306a36Sopenharmony_ci	case ETHTOOL_GRXRINGS:
98862306a36Sopenharmony_ci		cmd->data = h->kinfo.num_tqps;
98962306a36Sopenharmony_ci		return 0;
99062306a36Sopenharmony_ci	case ETHTOOL_GRXFH:
99162306a36Sopenharmony_ci		if (h->ae_algo->ops->get_rss_tuple)
99262306a36Sopenharmony_ci			return h->ae_algo->ops->get_rss_tuple(h, cmd);
99362306a36Sopenharmony_ci		return -EOPNOTSUPP;
99462306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRLCNT:
99562306a36Sopenharmony_ci		if (h->ae_algo->ops->get_fd_rule_cnt)
99662306a36Sopenharmony_ci			return h->ae_algo->ops->get_fd_rule_cnt(h, cmd);
99762306a36Sopenharmony_ci		return -EOPNOTSUPP;
99862306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRULE:
99962306a36Sopenharmony_ci		if (h->ae_algo->ops->get_fd_rule_info)
100062306a36Sopenharmony_ci			return h->ae_algo->ops->get_fd_rule_info(h, cmd);
100162306a36Sopenharmony_ci		return -EOPNOTSUPP;
100262306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRLALL:
100362306a36Sopenharmony_ci		if (h->ae_algo->ops->get_fd_all_rules)
100462306a36Sopenharmony_ci			return h->ae_algo->ops->get_fd_all_rules(h, cmd,
100562306a36Sopenharmony_ci								 rule_locs);
100662306a36Sopenharmony_ci		return -EOPNOTSUPP;
100762306a36Sopenharmony_ci	default:
100862306a36Sopenharmony_ci		return -EOPNOTSUPP;
100962306a36Sopenharmony_ci	}
101062306a36Sopenharmony_ci}
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_cistatic const struct hns3_reset_type_map hns3_reset_type[] = {
101362306a36Sopenharmony_ci	{ETH_RESET_MGMT, HNAE3_IMP_RESET},
101462306a36Sopenharmony_ci	{ETH_RESET_ALL, HNAE3_GLOBAL_RESET},
101562306a36Sopenharmony_ci	{ETH_RESET_DEDICATED, HNAE3_FUNC_RESET},
101662306a36Sopenharmony_ci};
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_cistatic const struct hns3_reset_type_map hns3vf_reset_type[] = {
101962306a36Sopenharmony_ci	{ETH_RESET_DEDICATED, HNAE3_VF_FUNC_RESET},
102062306a36Sopenharmony_ci};
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_cistatic int hns3_set_reset(struct net_device *netdev, u32 *flags)
102362306a36Sopenharmony_ci{
102462306a36Sopenharmony_ci	enum hnae3_reset_type rst_type = HNAE3_NONE_RESET;
102562306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
102662306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
102762306a36Sopenharmony_ci	const struct hnae3_ae_ops *ops = h->ae_algo->ops;
102862306a36Sopenharmony_ci	const struct hns3_reset_type_map *rst_type_map;
102962306a36Sopenharmony_ci	enum ethtool_reset_flags rst_flags;
103062306a36Sopenharmony_ci	u32 i, size;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	if (ops->ae_dev_resetting && ops->ae_dev_resetting(h))
103362306a36Sopenharmony_ci		return -EBUSY;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	if (!ops->set_default_reset_request || !ops->reset_event)
103662306a36Sopenharmony_ci		return -EOPNOTSUPP;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	if (h->flags & HNAE3_SUPPORT_VF) {
103962306a36Sopenharmony_ci		rst_type_map = hns3vf_reset_type;
104062306a36Sopenharmony_ci		size = ARRAY_SIZE(hns3vf_reset_type);
104162306a36Sopenharmony_ci	} else {
104262306a36Sopenharmony_ci		rst_type_map = hns3_reset_type;
104362306a36Sopenharmony_ci		size = ARRAY_SIZE(hns3_reset_type);
104462306a36Sopenharmony_ci	}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
104762306a36Sopenharmony_ci		if (rst_type_map[i].rst_flags == *flags) {
104862306a36Sopenharmony_ci			rst_type = rst_type_map[i].rst_type;
104962306a36Sopenharmony_ci			rst_flags = rst_type_map[i].rst_flags;
105062306a36Sopenharmony_ci			break;
105162306a36Sopenharmony_ci		}
105262306a36Sopenharmony_ci	}
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	if (rst_type == HNAE3_NONE_RESET ||
105562306a36Sopenharmony_ci	    (rst_type == HNAE3_IMP_RESET &&
105662306a36Sopenharmony_ci	     ae_dev->dev_version <= HNAE3_DEVICE_VERSION_V2))
105762306a36Sopenharmony_ci		return -EOPNOTSUPP;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	netdev_info(netdev, "Setting reset type %d\n", rst_type);
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	ops->set_default_reset_request(ae_dev, rst_type);
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	ops->reset_event(h->pdev, h);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	*flags &= ~rst_flags;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	return 0;
106862306a36Sopenharmony_ci}
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_cistatic void hns3_change_all_ring_bd_num(struct hns3_nic_priv *priv,
107162306a36Sopenharmony_ci					u32 tx_desc_num, u32 rx_desc_num)
107262306a36Sopenharmony_ci{
107362306a36Sopenharmony_ci	struct hnae3_handle *h = priv->ae_handle;
107462306a36Sopenharmony_ci	int i;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	h->kinfo.num_tx_desc = tx_desc_num;
107762306a36Sopenharmony_ci	h->kinfo.num_rx_desc = rx_desc_num;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	for (i = 0; i < h->kinfo.num_tqps; i++) {
108062306a36Sopenharmony_ci		priv->ring[i].desc_num = tx_desc_num;
108162306a36Sopenharmony_ci		priv->ring[i + h->kinfo.num_tqps].desc_num = rx_desc_num;
108262306a36Sopenharmony_ci	}
108362306a36Sopenharmony_ci}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_cistatic struct hns3_enet_ring *hns3_backup_ringparam(struct hns3_nic_priv *priv)
108662306a36Sopenharmony_ci{
108762306a36Sopenharmony_ci	struct hnae3_handle *handle = priv->ae_handle;
108862306a36Sopenharmony_ci	struct hns3_enet_ring *tmp_rings;
108962306a36Sopenharmony_ci	int i;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	tmp_rings = kcalloc(handle->kinfo.num_tqps * 2,
109262306a36Sopenharmony_ci			    sizeof(struct hns3_enet_ring), GFP_KERNEL);
109362306a36Sopenharmony_ci	if (!tmp_rings)
109462306a36Sopenharmony_ci		return NULL;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	for (i = 0; i < handle->kinfo.num_tqps * 2; i++) {
109762306a36Sopenharmony_ci		memcpy(&tmp_rings[i], &priv->ring[i],
109862306a36Sopenharmony_ci		       sizeof(struct hns3_enet_ring));
109962306a36Sopenharmony_ci		tmp_rings[i].skb = NULL;
110062306a36Sopenharmony_ci	}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	return tmp_rings;
110362306a36Sopenharmony_ci}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_cistatic int hns3_check_ringparam(struct net_device *ndev,
110662306a36Sopenharmony_ci				struct ethtool_ringparam *param,
110762306a36Sopenharmony_ci				struct kernel_ethtool_ringparam *kernel_param)
110862306a36Sopenharmony_ci{
110962306a36Sopenharmony_ci#define RX_BUF_LEN_2K 2048
111062306a36Sopenharmony_ci#define RX_BUF_LEN_4K 4096
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	struct hns3_nic_priv *priv = netdev_priv(ndev);
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	if (hns3_nic_resetting(ndev) || !priv->ring) {
111562306a36Sopenharmony_ci		netdev_err(ndev, "failed to set ringparam value, due to dev resetting or uninited\n");
111662306a36Sopenharmony_ci		return -EBUSY;
111762306a36Sopenharmony_ci	}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	if (param->rx_mini_pending || param->rx_jumbo_pending)
112162306a36Sopenharmony_ci		return -EINVAL;
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	if (kernel_param->rx_buf_len != RX_BUF_LEN_2K &&
112462306a36Sopenharmony_ci	    kernel_param->rx_buf_len != RX_BUF_LEN_4K) {
112562306a36Sopenharmony_ci		netdev_err(ndev, "Rx buf len only support 2048 and 4096\n");
112662306a36Sopenharmony_ci		return -EINVAL;
112762306a36Sopenharmony_ci	}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	if (param->tx_pending > HNS3_RING_MAX_PENDING ||
113062306a36Sopenharmony_ci	    param->tx_pending < HNS3_RING_MIN_PENDING ||
113162306a36Sopenharmony_ci	    param->rx_pending > HNS3_RING_MAX_PENDING ||
113262306a36Sopenharmony_ci	    param->rx_pending < HNS3_RING_MIN_PENDING) {
113362306a36Sopenharmony_ci		netdev_err(ndev, "Queue depth out of range [%d-%d]\n",
113462306a36Sopenharmony_ci			   HNS3_RING_MIN_PENDING, HNS3_RING_MAX_PENDING);
113562306a36Sopenharmony_ci		return -EINVAL;
113662306a36Sopenharmony_ci	}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	return 0;
113962306a36Sopenharmony_ci}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_cistatic bool
114262306a36Sopenharmony_cihns3_is_ringparam_changed(struct net_device *ndev,
114362306a36Sopenharmony_ci			  struct ethtool_ringparam *param,
114462306a36Sopenharmony_ci			  struct kernel_ethtool_ringparam *kernel_param,
114562306a36Sopenharmony_ci			  struct hns3_ring_param *old_ringparam,
114662306a36Sopenharmony_ci			  struct hns3_ring_param *new_ringparam)
114762306a36Sopenharmony_ci{
114862306a36Sopenharmony_ci	struct hns3_nic_priv *priv = netdev_priv(ndev);
114962306a36Sopenharmony_ci	struct hnae3_handle *h = priv->ae_handle;
115062306a36Sopenharmony_ci	u16 queue_num = h->kinfo.num_tqps;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	new_ringparam->tx_desc_num = ALIGN(param->tx_pending,
115362306a36Sopenharmony_ci					   HNS3_RING_BD_MULTIPLE);
115462306a36Sopenharmony_ci	new_ringparam->rx_desc_num = ALIGN(param->rx_pending,
115562306a36Sopenharmony_ci					   HNS3_RING_BD_MULTIPLE);
115662306a36Sopenharmony_ci	old_ringparam->tx_desc_num = priv->ring[0].desc_num;
115762306a36Sopenharmony_ci	old_ringparam->rx_desc_num = priv->ring[queue_num].desc_num;
115862306a36Sopenharmony_ci	old_ringparam->rx_buf_len = priv->ring[queue_num].buf_size;
115962306a36Sopenharmony_ci	new_ringparam->rx_buf_len = kernel_param->rx_buf_len;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	if (old_ringparam->tx_desc_num == new_ringparam->tx_desc_num &&
116262306a36Sopenharmony_ci	    old_ringparam->rx_desc_num == new_ringparam->rx_desc_num &&
116362306a36Sopenharmony_ci	    old_ringparam->rx_buf_len == new_ringparam->rx_buf_len) {
116462306a36Sopenharmony_ci		netdev_info(ndev, "descriptor number and rx buffer length not changed\n");
116562306a36Sopenharmony_ci		return false;
116662306a36Sopenharmony_ci	}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	return true;
116962306a36Sopenharmony_ci}
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_cistatic int hns3_change_rx_buf_len(struct net_device *ndev, u32 rx_buf_len)
117262306a36Sopenharmony_ci{
117362306a36Sopenharmony_ci	struct hns3_nic_priv *priv = netdev_priv(ndev);
117462306a36Sopenharmony_ci	struct hnae3_handle *h = priv->ae_handle;
117562306a36Sopenharmony_ci	int i;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	h->kinfo.rx_buf_len = rx_buf_len;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	for (i = 0; i < h->kinfo.num_tqps; i++) {
118062306a36Sopenharmony_ci		h->kinfo.tqp[i]->buf_size = rx_buf_len;
118162306a36Sopenharmony_ci		priv->ring[i + h->kinfo.num_tqps].buf_size = rx_buf_len;
118262306a36Sopenharmony_ci	}
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	return 0;
118562306a36Sopenharmony_ci}
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_cistatic int hns3_set_tx_push(struct net_device *netdev, u32 tx_push)
118862306a36Sopenharmony_ci{
118962306a36Sopenharmony_ci	struct hns3_nic_priv *priv = netdev_priv(netdev);
119062306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
119162306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
119262306a36Sopenharmony_ci	u32 old_state = test_bit(HNS3_NIC_STATE_TX_PUSH_ENABLE, &priv->state);
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	if (!test_bit(HNAE3_DEV_SUPPORT_TX_PUSH_B, ae_dev->caps) && tx_push)
119562306a36Sopenharmony_ci		return -EOPNOTSUPP;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	if (tx_push == old_state)
119862306a36Sopenharmony_ci		return 0;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	netdev_dbg(netdev, "Changing tx push from %s to %s\n",
120162306a36Sopenharmony_ci		   old_state ? "on" : "off", tx_push ? "on" : "off");
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	if (tx_push)
120462306a36Sopenharmony_ci		set_bit(HNS3_NIC_STATE_TX_PUSH_ENABLE, &priv->state);
120562306a36Sopenharmony_ci	else
120662306a36Sopenharmony_ci		clear_bit(HNS3_NIC_STATE_TX_PUSH_ENABLE, &priv->state);
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	return 0;
120962306a36Sopenharmony_ci}
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_cistatic int hns3_set_ringparam(struct net_device *ndev,
121262306a36Sopenharmony_ci			      struct ethtool_ringparam *param,
121362306a36Sopenharmony_ci			      struct kernel_ethtool_ringparam *kernel_param,
121462306a36Sopenharmony_ci			      struct netlink_ext_ack *extack)
121562306a36Sopenharmony_ci{
121662306a36Sopenharmony_ci	struct hns3_ring_param old_ringparam, new_ringparam;
121762306a36Sopenharmony_ci	struct hns3_nic_priv *priv = netdev_priv(ndev);
121862306a36Sopenharmony_ci	struct hnae3_handle *h = priv->ae_handle;
121962306a36Sopenharmony_ci	struct hns3_enet_ring *tmp_rings;
122062306a36Sopenharmony_ci	bool if_running = netif_running(ndev);
122162306a36Sopenharmony_ci	int ret, i;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	ret = hns3_check_ringparam(ndev, param, kernel_param);
122462306a36Sopenharmony_ci	if (ret)
122562306a36Sopenharmony_ci		return ret;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	ret = hns3_set_tx_push(ndev, kernel_param->tx_push);
122862306a36Sopenharmony_ci	if (ret)
122962306a36Sopenharmony_ci		return ret;
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	if (!hns3_is_ringparam_changed(ndev, param, kernel_param,
123262306a36Sopenharmony_ci				       &old_ringparam, &new_ringparam))
123362306a36Sopenharmony_ci		return 0;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	tmp_rings = hns3_backup_ringparam(priv);
123662306a36Sopenharmony_ci	if (!tmp_rings) {
123762306a36Sopenharmony_ci		netdev_err(ndev, "backup ring param failed by allocating memory fail\n");
123862306a36Sopenharmony_ci		return -ENOMEM;
123962306a36Sopenharmony_ci	}
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	netdev_info(ndev,
124262306a36Sopenharmony_ci		    "Changing Tx/Rx ring depth from %u/%u to %u/%u, Changing rx buffer len from %u to %u\n",
124362306a36Sopenharmony_ci		    old_ringparam.tx_desc_num, old_ringparam.rx_desc_num,
124462306a36Sopenharmony_ci		    new_ringparam.tx_desc_num, new_ringparam.rx_desc_num,
124562306a36Sopenharmony_ci		    old_ringparam.rx_buf_len, new_ringparam.rx_buf_len);
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	if (if_running)
124862306a36Sopenharmony_ci		ndev->netdev_ops->ndo_stop(ndev);
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	hns3_change_all_ring_bd_num(priv, new_ringparam.tx_desc_num,
125162306a36Sopenharmony_ci				    new_ringparam.rx_desc_num);
125262306a36Sopenharmony_ci	hns3_change_rx_buf_len(ndev, new_ringparam.rx_buf_len);
125362306a36Sopenharmony_ci	ret = hns3_init_all_ring(priv);
125462306a36Sopenharmony_ci	if (ret) {
125562306a36Sopenharmony_ci		netdev_err(ndev, "set ringparam fail, revert to old value(%d)\n",
125662306a36Sopenharmony_ci			   ret);
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci		hns3_change_rx_buf_len(ndev, old_ringparam.rx_buf_len);
125962306a36Sopenharmony_ci		hns3_change_all_ring_bd_num(priv, old_ringparam.tx_desc_num,
126062306a36Sopenharmony_ci					    old_ringparam.rx_desc_num);
126162306a36Sopenharmony_ci		for (i = 0; i < h->kinfo.num_tqps * 2; i++)
126262306a36Sopenharmony_ci			memcpy(&priv->ring[i], &tmp_rings[i],
126362306a36Sopenharmony_ci			       sizeof(struct hns3_enet_ring));
126462306a36Sopenharmony_ci	} else {
126562306a36Sopenharmony_ci		for (i = 0; i < h->kinfo.num_tqps * 2; i++)
126662306a36Sopenharmony_ci			hns3_fini_ring(&tmp_rings[i]);
126762306a36Sopenharmony_ci	}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	kfree(tmp_rings);
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	if (if_running)
127262306a36Sopenharmony_ci		ret = ndev->netdev_ops->ndo_open(ndev);
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	return ret;
127562306a36Sopenharmony_ci}
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_cistatic int hns3_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
127862306a36Sopenharmony_ci{
127962306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	switch (cmd->cmd) {
128262306a36Sopenharmony_ci	case ETHTOOL_SRXFH:
128362306a36Sopenharmony_ci		if (h->ae_algo->ops->set_rss_tuple)
128462306a36Sopenharmony_ci			return h->ae_algo->ops->set_rss_tuple(h, cmd);
128562306a36Sopenharmony_ci		return -EOPNOTSUPP;
128662306a36Sopenharmony_ci	case ETHTOOL_SRXCLSRLINS:
128762306a36Sopenharmony_ci		if (h->ae_algo->ops->add_fd_entry)
128862306a36Sopenharmony_ci			return h->ae_algo->ops->add_fd_entry(h, cmd);
128962306a36Sopenharmony_ci		return -EOPNOTSUPP;
129062306a36Sopenharmony_ci	case ETHTOOL_SRXCLSRLDEL:
129162306a36Sopenharmony_ci		if (h->ae_algo->ops->del_fd_entry)
129262306a36Sopenharmony_ci			return h->ae_algo->ops->del_fd_entry(h, cmd);
129362306a36Sopenharmony_ci		return -EOPNOTSUPP;
129462306a36Sopenharmony_ci	default:
129562306a36Sopenharmony_ci		return -EOPNOTSUPP;
129662306a36Sopenharmony_ci	}
129762306a36Sopenharmony_ci}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_cistatic int hns3_nway_reset(struct net_device *netdev)
130062306a36Sopenharmony_ci{
130162306a36Sopenharmony_ci	struct hnae3_handle *handle = hns3_get_handle(netdev);
130262306a36Sopenharmony_ci	const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
130362306a36Sopenharmony_ci	struct phy_device *phy = netdev->phydev;
130462306a36Sopenharmony_ci	int autoneg;
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	if (!netif_running(netdev))
130762306a36Sopenharmony_ci		return 0;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	if (hns3_nic_resetting(netdev)) {
131062306a36Sopenharmony_ci		netdev_err(netdev, "dev resetting!");
131162306a36Sopenharmony_ci		return -EBUSY;
131262306a36Sopenharmony_ci	}
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	if (!ops->get_autoneg || !ops->restart_autoneg)
131562306a36Sopenharmony_ci		return -EOPNOTSUPP;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	autoneg = ops->get_autoneg(handle);
131862306a36Sopenharmony_ci	if (autoneg != AUTONEG_ENABLE) {
131962306a36Sopenharmony_ci		netdev_err(netdev,
132062306a36Sopenharmony_ci			   "Autoneg is off, don't support to restart it\n");
132162306a36Sopenharmony_ci		return -EINVAL;
132262306a36Sopenharmony_ci	}
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	netif_dbg(handle, drv, netdev,
132562306a36Sopenharmony_ci		  "nway reset (using %s)\n", phy ? "phy" : "mac");
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	if (phy)
132862306a36Sopenharmony_ci		return genphy_restart_aneg(phy);
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	return ops->restart_autoneg(handle);
133162306a36Sopenharmony_ci}
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_cistatic void hns3_get_channels(struct net_device *netdev,
133462306a36Sopenharmony_ci			      struct ethtool_channels *ch)
133562306a36Sopenharmony_ci{
133662306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	if (h->ae_algo->ops->get_channels)
133962306a36Sopenharmony_ci		h->ae_algo->ops->get_channels(h, ch);
134062306a36Sopenharmony_ci}
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_cistatic int hns3_get_coalesce(struct net_device *netdev,
134362306a36Sopenharmony_ci			     struct ethtool_coalesce *cmd,
134462306a36Sopenharmony_ci			     struct kernel_ethtool_coalesce *kernel_coal,
134562306a36Sopenharmony_ci			     struct netlink_ext_ack *extack)
134662306a36Sopenharmony_ci{
134762306a36Sopenharmony_ci	struct hns3_nic_priv *priv = netdev_priv(netdev);
134862306a36Sopenharmony_ci	struct hns3_enet_coalesce *tx_coal = &priv->tx_coal;
134962306a36Sopenharmony_ci	struct hns3_enet_coalesce *rx_coal = &priv->rx_coal;
135062306a36Sopenharmony_ci	struct hnae3_handle *h = priv->ae_handle;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	if (hns3_nic_resetting(netdev))
135362306a36Sopenharmony_ci		return -EBUSY;
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	cmd->use_adaptive_tx_coalesce = tx_coal->adapt_enable;
135662306a36Sopenharmony_ci	cmd->use_adaptive_rx_coalesce = rx_coal->adapt_enable;
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	cmd->tx_coalesce_usecs = tx_coal->int_gl;
135962306a36Sopenharmony_ci	cmd->rx_coalesce_usecs = rx_coal->int_gl;
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	cmd->tx_coalesce_usecs_high = h->kinfo.int_rl_setting;
136262306a36Sopenharmony_ci	cmd->rx_coalesce_usecs_high = h->kinfo.int_rl_setting;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	cmd->tx_max_coalesced_frames = tx_coal->int_ql;
136562306a36Sopenharmony_ci	cmd->rx_max_coalesced_frames = rx_coal->int_ql;
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	kernel_coal->use_cqe_mode_tx = (priv->tx_cqe_mode ==
136862306a36Sopenharmony_ci					DIM_CQ_PERIOD_MODE_START_FROM_CQE);
136962306a36Sopenharmony_ci	kernel_coal->use_cqe_mode_rx = (priv->rx_cqe_mode ==
137062306a36Sopenharmony_ci					DIM_CQ_PERIOD_MODE_START_FROM_CQE);
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	return 0;
137362306a36Sopenharmony_ci}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_cistatic int hns3_check_gl_coalesce_para(struct net_device *netdev,
137662306a36Sopenharmony_ci				       struct ethtool_coalesce *cmd)
137762306a36Sopenharmony_ci{
137862306a36Sopenharmony_ci	struct hnae3_handle *handle = hns3_get_handle(netdev);
137962306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev);
138062306a36Sopenharmony_ci	u32 rx_gl, tx_gl;
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	if (cmd->rx_coalesce_usecs > ae_dev->dev_specs.max_int_gl) {
138362306a36Sopenharmony_ci		netdev_err(netdev,
138462306a36Sopenharmony_ci			   "invalid rx-usecs value, rx-usecs range is 0-%u\n",
138562306a36Sopenharmony_ci			   ae_dev->dev_specs.max_int_gl);
138662306a36Sopenharmony_ci		return -EINVAL;
138762306a36Sopenharmony_ci	}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	if (cmd->tx_coalesce_usecs > ae_dev->dev_specs.max_int_gl) {
139062306a36Sopenharmony_ci		netdev_err(netdev,
139162306a36Sopenharmony_ci			   "invalid tx-usecs value, tx-usecs range is 0-%u\n",
139262306a36Sopenharmony_ci			   ae_dev->dev_specs.max_int_gl);
139362306a36Sopenharmony_ci		return -EINVAL;
139462306a36Sopenharmony_ci	}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	/* device version above V3(include V3), GL uses 1us unit,
139762306a36Sopenharmony_ci	 * so the round down is not needed.
139862306a36Sopenharmony_ci	 */
139962306a36Sopenharmony_ci	if (ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V3)
140062306a36Sopenharmony_ci		return 0;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	rx_gl = hns3_gl_round_down(cmd->rx_coalesce_usecs);
140362306a36Sopenharmony_ci	if (rx_gl != cmd->rx_coalesce_usecs) {
140462306a36Sopenharmony_ci		netdev_info(netdev,
140562306a36Sopenharmony_ci			    "rx_usecs(%u) rounded down to %u, because it must be multiple of 2.\n",
140662306a36Sopenharmony_ci			    cmd->rx_coalesce_usecs, rx_gl);
140762306a36Sopenharmony_ci	}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	tx_gl = hns3_gl_round_down(cmd->tx_coalesce_usecs);
141062306a36Sopenharmony_ci	if (tx_gl != cmd->tx_coalesce_usecs) {
141162306a36Sopenharmony_ci		netdev_info(netdev,
141262306a36Sopenharmony_ci			    "tx_usecs(%u) rounded down to %u, because it must be multiple of 2.\n",
141362306a36Sopenharmony_ci			    cmd->tx_coalesce_usecs, tx_gl);
141462306a36Sopenharmony_ci	}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	return 0;
141762306a36Sopenharmony_ci}
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_cistatic int hns3_check_rl_coalesce_para(struct net_device *netdev,
142062306a36Sopenharmony_ci				       struct ethtool_coalesce *cmd)
142162306a36Sopenharmony_ci{
142262306a36Sopenharmony_ci	u32 rl;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	if (cmd->tx_coalesce_usecs_high != cmd->rx_coalesce_usecs_high) {
142562306a36Sopenharmony_ci		netdev_err(netdev,
142662306a36Sopenharmony_ci			   "tx_usecs_high must be same as rx_usecs_high.\n");
142762306a36Sopenharmony_ci		return -EINVAL;
142862306a36Sopenharmony_ci	}
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	if (cmd->rx_coalesce_usecs_high > HNS3_INT_RL_MAX) {
143162306a36Sopenharmony_ci		netdev_err(netdev,
143262306a36Sopenharmony_ci			   "Invalid usecs_high value, usecs_high range is 0-%d\n",
143362306a36Sopenharmony_ci			   HNS3_INT_RL_MAX);
143462306a36Sopenharmony_ci		return -EINVAL;
143562306a36Sopenharmony_ci	}
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	rl = hns3_rl_round_down(cmd->rx_coalesce_usecs_high);
143862306a36Sopenharmony_ci	if (rl != cmd->rx_coalesce_usecs_high) {
143962306a36Sopenharmony_ci		netdev_info(netdev,
144062306a36Sopenharmony_ci			    "usecs_high(%u) rounded down to %u, because it must be multiple of 4.\n",
144162306a36Sopenharmony_ci			    cmd->rx_coalesce_usecs_high, rl);
144262306a36Sopenharmony_ci	}
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	return 0;
144562306a36Sopenharmony_ci}
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_cistatic int hns3_check_ql_coalesce_param(struct net_device *netdev,
144862306a36Sopenharmony_ci					struct ethtool_coalesce *cmd)
144962306a36Sopenharmony_ci{
145062306a36Sopenharmony_ci	struct hnae3_handle *handle = hns3_get_handle(netdev);
145162306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev);
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	if ((cmd->tx_max_coalesced_frames || cmd->rx_max_coalesced_frames) &&
145462306a36Sopenharmony_ci	    !ae_dev->dev_specs.int_ql_max) {
145562306a36Sopenharmony_ci		netdev_err(netdev, "coalesced frames is not supported\n");
145662306a36Sopenharmony_ci		return -EOPNOTSUPP;
145762306a36Sopenharmony_ci	}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	if (cmd->tx_max_coalesced_frames > ae_dev->dev_specs.int_ql_max ||
146062306a36Sopenharmony_ci	    cmd->rx_max_coalesced_frames > ae_dev->dev_specs.int_ql_max) {
146162306a36Sopenharmony_ci		netdev_err(netdev,
146262306a36Sopenharmony_ci			   "invalid coalesced_frames value, range is 0-%u\n",
146362306a36Sopenharmony_ci			   ae_dev->dev_specs.int_ql_max);
146462306a36Sopenharmony_ci		return -ERANGE;
146562306a36Sopenharmony_ci	}
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	return 0;
146862306a36Sopenharmony_ci}
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_cistatic int
147162306a36Sopenharmony_cihns3_check_cqe_coalesce_param(struct net_device *netdev,
147262306a36Sopenharmony_ci			      struct kernel_ethtool_coalesce *kernel_coal)
147362306a36Sopenharmony_ci{
147462306a36Sopenharmony_ci	struct hnae3_handle *handle = hns3_get_handle(netdev);
147562306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev);
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	if ((kernel_coal->use_cqe_mode_tx || kernel_coal->use_cqe_mode_rx) &&
147862306a36Sopenharmony_ci	    !hnae3_ae_dev_cq_supported(ae_dev)) {
147962306a36Sopenharmony_ci		netdev_err(netdev, "coalesced cqe mode is not supported\n");
148062306a36Sopenharmony_ci		return -EOPNOTSUPP;
148162306a36Sopenharmony_ci	}
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	return 0;
148462306a36Sopenharmony_ci}
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_cistatic int
148762306a36Sopenharmony_cihns3_check_coalesce_para(struct net_device *netdev,
148862306a36Sopenharmony_ci			 struct ethtool_coalesce *cmd,
148962306a36Sopenharmony_ci			 struct kernel_ethtool_coalesce *kernel_coal)
149062306a36Sopenharmony_ci{
149162306a36Sopenharmony_ci	int ret;
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	ret = hns3_check_cqe_coalesce_param(netdev, kernel_coal);
149462306a36Sopenharmony_ci	if (ret)
149562306a36Sopenharmony_ci		return ret;
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	ret = hns3_check_gl_coalesce_para(netdev, cmd);
149862306a36Sopenharmony_ci	if (ret) {
149962306a36Sopenharmony_ci		netdev_err(netdev,
150062306a36Sopenharmony_ci			   "Check gl coalesce param fail. ret = %d\n", ret);
150162306a36Sopenharmony_ci		return ret;
150262306a36Sopenharmony_ci	}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	ret = hns3_check_rl_coalesce_para(netdev, cmd);
150562306a36Sopenharmony_ci	if (ret) {
150662306a36Sopenharmony_ci		netdev_err(netdev,
150762306a36Sopenharmony_ci			   "Check rl coalesce param fail. ret = %d\n", ret);
150862306a36Sopenharmony_ci		return ret;
150962306a36Sopenharmony_ci	}
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	return hns3_check_ql_coalesce_param(netdev, cmd);
151262306a36Sopenharmony_ci}
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_cistatic void hns3_set_coalesce_per_queue(struct net_device *netdev,
151562306a36Sopenharmony_ci					struct ethtool_coalesce *cmd,
151662306a36Sopenharmony_ci					u32 queue)
151762306a36Sopenharmony_ci{
151862306a36Sopenharmony_ci	struct hns3_enet_tqp_vector *tx_vector, *rx_vector;
151962306a36Sopenharmony_ci	struct hns3_nic_priv *priv = netdev_priv(netdev);
152062306a36Sopenharmony_ci	struct hnae3_handle *h = priv->ae_handle;
152162306a36Sopenharmony_ci	int queue_num = h->kinfo.num_tqps;
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	tx_vector = priv->ring[queue].tqp_vector;
152462306a36Sopenharmony_ci	rx_vector = priv->ring[queue_num + queue].tqp_vector;
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	tx_vector->tx_group.coal.adapt_enable =
152762306a36Sopenharmony_ci				cmd->use_adaptive_tx_coalesce;
152862306a36Sopenharmony_ci	rx_vector->rx_group.coal.adapt_enable =
152962306a36Sopenharmony_ci				cmd->use_adaptive_rx_coalesce;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	tx_vector->tx_group.coal.int_gl = cmd->tx_coalesce_usecs;
153262306a36Sopenharmony_ci	rx_vector->rx_group.coal.int_gl = cmd->rx_coalesce_usecs;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	tx_vector->tx_group.coal.int_ql = cmd->tx_max_coalesced_frames;
153562306a36Sopenharmony_ci	rx_vector->rx_group.coal.int_ql = cmd->rx_max_coalesced_frames;
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	hns3_set_vector_coalesce_tx_gl(tx_vector,
153862306a36Sopenharmony_ci				       tx_vector->tx_group.coal.int_gl);
153962306a36Sopenharmony_ci	hns3_set_vector_coalesce_rx_gl(rx_vector,
154062306a36Sopenharmony_ci				       rx_vector->rx_group.coal.int_gl);
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	hns3_set_vector_coalesce_rl(tx_vector, h->kinfo.int_rl_setting);
154362306a36Sopenharmony_ci	hns3_set_vector_coalesce_rl(rx_vector, h->kinfo.int_rl_setting);
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	if (tx_vector->tx_group.coal.ql_enable)
154662306a36Sopenharmony_ci		hns3_set_vector_coalesce_tx_ql(tx_vector,
154762306a36Sopenharmony_ci					       tx_vector->tx_group.coal.int_ql);
154862306a36Sopenharmony_ci	if (rx_vector->rx_group.coal.ql_enable)
154962306a36Sopenharmony_ci		hns3_set_vector_coalesce_rx_ql(rx_vector,
155062306a36Sopenharmony_ci					       rx_vector->rx_group.coal.int_ql);
155162306a36Sopenharmony_ci}
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_cistatic int hns3_set_coalesce(struct net_device *netdev,
155462306a36Sopenharmony_ci			     struct ethtool_coalesce *cmd,
155562306a36Sopenharmony_ci			     struct kernel_ethtool_coalesce *kernel_coal,
155662306a36Sopenharmony_ci			     struct netlink_ext_ack *extack)
155762306a36Sopenharmony_ci{
155862306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
155962306a36Sopenharmony_ci	struct hns3_nic_priv *priv = netdev_priv(netdev);
156062306a36Sopenharmony_ci	struct hns3_enet_coalesce *tx_coal = &priv->tx_coal;
156162306a36Sopenharmony_ci	struct hns3_enet_coalesce *rx_coal = &priv->rx_coal;
156262306a36Sopenharmony_ci	u16 queue_num = h->kinfo.num_tqps;
156362306a36Sopenharmony_ci	enum dim_cq_period_mode tx_mode;
156462306a36Sopenharmony_ci	enum dim_cq_period_mode rx_mode;
156562306a36Sopenharmony_ci	int ret;
156662306a36Sopenharmony_ci	int i;
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	if (hns3_nic_resetting(netdev))
156962306a36Sopenharmony_ci		return -EBUSY;
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	ret = hns3_check_coalesce_para(netdev, cmd, kernel_coal);
157262306a36Sopenharmony_ci	if (ret)
157362306a36Sopenharmony_ci		return ret;
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	h->kinfo.int_rl_setting =
157662306a36Sopenharmony_ci		hns3_rl_round_down(cmd->rx_coalesce_usecs_high);
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	tx_coal->adapt_enable = cmd->use_adaptive_tx_coalesce;
157962306a36Sopenharmony_ci	rx_coal->adapt_enable = cmd->use_adaptive_rx_coalesce;
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	tx_coal->int_gl = cmd->tx_coalesce_usecs;
158262306a36Sopenharmony_ci	rx_coal->int_gl = cmd->rx_coalesce_usecs;
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	tx_coal->int_ql = cmd->tx_max_coalesced_frames;
158562306a36Sopenharmony_ci	rx_coal->int_ql = cmd->rx_max_coalesced_frames;
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	for (i = 0; i < queue_num; i++)
158862306a36Sopenharmony_ci		hns3_set_coalesce_per_queue(netdev, cmd, i);
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	tx_mode = kernel_coal->use_cqe_mode_tx ?
159162306a36Sopenharmony_ci		  DIM_CQ_PERIOD_MODE_START_FROM_CQE :
159262306a36Sopenharmony_ci		  DIM_CQ_PERIOD_MODE_START_FROM_EQE;
159362306a36Sopenharmony_ci	rx_mode = kernel_coal->use_cqe_mode_rx ?
159462306a36Sopenharmony_ci		  DIM_CQ_PERIOD_MODE_START_FROM_CQE :
159562306a36Sopenharmony_ci		  DIM_CQ_PERIOD_MODE_START_FROM_EQE;
159662306a36Sopenharmony_ci	hns3_cq_period_mode_init(priv, tx_mode, rx_mode);
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	return 0;
159962306a36Sopenharmony_ci}
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_cistatic int hns3_get_regs_len(struct net_device *netdev)
160262306a36Sopenharmony_ci{
160362306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	if (!h->ae_algo->ops->get_regs_len)
160662306a36Sopenharmony_ci		return -EOPNOTSUPP;
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	return h->ae_algo->ops->get_regs_len(h);
160962306a36Sopenharmony_ci}
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_cistatic void hns3_get_regs(struct net_device *netdev,
161262306a36Sopenharmony_ci			  struct ethtool_regs *cmd, void *data)
161362306a36Sopenharmony_ci{
161462306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	if (!h->ae_algo->ops->get_regs)
161762306a36Sopenharmony_ci		return;
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	h->ae_algo->ops->get_regs(h, &cmd->version, data);
162062306a36Sopenharmony_ci}
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_cistatic int hns3_set_phys_id(struct net_device *netdev,
162362306a36Sopenharmony_ci			    enum ethtool_phys_id_state state)
162462306a36Sopenharmony_ci{
162562306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	if (!h->ae_algo->ops->set_led_id)
162862306a36Sopenharmony_ci		return -EOPNOTSUPP;
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	return h->ae_algo->ops->set_led_id(h, state);
163162306a36Sopenharmony_ci}
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_cistatic u32 hns3_get_msglevel(struct net_device *netdev)
163462306a36Sopenharmony_ci{
163562306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	return h->msg_enable;
163862306a36Sopenharmony_ci}
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_cistatic void hns3_set_msglevel(struct net_device *netdev, u32 msg_level)
164162306a36Sopenharmony_ci{
164262306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	h->msg_enable = msg_level;
164562306a36Sopenharmony_ci}
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_cistatic void hns3_get_fec_stats(struct net_device *netdev,
164862306a36Sopenharmony_ci			       struct ethtool_fec_stats *fec_stats)
164962306a36Sopenharmony_ci{
165062306a36Sopenharmony_ci	struct hnae3_handle *handle = hns3_get_handle(netdev);
165162306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev);
165262306a36Sopenharmony_ci	const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	if (!hnae3_ae_dev_fec_stats_supported(ae_dev) || !ops->get_fec_stats)
165562306a36Sopenharmony_ci		return;
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	ops->get_fec_stats(handle, fec_stats);
165862306a36Sopenharmony_ci}
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci/* Translate local fec value into ethtool value. */
166162306a36Sopenharmony_cistatic unsigned int loc_to_eth_fec(u8 loc_fec)
166262306a36Sopenharmony_ci{
166362306a36Sopenharmony_ci	u32 eth_fec = 0;
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	if (loc_fec & BIT(HNAE3_FEC_AUTO))
166662306a36Sopenharmony_ci		eth_fec |= ETHTOOL_FEC_AUTO;
166762306a36Sopenharmony_ci	if (loc_fec & BIT(HNAE3_FEC_RS))
166862306a36Sopenharmony_ci		eth_fec |= ETHTOOL_FEC_RS;
166962306a36Sopenharmony_ci	if (loc_fec & BIT(HNAE3_FEC_LLRS))
167062306a36Sopenharmony_ci		eth_fec |= ETHTOOL_FEC_LLRS;
167162306a36Sopenharmony_ci	if (loc_fec & BIT(HNAE3_FEC_BASER))
167262306a36Sopenharmony_ci		eth_fec |= ETHTOOL_FEC_BASER;
167362306a36Sopenharmony_ci	if (loc_fec & BIT(HNAE3_FEC_NONE))
167462306a36Sopenharmony_ci		eth_fec |= ETHTOOL_FEC_OFF;
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	return eth_fec;
167762306a36Sopenharmony_ci}
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci/* Translate ethtool fec value into local value. */
168062306a36Sopenharmony_cistatic unsigned int eth_to_loc_fec(unsigned int eth_fec)
168162306a36Sopenharmony_ci{
168262306a36Sopenharmony_ci	u32 loc_fec = 0;
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	if (eth_fec & ETHTOOL_FEC_OFF)
168562306a36Sopenharmony_ci		loc_fec |= BIT(HNAE3_FEC_NONE);
168662306a36Sopenharmony_ci	if (eth_fec & ETHTOOL_FEC_AUTO)
168762306a36Sopenharmony_ci		loc_fec |= BIT(HNAE3_FEC_AUTO);
168862306a36Sopenharmony_ci	if (eth_fec & ETHTOOL_FEC_RS)
168962306a36Sopenharmony_ci		loc_fec |= BIT(HNAE3_FEC_RS);
169062306a36Sopenharmony_ci	if (eth_fec & ETHTOOL_FEC_LLRS)
169162306a36Sopenharmony_ci		loc_fec |= BIT(HNAE3_FEC_LLRS);
169262306a36Sopenharmony_ci	if (eth_fec & ETHTOOL_FEC_BASER)
169362306a36Sopenharmony_ci		loc_fec |= BIT(HNAE3_FEC_BASER);
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	return loc_fec;
169662306a36Sopenharmony_ci}
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_cistatic int hns3_get_fecparam(struct net_device *netdev,
169962306a36Sopenharmony_ci			     struct ethtool_fecparam *fec)
170062306a36Sopenharmony_ci{
170162306a36Sopenharmony_ci	struct hnae3_handle *handle = hns3_get_handle(netdev);
170262306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev);
170362306a36Sopenharmony_ci	const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
170462306a36Sopenharmony_ci	u8 fec_ability;
170562306a36Sopenharmony_ci	u8 fec_mode;
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci	if (!test_bit(HNAE3_DEV_SUPPORT_FEC_B, ae_dev->caps))
170862306a36Sopenharmony_ci		return -EOPNOTSUPP;
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci	if (!ops->get_fec)
171162306a36Sopenharmony_ci		return -EOPNOTSUPP;
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	ops->get_fec(handle, &fec_ability, &fec_mode);
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	fec->fec = loc_to_eth_fec(fec_ability);
171662306a36Sopenharmony_ci	fec->active_fec = loc_to_eth_fec(fec_mode);
171762306a36Sopenharmony_ci	if (!fec->active_fec)
171862306a36Sopenharmony_ci		fec->active_fec = ETHTOOL_FEC_OFF;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	return 0;
172162306a36Sopenharmony_ci}
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_cistatic int hns3_set_fecparam(struct net_device *netdev,
172462306a36Sopenharmony_ci			     struct ethtool_fecparam *fec)
172562306a36Sopenharmony_ci{
172662306a36Sopenharmony_ci	struct hnae3_handle *handle = hns3_get_handle(netdev);
172762306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev);
172862306a36Sopenharmony_ci	const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
172962306a36Sopenharmony_ci	u32 fec_mode;
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	if (!test_bit(HNAE3_DEV_SUPPORT_FEC_B, ae_dev->caps))
173262306a36Sopenharmony_ci		return -EOPNOTSUPP;
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci	if (!ops->set_fec)
173562306a36Sopenharmony_ci		return -EOPNOTSUPP;
173662306a36Sopenharmony_ci	fec_mode = eth_to_loc_fec(fec->fec);
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci	netif_dbg(handle, drv, netdev, "set fecparam: mode=%u\n", fec_mode);
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci	return ops->set_fec(handle, fec_mode);
174162306a36Sopenharmony_ci}
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_cistatic int hns3_get_module_info(struct net_device *netdev,
174462306a36Sopenharmony_ci				struct ethtool_modinfo *modinfo)
174562306a36Sopenharmony_ci{
174662306a36Sopenharmony_ci#define HNS3_SFF_8636_V1_3 0x03
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	struct hnae3_handle *handle = hns3_get_handle(netdev);
174962306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev);
175062306a36Sopenharmony_ci	const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
175162306a36Sopenharmony_ci	struct hns3_sfp_type sfp_type;
175262306a36Sopenharmony_ci	int ret;
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	if (ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2 ||
175562306a36Sopenharmony_ci	    !ops->get_module_eeprom)
175662306a36Sopenharmony_ci		return -EOPNOTSUPP;
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	memset(&sfp_type, 0, sizeof(sfp_type));
175962306a36Sopenharmony_ci	ret = ops->get_module_eeprom(handle, 0, sizeof(sfp_type) / sizeof(u8),
176062306a36Sopenharmony_ci				     (u8 *)&sfp_type);
176162306a36Sopenharmony_ci	if (ret)
176262306a36Sopenharmony_ci		return ret;
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	switch (sfp_type.type) {
176562306a36Sopenharmony_ci	case SFF8024_ID_SFP:
176662306a36Sopenharmony_ci		modinfo->type = ETH_MODULE_SFF_8472;
176762306a36Sopenharmony_ci		modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
176862306a36Sopenharmony_ci		break;
176962306a36Sopenharmony_ci	case SFF8024_ID_QSFP_8438:
177062306a36Sopenharmony_ci		modinfo->type = ETH_MODULE_SFF_8436;
177162306a36Sopenharmony_ci		modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN;
177262306a36Sopenharmony_ci		break;
177362306a36Sopenharmony_ci	case SFF8024_ID_QSFP_8436_8636:
177462306a36Sopenharmony_ci		if (sfp_type.ext_type < HNS3_SFF_8636_V1_3) {
177562306a36Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8436;
177662306a36Sopenharmony_ci			modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN;
177762306a36Sopenharmony_ci		} else {
177862306a36Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8636;
177962306a36Sopenharmony_ci			modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN;
178062306a36Sopenharmony_ci		}
178162306a36Sopenharmony_ci		break;
178262306a36Sopenharmony_ci	case SFF8024_ID_QSFP28_8636:
178362306a36Sopenharmony_ci		modinfo->type = ETH_MODULE_SFF_8636;
178462306a36Sopenharmony_ci		modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN;
178562306a36Sopenharmony_ci		break;
178662306a36Sopenharmony_ci	default:
178762306a36Sopenharmony_ci		netdev_err(netdev, "Optical module unknown: %#x\n",
178862306a36Sopenharmony_ci			   sfp_type.type);
178962306a36Sopenharmony_ci		return -EINVAL;
179062306a36Sopenharmony_ci	}
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	return 0;
179362306a36Sopenharmony_ci}
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_cistatic int hns3_get_module_eeprom(struct net_device *netdev,
179662306a36Sopenharmony_ci				  struct ethtool_eeprom *ee, u8 *data)
179762306a36Sopenharmony_ci{
179862306a36Sopenharmony_ci	struct hnae3_handle *handle = hns3_get_handle(netdev);
179962306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev);
180062306a36Sopenharmony_ci	const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci	if (ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2 ||
180362306a36Sopenharmony_ci	    !ops->get_module_eeprom)
180462306a36Sopenharmony_ci		return -EOPNOTSUPP;
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	if (!ee->len)
180762306a36Sopenharmony_ci		return -EINVAL;
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	memset(data, 0, ee->len);
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	return ops->get_module_eeprom(handle, ee->offset, ee->len, data);
181262306a36Sopenharmony_ci}
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_cistatic u32 hns3_get_priv_flags(struct net_device *netdev)
181562306a36Sopenharmony_ci{
181662306a36Sopenharmony_ci	struct hnae3_handle *handle = hns3_get_handle(netdev);
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	return handle->priv_flags;
181962306a36Sopenharmony_ci}
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_cistatic int hns3_check_priv_flags(struct hnae3_handle *h, u32 changed)
182262306a36Sopenharmony_ci{
182362306a36Sopenharmony_ci	u32 i;
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	for (i = 0; i < HNAE3_PFLAG_MAX; i++)
182662306a36Sopenharmony_ci		if ((changed & BIT(i)) && !test_bit(i, &h->supported_pflags)) {
182762306a36Sopenharmony_ci			netdev_err(h->netdev, "%s is unsupported\n",
182862306a36Sopenharmony_ci				   hns3_priv_flags[i].name);
182962306a36Sopenharmony_ci			return -EOPNOTSUPP;
183062306a36Sopenharmony_ci		}
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	return 0;
183362306a36Sopenharmony_ci}
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_cistatic int hns3_set_priv_flags(struct net_device *netdev, u32 pflags)
183662306a36Sopenharmony_ci{
183762306a36Sopenharmony_ci	struct hnae3_handle *handle = hns3_get_handle(netdev);
183862306a36Sopenharmony_ci	u32 changed = pflags ^ handle->priv_flags;
183962306a36Sopenharmony_ci	int ret;
184062306a36Sopenharmony_ci	u32 i;
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	ret = hns3_check_priv_flags(handle, changed);
184362306a36Sopenharmony_ci	if (ret)
184462306a36Sopenharmony_ci		return ret;
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	for (i = 0; i < HNAE3_PFLAG_MAX; i++) {
184762306a36Sopenharmony_ci		if (changed & BIT(i)) {
184862306a36Sopenharmony_ci			bool enable = !(handle->priv_flags & BIT(i));
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci			if (enable)
185162306a36Sopenharmony_ci				handle->priv_flags |= BIT(i);
185262306a36Sopenharmony_ci			else
185362306a36Sopenharmony_ci				handle->priv_flags &= ~BIT(i);
185462306a36Sopenharmony_ci			hns3_priv_flags[i].handler(netdev, enable);
185562306a36Sopenharmony_ci		}
185662306a36Sopenharmony_ci	}
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	return 0;
185962306a36Sopenharmony_ci}
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_cistatic int hns3_get_tunable(struct net_device *netdev,
186262306a36Sopenharmony_ci			    const struct ethtool_tunable *tuna,
186362306a36Sopenharmony_ci			    void *data)
186462306a36Sopenharmony_ci{
186562306a36Sopenharmony_ci	struct hns3_nic_priv *priv = netdev_priv(netdev);
186662306a36Sopenharmony_ci	struct hnae3_handle *h = priv->ae_handle;
186762306a36Sopenharmony_ci	int ret = 0;
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	switch (tuna->id) {
187062306a36Sopenharmony_ci	case ETHTOOL_TX_COPYBREAK:
187162306a36Sopenharmony_ci		/* all the tx rings have the same tx_copybreak */
187262306a36Sopenharmony_ci		*(u32 *)data = priv->tx_copybreak;
187362306a36Sopenharmony_ci		break;
187462306a36Sopenharmony_ci	case ETHTOOL_RX_COPYBREAK:
187562306a36Sopenharmony_ci		*(u32 *)data = priv->rx_copybreak;
187662306a36Sopenharmony_ci		break;
187762306a36Sopenharmony_ci	case ETHTOOL_TX_COPYBREAK_BUF_SIZE:
187862306a36Sopenharmony_ci		*(u32 *)data = h->kinfo.tx_spare_buf_size;
187962306a36Sopenharmony_ci		break;
188062306a36Sopenharmony_ci	default:
188162306a36Sopenharmony_ci		ret = -EOPNOTSUPP;
188262306a36Sopenharmony_ci		break;
188362306a36Sopenharmony_ci	}
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	return ret;
188662306a36Sopenharmony_ci}
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_cistatic int hns3_set_tx_spare_buf_size(struct net_device *netdev,
188962306a36Sopenharmony_ci				      u32 data)
189062306a36Sopenharmony_ci{
189162306a36Sopenharmony_ci	struct hns3_nic_priv *priv = netdev_priv(netdev);
189262306a36Sopenharmony_ci	struct hnae3_handle *h = priv->ae_handle;
189362306a36Sopenharmony_ci	int ret;
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	h->kinfo.tx_spare_buf_size = data;
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci	ret = hns3_reset_notify(h, HNAE3_DOWN_CLIENT);
189862306a36Sopenharmony_ci	if (ret)
189962306a36Sopenharmony_ci		return ret;
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	ret = hns3_reset_notify(h, HNAE3_UNINIT_CLIENT);
190262306a36Sopenharmony_ci	if (ret)
190362306a36Sopenharmony_ci		return ret;
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	ret = hns3_reset_notify(h, HNAE3_INIT_CLIENT);
190662306a36Sopenharmony_ci	if (ret)
190762306a36Sopenharmony_ci		return ret;
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	ret = hns3_reset_notify(h, HNAE3_UP_CLIENT);
191062306a36Sopenharmony_ci	if (ret)
191162306a36Sopenharmony_ci		hns3_reset_notify(h, HNAE3_UNINIT_CLIENT);
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	return ret;
191462306a36Sopenharmony_ci}
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_cistatic int hns3_set_tunable(struct net_device *netdev,
191762306a36Sopenharmony_ci			    const struct ethtool_tunable *tuna,
191862306a36Sopenharmony_ci			    const void *data)
191962306a36Sopenharmony_ci{
192062306a36Sopenharmony_ci	struct hns3_nic_priv *priv = netdev_priv(netdev);
192162306a36Sopenharmony_ci	u32 old_tx_spare_buf_size, new_tx_spare_buf_size;
192262306a36Sopenharmony_ci	struct hnae3_handle *h = priv->ae_handle;
192362306a36Sopenharmony_ci	int i, ret = 0;
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci	if (hns3_nic_resetting(netdev) || !priv->ring) {
192662306a36Sopenharmony_ci		netdev_err(netdev, "failed to set tunable value, dev resetting!");
192762306a36Sopenharmony_ci		return -EBUSY;
192862306a36Sopenharmony_ci	}
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	switch (tuna->id) {
193162306a36Sopenharmony_ci	case ETHTOOL_TX_COPYBREAK:
193262306a36Sopenharmony_ci		priv->tx_copybreak = *(u32 *)data;
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci		for (i = 0; i < h->kinfo.num_tqps; i++)
193562306a36Sopenharmony_ci			priv->ring[i].tx_copybreak = priv->tx_copybreak;
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci		break;
193862306a36Sopenharmony_ci	case ETHTOOL_RX_COPYBREAK:
193962306a36Sopenharmony_ci		priv->rx_copybreak = *(u32 *)data;
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci		for (i = h->kinfo.num_tqps; i < h->kinfo.num_tqps * 2; i++)
194262306a36Sopenharmony_ci			priv->ring[i].rx_copybreak = priv->rx_copybreak;
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci		break;
194562306a36Sopenharmony_ci	case ETHTOOL_TX_COPYBREAK_BUF_SIZE:
194662306a36Sopenharmony_ci		old_tx_spare_buf_size = h->kinfo.tx_spare_buf_size;
194762306a36Sopenharmony_ci		new_tx_spare_buf_size = *(u32 *)data;
194862306a36Sopenharmony_ci		netdev_info(netdev, "request to set tx spare buf size from %u to %u\n",
194962306a36Sopenharmony_ci			    old_tx_spare_buf_size, new_tx_spare_buf_size);
195062306a36Sopenharmony_ci		ret = hns3_set_tx_spare_buf_size(netdev, new_tx_spare_buf_size);
195162306a36Sopenharmony_ci		if (ret ||
195262306a36Sopenharmony_ci		    (!priv->ring->tx_spare && new_tx_spare_buf_size != 0)) {
195362306a36Sopenharmony_ci			int ret1;
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci			netdev_warn(netdev, "change tx spare buf size fail, revert to old value\n");
195662306a36Sopenharmony_ci			ret1 = hns3_set_tx_spare_buf_size(netdev,
195762306a36Sopenharmony_ci							  old_tx_spare_buf_size);
195862306a36Sopenharmony_ci			if (ret1) {
195962306a36Sopenharmony_ci				netdev_err(netdev, "revert to old tx spare buf size fail\n");
196062306a36Sopenharmony_ci				return ret1;
196162306a36Sopenharmony_ci			}
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci			return ret;
196462306a36Sopenharmony_ci		}
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci		if (!priv->ring->tx_spare)
196762306a36Sopenharmony_ci			netdev_info(netdev, "the active tx spare buf size is 0, disable tx spare buffer\n");
196862306a36Sopenharmony_ci		else
196962306a36Sopenharmony_ci			netdev_info(netdev, "the active tx spare buf size is %u, due to page order\n",
197062306a36Sopenharmony_ci				    priv->ring->tx_spare->len);
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci		break;
197362306a36Sopenharmony_ci	default:
197462306a36Sopenharmony_ci		ret = -EOPNOTSUPP;
197562306a36Sopenharmony_ci		break;
197662306a36Sopenharmony_ci	}
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	return ret;
197962306a36Sopenharmony_ci}
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci#define HNS3_ETHTOOL_COALESCE	(ETHTOOL_COALESCE_USECS |		\
198262306a36Sopenharmony_ci				 ETHTOOL_COALESCE_USE_ADAPTIVE |	\
198362306a36Sopenharmony_ci				 ETHTOOL_COALESCE_RX_USECS_HIGH |	\
198462306a36Sopenharmony_ci				 ETHTOOL_COALESCE_TX_USECS_HIGH |	\
198562306a36Sopenharmony_ci				 ETHTOOL_COALESCE_MAX_FRAMES |		\
198662306a36Sopenharmony_ci				 ETHTOOL_COALESCE_USE_CQE)
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci#define HNS3_ETHTOOL_RING	(ETHTOOL_RING_USE_RX_BUF_LEN |		\
198962306a36Sopenharmony_ci				 ETHTOOL_RING_USE_TX_PUSH)
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_cistatic int hns3_get_ts_info(struct net_device *netdev,
199262306a36Sopenharmony_ci			    struct ethtool_ts_info *info)
199362306a36Sopenharmony_ci{
199462306a36Sopenharmony_ci	struct hnae3_handle *handle = hns3_get_handle(netdev);
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	if (handle->ae_algo->ops->get_ts_info)
199762306a36Sopenharmony_ci		return handle->ae_algo->ops->get_ts_info(handle, info);
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	return ethtool_op_get_ts_info(netdev, info);
200062306a36Sopenharmony_ci}
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_cistatic const struct hns3_ethtool_link_ext_state_mapping
200362306a36Sopenharmony_cihns3_link_ext_state_map[] = {
200462306a36Sopenharmony_ci	{1, ETHTOOL_LINK_EXT_STATE_AUTONEG,
200562306a36Sopenharmony_ci		ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_HCD},
200662306a36Sopenharmony_ci	{2, ETHTOOL_LINK_EXT_STATE_AUTONEG,
200762306a36Sopenharmony_ci		ETHTOOL_LINK_EXT_SUBSTATE_AN_ACK_NOT_RECEIVED},
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	{256, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
201062306a36Sopenharmony_ci		ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_INHIBIT_TIMEOUT},
201162306a36Sopenharmony_ci	{257, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
201262306a36Sopenharmony_ci		ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_PARTNER_DID_NOT_SET_RECEIVER_READY},
201362306a36Sopenharmony_ci	{512, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
201462306a36Sopenharmony_ci		ETHTOOL_LINK_EXT_SUBSTATE_LT_REMOTE_FAULT},
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	{513, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
201762306a36Sopenharmony_ci		ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_BLOCK_LOCK},
201862306a36Sopenharmony_ci	{514, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
201962306a36Sopenharmony_ci		ETHTOOL_LINK_EXT_SUBSTATE_LLM_FC_FEC_IS_NOT_LOCKED},
202062306a36Sopenharmony_ci	{515, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
202162306a36Sopenharmony_ci		ETHTOOL_LINK_EXT_SUBSTATE_LLM_RS_FEC_IS_NOT_LOCKED},
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	{768, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY,
202462306a36Sopenharmony_ci		ETHTOOL_LINK_EXT_SUBSTATE_BSI_LARGE_NUMBER_OF_PHYSICAL_ERRORS},
202562306a36Sopenharmony_ci	{769, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY,
202662306a36Sopenharmony_ci		ETHTOOL_LINK_EXT_SUBSTATE_BSI_SERDES_REFERENCE_CLOCK_LOST},
202762306a36Sopenharmony_ci	{770, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY,
202862306a36Sopenharmony_ci		ETHTOOL_LINK_EXT_SUBSTATE_BSI_SERDES_ALOS},
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	{1024, ETHTOOL_LINK_EXT_STATE_NO_CABLE, 0},
203162306a36Sopenharmony_ci	{1025, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
203262306a36Sopenharmony_ci		ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci	{1026, ETHTOOL_LINK_EXT_STATE_EEPROM_ISSUE, 0},
203562306a36Sopenharmony_ci};
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_cistatic int hns3_get_link_ext_state(struct net_device *netdev,
203862306a36Sopenharmony_ci				   struct ethtool_link_ext_state_info *info)
203962306a36Sopenharmony_ci{
204062306a36Sopenharmony_ci	const struct hns3_ethtool_link_ext_state_mapping *map;
204162306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
204262306a36Sopenharmony_ci	u32 status_code, i;
204362306a36Sopenharmony_ci	int ret;
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci	if (netif_carrier_ok(netdev))
204662306a36Sopenharmony_ci		return -ENODATA;
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	if (!h->ae_algo->ops->get_link_diagnosis_info)
204962306a36Sopenharmony_ci		return -EOPNOTSUPP;
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci	ret = h->ae_algo->ops->get_link_diagnosis_info(h, &status_code);
205262306a36Sopenharmony_ci	if (ret)
205362306a36Sopenharmony_ci		return ret;
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(hns3_link_ext_state_map); i++) {
205662306a36Sopenharmony_ci		map = &hns3_link_ext_state_map[i];
205762306a36Sopenharmony_ci		if (map->status_code == status_code) {
205862306a36Sopenharmony_ci			info->link_ext_state = map->link_ext_state;
205962306a36Sopenharmony_ci			info->__link_ext_substate = map->link_ext_substate;
206062306a36Sopenharmony_ci			return 0;
206162306a36Sopenharmony_ci		}
206262306a36Sopenharmony_ci	}
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	return -ENODATA;
206562306a36Sopenharmony_ci}
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_cistatic void hns3_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
206862306a36Sopenharmony_ci{
206962306a36Sopenharmony_ci	struct hnae3_handle *handle = hns3_get_handle(netdev);
207062306a36Sopenharmony_ci	const struct hnae3_ae_ops *ops = hns3_get_ops(handle);
207162306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = hns3_get_ae_dev(handle);
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci	if (!hnae3_ae_dev_wol_supported(ae_dev))
207462306a36Sopenharmony_ci		return;
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci	ops->get_wol(handle, wol);
207762306a36Sopenharmony_ci}
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_cistatic int hns3_set_wol(struct net_device *netdev,
208062306a36Sopenharmony_ci			struct ethtool_wolinfo *wol)
208162306a36Sopenharmony_ci{
208262306a36Sopenharmony_ci	struct hnae3_handle *handle = hns3_get_handle(netdev);
208362306a36Sopenharmony_ci	const struct hnae3_ae_ops *ops = hns3_get_ops(handle);
208462306a36Sopenharmony_ci	struct hnae3_ae_dev *ae_dev = hns3_get_ae_dev(handle);
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	if (!hnae3_ae_dev_wol_supported(ae_dev))
208762306a36Sopenharmony_ci		return -EOPNOTSUPP;
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci	return ops->set_wol(handle, wol);
209062306a36Sopenharmony_ci}
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_cistatic const struct ethtool_ops hns3vf_ethtool_ops = {
209362306a36Sopenharmony_ci	.supported_coalesce_params = HNS3_ETHTOOL_COALESCE,
209462306a36Sopenharmony_ci	.supported_ring_params = HNS3_ETHTOOL_RING,
209562306a36Sopenharmony_ci	.get_drvinfo = hns3_get_drvinfo,
209662306a36Sopenharmony_ci	.get_ringparam = hns3_get_ringparam,
209762306a36Sopenharmony_ci	.set_ringparam = hns3_set_ringparam,
209862306a36Sopenharmony_ci	.get_strings = hns3_get_strings,
209962306a36Sopenharmony_ci	.get_ethtool_stats = hns3_get_stats,
210062306a36Sopenharmony_ci	.get_sset_count = hns3_get_sset_count,
210162306a36Sopenharmony_ci	.get_rxnfc = hns3_get_rxnfc,
210262306a36Sopenharmony_ci	.set_rxnfc = hns3_set_rxnfc,
210362306a36Sopenharmony_ci	.get_rxfh_key_size = hns3_get_rss_key_size,
210462306a36Sopenharmony_ci	.get_rxfh_indir_size = hns3_get_rss_indir_size,
210562306a36Sopenharmony_ci	.get_rxfh = hns3_get_rss,
210662306a36Sopenharmony_ci	.set_rxfh = hns3_set_rss,
210762306a36Sopenharmony_ci	.get_link_ksettings = hns3_get_link_ksettings,
210862306a36Sopenharmony_ci	.get_channels = hns3_get_channels,
210962306a36Sopenharmony_ci	.set_channels = hns3_set_channels,
211062306a36Sopenharmony_ci	.get_coalesce = hns3_get_coalesce,
211162306a36Sopenharmony_ci	.set_coalesce = hns3_set_coalesce,
211262306a36Sopenharmony_ci	.get_regs_len = hns3_get_regs_len,
211362306a36Sopenharmony_ci	.get_regs = hns3_get_regs,
211462306a36Sopenharmony_ci	.get_link = hns3_get_link,
211562306a36Sopenharmony_ci	.get_msglevel = hns3_get_msglevel,
211662306a36Sopenharmony_ci	.set_msglevel = hns3_set_msglevel,
211762306a36Sopenharmony_ci	.get_priv_flags = hns3_get_priv_flags,
211862306a36Sopenharmony_ci	.set_priv_flags = hns3_set_priv_flags,
211962306a36Sopenharmony_ci	.get_tunable = hns3_get_tunable,
212062306a36Sopenharmony_ci	.set_tunable = hns3_set_tunable,
212162306a36Sopenharmony_ci	.reset = hns3_set_reset,
212262306a36Sopenharmony_ci};
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_cistatic const struct ethtool_ops hns3_ethtool_ops = {
212562306a36Sopenharmony_ci	.supported_coalesce_params = HNS3_ETHTOOL_COALESCE,
212662306a36Sopenharmony_ci	.supported_ring_params = HNS3_ETHTOOL_RING,
212762306a36Sopenharmony_ci	.cap_link_lanes_supported = true,
212862306a36Sopenharmony_ci	.self_test = hns3_self_test,
212962306a36Sopenharmony_ci	.get_drvinfo = hns3_get_drvinfo,
213062306a36Sopenharmony_ci	.get_link = hns3_get_link,
213162306a36Sopenharmony_ci	.get_ringparam = hns3_get_ringparam,
213262306a36Sopenharmony_ci	.set_ringparam = hns3_set_ringparam,
213362306a36Sopenharmony_ci	.get_pauseparam = hns3_get_pauseparam,
213462306a36Sopenharmony_ci	.set_pauseparam = hns3_set_pauseparam,
213562306a36Sopenharmony_ci	.get_strings = hns3_get_strings,
213662306a36Sopenharmony_ci	.get_ethtool_stats = hns3_get_stats,
213762306a36Sopenharmony_ci	.get_sset_count = hns3_get_sset_count,
213862306a36Sopenharmony_ci	.get_rxnfc = hns3_get_rxnfc,
213962306a36Sopenharmony_ci	.set_rxnfc = hns3_set_rxnfc,
214062306a36Sopenharmony_ci	.get_rxfh_key_size = hns3_get_rss_key_size,
214162306a36Sopenharmony_ci	.get_rxfh_indir_size = hns3_get_rss_indir_size,
214262306a36Sopenharmony_ci	.get_rxfh = hns3_get_rss,
214362306a36Sopenharmony_ci	.set_rxfh = hns3_set_rss,
214462306a36Sopenharmony_ci	.get_link_ksettings = hns3_get_link_ksettings,
214562306a36Sopenharmony_ci	.set_link_ksettings = hns3_set_link_ksettings,
214662306a36Sopenharmony_ci	.nway_reset = hns3_nway_reset,
214762306a36Sopenharmony_ci	.get_channels = hns3_get_channels,
214862306a36Sopenharmony_ci	.set_channels = hns3_set_channels,
214962306a36Sopenharmony_ci	.get_coalesce = hns3_get_coalesce,
215062306a36Sopenharmony_ci	.set_coalesce = hns3_set_coalesce,
215162306a36Sopenharmony_ci	.get_regs_len = hns3_get_regs_len,
215262306a36Sopenharmony_ci	.get_regs = hns3_get_regs,
215362306a36Sopenharmony_ci	.set_phys_id = hns3_set_phys_id,
215462306a36Sopenharmony_ci	.get_msglevel = hns3_get_msglevel,
215562306a36Sopenharmony_ci	.set_msglevel = hns3_set_msglevel,
215662306a36Sopenharmony_ci	.get_fecparam = hns3_get_fecparam,
215762306a36Sopenharmony_ci	.set_fecparam = hns3_set_fecparam,
215862306a36Sopenharmony_ci	.get_fec_stats = hns3_get_fec_stats,
215962306a36Sopenharmony_ci	.get_module_info = hns3_get_module_info,
216062306a36Sopenharmony_ci	.get_module_eeprom = hns3_get_module_eeprom,
216162306a36Sopenharmony_ci	.get_priv_flags = hns3_get_priv_flags,
216262306a36Sopenharmony_ci	.set_priv_flags = hns3_set_priv_flags,
216362306a36Sopenharmony_ci	.get_ts_info = hns3_get_ts_info,
216462306a36Sopenharmony_ci	.get_tunable = hns3_get_tunable,
216562306a36Sopenharmony_ci	.set_tunable = hns3_set_tunable,
216662306a36Sopenharmony_ci	.reset = hns3_set_reset,
216762306a36Sopenharmony_ci	.get_link_ext_state = hns3_get_link_ext_state,
216862306a36Sopenharmony_ci	.get_wol = hns3_get_wol,
216962306a36Sopenharmony_ci	.set_wol = hns3_set_wol,
217062306a36Sopenharmony_ci};
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_civoid hns3_ethtool_set_ops(struct net_device *netdev)
217362306a36Sopenharmony_ci{
217462306a36Sopenharmony_ci	struct hnae3_handle *h = hns3_get_handle(netdev);
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci	if (h->flags & HNAE3_SUPPORT_VF)
217762306a36Sopenharmony_ci		netdev->ethtool_ops = &hns3vf_ethtool_ops;
217862306a36Sopenharmony_ci	else
217962306a36Sopenharmony_ci		netdev->ethtool_ops = &hns3_ethtool_ops;
218062306a36Sopenharmony_ci}
2181