1 // SPDX-License-Identifier: GPL-2.0+ 2 // Copyright (c) 2024 Hisilicon Limited. 3 4 #include <linux/ethtool.h> 5 #include <linux/phy.h> 6 #include <linux/rtnetlink.h> 7 #include "hbg_common.h" 8 #include "hbg_err.h" 9 #include "hbg_ethtool.h" 10 #include "hbg_hw.h" 11 12 enum hbg_reg_dump_type { 13 HBG_DUMP_REG_TYPE_SPEC = 0, 14 HBG_DUMP_REG_TYPE_MDIO, 15 HBG_DUMP_REG_TYPE_GMAC, 16 HBG_DUMP_REG_TYPE_PCU, 17 }; 18 19 struct hbg_reg_info { 20 u32 type; 21 u32 offset; 22 u32 val; 23 }; 24 25 #define HBG_DUMP_SPEC_I(offset) {HBG_DUMP_REG_TYPE_SPEC, offset, 0} 26 #define HBG_DUMP_MDIO_I(offset) {HBG_DUMP_REG_TYPE_MDIO, offset, 0} 27 #define HBG_DUMP_GMAC_I(offset) {HBG_DUMP_REG_TYPE_GMAC, offset, 0} 28 #define HBG_DUMP_PCU_I(offset) {HBG_DUMP_REG_TYPE_PCU, offset, 0} 29 30 static const struct hbg_reg_info hbg_dump_reg_infos[] = { 31 /* dev specs */ 32 HBG_DUMP_SPEC_I(HBG_REG_SPEC_VALID_ADDR), 33 HBG_DUMP_SPEC_I(HBG_REG_EVENT_REQ_ADDR), 34 HBG_DUMP_SPEC_I(HBG_REG_MAC_ID_ADDR), 35 HBG_DUMP_SPEC_I(HBG_REG_PHY_ID_ADDR), 36 HBG_DUMP_SPEC_I(HBG_REG_MAC_ADDR_ADDR), 37 HBG_DUMP_SPEC_I(HBG_REG_MAC_ADDR_HIGH_ADDR), 38 HBG_DUMP_SPEC_I(HBG_REG_UC_MAC_NUM_ADDR), 39 HBG_DUMP_SPEC_I(HBG_REG_MDIO_FREQ_ADDR), 40 HBG_DUMP_SPEC_I(HBG_REG_MAX_MTU_ADDR), 41 HBG_DUMP_SPEC_I(HBG_REG_MIN_MTU_ADDR), 42 HBG_DUMP_SPEC_I(HBG_REG_TX_FIFO_NUM_ADDR), 43 HBG_DUMP_SPEC_I(HBG_REG_RX_FIFO_NUM_ADDR), 44 HBG_DUMP_SPEC_I(HBG_REG_VLAN_LAYERS_ADDR), 45 46 /* mdio */ 47 HBG_DUMP_MDIO_I(HBG_REG_MDIO_COMMAND_ADDR), 48 HBG_DUMP_MDIO_I(HBG_REG_MDIO_ADDR_ADDR), 49 HBG_DUMP_MDIO_I(HBG_REG_MDIO_WDATA_ADDR), 50 HBG_DUMP_MDIO_I(HBG_REG_MDIO_RDATA_ADDR), 51 HBG_DUMP_MDIO_I(HBG_REG_MDIO_STA_ADDR), 52 53 /* gmac */ 54 HBG_DUMP_GMAC_I(HBG_REG_DUPLEX_TYPE_ADDR), 55 HBG_DUMP_GMAC_I(HBG_REG_FD_FC_TYPE_ADDR), 56 HBG_DUMP_GMAC_I(HBG_REG_FC_TX_TIMER_ADDR), 57 HBG_DUMP_GMAC_I(HBG_REG_FD_FC_ADDR_LOW_ADDR), 58 HBG_DUMP_GMAC_I(HBG_REG_FD_FC_ADDR_HIGH_ADDR), 59 HBG_DUMP_GMAC_I(HBG_REG_MAX_FRAME_SIZE_ADDR), 60 HBG_DUMP_GMAC_I(HBG_REG_PORT_MODE_ADDR), 61 HBG_DUMP_GMAC_I(HBG_REG_PORT_ENABLE_ADDR), 62 HBG_DUMP_GMAC_I(HBG_REG_PAUSE_ENABLE_ADDR), 63 HBG_DUMP_GMAC_I(HBG_REG_AN_NEG_STATE_ADDR), 64 HBG_DUMP_GMAC_I(HBG_REG_TRANSMIT_CTRL_ADDR), 65 HBG_DUMP_GMAC_I(HBG_REG_REC_FILT_CTRL_ADDR), 66 HBG_DUMP_GMAC_I(HBG_REG_LINE_LOOP_BACK_ADDR), 67 HBG_DUMP_GMAC_I(HBG_REG_CF_CRC_STRIP_ADDR), 68 HBG_DUMP_GMAC_I(HBG_REG_MODE_CHANGE_EN_ADDR), 69 HBG_DUMP_GMAC_I(HBG_REG_LOOP_REG_ADDR), 70 HBG_DUMP_GMAC_I(HBG_REG_RECV_CTRL_ADDR), 71 HBG_DUMP_GMAC_I(HBG_REG_VLAN_CODE_ADDR), 72 HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_LOW_0_ADDR), 73 HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_HIGH_0_ADDR), 74 HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_LOW_1_ADDR), 75 HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_HIGH_1_ADDR), 76 HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_LOW_2_ADDR), 77 HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_HIGH_2_ADDR), 78 HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_LOW_3_ADDR), 79 HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_HIGH_3_ADDR), 80 HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_LOW_4_ADDR), 81 HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_HIGH_4_ADDR), 82 HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_LOW_5_ADDR), 83 HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_HIGH_5_ADDR), 84 85 /* pcu */ 86 HBG_DUMP_PCU_I(HBG_REG_TX_FIFO_THRSLD_ADDR), 87 HBG_DUMP_PCU_I(HBG_REG_RX_FIFO_THRSLD_ADDR), 88 HBG_DUMP_PCU_I(HBG_REG_CFG_FIFO_THRSLD_ADDR), 89 HBG_DUMP_PCU_I(HBG_REG_CF_INTRPT_MSK_ADDR), 90 HBG_DUMP_PCU_I(HBG_REG_CF_INTRPT_STAT_ADDR), 91 HBG_DUMP_PCU_I(HBG_REG_CF_INTRPT_CLR_ADDR), 92 HBG_DUMP_PCU_I(HBG_REG_TX_BUS_ERR_ADDR_ADDR), 93 HBG_DUMP_PCU_I(HBG_REG_RX_BUS_ERR_ADDR_ADDR), 94 HBG_DUMP_PCU_I(HBG_REG_MAX_FRAME_LEN_ADDR), 95 HBG_DUMP_PCU_I(HBG_REG_DEBUG_ST_MCH_ADDR), 96 HBG_DUMP_PCU_I(HBG_REG_FIFO_CURR_STATUS_ADDR), 97 HBG_DUMP_PCU_I(HBG_REG_FIFO_HIST_STATUS_ADDR), 98 HBG_DUMP_PCU_I(HBG_REG_CF_CFF_DATA_NUM_ADDR), 99 HBG_DUMP_PCU_I(HBG_REG_CF_TX_PAUSE_ADDR), 100 HBG_DUMP_PCU_I(HBG_REG_RX_CFF_ADDR_ADDR), 101 HBG_DUMP_PCU_I(HBG_REG_RX_BUF_SIZE_ADDR), 102 HBG_DUMP_PCU_I(HBG_REG_BUS_CTRL_ADDR), 103 HBG_DUMP_PCU_I(HBG_REG_RX_CTRL_ADDR), 104 HBG_DUMP_PCU_I(HBG_REG_RX_PKT_MODE_ADDR), 105 HBG_DUMP_PCU_I(HBG_REG_DBG_ST0_ADDR), 106 HBG_DUMP_PCU_I(HBG_REG_DBG_ST1_ADDR), 107 HBG_DUMP_PCU_I(HBG_REG_DBG_ST2_ADDR), 108 HBG_DUMP_PCU_I(HBG_REG_BUS_RST_EN_ADDR), 109 HBG_DUMP_PCU_I(HBG_REG_CF_IND_TXINT_MSK_ADDR), 110 HBG_DUMP_PCU_I(HBG_REG_CF_IND_TXINT_STAT_ADDR), 111 HBG_DUMP_PCU_I(HBG_REG_CF_IND_TXINT_CLR_ADDR), 112 HBG_DUMP_PCU_I(HBG_REG_CF_IND_RXINT_MSK_ADDR), 113 HBG_DUMP_PCU_I(HBG_REG_CF_IND_RXINT_STAT_ADDR), 114 HBG_DUMP_PCU_I(HBG_REG_CF_IND_RXINT_CLR_ADDR), 115 }; 116 117 static const u32 hbg_dump_type_base_array[] = { 118 [HBG_DUMP_REG_TYPE_SPEC] = 0, 119 [HBG_DUMP_REG_TYPE_MDIO] = HBG_REG_MDIO_BASE, 120 [HBG_DUMP_REG_TYPE_GMAC] = HBG_REG_SGMII_BASE, 121 [HBG_DUMP_REG_TYPE_PCU] = HBG_REG_SGMII_BASE, 122 }; 123 124 static int hbg_ethtool_get_regs_len(struct net_device *netdev) 125 { 126 return ARRAY_SIZE(hbg_dump_reg_infos) * sizeof(struct hbg_reg_info); 127 } 128 129 static void hbg_ethtool_get_regs(struct net_device *netdev, 130 struct ethtool_regs *regs, void *data) 131 { 132 struct hbg_priv *priv = netdev_priv(netdev); 133 struct hbg_reg_info *info; 134 u32 i, offset = 0; 135 136 regs->version = 0; 137 for (i = 0; i < ARRAY_SIZE(hbg_dump_reg_infos); i++) { 138 info = data + offset; 139 140 *info = hbg_dump_reg_infos[i]; 141 info->val = hbg_reg_read(priv, info->offset); 142 info->offset -= hbg_dump_type_base_array[info->type]; 143 144 offset += sizeof(*info); 145 } 146 } 147 148 static void hbg_ethtool_get_pauseparam(struct net_device *net_dev, 149 struct ethtool_pauseparam *param) 150 { 151 struct hbg_priv *priv = netdev_priv(net_dev); 152 153 param->autoneg = priv->mac.pause_autoneg; 154 hbg_hw_get_pause_enable(priv, ¶m->tx_pause, ¶m->rx_pause); 155 } 156 157 static int hbg_ethtool_set_pauseparam(struct net_device *net_dev, 158 struct ethtool_pauseparam *param) 159 { 160 struct hbg_priv *priv = netdev_priv(net_dev); 161 162 priv->mac.pause_autoneg = param->autoneg; 163 phy_set_asym_pause(priv->mac.phydev, param->rx_pause, param->tx_pause); 164 165 if (!param->autoneg) 166 hbg_hw_set_pause_enable(priv, param->tx_pause, param->rx_pause); 167 168 priv->user_def.pause_param = *param; 169 return 0; 170 } 171 172 static int hbg_ethtool_reset(struct net_device *netdev, u32 *flags) 173 { 174 struct hbg_priv *priv = netdev_priv(netdev); 175 176 if (*flags != ETH_RESET_DEDICATED) 177 return -EOPNOTSUPP; 178 179 *flags = 0; 180 return hbg_reset(priv); 181 } 182 183 static const struct ethtool_ops hbg_ethtool_ops = { 184 .get_link = ethtool_op_get_link, 185 .get_link_ksettings = phy_ethtool_get_link_ksettings, 186 .set_link_ksettings = phy_ethtool_set_link_ksettings, 187 .get_regs_len = hbg_ethtool_get_regs_len, 188 .get_regs = hbg_ethtool_get_regs, 189 .get_pauseparam = hbg_ethtool_get_pauseparam, 190 .set_pauseparam = hbg_ethtool_set_pauseparam, 191 .reset = hbg_ethtool_reset, 192 .nway_reset = phy_ethtool_nway_reset, 193 }; 194 195 void hbg_ethtool_set_ops(struct net_device *netdev) 196 { 197 netdev->ethtool_ops = &hbg_ethtool_ops; 198 } 199