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, ¶m->autoneg, 70362306a36Sopenharmony_ci ¶m->rx_pause, ¶m->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