1e8d13548SJijie Shao // SPDX-License-Identifier: GPL-2.0+ 2e8d13548SJijie Shao // Copyright (c) 2024 Hisilicon Limited. 3e8d13548SJijie Shao 4e8d13548SJijie Shao #include <linux/ethtool.h> 5e8d13548SJijie Shao #include <linux/phy.h> 63f5a61f6SJijie Shao #include <linux/rtnetlink.h> 751574da8SJijie Shao #include "hbg_common.h" 83f5a61f6SJijie Shao #include "hbg_err.h" 9e8d13548SJijie Shao #include "hbg_ethtool.h" 1051574da8SJijie Shao #include "hbg_hw.h" 1151574da8SJijie Shao 1251574da8SJijie Shao enum hbg_reg_dump_type { 1351574da8SJijie Shao HBG_DUMP_REG_TYPE_SPEC = 0, 1451574da8SJijie Shao HBG_DUMP_REG_TYPE_MDIO, 1551574da8SJijie Shao HBG_DUMP_REG_TYPE_GMAC, 1651574da8SJijie Shao HBG_DUMP_REG_TYPE_PCU, 1751574da8SJijie Shao }; 1851574da8SJijie Shao 1951574da8SJijie Shao struct hbg_reg_info { 2051574da8SJijie Shao u32 type; 2151574da8SJijie Shao u32 offset; 2251574da8SJijie Shao u32 val; 2351574da8SJijie Shao }; 2451574da8SJijie Shao 2551574da8SJijie Shao #define HBG_DUMP_SPEC_I(offset) {HBG_DUMP_REG_TYPE_SPEC, offset, 0} 2651574da8SJijie Shao #define HBG_DUMP_MDIO_I(offset) {HBG_DUMP_REG_TYPE_MDIO, offset, 0} 2751574da8SJijie Shao #define HBG_DUMP_GMAC_I(offset) {HBG_DUMP_REG_TYPE_GMAC, offset, 0} 2851574da8SJijie Shao #define HBG_DUMP_PCU_I(offset) {HBG_DUMP_REG_TYPE_PCU, offset, 0} 2951574da8SJijie Shao 3051574da8SJijie Shao static const struct hbg_reg_info hbg_dump_reg_infos[] = { 3151574da8SJijie Shao /* dev specs */ 3251574da8SJijie Shao HBG_DUMP_SPEC_I(HBG_REG_SPEC_VALID_ADDR), 3351574da8SJijie Shao HBG_DUMP_SPEC_I(HBG_REG_EVENT_REQ_ADDR), 3451574da8SJijie Shao HBG_DUMP_SPEC_I(HBG_REG_MAC_ID_ADDR), 3551574da8SJijie Shao HBG_DUMP_SPEC_I(HBG_REG_PHY_ID_ADDR), 3651574da8SJijie Shao HBG_DUMP_SPEC_I(HBG_REG_MAC_ADDR_ADDR), 3751574da8SJijie Shao HBG_DUMP_SPEC_I(HBG_REG_MAC_ADDR_HIGH_ADDR), 3851574da8SJijie Shao HBG_DUMP_SPEC_I(HBG_REG_UC_MAC_NUM_ADDR), 3951574da8SJijie Shao HBG_DUMP_SPEC_I(HBG_REG_MDIO_FREQ_ADDR), 4051574da8SJijie Shao HBG_DUMP_SPEC_I(HBG_REG_MAX_MTU_ADDR), 4151574da8SJijie Shao HBG_DUMP_SPEC_I(HBG_REG_MIN_MTU_ADDR), 4251574da8SJijie Shao HBG_DUMP_SPEC_I(HBG_REG_TX_FIFO_NUM_ADDR), 4351574da8SJijie Shao HBG_DUMP_SPEC_I(HBG_REG_RX_FIFO_NUM_ADDR), 4451574da8SJijie Shao HBG_DUMP_SPEC_I(HBG_REG_VLAN_LAYERS_ADDR), 4551574da8SJijie Shao 4651574da8SJijie Shao /* mdio */ 4751574da8SJijie Shao HBG_DUMP_MDIO_I(HBG_REG_MDIO_COMMAND_ADDR), 4851574da8SJijie Shao HBG_DUMP_MDIO_I(HBG_REG_MDIO_ADDR_ADDR), 4951574da8SJijie Shao HBG_DUMP_MDIO_I(HBG_REG_MDIO_WDATA_ADDR), 5051574da8SJijie Shao HBG_DUMP_MDIO_I(HBG_REG_MDIO_RDATA_ADDR), 5151574da8SJijie Shao HBG_DUMP_MDIO_I(HBG_REG_MDIO_STA_ADDR), 5251574da8SJijie Shao 5351574da8SJijie Shao /* gmac */ 5451574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_DUPLEX_TYPE_ADDR), 5551574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_FD_FC_TYPE_ADDR), 5651574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_FC_TX_TIMER_ADDR), 5751574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_FD_FC_ADDR_LOW_ADDR), 5851574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_FD_FC_ADDR_HIGH_ADDR), 5951574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_MAX_FRAME_SIZE_ADDR), 6051574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_PORT_MODE_ADDR), 6151574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_PORT_ENABLE_ADDR), 6251574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_PAUSE_ENABLE_ADDR), 6351574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_AN_NEG_STATE_ADDR), 6451574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_TRANSMIT_CTRL_ADDR), 6551574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_REC_FILT_CTRL_ADDR), 6651574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_LINE_LOOP_BACK_ADDR), 6751574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_CF_CRC_STRIP_ADDR), 6851574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_MODE_CHANGE_EN_ADDR), 6951574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_LOOP_REG_ADDR), 7051574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_RECV_CTRL_ADDR), 7151574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_VLAN_CODE_ADDR), 7251574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_LOW_0_ADDR), 7351574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_HIGH_0_ADDR), 7451574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_LOW_1_ADDR), 7551574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_HIGH_1_ADDR), 7651574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_LOW_2_ADDR), 7751574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_HIGH_2_ADDR), 7851574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_LOW_3_ADDR), 7951574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_HIGH_3_ADDR), 8051574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_LOW_4_ADDR), 8151574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_HIGH_4_ADDR), 8251574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_LOW_5_ADDR), 8351574da8SJijie Shao HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_HIGH_5_ADDR), 8451574da8SJijie Shao 8551574da8SJijie Shao /* pcu */ 8651574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_TX_FIFO_THRSLD_ADDR), 8751574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_RX_FIFO_THRSLD_ADDR), 8851574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_CFG_FIFO_THRSLD_ADDR), 8951574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_CF_INTRPT_MSK_ADDR), 9051574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_CF_INTRPT_STAT_ADDR), 9151574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_CF_INTRPT_CLR_ADDR), 9251574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_TX_BUS_ERR_ADDR_ADDR), 9351574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_RX_BUS_ERR_ADDR_ADDR), 9451574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_MAX_FRAME_LEN_ADDR), 9551574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_DEBUG_ST_MCH_ADDR), 9651574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_FIFO_CURR_STATUS_ADDR), 9751574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_FIFO_HIST_STATUS_ADDR), 9851574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_CF_CFF_DATA_NUM_ADDR), 9951574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_CF_TX_PAUSE_ADDR), 10051574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_RX_CFF_ADDR_ADDR), 10151574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_RX_BUF_SIZE_ADDR), 10251574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_BUS_CTRL_ADDR), 10351574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_RX_CTRL_ADDR), 10451574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_RX_PKT_MODE_ADDR), 10551574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_DBG_ST0_ADDR), 10651574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_DBG_ST1_ADDR), 10751574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_DBG_ST2_ADDR), 10851574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_BUS_RST_EN_ADDR), 10951574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_CF_IND_TXINT_MSK_ADDR), 11051574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_CF_IND_TXINT_STAT_ADDR), 11151574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_CF_IND_TXINT_CLR_ADDR), 11251574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_CF_IND_RXINT_MSK_ADDR), 11351574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_CF_IND_RXINT_STAT_ADDR), 11451574da8SJijie Shao HBG_DUMP_PCU_I(HBG_REG_CF_IND_RXINT_CLR_ADDR), 11551574da8SJijie Shao }; 11651574da8SJijie Shao 11751574da8SJijie Shao static const u32 hbg_dump_type_base_array[] = { 11851574da8SJijie Shao [HBG_DUMP_REG_TYPE_SPEC] = 0, 11951574da8SJijie Shao [HBG_DUMP_REG_TYPE_MDIO] = HBG_REG_MDIO_BASE, 12051574da8SJijie Shao [HBG_DUMP_REG_TYPE_GMAC] = HBG_REG_SGMII_BASE, 12151574da8SJijie Shao [HBG_DUMP_REG_TYPE_PCU] = HBG_REG_SGMII_BASE, 12251574da8SJijie Shao }; 12351574da8SJijie Shao 12451574da8SJijie Shao static int hbg_ethtool_get_regs_len(struct net_device *netdev) 12551574da8SJijie Shao { 12651574da8SJijie Shao return ARRAY_SIZE(hbg_dump_reg_infos) * sizeof(struct hbg_reg_info); 12751574da8SJijie Shao } 12851574da8SJijie Shao 12951574da8SJijie Shao static void hbg_ethtool_get_regs(struct net_device *netdev, 13051574da8SJijie Shao struct ethtool_regs *regs, void *data) 13151574da8SJijie Shao { 13251574da8SJijie Shao struct hbg_priv *priv = netdev_priv(netdev); 13351574da8SJijie Shao struct hbg_reg_info *info; 13451574da8SJijie Shao u32 i, offset = 0; 13551574da8SJijie Shao 13651574da8SJijie Shao regs->version = 0; 13751574da8SJijie Shao for (i = 0; i < ARRAY_SIZE(hbg_dump_reg_infos); i++) { 13851574da8SJijie Shao info = data + offset; 13951574da8SJijie Shao 14051574da8SJijie Shao *info = hbg_dump_reg_infos[i]; 14151574da8SJijie Shao info->val = hbg_reg_read(priv, info->offset); 14251574da8SJijie Shao info->offset -= hbg_dump_type_base_array[info->type]; 14351574da8SJijie Shao 14451574da8SJijie Shao offset += sizeof(*info); 14551574da8SJijie Shao } 14651574da8SJijie Shao } 147e8d13548SJijie Shao 1483a03763fSJijie Shao static void hbg_ethtool_get_pauseparam(struct net_device *net_dev, 1493a03763fSJijie Shao struct ethtool_pauseparam *param) 1503a03763fSJijie Shao { 1513a03763fSJijie Shao struct hbg_priv *priv = netdev_priv(net_dev); 1523a03763fSJijie Shao 1533a03763fSJijie Shao param->autoneg = priv->mac.pause_autoneg; 1543a03763fSJijie Shao hbg_hw_get_pause_enable(priv, ¶m->tx_pause, ¶m->rx_pause); 1553a03763fSJijie Shao } 1563a03763fSJijie Shao 1573a03763fSJijie Shao static int hbg_ethtool_set_pauseparam(struct net_device *net_dev, 1583a03763fSJijie Shao struct ethtool_pauseparam *param) 1593a03763fSJijie Shao { 1603a03763fSJijie Shao struct hbg_priv *priv = netdev_priv(net_dev); 1613a03763fSJijie Shao 1623a03763fSJijie Shao priv->mac.pause_autoneg = param->autoneg; 1633a03763fSJijie Shao phy_set_asym_pause(priv->mac.phydev, param->rx_pause, param->tx_pause); 1643a03763fSJijie Shao 1653a03763fSJijie Shao if (!param->autoneg) 1663a03763fSJijie Shao hbg_hw_set_pause_enable(priv, param->tx_pause, param->rx_pause); 1673a03763fSJijie Shao 1683f5a61f6SJijie Shao priv->user_def.pause_param = *param; 1693a03763fSJijie Shao return 0; 1703a03763fSJijie Shao } 1713a03763fSJijie Shao 1723f5a61f6SJijie Shao static int hbg_ethtool_reset(struct net_device *netdev, u32 *flags) 1733f5a61f6SJijie Shao { 1743f5a61f6SJijie Shao struct hbg_priv *priv = netdev_priv(netdev); 1753f5a61f6SJijie Shao 1763f5a61f6SJijie Shao if (*flags != ETH_RESET_DEDICATED) 1773f5a61f6SJijie Shao return -EOPNOTSUPP; 1783f5a61f6SJijie Shao 1793f5a61f6SJijie Shao *flags = 0; 1803f5a61f6SJijie Shao return hbg_reset(priv); 1813f5a61f6SJijie Shao } 1823f5a61f6SJijie Shao 183e8d13548SJijie Shao static const struct ethtool_ops hbg_ethtool_ops = { 184e8d13548SJijie Shao .get_link = ethtool_op_get_link, 185e8d13548SJijie Shao .get_link_ksettings = phy_ethtool_get_link_ksettings, 186e8d13548SJijie Shao .set_link_ksettings = phy_ethtool_set_link_ksettings, 18751574da8SJijie Shao .get_regs_len = hbg_ethtool_get_regs_len, 18851574da8SJijie Shao .get_regs = hbg_ethtool_get_regs, 1893a03763fSJijie Shao .get_pauseparam = hbg_ethtool_get_pauseparam, 1903a03763fSJijie Shao .set_pauseparam = hbg_ethtool_set_pauseparam, 1913f5a61f6SJijie Shao .reset = hbg_ethtool_reset, 192*adb42b1eSJijie Shao .nway_reset = phy_ethtool_nway_reset, 193e8d13548SJijie Shao }; 194e8d13548SJijie Shao 195e8d13548SJijie Shao void hbg_ethtool_set_ops(struct net_device *netdev) 196e8d13548SJijie Shao { 197e8d13548SJijie Shao netdev->ethtool_ops = &hbg_ethtool_ops; 198e8d13548SJijie Shao } 199