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
hbg_ethtool_get_regs_len(struct net_device * netdev)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
hbg_ethtool_get_regs(struct net_device * netdev,struct ethtool_regs * regs,void * data)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
hbg_ethtool_get_pauseparam(struct net_device * net_dev,struct ethtool_pauseparam * param)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
hbg_ethtool_set_pauseparam(struct net_device * net_dev,struct ethtool_pauseparam * param)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
hbg_ethtool_reset(struct net_device * netdev,u32 * flags)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
hbg_ethtool_set_ops(struct net_device * netdev)195 void hbg_ethtool_set_ops(struct net_device *netdev)
196 {
197 netdev->ethtool_ops = &hbg_ethtool_ops;
198 }
199