162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2014-2015 Hisilicon Limited.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/etherdevice.h>
762306a36Sopenharmony_ci#include <linux/interrupt.h>
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/platform_device.h>
1062306a36Sopenharmony_ci#include "hns_enet.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define HNS_PHY_PAGE_MDIX	0
1362306a36Sopenharmony_ci#define HNS_PHY_PAGE_LED	3
1462306a36Sopenharmony_ci#define HNS_PHY_PAGE_COPPER	0
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define HNS_PHY_PAGE_REG	22	/* Page Selection Reg. */
1762306a36Sopenharmony_ci#define HNS_PHY_CSC_REG		16	/* Copper Specific Control Register */
1862306a36Sopenharmony_ci#define HNS_PHY_CSS_REG		17	/* Copper Specific Status Register */
1962306a36Sopenharmony_ci#define HNS_LED_FC_REG		16	/* LED Function Control Reg. */
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define HNS_LED_FORCE_ON	9
2262306a36Sopenharmony_ci#define HNS_LED_FORCE_OFF	8
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define HNS_CHIP_VERSION 660
2562306a36Sopenharmony_ci#define HNS_NET_STATS_CNT 26
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define PHY_MDIX_CTRL_S		(5)
2862306a36Sopenharmony_ci#define PHY_MDIX_CTRL_M		(3 << PHY_MDIX_CTRL_S)
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define PHY_MDIX_STATUS_B	(6)
3162306a36Sopenharmony_ci#define PHY_SPEED_DUP_RESOLVE_B	(11)
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/**
3462306a36Sopenharmony_ci *hns_nic_get_link - get current link status
3562306a36Sopenharmony_ci *@net_dev: net_device
3662306a36Sopenharmony_ci *retuen 0 - success , negative --fail
3762306a36Sopenharmony_ci */
3862306a36Sopenharmony_cistatic u32 hns_nic_get_link(struct net_device *net_dev)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(net_dev);
4162306a36Sopenharmony_ci	u32 link_stat = priv->link;
4262306a36Sopenharmony_ci	struct hnae_handle *h;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	h = priv->ae_handle;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	if (net_dev->phydev) {
4762306a36Sopenharmony_ci		if (!genphy_read_status(net_dev->phydev))
4862306a36Sopenharmony_ci			link_stat = net_dev->phydev->link;
4962306a36Sopenharmony_ci		else
5062306a36Sopenharmony_ci			link_stat = 0;
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	if (h->dev && h->dev->ops && h->dev->ops->get_status)
5462306a36Sopenharmony_ci		link_stat = link_stat && h->dev->ops->get_status(h);
5562306a36Sopenharmony_ci	else
5662306a36Sopenharmony_ci		link_stat = 0;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	return link_stat;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic void hns_get_mdix_mode(struct net_device *net_dev,
6262306a36Sopenharmony_ci			      struct ethtool_link_ksettings *cmd)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	int mdix_ctrl, mdix, retval, is_resolved;
6562306a36Sopenharmony_ci	struct phy_device *phy_dev = net_dev->phydev;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	if (!phy_dev || !phy_dev->mdio.bus) {
6862306a36Sopenharmony_ci		cmd->base.eth_tp_mdix_ctrl = ETH_TP_MDI_INVALID;
6962306a36Sopenharmony_ci		cmd->base.eth_tp_mdix = ETH_TP_MDI_INVALID;
7062306a36Sopenharmony_ci		return;
7162306a36Sopenharmony_ci	}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	phy_write(phy_dev, HNS_PHY_PAGE_REG, HNS_PHY_PAGE_MDIX);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	retval = phy_read(phy_dev, HNS_PHY_CSC_REG);
7662306a36Sopenharmony_ci	mdix_ctrl = hnae_get_field(retval, PHY_MDIX_CTRL_M, PHY_MDIX_CTRL_S);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	retval = phy_read(phy_dev, HNS_PHY_CSS_REG);
7962306a36Sopenharmony_ci	mdix = hnae_get_bit(retval, PHY_MDIX_STATUS_B);
8062306a36Sopenharmony_ci	is_resolved = hnae_get_bit(retval, PHY_SPEED_DUP_RESOLVE_B);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	phy_write(phy_dev, HNS_PHY_PAGE_REG, HNS_PHY_PAGE_COPPER);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	switch (mdix_ctrl) {
8562306a36Sopenharmony_ci	case 0x0:
8662306a36Sopenharmony_ci		cmd->base.eth_tp_mdix_ctrl = ETH_TP_MDI;
8762306a36Sopenharmony_ci		break;
8862306a36Sopenharmony_ci	case 0x1:
8962306a36Sopenharmony_ci		cmd->base.eth_tp_mdix_ctrl = ETH_TP_MDI_X;
9062306a36Sopenharmony_ci		break;
9162306a36Sopenharmony_ci	case 0x3:
9262306a36Sopenharmony_ci		cmd->base.eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO;
9362306a36Sopenharmony_ci		break;
9462306a36Sopenharmony_ci	default:
9562306a36Sopenharmony_ci		cmd->base.eth_tp_mdix_ctrl = ETH_TP_MDI_INVALID;
9662306a36Sopenharmony_ci		break;
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	if (!is_resolved)
10062306a36Sopenharmony_ci		cmd->base.eth_tp_mdix = ETH_TP_MDI_INVALID;
10162306a36Sopenharmony_ci	else if (mdix)
10262306a36Sopenharmony_ci		cmd->base.eth_tp_mdix = ETH_TP_MDI_X;
10362306a36Sopenharmony_ci	else
10462306a36Sopenharmony_ci		cmd->base.eth_tp_mdix = ETH_TP_MDI;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci/**
10862306a36Sopenharmony_ci *hns_nic_get_link_ksettings - implement ethtool get link ksettings
10962306a36Sopenharmony_ci *@net_dev: net_device
11062306a36Sopenharmony_ci *@cmd: ethtool_link_ksettings
11162306a36Sopenharmony_ci *retuen 0 - success , negative --fail
11262306a36Sopenharmony_ci */
11362306a36Sopenharmony_cistatic int hns_nic_get_link_ksettings(struct net_device *net_dev,
11462306a36Sopenharmony_ci				      struct ethtool_link_ksettings *cmd)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(net_dev);
11762306a36Sopenharmony_ci	struct hnae_handle *h;
11862306a36Sopenharmony_ci	u32 link_stat;
11962306a36Sopenharmony_ci	int ret;
12062306a36Sopenharmony_ci	u8 duplex;
12162306a36Sopenharmony_ci	u16 speed;
12262306a36Sopenharmony_ci	u32 supported, advertising;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (!priv || !priv->ae_handle)
12562306a36Sopenharmony_ci		return -ESRCH;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	h = priv->ae_handle;
12862306a36Sopenharmony_ci	if (!h->dev || !h->dev->ops || !h->dev->ops->get_info)
12962306a36Sopenharmony_ci		return -ESRCH;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	ret = h->dev->ops->get_info(h, NULL, &speed, &duplex);
13262306a36Sopenharmony_ci	if (ret < 0) {
13362306a36Sopenharmony_ci		netdev_err(net_dev, "%s get_info error!\n", __func__);
13462306a36Sopenharmony_ci		return -EINVAL;
13562306a36Sopenharmony_ci	}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	ethtool_convert_link_mode_to_legacy_u32(&supported,
13862306a36Sopenharmony_ci						cmd->link_modes.supported);
13962306a36Sopenharmony_ci	ethtool_convert_link_mode_to_legacy_u32(&advertising,
14062306a36Sopenharmony_ci						cmd->link_modes.advertising);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/* When there is no phy, autoneg is off. */
14362306a36Sopenharmony_ci	cmd->base.autoneg = false;
14462306a36Sopenharmony_ci	cmd->base.speed = speed;
14562306a36Sopenharmony_ci	cmd->base.duplex = duplex;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (net_dev->phydev)
14862306a36Sopenharmony_ci		phy_ethtool_ksettings_get(net_dev->phydev, cmd);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	link_stat = hns_nic_get_link(net_dev);
15162306a36Sopenharmony_ci	if (!link_stat) {
15262306a36Sopenharmony_ci		cmd->base.speed = (u32)SPEED_UNKNOWN;
15362306a36Sopenharmony_ci		cmd->base.duplex = DUPLEX_UNKNOWN;
15462306a36Sopenharmony_ci	}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	if (cmd->base.autoneg)
15762306a36Sopenharmony_ci		advertising |= ADVERTISED_Autoneg;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	supported |= h->if_support;
16062306a36Sopenharmony_ci	if (h->phy_if == PHY_INTERFACE_MODE_SGMII) {
16162306a36Sopenharmony_ci		supported |= SUPPORTED_TP;
16262306a36Sopenharmony_ci		advertising |= ADVERTISED_1000baseT_Full;
16362306a36Sopenharmony_ci	} else if (h->phy_if == PHY_INTERFACE_MODE_XGMII) {
16462306a36Sopenharmony_ci		supported |= SUPPORTED_FIBRE;
16562306a36Sopenharmony_ci		advertising |= ADVERTISED_10000baseKR_Full;
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	switch (h->media_type) {
16962306a36Sopenharmony_ci	case HNAE_MEDIA_TYPE_FIBER:
17062306a36Sopenharmony_ci		cmd->base.port = PORT_FIBRE;
17162306a36Sopenharmony_ci		break;
17262306a36Sopenharmony_ci	case HNAE_MEDIA_TYPE_COPPER:
17362306a36Sopenharmony_ci		cmd->base.port = PORT_TP;
17462306a36Sopenharmony_ci		break;
17562306a36Sopenharmony_ci	case HNAE_MEDIA_TYPE_UNKNOWN:
17662306a36Sopenharmony_ci	default:
17762306a36Sopenharmony_ci		break;
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	if (!(AE_IS_VER1(priv->enet_ver) && h->port_type == HNAE_PORT_DEBUG))
18162306a36Sopenharmony_ci		supported |= SUPPORTED_Pause;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
18462306a36Sopenharmony_ci						supported);
18562306a36Sopenharmony_ci	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
18662306a36Sopenharmony_ci						advertising);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	cmd->base.mdio_support = ETH_MDIO_SUPPORTS_C45 | ETH_MDIO_SUPPORTS_C22;
18962306a36Sopenharmony_ci	hns_get_mdix_mode(net_dev, cmd);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	return 0;
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci/**
19562306a36Sopenharmony_ci *hns_nic_set_link_ksettings - implement ethtool set link ksettings
19662306a36Sopenharmony_ci *@net_dev: net_device
19762306a36Sopenharmony_ci *@cmd: ethtool_link_ksettings
19862306a36Sopenharmony_ci *retuen 0 - success , negative --fail
19962306a36Sopenharmony_ci */
20062306a36Sopenharmony_cistatic int hns_nic_set_link_ksettings(struct net_device *net_dev,
20162306a36Sopenharmony_ci				      const struct ethtool_link_ksettings *cmd)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(net_dev);
20462306a36Sopenharmony_ci	struct hnae_handle *h;
20562306a36Sopenharmony_ci	u32 speed;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	if (!netif_running(net_dev))
20862306a36Sopenharmony_ci		return -ESRCH;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	if (!priv || !priv->ae_handle || !priv->ae_handle->dev ||
21162306a36Sopenharmony_ci	    !priv->ae_handle->dev->ops)
21262306a36Sopenharmony_ci		return -ENODEV;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	h = priv->ae_handle;
21562306a36Sopenharmony_ci	speed = cmd->base.speed;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	if (h->phy_if == PHY_INTERFACE_MODE_XGMII) {
21862306a36Sopenharmony_ci		if (cmd->base.autoneg == AUTONEG_ENABLE ||
21962306a36Sopenharmony_ci		    speed != SPEED_10000 ||
22062306a36Sopenharmony_ci		    cmd->base.duplex != DUPLEX_FULL)
22162306a36Sopenharmony_ci			return -EINVAL;
22262306a36Sopenharmony_ci	} else if (h->phy_if == PHY_INTERFACE_MODE_SGMII) {
22362306a36Sopenharmony_ci		if (!net_dev->phydev && cmd->base.autoneg == AUTONEG_ENABLE)
22462306a36Sopenharmony_ci			return -EINVAL;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci		if (speed == SPEED_1000 && cmd->base.duplex == DUPLEX_HALF)
22762306a36Sopenharmony_ci			return -EINVAL;
22862306a36Sopenharmony_ci		if (net_dev->phydev)
22962306a36Sopenharmony_ci			return phy_ethtool_ksettings_set(net_dev->phydev, cmd);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci		if ((speed != SPEED_10 && speed != SPEED_100 &&
23262306a36Sopenharmony_ci		     speed != SPEED_1000) || (cmd->base.duplex != DUPLEX_HALF &&
23362306a36Sopenharmony_ci		     cmd->base.duplex != DUPLEX_FULL))
23462306a36Sopenharmony_ci			return -EINVAL;
23562306a36Sopenharmony_ci	} else {
23662306a36Sopenharmony_ci		netdev_err(net_dev, "Not supported!");
23762306a36Sopenharmony_ci		return -ENOTSUPP;
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	if (h->dev->ops->adjust_link) {
24162306a36Sopenharmony_ci		netif_carrier_off(net_dev);
24262306a36Sopenharmony_ci		h->dev->ops->adjust_link(h, (int)speed, cmd->base.duplex);
24362306a36Sopenharmony_ci		netif_carrier_on(net_dev);
24462306a36Sopenharmony_ci		return 0;
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	netdev_err(net_dev, "Not supported!");
24862306a36Sopenharmony_ci	return -ENOTSUPP;
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic const char hns_nic_test_strs[][ETH_GSTRING_LEN] = {
25262306a36Sopenharmony_ci	"Mac    Loopback test",
25362306a36Sopenharmony_ci	"Serdes Loopback test",
25462306a36Sopenharmony_ci	"Phy    Loopback test"
25562306a36Sopenharmony_ci};
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic int hns_nic_config_phy_loopback(struct phy_device *phy_dev, u8 en)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	int err;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	if (en) {
26262306a36Sopenharmony_ci		/* Doing phy loopback in offline state, phy resuming is
26362306a36Sopenharmony_ci		 * needed to power up the device.
26462306a36Sopenharmony_ci		 */
26562306a36Sopenharmony_ci		err = phy_resume(phy_dev);
26662306a36Sopenharmony_ci		if (err)
26762306a36Sopenharmony_ci			goto out;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci		err = phy_loopback(phy_dev, true);
27062306a36Sopenharmony_ci	} else {
27162306a36Sopenharmony_ci		err = phy_loopback(phy_dev, false);
27262306a36Sopenharmony_ci		if (err)
27362306a36Sopenharmony_ci			goto out;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci		err = phy_suspend(phy_dev);
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ciout:
27962306a36Sopenharmony_ci	return err;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int __lb_setup(struct net_device *ndev,
28362306a36Sopenharmony_ci		      enum hnae_loop loop)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	int ret = 0;
28662306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
28762306a36Sopenharmony_ci	struct phy_device *phy_dev = ndev->phydev;
28862306a36Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	switch (loop) {
29162306a36Sopenharmony_ci	case MAC_INTERNALLOOP_PHY:
29262306a36Sopenharmony_ci		ret = hns_nic_config_phy_loopback(phy_dev, 0x1);
29362306a36Sopenharmony_ci		if (!ret)
29462306a36Sopenharmony_ci			ret = h->dev->ops->set_loopback(h, loop, 0x1);
29562306a36Sopenharmony_ci		break;
29662306a36Sopenharmony_ci	case MAC_INTERNALLOOP_MAC:
29762306a36Sopenharmony_ci		if ((h->dev->ops->set_loopback) &&
29862306a36Sopenharmony_ci		    (priv->ae_handle->phy_if != PHY_INTERFACE_MODE_XGMII))
29962306a36Sopenharmony_ci			ret = h->dev->ops->set_loopback(h, loop, 0x1);
30062306a36Sopenharmony_ci		break;
30162306a36Sopenharmony_ci	case MAC_INTERNALLOOP_SERDES:
30262306a36Sopenharmony_ci		if (h->dev->ops->set_loopback)
30362306a36Sopenharmony_ci			ret = h->dev->ops->set_loopback(h, loop, 0x1);
30462306a36Sopenharmony_ci		break;
30562306a36Sopenharmony_ci	case MAC_LOOP_PHY_NONE:
30662306a36Sopenharmony_ci		ret = hns_nic_config_phy_loopback(phy_dev, 0x0);
30762306a36Sopenharmony_ci		fallthrough;
30862306a36Sopenharmony_ci	case MAC_LOOP_NONE:
30962306a36Sopenharmony_ci		if (!ret && h->dev->ops->set_loopback) {
31062306a36Sopenharmony_ci			if (priv->ae_handle->phy_if != PHY_INTERFACE_MODE_XGMII)
31162306a36Sopenharmony_ci				ret = h->dev->ops->set_loopback(h,
31262306a36Sopenharmony_ci					MAC_INTERNALLOOP_MAC, 0x0);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci			if (!ret)
31562306a36Sopenharmony_ci				ret = h->dev->ops->set_loopback(h,
31662306a36Sopenharmony_ci					MAC_INTERNALLOOP_SERDES, 0x0);
31762306a36Sopenharmony_ci		}
31862306a36Sopenharmony_ci		break;
31962306a36Sopenharmony_ci	default:
32062306a36Sopenharmony_ci		ret = -EINVAL;
32162306a36Sopenharmony_ci		break;
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (!ret) {
32562306a36Sopenharmony_ci		if (loop == MAC_LOOP_NONE)
32662306a36Sopenharmony_ci			h->dev->ops->set_promisc_mode(
32762306a36Sopenharmony_ci				h, ndev->flags & IFF_PROMISC);
32862306a36Sopenharmony_ci		else
32962306a36Sopenharmony_ci			h->dev->ops->set_promisc_mode(h, 1);
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci	return ret;
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic int __lb_up(struct net_device *ndev,
33562306a36Sopenharmony_ci		   enum hnae_loop loop_mode)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci#define NIC_LB_TEST_WAIT_PHY_LINK_TIME 300
33862306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
33962306a36Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
34062306a36Sopenharmony_ci	int speed, duplex;
34162306a36Sopenharmony_ci	int ret;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	hns_nic_net_reset(ndev);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	ret = __lb_setup(ndev, loop_mode);
34662306a36Sopenharmony_ci	if (ret)
34762306a36Sopenharmony_ci		return ret;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	msleep(200);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	ret = h->dev->ops->start ? h->dev->ops->start(h) : 0;
35262306a36Sopenharmony_ci	if (ret)
35362306a36Sopenharmony_ci		return ret;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	/* link adjust duplex*/
35662306a36Sopenharmony_ci	if (priv->ae_handle->phy_if != PHY_INTERFACE_MODE_XGMII)
35762306a36Sopenharmony_ci		speed = 1000;
35862306a36Sopenharmony_ci	else
35962306a36Sopenharmony_ci		speed = 10000;
36062306a36Sopenharmony_ci	duplex = 1;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	h->dev->ops->adjust_link(h, speed, duplex);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	/* wait adjust link done and phy ready */
36562306a36Sopenharmony_ci	msleep(NIC_LB_TEST_WAIT_PHY_LINK_TIME);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	return 0;
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_cistatic void __lb_other_process(struct hns_nic_ring_data *ring_data,
37162306a36Sopenharmony_ci			       struct sk_buff *skb)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	struct net_device *ndev;
37462306a36Sopenharmony_ci	struct hns_nic_priv *priv;
37562306a36Sopenharmony_ci	struct hnae_ring *ring;
37662306a36Sopenharmony_ci	struct netdev_queue *dev_queue;
37762306a36Sopenharmony_ci	struct sk_buff *new_skb;
37862306a36Sopenharmony_ci	unsigned int frame_size;
37962306a36Sopenharmony_ci	int check_ok;
38062306a36Sopenharmony_ci	u32 i;
38162306a36Sopenharmony_ci	char buff[33]; /* 32B data and the last character '\0' */
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	if (!ring_data) { /* Just for doing create frame*/
38462306a36Sopenharmony_ci		ndev = skb->dev;
38562306a36Sopenharmony_ci		priv = netdev_priv(ndev);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci		frame_size = skb->len;
38862306a36Sopenharmony_ci		memset(skb->data, 0xFF, frame_size);
38962306a36Sopenharmony_ci		if ((!AE_IS_VER1(priv->enet_ver)) &&
39062306a36Sopenharmony_ci		    (priv->ae_handle->port_type == HNAE_PORT_SERVICE)) {
39162306a36Sopenharmony_ci			memcpy(skb->data, ndev->dev_addr, 6);
39262306a36Sopenharmony_ci			skb->data[5] += 0x1f;
39362306a36Sopenharmony_ci		}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci		frame_size &= ~1ul;
39662306a36Sopenharmony_ci		memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);
39762306a36Sopenharmony_ci		memset(&skb->data[frame_size / 2 + 10], 0xBE,
39862306a36Sopenharmony_ci		       frame_size / 2 - 11);
39962306a36Sopenharmony_ci		memset(&skb->data[frame_size / 2 + 12], 0xAF,
40062306a36Sopenharmony_ci		       frame_size / 2 - 13);
40162306a36Sopenharmony_ci		return;
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	ring = ring_data->ring;
40562306a36Sopenharmony_ci	ndev = ring_data->napi.dev;
40662306a36Sopenharmony_ci	if (is_tx_ring(ring)) { /* for tx queue reset*/
40762306a36Sopenharmony_ci		dev_queue = netdev_get_tx_queue(ndev, ring_data->queue_index);
40862306a36Sopenharmony_ci		netdev_tx_reset_queue(dev_queue);
40962306a36Sopenharmony_ci		return;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	frame_size = skb->len;
41362306a36Sopenharmony_ci	frame_size &= ~1ul;
41462306a36Sopenharmony_ci	/* for mutl buffer*/
41562306a36Sopenharmony_ci	new_skb = skb_copy(skb, GFP_ATOMIC);
41662306a36Sopenharmony_ci	dev_kfree_skb_any(skb);
41762306a36Sopenharmony_ci	if (!new_skb) {
41862306a36Sopenharmony_ci		netdev_err(ndev, "skb alloc failed\n");
41962306a36Sopenharmony_ci		return;
42062306a36Sopenharmony_ci	}
42162306a36Sopenharmony_ci	skb = new_skb;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	check_ok = 0;
42462306a36Sopenharmony_ci	if (*(skb->data + 10) == 0xFF) { /* for rx check frame*/
42562306a36Sopenharmony_ci		if ((*(skb->data + frame_size / 2 + 10) == 0xBE) &&
42662306a36Sopenharmony_ci		    (*(skb->data + frame_size / 2 + 12) == 0xAF))
42762306a36Sopenharmony_ci			check_ok = 1;
42862306a36Sopenharmony_ci	}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	if (check_ok) {
43162306a36Sopenharmony_ci		ndev->stats.rx_packets++;
43262306a36Sopenharmony_ci		ndev->stats.rx_bytes += skb->len;
43362306a36Sopenharmony_ci	} else {
43462306a36Sopenharmony_ci		ndev->stats.rx_frame_errors++;
43562306a36Sopenharmony_ci		for (i = 0; i < skb->len; i++) {
43662306a36Sopenharmony_ci			snprintf(buff + i % 16 * 2, 3, /* tailing \0*/
43762306a36Sopenharmony_ci				 "%02x", *(skb->data + i));
43862306a36Sopenharmony_ci			if ((i % 16 == 15) || (i == skb->len - 1))
43962306a36Sopenharmony_ci				pr_info("%s\n", buff);
44062306a36Sopenharmony_ci		}
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci	dev_kfree_skb_any(skb);
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic int __lb_clean_rings(struct hns_nic_priv *priv,
44662306a36Sopenharmony_ci			    int ringid0, int ringid1, int budget)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	int i, ret;
44962306a36Sopenharmony_ci	struct hns_nic_ring_data *ring_data;
45062306a36Sopenharmony_ci	struct net_device *ndev = priv->netdev;
45162306a36Sopenharmony_ci	unsigned long rx_packets = ndev->stats.rx_packets;
45262306a36Sopenharmony_ci	unsigned long rx_bytes = ndev->stats.rx_bytes;
45362306a36Sopenharmony_ci	unsigned long rx_frame_errors = ndev->stats.rx_frame_errors;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	for (i = ringid0; i <= ringid1; i++) {
45662306a36Sopenharmony_ci		ring_data = &priv->ring_data[i];
45762306a36Sopenharmony_ci		(void)ring_data->poll_one(ring_data,
45862306a36Sopenharmony_ci					  budget, __lb_other_process);
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci	ret = (int)(ndev->stats.rx_packets - rx_packets);
46162306a36Sopenharmony_ci	ndev->stats.rx_packets = rx_packets;
46262306a36Sopenharmony_ci	ndev->stats.rx_bytes = rx_bytes;
46362306a36Sopenharmony_ci	ndev->stats.rx_frame_errors = rx_frame_errors;
46462306a36Sopenharmony_ci	return ret;
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci/**
46862306a36Sopenharmony_ci * __lb_run_test -  run loopback test
46962306a36Sopenharmony_ci * @ndev: net device
47062306a36Sopenharmony_ci * @loop_mode: loopback mode
47162306a36Sopenharmony_ci */
47262306a36Sopenharmony_cistatic int __lb_run_test(struct net_device *ndev,
47362306a36Sopenharmony_ci			 enum hnae_loop loop_mode)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci#define NIC_LB_TEST_PKT_NUM_PER_CYCLE 1
47662306a36Sopenharmony_ci#define NIC_LB_TEST_RING_ID 0
47762306a36Sopenharmony_ci#define NIC_LB_TEST_FRAME_SIZE 128
47862306a36Sopenharmony_ci/* nic loopback test err  */
47962306a36Sopenharmony_ci#define NIC_LB_TEST_NO_MEM_ERR 1
48062306a36Sopenharmony_ci#define NIC_LB_TEST_TX_CNT_ERR 2
48162306a36Sopenharmony_ci#define NIC_LB_TEST_RX_CNT_ERR 3
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
48462306a36Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
48562306a36Sopenharmony_ci	int i, j, lc, good_cnt, ret_val = 0;
48662306a36Sopenharmony_ci	unsigned int size;
48762306a36Sopenharmony_ci	netdev_tx_t tx_ret_val;
48862306a36Sopenharmony_ci	struct sk_buff *skb;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	size = NIC_LB_TEST_FRAME_SIZE;
49162306a36Sopenharmony_ci	/* allocate test skb */
49262306a36Sopenharmony_ci	skb = alloc_skb(size, GFP_KERNEL);
49362306a36Sopenharmony_ci	if (!skb)
49462306a36Sopenharmony_ci		return NIC_LB_TEST_NO_MEM_ERR;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	/* place data into test skb */
49762306a36Sopenharmony_ci	(void)skb_put(skb, size);
49862306a36Sopenharmony_ci	skb->dev = ndev;
49962306a36Sopenharmony_ci	__lb_other_process(NULL, skb);
50062306a36Sopenharmony_ci	skb->queue_mapping = NIC_LB_TEST_RING_ID;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	lc = 1;
50362306a36Sopenharmony_ci	for (j = 0; j < lc; j++) {
50462306a36Sopenharmony_ci		/* reset count of good packets */
50562306a36Sopenharmony_ci		good_cnt = 0;
50662306a36Sopenharmony_ci		/* place 64 packets on the transmit queue*/
50762306a36Sopenharmony_ci		for (i = 0; i < NIC_LB_TEST_PKT_NUM_PER_CYCLE; i++) {
50862306a36Sopenharmony_ci			(void)skb_get(skb);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci			tx_ret_val = (netdev_tx_t)hns_nic_net_xmit_hw(
51162306a36Sopenharmony_ci				ndev, skb,
51262306a36Sopenharmony_ci				&tx_ring_data(priv, skb->queue_mapping));
51362306a36Sopenharmony_ci			if (tx_ret_val == NETDEV_TX_OK)
51462306a36Sopenharmony_ci				good_cnt++;
51562306a36Sopenharmony_ci			else
51662306a36Sopenharmony_ci				break;
51762306a36Sopenharmony_ci		}
51862306a36Sopenharmony_ci		if (good_cnt != NIC_LB_TEST_PKT_NUM_PER_CYCLE) {
51962306a36Sopenharmony_ci			ret_val = NIC_LB_TEST_TX_CNT_ERR;
52062306a36Sopenharmony_ci			dev_err(priv->dev, "%s sent fail, cnt=0x%x, budget=0x%x\n",
52162306a36Sopenharmony_ci				hns_nic_test_strs[loop_mode], good_cnt,
52262306a36Sopenharmony_ci				NIC_LB_TEST_PKT_NUM_PER_CYCLE);
52362306a36Sopenharmony_ci			break;
52462306a36Sopenharmony_ci		}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci		/* allow 100 milliseconds for packets to go from Tx to Rx */
52762306a36Sopenharmony_ci		msleep(100);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci		good_cnt = __lb_clean_rings(priv,
53062306a36Sopenharmony_ci					    h->q_num, h->q_num * 2 - 1,
53162306a36Sopenharmony_ci					    NIC_LB_TEST_PKT_NUM_PER_CYCLE);
53262306a36Sopenharmony_ci		if (good_cnt != NIC_LB_TEST_PKT_NUM_PER_CYCLE) {
53362306a36Sopenharmony_ci			ret_val = NIC_LB_TEST_RX_CNT_ERR;
53462306a36Sopenharmony_ci			dev_err(priv->dev, "%s recv fail, cnt=0x%x, budget=0x%x\n",
53562306a36Sopenharmony_ci				hns_nic_test_strs[loop_mode], good_cnt,
53662306a36Sopenharmony_ci				NIC_LB_TEST_PKT_NUM_PER_CYCLE);
53762306a36Sopenharmony_ci			break;
53862306a36Sopenharmony_ci		}
53962306a36Sopenharmony_ci		(void)__lb_clean_rings(priv,
54062306a36Sopenharmony_ci				       NIC_LB_TEST_RING_ID, NIC_LB_TEST_RING_ID,
54162306a36Sopenharmony_ci				       NIC_LB_TEST_PKT_NUM_PER_CYCLE);
54262306a36Sopenharmony_ci	}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	/* free the original skb */
54562306a36Sopenharmony_ci	kfree_skb(skb);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	return ret_val;
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cistatic int __lb_down(struct net_device *ndev, enum hnae_loop loop)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
55362306a36Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
55462306a36Sopenharmony_ci	int ret;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	if (loop == MAC_INTERNALLOOP_PHY)
55762306a36Sopenharmony_ci		ret = __lb_setup(ndev, MAC_LOOP_PHY_NONE);
55862306a36Sopenharmony_ci	else
55962306a36Sopenharmony_ci		ret = __lb_setup(ndev, MAC_LOOP_NONE);
56062306a36Sopenharmony_ci	if (ret)
56162306a36Sopenharmony_ci		netdev_err(ndev, "%s: __lb_setup return error(%d)!\n",
56262306a36Sopenharmony_ci			   __func__,
56362306a36Sopenharmony_ci			   ret);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	if (h->dev->ops->stop)
56662306a36Sopenharmony_ci		h->dev->ops->stop(h);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	usleep_range(10000, 20000);
56962306a36Sopenharmony_ci	(void)__lb_clean_rings(priv, 0, h->q_num - 1, 256);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	hns_nic_net_reset(ndev);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	return 0;
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci/**
57762306a36Sopenharmony_ci * hns_nic_self_test - self test
57862306a36Sopenharmony_ci * @ndev: net device
57962306a36Sopenharmony_ci * @eth_test: test cmd
58062306a36Sopenharmony_ci * @data: test result
58162306a36Sopenharmony_ci */
58262306a36Sopenharmony_cistatic void hns_nic_self_test(struct net_device *ndev,
58362306a36Sopenharmony_ci			      struct ethtool_test *eth_test, u64 *data)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
58662306a36Sopenharmony_ci	bool if_running = netif_running(ndev);
58762306a36Sopenharmony_ci#define SELF_TEST_TPYE_NUM 3
58862306a36Sopenharmony_ci	int st_param[SELF_TEST_TPYE_NUM][2];
58962306a36Sopenharmony_ci	int i;
59062306a36Sopenharmony_ci	int test_index = 0;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	st_param[0][0] = MAC_INTERNALLOOP_MAC; /* XGE not supported lb */
59362306a36Sopenharmony_ci	st_param[0][1] = (priv->ae_handle->phy_if != PHY_INTERFACE_MODE_XGMII);
59462306a36Sopenharmony_ci	st_param[1][0] = MAC_INTERNALLOOP_SERDES;
59562306a36Sopenharmony_ci	st_param[1][1] = 1; /*serdes must exist*/
59662306a36Sopenharmony_ci	st_param[2][0] = MAC_INTERNALLOOP_PHY; /* only supporte phy node*/
59762306a36Sopenharmony_ci	st_param[2][1] = ((!!(priv->ae_handle->phy_dev)) &&
59862306a36Sopenharmony_ci		(priv->ae_handle->phy_if != PHY_INTERFACE_MODE_XGMII));
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
60162306a36Sopenharmony_ci		set_bit(NIC_STATE_TESTING, &priv->state);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci		if (if_running)
60462306a36Sopenharmony_ci			dev_close(ndev);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci		for (i = 0; i < SELF_TEST_TPYE_NUM; i++) {
60762306a36Sopenharmony_ci			if (!st_param[i][1])
60862306a36Sopenharmony_ci				continue;	/* NEXT testing */
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci			data[test_index] = __lb_up(ndev,
61162306a36Sopenharmony_ci				(enum hnae_loop)st_param[i][0]);
61262306a36Sopenharmony_ci			if (!data[test_index]) {
61362306a36Sopenharmony_ci				data[test_index] = __lb_run_test(
61462306a36Sopenharmony_ci					ndev, (enum hnae_loop)st_param[i][0]);
61562306a36Sopenharmony_ci				(void)__lb_down(ndev,
61662306a36Sopenharmony_ci						(enum hnae_loop)st_param[i][0]);
61762306a36Sopenharmony_ci			}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci			if (data[test_index])
62062306a36Sopenharmony_ci				eth_test->flags |= ETH_TEST_FL_FAILED;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci			test_index++;
62362306a36Sopenharmony_ci		}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci		hns_nic_net_reset(priv->netdev);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci		clear_bit(NIC_STATE_TESTING, &priv->state);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci		if (if_running)
63062306a36Sopenharmony_ci			(void)dev_open(ndev, NULL);
63162306a36Sopenharmony_ci	}
63262306a36Sopenharmony_ci	/* Online tests aren't run; pass by default */
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	(void)msleep_interruptible(4 * 1000);
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci/**
63862306a36Sopenharmony_ci * hns_nic_get_drvinfo - get net driver info
63962306a36Sopenharmony_ci * @net_dev: net device
64062306a36Sopenharmony_ci * @drvinfo: driver info
64162306a36Sopenharmony_ci */
64262306a36Sopenharmony_cistatic void hns_nic_get_drvinfo(struct net_device *net_dev,
64362306a36Sopenharmony_ci				struct ethtool_drvinfo *drvinfo)
64462306a36Sopenharmony_ci{
64562306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(net_dev);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	strscpy(drvinfo->version, HNAE_DRIVER_VERSION,
64862306a36Sopenharmony_ci		sizeof(drvinfo->version));
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	strscpy(drvinfo->driver, HNAE_DRIVER_NAME, sizeof(drvinfo->driver));
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	strscpy(drvinfo->bus_info, priv->dev->bus->name,
65362306a36Sopenharmony_ci		sizeof(drvinfo->bus_info));
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	strscpy(drvinfo->fw_version, "N/A", ETHTOOL_FWVERS_LEN);
65662306a36Sopenharmony_ci	drvinfo->eedump_len = 0;
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci/**
66062306a36Sopenharmony_ci * hns_get_ringparam - get ring parameter
66162306a36Sopenharmony_ci * @net_dev: net device
66262306a36Sopenharmony_ci * @param: ethtool parameter
66362306a36Sopenharmony_ci * @kernel_param: ethtool external parameter
66462306a36Sopenharmony_ci * @extack: netlink extended ACK report struct
66562306a36Sopenharmony_ci */
66662306a36Sopenharmony_cistatic void hns_get_ringparam(struct net_device *net_dev,
66762306a36Sopenharmony_ci			      struct ethtool_ringparam *param,
66862306a36Sopenharmony_ci			      struct kernel_ethtool_ringparam *kernel_param,
66962306a36Sopenharmony_ci			      struct netlink_ext_ack *extack)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(net_dev);
67262306a36Sopenharmony_ci	struct hnae_ae_ops *ops;
67362306a36Sopenharmony_ci	struct hnae_queue *queue;
67462306a36Sopenharmony_ci	u32 uplimit = 0;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	queue = priv->ae_handle->qs[0];
67762306a36Sopenharmony_ci	ops = priv->ae_handle->dev->ops;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	if (ops->get_ring_bdnum_limit)
68062306a36Sopenharmony_ci		ops->get_ring_bdnum_limit(queue, &uplimit);
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	param->rx_max_pending = uplimit;
68362306a36Sopenharmony_ci	param->tx_max_pending = uplimit;
68462306a36Sopenharmony_ci	param->rx_pending = queue->rx_ring.desc_num;
68562306a36Sopenharmony_ci	param->tx_pending = queue->tx_ring.desc_num;
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci/**
68962306a36Sopenharmony_ci * hns_get_pauseparam - get pause parameter
69062306a36Sopenharmony_ci * @net_dev: net device
69162306a36Sopenharmony_ci * @param: pause parameter
69262306a36Sopenharmony_ci */
69362306a36Sopenharmony_cistatic void hns_get_pauseparam(struct net_device *net_dev,
69462306a36Sopenharmony_ci			       struct ethtool_pauseparam *param)
69562306a36Sopenharmony_ci{
69662306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(net_dev);
69762306a36Sopenharmony_ci	struct hnae_ae_ops *ops;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	ops = priv->ae_handle->dev->ops;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	if (ops->get_pauseparam)
70262306a36Sopenharmony_ci		ops->get_pauseparam(priv->ae_handle, &param->autoneg,
70362306a36Sopenharmony_ci					    &param->rx_pause, &param->tx_pause);
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci/**
70762306a36Sopenharmony_ci * hns_set_pauseparam - set pause parameter
70862306a36Sopenharmony_ci * @net_dev: net device
70962306a36Sopenharmony_ci * @param: pause parameter
71062306a36Sopenharmony_ci *
71162306a36Sopenharmony_ci * Return 0 on success, negative on failure
71262306a36Sopenharmony_ci */
71362306a36Sopenharmony_cistatic int hns_set_pauseparam(struct net_device *net_dev,
71462306a36Sopenharmony_ci			      struct ethtool_pauseparam *param)
71562306a36Sopenharmony_ci{
71662306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(net_dev);
71762306a36Sopenharmony_ci	struct hnae_handle *h;
71862306a36Sopenharmony_ci	struct hnae_ae_ops *ops;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	h = priv->ae_handle;
72162306a36Sopenharmony_ci	ops = h->dev->ops;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	if (!ops->set_pauseparam)
72462306a36Sopenharmony_ci		return -ESRCH;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	return ops->set_pauseparam(priv->ae_handle, param->autoneg,
72762306a36Sopenharmony_ci				   param->rx_pause, param->tx_pause);
72862306a36Sopenharmony_ci}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci/**
73162306a36Sopenharmony_ci * hns_get_coalesce - get coalesce info.
73262306a36Sopenharmony_ci * @net_dev: net device
73362306a36Sopenharmony_ci * @ec: coalesce info.
73462306a36Sopenharmony_ci * @kernel_coal: ethtool CQE mode setting structure
73562306a36Sopenharmony_ci * @extack: extack for reporting error messages
73662306a36Sopenharmony_ci *
73762306a36Sopenharmony_ci * Return 0 on success, negative on failure.
73862306a36Sopenharmony_ci */
73962306a36Sopenharmony_cistatic int hns_get_coalesce(struct net_device *net_dev,
74062306a36Sopenharmony_ci			    struct ethtool_coalesce *ec,
74162306a36Sopenharmony_ci			    struct kernel_ethtool_coalesce *kernel_coal,
74262306a36Sopenharmony_ci			    struct netlink_ext_ack *extack)
74362306a36Sopenharmony_ci{
74462306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(net_dev);
74562306a36Sopenharmony_ci	struct hnae_ae_ops *ops;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	ops = priv->ae_handle->dev->ops;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	ec->use_adaptive_rx_coalesce = priv->ae_handle->coal_adapt_en;
75062306a36Sopenharmony_ci	ec->use_adaptive_tx_coalesce = priv->ae_handle->coal_adapt_en;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	if ((!ops->get_coalesce_usecs) ||
75362306a36Sopenharmony_ci	    (!ops->get_max_coalesced_frames))
75462306a36Sopenharmony_ci		return -ESRCH;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	ops->get_coalesce_usecs(priv->ae_handle,
75762306a36Sopenharmony_ci					&ec->tx_coalesce_usecs,
75862306a36Sopenharmony_ci					&ec->rx_coalesce_usecs);
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	ops->get_max_coalesced_frames(
76162306a36Sopenharmony_ci		priv->ae_handle,
76262306a36Sopenharmony_ci		&ec->tx_max_coalesced_frames,
76362306a36Sopenharmony_ci		&ec->rx_max_coalesced_frames);
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	ops->get_coalesce_range(priv->ae_handle,
76662306a36Sopenharmony_ci				&ec->tx_max_coalesced_frames_low,
76762306a36Sopenharmony_ci				&ec->rx_max_coalesced_frames_low,
76862306a36Sopenharmony_ci				&ec->tx_max_coalesced_frames_high,
76962306a36Sopenharmony_ci				&ec->rx_max_coalesced_frames_high,
77062306a36Sopenharmony_ci				&ec->tx_coalesce_usecs_low,
77162306a36Sopenharmony_ci				&ec->rx_coalesce_usecs_low,
77262306a36Sopenharmony_ci				&ec->tx_coalesce_usecs_high,
77362306a36Sopenharmony_ci				&ec->rx_coalesce_usecs_high);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	return 0;
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci/**
77962306a36Sopenharmony_ci * hns_set_coalesce - set coalesce info.
78062306a36Sopenharmony_ci * @net_dev: net device
78162306a36Sopenharmony_ci * @ec: coalesce info.
78262306a36Sopenharmony_ci * @kernel_coal: ethtool CQE mode setting structure
78362306a36Sopenharmony_ci * @extack: extack for reporting error messages
78462306a36Sopenharmony_ci *
78562306a36Sopenharmony_ci * Return 0 on success, negative on failure.
78662306a36Sopenharmony_ci */
78762306a36Sopenharmony_cistatic int hns_set_coalesce(struct net_device *net_dev,
78862306a36Sopenharmony_ci			    struct ethtool_coalesce *ec,
78962306a36Sopenharmony_ci			    struct kernel_ethtool_coalesce *kernel_coal,
79062306a36Sopenharmony_ci			    struct netlink_ext_ack *extack)
79162306a36Sopenharmony_ci{
79262306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(net_dev);
79362306a36Sopenharmony_ci	struct hnae_ae_ops *ops;
79462306a36Sopenharmony_ci	int rc1, rc2;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	ops = priv->ae_handle->dev->ops;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	if (ec->tx_coalesce_usecs != ec->rx_coalesce_usecs)
79962306a36Sopenharmony_ci		return -EINVAL;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	if ((!ops->set_coalesce_usecs) ||
80262306a36Sopenharmony_ci	    (!ops->set_coalesce_frames))
80362306a36Sopenharmony_ci		return -ESRCH;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	if (ec->use_adaptive_rx_coalesce != priv->ae_handle->coal_adapt_en)
80662306a36Sopenharmony_ci		priv->ae_handle->coal_adapt_en = ec->use_adaptive_rx_coalesce;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	rc1 = ops->set_coalesce_usecs(priv->ae_handle,
80962306a36Sopenharmony_ci				      ec->rx_coalesce_usecs);
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	rc2 = ops->set_coalesce_frames(priv->ae_handle,
81262306a36Sopenharmony_ci				       ec->tx_max_coalesced_frames,
81362306a36Sopenharmony_ci				       ec->rx_max_coalesced_frames);
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	if (rc1 || rc2)
81662306a36Sopenharmony_ci		return -EINVAL;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	return 0;
81962306a36Sopenharmony_ci}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci/**
82262306a36Sopenharmony_ci * hns_get_channels - get channel info.
82362306a36Sopenharmony_ci * @net_dev: net device
82462306a36Sopenharmony_ci * @ch: channel info.
82562306a36Sopenharmony_ci */
82662306a36Sopenharmony_cistatic void
82762306a36Sopenharmony_cihns_get_channels(struct net_device *net_dev, struct ethtool_channels *ch)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(net_dev);
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	ch->max_rx = priv->ae_handle->q_num;
83262306a36Sopenharmony_ci	ch->max_tx = priv->ae_handle->q_num;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	ch->rx_count = priv->ae_handle->q_num;
83562306a36Sopenharmony_ci	ch->tx_count = priv->ae_handle->q_num;
83662306a36Sopenharmony_ci}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci/**
83962306a36Sopenharmony_ci * hns_get_ethtool_stats - get detail statistics.
84062306a36Sopenharmony_ci * @netdev: net device
84162306a36Sopenharmony_ci * @stats: statistics info.
84262306a36Sopenharmony_ci * @data: statistics data.
84362306a36Sopenharmony_ci */
84462306a36Sopenharmony_cistatic void hns_get_ethtool_stats(struct net_device *netdev,
84562306a36Sopenharmony_ci				  struct ethtool_stats *stats, u64 *data)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci	u64 *p = data;
84862306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
84962306a36Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
85062306a36Sopenharmony_ci	const struct rtnl_link_stats64 *net_stats;
85162306a36Sopenharmony_ci	struct rtnl_link_stats64 temp;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	if (!h->dev->ops->get_stats || !h->dev->ops->update_stats) {
85462306a36Sopenharmony_ci		netdev_err(netdev, "get_stats or update_stats is null!\n");
85562306a36Sopenharmony_ci		return;
85662306a36Sopenharmony_ci	}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	h->dev->ops->update_stats(h, &netdev->stats);
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	net_stats = dev_get_stats(netdev, &temp);
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	/* get netdev statistics */
86362306a36Sopenharmony_ci	p[0] = net_stats->rx_packets;
86462306a36Sopenharmony_ci	p[1] = net_stats->tx_packets;
86562306a36Sopenharmony_ci	p[2] = net_stats->rx_bytes;
86662306a36Sopenharmony_ci	p[3] = net_stats->tx_bytes;
86762306a36Sopenharmony_ci	p[4] = net_stats->rx_errors;
86862306a36Sopenharmony_ci	p[5] = net_stats->tx_errors;
86962306a36Sopenharmony_ci	p[6] = net_stats->rx_dropped;
87062306a36Sopenharmony_ci	p[7] = net_stats->tx_dropped;
87162306a36Sopenharmony_ci	p[8] = net_stats->multicast;
87262306a36Sopenharmony_ci	p[9] = net_stats->collisions;
87362306a36Sopenharmony_ci	p[10] = net_stats->rx_over_errors;
87462306a36Sopenharmony_ci	p[11] = net_stats->rx_crc_errors;
87562306a36Sopenharmony_ci	p[12] = net_stats->rx_frame_errors;
87662306a36Sopenharmony_ci	p[13] = net_stats->rx_fifo_errors;
87762306a36Sopenharmony_ci	p[14] = net_stats->rx_missed_errors;
87862306a36Sopenharmony_ci	p[15] = net_stats->tx_aborted_errors;
87962306a36Sopenharmony_ci	p[16] = net_stats->tx_carrier_errors;
88062306a36Sopenharmony_ci	p[17] = net_stats->tx_fifo_errors;
88162306a36Sopenharmony_ci	p[18] = net_stats->tx_heartbeat_errors;
88262306a36Sopenharmony_ci	p[19] = net_stats->rx_length_errors;
88362306a36Sopenharmony_ci	p[20] = net_stats->tx_window_errors;
88462306a36Sopenharmony_ci	p[21] = net_stats->rx_compressed;
88562306a36Sopenharmony_ci	p[22] = net_stats->tx_compressed;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	p[23] = 0; /* was netdev->rx_dropped.counter */
88862306a36Sopenharmony_ci	p[24] = 0; /* was netdev->tx_dropped.counter */
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	p[25] = priv->tx_timeout_count;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	/* get driver statistics */
89362306a36Sopenharmony_ci	h->dev->ops->get_stats(h, &p[26]);
89462306a36Sopenharmony_ci}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci/**
89762306a36Sopenharmony_ci * hns_get_strings: Return a set of strings that describe the requested objects
89862306a36Sopenharmony_ci * @netdev: net device
89962306a36Sopenharmony_ci * @stringset: string set ID.
90062306a36Sopenharmony_ci * @data: objects data.
90162306a36Sopenharmony_ci */
90262306a36Sopenharmony_cistatic void hns_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
90362306a36Sopenharmony_ci{
90462306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
90562306a36Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
90662306a36Sopenharmony_ci	u8 *buff = data;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	if (!h->dev->ops->get_strings) {
90962306a36Sopenharmony_ci		netdev_err(netdev, "h->dev->ops->get_strings is null!\n");
91062306a36Sopenharmony_ci		return;
91162306a36Sopenharmony_ci	}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	if (stringset == ETH_SS_TEST) {
91462306a36Sopenharmony_ci		if (priv->ae_handle->phy_if != PHY_INTERFACE_MODE_XGMII)
91562306a36Sopenharmony_ci			ethtool_sprintf(&buff,
91662306a36Sopenharmony_ci					hns_nic_test_strs[MAC_INTERNALLOOP_MAC]);
91762306a36Sopenharmony_ci		ethtool_sprintf(&buff,
91862306a36Sopenharmony_ci				hns_nic_test_strs[MAC_INTERNALLOOP_SERDES]);
91962306a36Sopenharmony_ci		if ((netdev->phydev) && (!netdev->phydev->is_c45))
92062306a36Sopenharmony_ci			ethtool_sprintf(&buff,
92162306a36Sopenharmony_ci					hns_nic_test_strs[MAC_INTERNALLOOP_PHY]);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	} else {
92462306a36Sopenharmony_ci		ethtool_sprintf(&buff, "rx_packets");
92562306a36Sopenharmony_ci		ethtool_sprintf(&buff, "tx_packets");
92662306a36Sopenharmony_ci		ethtool_sprintf(&buff, "rx_bytes");
92762306a36Sopenharmony_ci		ethtool_sprintf(&buff, "tx_bytes");
92862306a36Sopenharmony_ci		ethtool_sprintf(&buff, "rx_errors");
92962306a36Sopenharmony_ci		ethtool_sprintf(&buff, "tx_errors");
93062306a36Sopenharmony_ci		ethtool_sprintf(&buff, "rx_dropped");
93162306a36Sopenharmony_ci		ethtool_sprintf(&buff, "tx_dropped");
93262306a36Sopenharmony_ci		ethtool_sprintf(&buff, "multicast");
93362306a36Sopenharmony_ci		ethtool_sprintf(&buff, "collisions");
93462306a36Sopenharmony_ci		ethtool_sprintf(&buff, "rx_over_errors");
93562306a36Sopenharmony_ci		ethtool_sprintf(&buff, "rx_crc_errors");
93662306a36Sopenharmony_ci		ethtool_sprintf(&buff, "rx_frame_errors");
93762306a36Sopenharmony_ci		ethtool_sprintf(&buff, "rx_fifo_errors");
93862306a36Sopenharmony_ci		ethtool_sprintf(&buff, "rx_missed_errors");
93962306a36Sopenharmony_ci		ethtool_sprintf(&buff, "tx_aborted_errors");
94062306a36Sopenharmony_ci		ethtool_sprintf(&buff, "tx_carrier_errors");
94162306a36Sopenharmony_ci		ethtool_sprintf(&buff, "tx_fifo_errors");
94262306a36Sopenharmony_ci		ethtool_sprintf(&buff, "tx_heartbeat_errors");
94362306a36Sopenharmony_ci		ethtool_sprintf(&buff, "rx_length_errors");
94462306a36Sopenharmony_ci		ethtool_sprintf(&buff, "tx_window_errors");
94562306a36Sopenharmony_ci		ethtool_sprintf(&buff, "rx_compressed");
94662306a36Sopenharmony_ci		ethtool_sprintf(&buff, "tx_compressed");
94762306a36Sopenharmony_ci		ethtool_sprintf(&buff, "netdev_rx_dropped");
94862306a36Sopenharmony_ci		ethtool_sprintf(&buff, "netdev_tx_dropped");
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci		ethtool_sprintf(&buff, "netdev_tx_timeout");
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci		h->dev->ops->get_strings(h, stringset, buff);
95362306a36Sopenharmony_ci	}
95462306a36Sopenharmony_ci}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci/**
95762306a36Sopenharmony_ci * hns_get_sset_count - get string set count returned by nic_get_strings
95862306a36Sopenharmony_ci * @netdev: net device
95962306a36Sopenharmony_ci * @stringset: string set index, 0: self test string; 1: statistics string.
96062306a36Sopenharmony_ci *
96162306a36Sopenharmony_ci * Return string set count.
96262306a36Sopenharmony_ci */
96362306a36Sopenharmony_cistatic int hns_get_sset_count(struct net_device *netdev, int stringset)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
96662306a36Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
96762306a36Sopenharmony_ci	struct hnae_ae_ops *ops = h->dev->ops;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	if (!ops->get_sset_count) {
97062306a36Sopenharmony_ci		netdev_err(netdev, "get_sset_count is null!\n");
97162306a36Sopenharmony_ci		return -EOPNOTSUPP;
97262306a36Sopenharmony_ci	}
97362306a36Sopenharmony_ci	if (stringset == ETH_SS_TEST) {
97462306a36Sopenharmony_ci		u32 cnt = (sizeof(hns_nic_test_strs) / ETH_GSTRING_LEN);
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci		if (priv->ae_handle->phy_if == PHY_INTERFACE_MODE_XGMII)
97762306a36Sopenharmony_ci			cnt--;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci		if ((!netdev->phydev) || (netdev->phydev->is_c45))
98062306a36Sopenharmony_ci			cnt--;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci		return cnt;
98362306a36Sopenharmony_ci	} else if (stringset == ETH_SS_STATS) {
98462306a36Sopenharmony_ci		return (HNS_NET_STATS_CNT + ops->get_sset_count(h, stringset));
98562306a36Sopenharmony_ci	} else {
98662306a36Sopenharmony_ci		return -EOPNOTSUPP;
98762306a36Sopenharmony_ci	}
98862306a36Sopenharmony_ci}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci/**
99162306a36Sopenharmony_ci * hns_phy_led_set - set phy LED status.
99262306a36Sopenharmony_ci * @netdev: net device
99362306a36Sopenharmony_ci * @value: LED state.
99462306a36Sopenharmony_ci *
99562306a36Sopenharmony_ci * Return 0 on success, negative on failure.
99662306a36Sopenharmony_ci */
99762306a36Sopenharmony_cistatic int hns_phy_led_set(struct net_device *netdev, int value)
99862306a36Sopenharmony_ci{
99962306a36Sopenharmony_ci	int retval;
100062306a36Sopenharmony_ci	struct phy_device *phy_dev = netdev->phydev;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	retval = phy_write(phy_dev, HNS_PHY_PAGE_REG, HNS_PHY_PAGE_LED);
100362306a36Sopenharmony_ci	retval |= phy_write(phy_dev, HNS_LED_FC_REG, value);
100462306a36Sopenharmony_ci	retval |= phy_write(phy_dev, HNS_PHY_PAGE_REG, HNS_PHY_PAGE_COPPER);
100562306a36Sopenharmony_ci	if (retval) {
100662306a36Sopenharmony_ci		netdev_err(netdev, "mdiobus_write fail !\n");
100762306a36Sopenharmony_ci		return retval;
100862306a36Sopenharmony_ci	}
100962306a36Sopenharmony_ci	return 0;
101062306a36Sopenharmony_ci}
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci/**
101362306a36Sopenharmony_ci * hns_set_phys_id - set phy identify LED.
101462306a36Sopenharmony_ci * @netdev: net device
101562306a36Sopenharmony_ci * @state: LED state.
101662306a36Sopenharmony_ci *
101762306a36Sopenharmony_ci * Return 0 on success, negative on failure.
101862306a36Sopenharmony_ci */
101962306a36Sopenharmony_cistatic int
102062306a36Sopenharmony_cihns_set_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state)
102162306a36Sopenharmony_ci{
102262306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
102362306a36Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
102462306a36Sopenharmony_ci	struct phy_device *phy_dev = netdev->phydev;
102562306a36Sopenharmony_ci	int ret;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	if (phy_dev)
102862306a36Sopenharmony_ci		switch (state) {
102962306a36Sopenharmony_ci		case ETHTOOL_ID_ACTIVE:
103062306a36Sopenharmony_ci			ret = phy_write(phy_dev, HNS_PHY_PAGE_REG,
103162306a36Sopenharmony_ci					HNS_PHY_PAGE_LED);
103262306a36Sopenharmony_ci			if (ret)
103362306a36Sopenharmony_ci				return ret;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci			priv->phy_led_val = phy_read(phy_dev, HNS_LED_FC_REG);
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci			ret = phy_write(phy_dev, HNS_PHY_PAGE_REG,
103862306a36Sopenharmony_ci					HNS_PHY_PAGE_COPPER);
103962306a36Sopenharmony_ci			if (ret)
104062306a36Sopenharmony_ci				return ret;
104162306a36Sopenharmony_ci			return 2;
104262306a36Sopenharmony_ci		case ETHTOOL_ID_ON:
104362306a36Sopenharmony_ci			ret = hns_phy_led_set(netdev, HNS_LED_FORCE_ON);
104462306a36Sopenharmony_ci			if (ret)
104562306a36Sopenharmony_ci				return ret;
104662306a36Sopenharmony_ci			break;
104762306a36Sopenharmony_ci		case ETHTOOL_ID_OFF:
104862306a36Sopenharmony_ci			ret = hns_phy_led_set(netdev, HNS_LED_FORCE_OFF);
104962306a36Sopenharmony_ci			if (ret)
105062306a36Sopenharmony_ci				return ret;
105162306a36Sopenharmony_ci			break;
105262306a36Sopenharmony_ci		case ETHTOOL_ID_INACTIVE:
105362306a36Sopenharmony_ci			ret = phy_write(phy_dev, HNS_PHY_PAGE_REG,
105462306a36Sopenharmony_ci					HNS_PHY_PAGE_LED);
105562306a36Sopenharmony_ci			if (ret)
105662306a36Sopenharmony_ci				return ret;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci			ret = phy_write(phy_dev, HNS_LED_FC_REG,
105962306a36Sopenharmony_ci					priv->phy_led_val);
106062306a36Sopenharmony_ci			if (ret)
106162306a36Sopenharmony_ci				return ret;
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci			ret = phy_write(phy_dev, HNS_PHY_PAGE_REG,
106462306a36Sopenharmony_ci					HNS_PHY_PAGE_COPPER);
106562306a36Sopenharmony_ci			if (ret)
106662306a36Sopenharmony_ci				return ret;
106762306a36Sopenharmony_ci			break;
106862306a36Sopenharmony_ci		default:
106962306a36Sopenharmony_ci			return -EINVAL;
107062306a36Sopenharmony_ci		}
107162306a36Sopenharmony_ci	else
107262306a36Sopenharmony_ci		switch (state) {
107362306a36Sopenharmony_ci		case ETHTOOL_ID_ACTIVE:
107462306a36Sopenharmony_ci			return h->dev->ops->set_led_id(h, HNAE_LED_ACTIVE);
107562306a36Sopenharmony_ci		case ETHTOOL_ID_ON:
107662306a36Sopenharmony_ci			return h->dev->ops->set_led_id(h, HNAE_LED_ON);
107762306a36Sopenharmony_ci		case ETHTOOL_ID_OFF:
107862306a36Sopenharmony_ci			return h->dev->ops->set_led_id(h, HNAE_LED_OFF);
107962306a36Sopenharmony_ci		case ETHTOOL_ID_INACTIVE:
108062306a36Sopenharmony_ci			return h->dev->ops->set_led_id(h, HNAE_LED_INACTIVE);
108162306a36Sopenharmony_ci		default:
108262306a36Sopenharmony_ci			return -EINVAL;
108362306a36Sopenharmony_ci		}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	return 0;
108662306a36Sopenharmony_ci}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci/**
108962306a36Sopenharmony_ci * hns_get_regs - get net device register
109062306a36Sopenharmony_ci * @net_dev: net device
109162306a36Sopenharmony_ci * @cmd: ethtool cmd
109262306a36Sopenharmony_ci * @data: register data
109362306a36Sopenharmony_ci */
109462306a36Sopenharmony_cistatic void hns_get_regs(struct net_device *net_dev, struct ethtool_regs *cmd,
109562306a36Sopenharmony_ci			 void *data)
109662306a36Sopenharmony_ci{
109762306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(net_dev);
109862306a36Sopenharmony_ci	struct hnae_ae_ops *ops;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	ops = priv->ae_handle->dev->ops;
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	cmd->version = HNS_CHIP_VERSION;
110362306a36Sopenharmony_ci	if (!ops->get_regs) {
110462306a36Sopenharmony_ci		netdev_err(net_dev, "ops->get_regs is null!\n");
110562306a36Sopenharmony_ci		return;
110662306a36Sopenharmony_ci	}
110762306a36Sopenharmony_ci	ops->get_regs(priv->ae_handle, data);
110862306a36Sopenharmony_ci}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci/**
111162306a36Sopenharmony_ci * hns_get_regs_len - get total register len.
111262306a36Sopenharmony_ci * @net_dev: net device
111362306a36Sopenharmony_ci *
111462306a36Sopenharmony_ci * Return total register len.
111562306a36Sopenharmony_ci */
111662306a36Sopenharmony_cistatic int hns_get_regs_len(struct net_device *net_dev)
111762306a36Sopenharmony_ci{
111862306a36Sopenharmony_ci	u32 reg_num;
111962306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(net_dev);
112062306a36Sopenharmony_ci	struct hnae_ae_ops *ops;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	ops = priv->ae_handle->dev->ops;
112362306a36Sopenharmony_ci	if (!ops->get_regs_len) {
112462306a36Sopenharmony_ci		netdev_err(net_dev, "ops->get_regs_len is null!\n");
112562306a36Sopenharmony_ci		return -EOPNOTSUPP;
112662306a36Sopenharmony_ci	}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	reg_num = ops->get_regs_len(priv->ae_handle);
112962306a36Sopenharmony_ci	if (reg_num > 0)
113062306a36Sopenharmony_ci		return reg_num * sizeof(u32);
113162306a36Sopenharmony_ci	else
113262306a36Sopenharmony_ci		return reg_num;	/* error code */
113362306a36Sopenharmony_ci}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci/**
113662306a36Sopenharmony_ci * hns_nic_nway_reset - nway reset
113762306a36Sopenharmony_ci * @netdev: net device
113862306a36Sopenharmony_ci *
113962306a36Sopenharmony_ci * Return 0 on success, negative on failure
114062306a36Sopenharmony_ci */
114162306a36Sopenharmony_cistatic int hns_nic_nway_reset(struct net_device *netdev)
114262306a36Sopenharmony_ci{
114362306a36Sopenharmony_ci	struct phy_device *phy = netdev->phydev;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	if (!netif_running(netdev))
114662306a36Sopenharmony_ci		return 0;
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	if (!phy)
114962306a36Sopenharmony_ci		return -EOPNOTSUPP;
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	if (phy->autoneg != AUTONEG_ENABLE)
115262306a36Sopenharmony_ci		return -EINVAL;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	return genphy_restart_aneg(phy);
115562306a36Sopenharmony_ci}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_cistatic u32
115862306a36Sopenharmony_cihns_get_rss_key_size(struct net_device *netdev)
115962306a36Sopenharmony_ci{
116062306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
116162306a36Sopenharmony_ci	struct hnae_ae_ops *ops;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	if (AE_IS_VER1(priv->enet_ver)) {
116462306a36Sopenharmony_ci		netdev_err(netdev,
116562306a36Sopenharmony_ci			   "RSS feature is not supported on this hardware\n");
116662306a36Sopenharmony_ci		return 0;
116762306a36Sopenharmony_ci	}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	ops = priv->ae_handle->dev->ops;
117062306a36Sopenharmony_ci	return ops->get_rss_key_size(priv->ae_handle);
117162306a36Sopenharmony_ci}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_cistatic u32
117462306a36Sopenharmony_cihns_get_rss_indir_size(struct net_device *netdev)
117562306a36Sopenharmony_ci{
117662306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
117762306a36Sopenharmony_ci	struct hnae_ae_ops *ops;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	if (AE_IS_VER1(priv->enet_ver)) {
118062306a36Sopenharmony_ci		netdev_err(netdev,
118162306a36Sopenharmony_ci			   "RSS feature is not supported on this hardware\n");
118262306a36Sopenharmony_ci		return 0;
118362306a36Sopenharmony_ci	}
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	ops = priv->ae_handle->dev->ops;
118662306a36Sopenharmony_ci	return ops->get_rss_indir_size(priv->ae_handle);
118762306a36Sopenharmony_ci}
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_cistatic int
119062306a36Sopenharmony_cihns_get_rss(struct net_device *netdev, u32 *indir, u8 *key, u8 *hfunc)
119162306a36Sopenharmony_ci{
119262306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
119362306a36Sopenharmony_ci	struct hnae_ae_ops *ops;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	if (AE_IS_VER1(priv->enet_ver)) {
119662306a36Sopenharmony_ci		netdev_err(netdev,
119762306a36Sopenharmony_ci			   "RSS feature is not supported on this hardware\n");
119862306a36Sopenharmony_ci		return -EOPNOTSUPP;
119962306a36Sopenharmony_ci	}
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	ops = priv->ae_handle->dev->ops;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	if (!indir)
120462306a36Sopenharmony_ci		return 0;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	return ops->get_rss(priv->ae_handle, indir, key, hfunc);
120762306a36Sopenharmony_ci}
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_cistatic int
121062306a36Sopenharmony_cihns_set_rss(struct net_device *netdev, const u32 *indir, const u8 *key,
121162306a36Sopenharmony_ci	    const u8 hfunc)
121262306a36Sopenharmony_ci{
121362306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
121462306a36Sopenharmony_ci	struct hnae_ae_ops *ops;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	if (AE_IS_VER1(priv->enet_ver)) {
121762306a36Sopenharmony_ci		netdev_err(netdev,
121862306a36Sopenharmony_ci			   "RSS feature is not supported on this hardware\n");
121962306a36Sopenharmony_ci		return -EOPNOTSUPP;
122062306a36Sopenharmony_ci	}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	ops = priv->ae_handle->dev->ops;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) {
122562306a36Sopenharmony_ci		netdev_err(netdev, "Invalid hfunc!\n");
122662306a36Sopenharmony_ci		return -EOPNOTSUPP;
122762306a36Sopenharmony_ci	}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	return ops->set_rss(priv->ae_handle, indir, key, hfunc);
123062306a36Sopenharmony_ci}
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_cistatic int hns_get_rxnfc(struct net_device *netdev,
123362306a36Sopenharmony_ci			 struct ethtool_rxnfc *cmd,
123462306a36Sopenharmony_ci			 u32 *rule_locs)
123562306a36Sopenharmony_ci{
123662306a36Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	switch (cmd->cmd) {
123962306a36Sopenharmony_ci	case ETHTOOL_GRXRINGS:
124062306a36Sopenharmony_ci		cmd->data = priv->ae_handle->q_num;
124162306a36Sopenharmony_ci		break;
124262306a36Sopenharmony_ci	default:
124362306a36Sopenharmony_ci		return -EOPNOTSUPP;
124462306a36Sopenharmony_ci	}
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	return 0;
124762306a36Sopenharmony_ci}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_cistatic const struct ethtool_ops hns_ethtool_ops = {
125062306a36Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
125162306a36Sopenharmony_ci				     ETHTOOL_COALESCE_MAX_FRAMES |
125262306a36Sopenharmony_ci				     ETHTOOL_COALESCE_USE_ADAPTIVE |
125362306a36Sopenharmony_ci				     ETHTOOL_COALESCE_USECS_LOW_HIGH |
125462306a36Sopenharmony_ci				     ETHTOOL_COALESCE_MAX_FRAMES_LOW_HIGH,
125562306a36Sopenharmony_ci	.get_drvinfo = hns_nic_get_drvinfo,
125662306a36Sopenharmony_ci	.get_link  = hns_nic_get_link,
125762306a36Sopenharmony_ci	.get_ringparam = hns_get_ringparam,
125862306a36Sopenharmony_ci	.get_pauseparam = hns_get_pauseparam,
125962306a36Sopenharmony_ci	.set_pauseparam = hns_set_pauseparam,
126062306a36Sopenharmony_ci	.get_coalesce = hns_get_coalesce,
126162306a36Sopenharmony_ci	.set_coalesce = hns_set_coalesce,
126262306a36Sopenharmony_ci	.get_channels = hns_get_channels,
126362306a36Sopenharmony_ci	.self_test = hns_nic_self_test,
126462306a36Sopenharmony_ci	.get_strings = hns_get_strings,
126562306a36Sopenharmony_ci	.get_sset_count = hns_get_sset_count,
126662306a36Sopenharmony_ci	.get_ethtool_stats = hns_get_ethtool_stats,
126762306a36Sopenharmony_ci	.set_phys_id = hns_set_phys_id,
126862306a36Sopenharmony_ci	.get_regs_len = hns_get_regs_len,
126962306a36Sopenharmony_ci	.get_regs = hns_get_regs,
127062306a36Sopenharmony_ci	.nway_reset = hns_nic_nway_reset,
127162306a36Sopenharmony_ci	.get_rxfh_key_size = hns_get_rss_key_size,
127262306a36Sopenharmony_ci	.get_rxfh_indir_size = hns_get_rss_indir_size,
127362306a36Sopenharmony_ci	.get_rxfh = hns_get_rss,
127462306a36Sopenharmony_ci	.set_rxfh = hns_set_rss,
127562306a36Sopenharmony_ci	.get_rxnfc = hns_get_rxnfc,
127662306a36Sopenharmony_ci	.get_link_ksettings  = hns_nic_get_link_ksettings,
127762306a36Sopenharmony_ci	.set_link_ksettings  = hns_nic_set_link_ksettings,
127862306a36Sopenharmony_ci};
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_civoid hns_ethtool_set_ops(struct net_device *ndev)
128162306a36Sopenharmony_ci{
128262306a36Sopenharmony_ci	ndev->ethtool_ops = &hns_ethtool_ops;
128362306a36Sopenharmony_ci}
1284