1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2021 Gerhard Engleder <gerhard@engleder-embedded.com> */
3
4 #include "tsnep.h"
5
6 static const char tsnep_stats_strings[][ETH_GSTRING_LEN] = {
7 "rx_packets",
8 "rx_bytes",
9 "rx_dropped",
10 "rx_multicast",
11 "rx_phy_errors",
12 "rx_forwarded_phy_errors",
13 "rx_invalid_frame_errors",
14 "tx_packets",
15 "tx_bytes",
16 "tx_dropped",
17 };
18
19 struct tsnep_stats {
20 u64 rx_packets;
21 u64 rx_bytes;
22 u64 rx_dropped;
23 u64 rx_multicast;
24 u64 rx_phy_errors;
25 u64 rx_forwarded_phy_errors;
26 u64 rx_invalid_frame_errors;
27 u64 tx_packets;
28 u64 tx_bytes;
29 u64 tx_dropped;
30 };
31
32 #define TSNEP_STATS_COUNT (sizeof(struct tsnep_stats) / sizeof(u64))
33
34 static const char tsnep_rx_queue_stats_strings[][ETH_GSTRING_LEN] = {
35 "rx_%d_packets",
36 "rx_%d_bytes",
37 "rx_%d_dropped",
38 "rx_%d_multicast",
39 "rx_%d_no_descriptor_errors",
40 "rx_%d_buffer_too_small_errors",
41 "rx_%d_fifo_overflow_errors",
42 "rx_%d_invalid_frame_errors",
43 };
44
45 struct tsnep_rx_queue_stats {
46 u64 rx_packets;
47 u64 rx_bytes;
48 u64 rx_dropped;
49 u64 rx_multicast;
50 u64 rx_no_descriptor_errors;
51 u64 rx_buffer_too_small_errors;
52 u64 rx_fifo_overflow_errors;
53 u64 rx_invalid_frame_errors;
54 };
55
56 #define TSNEP_RX_QUEUE_STATS_COUNT (sizeof(struct tsnep_rx_queue_stats) / \
57 sizeof(u64))
58
59 static const char tsnep_tx_queue_stats_strings[][ETH_GSTRING_LEN] = {
60 "tx_%d_packets",
61 "tx_%d_bytes",
62 "tx_%d_dropped",
63 };
64
65 struct tsnep_tx_queue_stats {
66 u64 tx_packets;
67 u64 tx_bytes;
68 u64 tx_dropped;
69 };
70
71 #define TSNEP_TX_QUEUE_STATS_COUNT (sizeof(struct tsnep_tx_queue_stats) / \
72 sizeof(u64))
73
tsnep_ethtool_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * drvinfo)74 static void tsnep_ethtool_get_drvinfo(struct net_device *netdev,
75 struct ethtool_drvinfo *drvinfo)
76 {
77 struct tsnep_adapter *adapter = netdev_priv(netdev);
78
79 strscpy(drvinfo->driver, TSNEP, sizeof(drvinfo->driver));
80 strscpy(drvinfo->bus_info, dev_name(&adapter->pdev->dev),
81 sizeof(drvinfo->bus_info));
82 }
83
tsnep_ethtool_get_regs_len(struct net_device * netdev)84 static int tsnep_ethtool_get_regs_len(struct net_device *netdev)
85 {
86 struct tsnep_adapter *adapter = netdev_priv(netdev);
87 int len;
88 int num_additional_queues;
89
90 len = TSNEP_MAC_SIZE;
91
92 /* first queue pair is within TSNEP_MAC_SIZE, only queues additional to
93 * the first queue pair extend the register length by TSNEP_QUEUE_SIZE
94 */
95 num_additional_queues =
96 max(adapter->num_tx_queues, adapter->num_rx_queues) - 1;
97 len += TSNEP_QUEUE_SIZE * num_additional_queues;
98
99 return len;
100 }
101
tsnep_ethtool_get_regs(struct net_device * netdev,struct ethtool_regs * regs,void * p)102 static void tsnep_ethtool_get_regs(struct net_device *netdev,
103 struct ethtool_regs *regs,
104 void *p)
105 {
106 struct tsnep_adapter *adapter = netdev_priv(netdev);
107
108 regs->version = 1;
109
110 memcpy_fromio(p, adapter->addr, regs->len);
111 }
112
tsnep_ethtool_get_msglevel(struct net_device * netdev)113 static u32 tsnep_ethtool_get_msglevel(struct net_device *netdev)
114 {
115 struct tsnep_adapter *adapter = netdev_priv(netdev);
116
117 return adapter->msg_enable;
118 }
119
tsnep_ethtool_set_msglevel(struct net_device * netdev,u32 data)120 static void tsnep_ethtool_set_msglevel(struct net_device *netdev, u32 data)
121 {
122 struct tsnep_adapter *adapter = netdev_priv(netdev);
123
124 adapter->msg_enable = data;
125 }
126
tsnep_ethtool_get_strings(struct net_device * netdev,u32 stringset,u8 * data)127 static void tsnep_ethtool_get_strings(struct net_device *netdev, u32 stringset,
128 u8 *data)
129 {
130 struct tsnep_adapter *adapter = netdev_priv(netdev);
131 int rx_count = adapter->num_rx_queues;
132 int tx_count = adapter->num_tx_queues;
133 int i, j;
134
135 switch (stringset) {
136 case ETH_SS_STATS:
137 memcpy(data, tsnep_stats_strings, sizeof(tsnep_stats_strings));
138 data += sizeof(tsnep_stats_strings);
139
140 for (i = 0; i < rx_count; i++) {
141 for (j = 0; j < TSNEP_RX_QUEUE_STATS_COUNT; j++) {
142 snprintf(data, ETH_GSTRING_LEN,
143 tsnep_rx_queue_stats_strings[j], i);
144 data += ETH_GSTRING_LEN;
145 }
146 }
147
148 for (i = 0; i < tx_count; i++) {
149 for (j = 0; j < TSNEP_TX_QUEUE_STATS_COUNT; j++) {
150 snprintf(data, ETH_GSTRING_LEN,
151 tsnep_tx_queue_stats_strings[j], i);
152 data += ETH_GSTRING_LEN;
153 }
154 }
155 break;
156 case ETH_SS_TEST:
157 tsnep_ethtool_get_test_strings(data);
158 break;
159 }
160 }
161
tsnep_ethtool_get_ethtool_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * data)162 static void tsnep_ethtool_get_ethtool_stats(struct net_device *netdev,
163 struct ethtool_stats *stats,
164 u64 *data)
165 {
166 struct tsnep_adapter *adapter = netdev_priv(netdev);
167 int rx_count = adapter->num_rx_queues;
168 int tx_count = adapter->num_tx_queues;
169 struct tsnep_stats tsnep_stats;
170 struct tsnep_rx_queue_stats tsnep_rx_queue_stats;
171 struct tsnep_tx_queue_stats tsnep_tx_queue_stats;
172 u32 reg;
173 int i;
174
175 memset(&tsnep_stats, 0, sizeof(tsnep_stats));
176 for (i = 0; i < adapter->num_rx_queues; i++) {
177 tsnep_stats.rx_packets += adapter->rx[i].packets;
178 tsnep_stats.rx_bytes += adapter->rx[i].bytes;
179 tsnep_stats.rx_dropped += adapter->rx[i].dropped;
180 tsnep_stats.rx_multicast += adapter->rx[i].multicast;
181 }
182 reg = ioread32(adapter->addr + ECM_STAT);
183 tsnep_stats.rx_phy_errors =
184 (reg & ECM_STAT_RX_ERR_MASK) >> ECM_STAT_RX_ERR_SHIFT;
185 tsnep_stats.rx_forwarded_phy_errors =
186 (reg & ECM_STAT_FWD_RX_ERR_MASK) >> ECM_STAT_FWD_RX_ERR_SHIFT;
187 tsnep_stats.rx_invalid_frame_errors =
188 (reg & ECM_STAT_INV_FRM_MASK) >> ECM_STAT_INV_FRM_SHIFT;
189 for (i = 0; i < adapter->num_tx_queues; i++) {
190 tsnep_stats.tx_packets += adapter->tx[i].packets;
191 tsnep_stats.tx_bytes += adapter->tx[i].bytes;
192 tsnep_stats.tx_dropped += adapter->tx[i].dropped;
193 }
194 memcpy(data, &tsnep_stats, sizeof(tsnep_stats));
195 data += TSNEP_STATS_COUNT;
196
197 for (i = 0; i < rx_count; i++) {
198 memset(&tsnep_rx_queue_stats, 0, sizeof(tsnep_rx_queue_stats));
199 tsnep_rx_queue_stats.rx_packets = adapter->rx[i].packets;
200 tsnep_rx_queue_stats.rx_bytes = adapter->rx[i].bytes;
201 tsnep_rx_queue_stats.rx_dropped = adapter->rx[i].dropped;
202 tsnep_rx_queue_stats.rx_multicast = adapter->rx[i].multicast;
203 reg = ioread32(adapter->addr + TSNEP_QUEUE(i) +
204 TSNEP_RX_STATISTIC);
205 tsnep_rx_queue_stats.rx_no_descriptor_errors =
206 (reg & TSNEP_RX_STATISTIC_NO_DESC_MASK) >>
207 TSNEP_RX_STATISTIC_NO_DESC_SHIFT;
208 tsnep_rx_queue_stats.rx_buffer_too_small_errors =
209 (reg & TSNEP_RX_STATISTIC_BUFFER_TOO_SMALL_MASK) >>
210 TSNEP_RX_STATISTIC_BUFFER_TOO_SMALL_SHIFT;
211 tsnep_rx_queue_stats.rx_fifo_overflow_errors =
212 (reg & TSNEP_RX_STATISTIC_FIFO_OVERFLOW_MASK) >>
213 TSNEP_RX_STATISTIC_FIFO_OVERFLOW_SHIFT;
214 tsnep_rx_queue_stats.rx_invalid_frame_errors =
215 (reg & TSNEP_RX_STATISTIC_INVALID_FRAME_MASK) >>
216 TSNEP_RX_STATISTIC_INVALID_FRAME_SHIFT;
217 memcpy(data, &tsnep_rx_queue_stats,
218 sizeof(tsnep_rx_queue_stats));
219 data += TSNEP_RX_QUEUE_STATS_COUNT;
220 }
221
222 for (i = 0; i < tx_count; i++) {
223 memset(&tsnep_tx_queue_stats, 0, sizeof(tsnep_tx_queue_stats));
224 tsnep_tx_queue_stats.tx_packets += adapter->tx[i].packets;
225 tsnep_tx_queue_stats.tx_bytes += adapter->tx[i].bytes;
226 tsnep_tx_queue_stats.tx_dropped += adapter->tx[i].dropped;
227 memcpy(data, &tsnep_tx_queue_stats,
228 sizeof(tsnep_tx_queue_stats));
229 data += TSNEP_TX_QUEUE_STATS_COUNT;
230 }
231 }
232
tsnep_ethtool_get_sset_count(struct net_device * netdev,int sset)233 static int tsnep_ethtool_get_sset_count(struct net_device *netdev, int sset)
234 {
235 struct tsnep_adapter *adapter = netdev_priv(netdev);
236 int rx_count;
237 int tx_count;
238
239 switch (sset) {
240 case ETH_SS_STATS:
241 rx_count = adapter->num_rx_queues;
242 tx_count = adapter->num_tx_queues;
243 return TSNEP_STATS_COUNT +
244 TSNEP_RX_QUEUE_STATS_COUNT * rx_count +
245 TSNEP_TX_QUEUE_STATS_COUNT * tx_count;
246 case ETH_SS_TEST:
247 return tsnep_ethtool_get_test_count();
248 default:
249 return -EOPNOTSUPP;
250 }
251 }
252
tsnep_ethtool_get_rxnfc(struct net_device * dev,struct ethtool_rxnfc * cmd,u32 * rule_locs)253 static int tsnep_ethtool_get_rxnfc(struct net_device *dev,
254 struct ethtool_rxnfc *cmd, u32 *rule_locs)
255 {
256 struct tsnep_adapter *adapter = netdev_priv(dev);
257
258 switch (cmd->cmd) {
259 case ETHTOOL_GRXRINGS:
260 cmd->data = adapter->num_rx_queues;
261 return 0;
262 case ETHTOOL_GRXCLSRLCNT:
263 cmd->rule_cnt = adapter->rxnfc_count;
264 cmd->data = adapter->rxnfc_max;
265 cmd->data |= RX_CLS_LOC_SPECIAL;
266 return 0;
267 case ETHTOOL_GRXCLSRULE:
268 return tsnep_rxnfc_get_rule(adapter, cmd);
269 case ETHTOOL_GRXCLSRLALL:
270 return tsnep_rxnfc_get_all(adapter, cmd, rule_locs);
271 default:
272 return -EOPNOTSUPP;
273 }
274 }
275
tsnep_ethtool_set_rxnfc(struct net_device * dev,struct ethtool_rxnfc * cmd)276 static int tsnep_ethtool_set_rxnfc(struct net_device *dev,
277 struct ethtool_rxnfc *cmd)
278 {
279 struct tsnep_adapter *adapter = netdev_priv(dev);
280
281 switch (cmd->cmd) {
282 case ETHTOOL_SRXCLSRLINS:
283 return tsnep_rxnfc_add_rule(adapter, cmd);
284 case ETHTOOL_SRXCLSRLDEL:
285 return tsnep_rxnfc_del_rule(adapter, cmd);
286 default:
287 return -EOPNOTSUPP;
288 }
289 }
290
tsnep_ethtool_get_ts_info(struct net_device * dev,struct ethtool_ts_info * info)291 static int tsnep_ethtool_get_ts_info(struct net_device *dev,
292 struct ethtool_ts_info *info)
293 {
294 struct tsnep_adapter *adapter = netdev_priv(dev);
295
296 info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
297 SOF_TIMESTAMPING_RX_SOFTWARE |
298 SOF_TIMESTAMPING_SOFTWARE |
299 SOF_TIMESTAMPING_TX_HARDWARE |
300 SOF_TIMESTAMPING_RX_HARDWARE |
301 SOF_TIMESTAMPING_RAW_HARDWARE;
302
303 if (adapter->ptp_clock)
304 info->phc_index = ptp_clock_index(adapter->ptp_clock);
305 else
306 info->phc_index = -1;
307
308 info->tx_types = BIT(HWTSTAMP_TX_OFF) |
309 BIT(HWTSTAMP_TX_ON);
310 info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
311 BIT(HWTSTAMP_FILTER_ALL);
312
313 return 0;
314 }
315
316 const struct ethtool_ops tsnep_ethtool_ops = {
317 .get_drvinfo = tsnep_ethtool_get_drvinfo,
318 .get_regs_len = tsnep_ethtool_get_regs_len,
319 .get_regs = tsnep_ethtool_get_regs,
320 .get_msglevel = tsnep_ethtool_get_msglevel,
321 .set_msglevel = tsnep_ethtool_set_msglevel,
322 .nway_reset = phy_ethtool_nway_reset,
323 .get_link = ethtool_op_get_link,
324 .self_test = tsnep_ethtool_self_test,
325 .get_strings = tsnep_ethtool_get_strings,
326 .get_ethtool_stats = tsnep_ethtool_get_ethtool_stats,
327 .get_sset_count = tsnep_ethtool_get_sset_count,
328 .get_rxnfc = tsnep_ethtool_get_rxnfc,
329 .set_rxnfc = tsnep_ethtool_set_rxnfc,
330 .get_ts_info = tsnep_ethtool_get_ts_info,
331 .get_link_ksettings = phy_ethtool_get_link_ksettings,
332 .set_link_ksettings = phy_ethtool_set_link_ksettings,
333 };
334