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_alloc_failed",
12 "rx_phy_errors",
13 "rx_forwarded_phy_errors",
14 "rx_invalid_frame_errors",
15 "tx_packets",
16 "tx_bytes",
17 "tx_dropped",
18 };
19
20 struct tsnep_stats {
21 u64 rx_packets;
22 u64 rx_bytes;
23 u64 rx_dropped;
24 u64 rx_multicast;
25 u64 rx_alloc_failed;
26 u64 rx_phy_errors;
27 u64 rx_forwarded_phy_errors;
28 u64 rx_invalid_frame_errors;
29 u64 tx_packets;
30 u64 tx_bytes;
31 u64 tx_dropped;
32 };
33
34 #define TSNEP_STATS_COUNT (sizeof(struct tsnep_stats) / sizeof(u64))
35
36 static const char tsnep_rx_queue_stats_strings[][ETH_GSTRING_LEN] = {
37 "rx_%d_packets",
38 "rx_%d_bytes",
39 "rx_%d_dropped",
40 "rx_%d_multicast",
41 "rx_%d_alloc_failed",
42 "rx_%d_no_descriptor_errors",
43 "rx_%d_buffer_too_small_errors",
44 "rx_%d_fifo_overflow_errors",
45 "rx_%d_invalid_frame_errors",
46 };
47
48 struct tsnep_rx_queue_stats {
49 u64 rx_packets;
50 u64 rx_bytes;
51 u64 rx_dropped;
52 u64 rx_multicast;
53 u64 rx_alloc_failed;
54 u64 rx_no_descriptor_errors;
55 u64 rx_buffer_too_small_errors;
56 u64 rx_fifo_overflow_errors;
57 u64 rx_invalid_frame_errors;
58 };
59
60 #define TSNEP_RX_QUEUE_STATS_COUNT (sizeof(struct tsnep_rx_queue_stats) / \
61 sizeof(u64))
62
63 static const char tsnep_tx_queue_stats_strings[][ETH_GSTRING_LEN] = {
64 "tx_%d_packets",
65 "tx_%d_bytes",
66 "tx_%d_dropped",
67 };
68
69 struct tsnep_tx_queue_stats {
70 u64 tx_packets;
71 u64 tx_bytes;
72 u64 tx_dropped;
73 };
74
75 #define TSNEP_TX_QUEUE_STATS_COUNT (sizeof(struct tsnep_tx_queue_stats) / \
76 sizeof(u64))
77
tsnep_ethtool_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * drvinfo)78 static void tsnep_ethtool_get_drvinfo(struct net_device *netdev,
79 struct ethtool_drvinfo *drvinfo)
80 {
81 struct tsnep_adapter *adapter = netdev_priv(netdev);
82
83 strscpy(drvinfo->driver, TSNEP, sizeof(drvinfo->driver));
84 strscpy(drvinfo->bus_info, dev_name(&adapter->pdev->dev),
85 sizeof(drvinfo->bus_info));
86 }
87
tsnep_ethtool_get_regs_len(struct net_device * netdev)88 static int tsnep_ethtool_get_regs_len(struct net_device *netdev)
89 {
90 struct tsnep_adapter *adapter = netdev_priv(netdev);
91 int len;
92 int num_additional_queues;
93
94 len = TSNEP_MAC_SIZE;
95
96 /* first queue pair is within TSNEP_MAC_SIZE, only queues additional to
97 * the first queue pair extend the register length by TSNEP_QUEUE_SIZE
98 */
99 num_additional_queues =
100 max(adapter->num_tx_queues, adapter->num_rx_queues) - 1;
101 len += TSNEP_QUEUE_SIZE * num_additional_queues;
102
103 return len;
104 }
105
tsnep_ethtool_get_regs(struct net_device * netdev,struct ethtool_regs * regs,void * p)106 static void tsnep_ethtool_get_regs(struct net_device *netdev,
107 struct ethtool_regs *regs,
108 void *p)
109 {
110 struct tsnep_adapter *adapter = netdev_priv(netdev);
111
112 regs->version = 1;
113
114 memcpy_fromio(p, adapter->addr, regs->len);
115 }
116
tsnep_ethtool_get_msglevel(struct net_device * netdev)117 static u32 tsnep_ethtool_get_msglevel(struct net_device *netdev)
118 {
119 struct tsnep_adapter *adapter = netdev_priv(netdev);
120
121 return adapter->msg_enable;
122 }
123
tsnep_ethtool_set_msglevel(struct net_device * netdev,u32 data)124 static void tsnep_ethtool_set_msglevel(struct net_device *netdev, u32 data)
125 {
126 struct tsnep_adapter *adapter = netdev_priv(netdev);
127
128 adapter->msg_enable = data;
129 }
130
tsnep_ethtool_get_strings(struct net_device * netdev,u32 stringset,u8 * data)131 static void tsnep_ethtool_get_strings(struct net_device *netdev, u32 stringset,
132 u8 *data)
133 {
134 struct tsnep_adapter *adapter = netdev_priv(netdev);
135 int rx_count = adapter->num_rx_queues;
136 int tx_count = adapter->num_tx_queues;
137 int i, j;
138
139 switch (stringset) {
140 case ETH_SS_STATS:
141 memcpy(data, tsnep_stats_strings, sizeof(tsnep_stats_strings));
142 data += sizeof(tsnep_stats_strings);
143
144 for (i = 0; i < rx_count; i++) {
145 for (j = 0; j < TSNEP_RX_QUEUE_STATS_COUNT; j++) {
146 snprintf(data, ETH_GSTRING_LEN,
147 tsnep_rx_queue_stats_strings[j], i);
148 data += ETH_GSTRING_LEN;
149 }
150 }
151
152 for (i = 0; i < tx_count; i++) {
153 for (j = 0; j < TSNEP_TX_QUEUE_STATS_COUNT; j++) {
154 snprintf(data, ETH_GSTRING_LEN,
155 tsnep_tx_queue_stats_strings[j], i);
156 data += ETH_GSTRING_LEN;
157 }
158 }
159 break;
160 case ETH_SS_TEST:
161 tsnep_ethtool_get_test_strings(data);
162 break;
163 }
164 }
165
tsnep_ethtool_get_ethtool_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * data)166 static void tsnep_ethtool_get_ethtool_stats(struct net_device *netdev,
167 struct ethtool_stats *stats,
168 u64 *data)
169 {
170 struct tsnep_adapter *adapter = netdev_priv(netdev);
171 int rx_count = adapter->num_rx_queues;
172 int tx_count = adapter->num_tx_queues;
173 struct tsnep_stats tsnep_stats;
174 struct tsnep_rx_queue_stats tsnep_rx_queue_stats;
175 struct tsnep_tx_queue_stats tsnep_tx_queue_stats;
176 u32 reg;
177 int i;
178
179 memset(&tsnep_stats, 0, sizeof(tsnep_stats));
180 for (i = 0; i < adapter->num_rx_queues; i++) {
181 tsnep_stats.rx_packets += adapter->rx[i].packets;
182 tsnep_stats.rx_bytes += adapter->rx[i].bytes;
183 tsnep_stats.rx_dropped += adapter->rx[i].dropped;
184 tsnep_stats.rx_multicast += adapter->rx[i].multicast;
185 tsnep_stats.rx_alloc_failed += adapter->rx[i].alloc_failed;
186 }
187 reg = ioread32(adapter->addr + ECM_STAT);
188 tsnep_stats.rx_phy_errors =
189 (reg & ECM_STAT_RX_ERR_MASK) >> ECM_STAT_RX_ERR_SHIFT;
190 tsnep_stats.rx_forwarded_phy_errors =
191 (reg & ECM_STAT_FWD_RX_ERR_MASK) >> ECM_STAT_FWD_RX_ERR_SHIFT;
192 tsnep_stats.rx_invalid_frame_errors =
193 (reg & ECM_STAT_INV_FRM_MASK) >> ECM_STAT_INV_FRM_SHIFT;
194 for (i = 0; i < adapter->num_tx_queues; i++) {
195 tsnep_stats.tx_packets += adapter->tx[i].packets;
196 tsnep_stats.tx_bytes += adapter->tx[i].bytes;
197 tsnep_stats.tx_dropped += adapter->tx[i].dropped;
198 }
199 memcpy(data, &tsnep_stats, sizeof(tsnep_stats));
200 data += TSNEP_STATS_COUNT;
201
202 for (i = 0; i < rx_count; i++) {
203 memset(&tsnep_rx_queue_stats, 0, sizeof(tsnep_rx_queue_stats));
204 tsnep_rx_queue_stats.rx_packets = adapter->rx[i].packets;
205 tsnep_rx_queue_stats.rx_bytes = adapter->rx[i].bytes;
206 tsnep_rx_queue_stats.rx_dropped = adapter->rx[i].dropped;
207 tsnep_rx_queue_stats.rx_multicast = adapter->rx[i].multicast;
208 tsnep_rx_queue_stats.rx_alloc_failed =
209 adapter->rx[i].alloc_failed;
210 reg = ioread32(adapter->addr + TSNEP_QUEUE(i) +
211 TSNEP_RX_STATISTIC);
212 tsnep_rx_queue_stats.rx_no_descriptor_errors =
213 (reg & TSNEP_RX_STATISTIC_NO_DESC_MASK) >>
214 TSNEP_RX_STATISTIC_NO_DESC_SHIFT;
215 tsnep_rx_queue_stats.rx_buffer_too_small_errors =
216 (reg & TSNEP_RX_STATISTIC_BUFFER_TOO_SMALL_MASK) >>
217 TSNEP_RX_STATISTIC_BUFFER_TOO_SMALL_SHIFT;
218 tsnep_rx_queue_stats.rx_fifo_overflow_errors =
219 (reg & TSNEP_RX_STATISTIC_FIFO_OVERFLOW_MASK) >>
220 TSNEP_RX_STATISTIC_FIFO_OVERFLOW_SHIFT;
221 tsnep_rx_queue_stats.rx_invalid_frame_errors =
222 (reg & TSNEP_RX_STATISTIC_INVALID_FRAME_MASK) >>
223 TSNEP_RX_STATISTIC_INVALID_FRAME_SHIFT;
224 memcpy(data, &tsnep_rx_queue_stats,
225 sizeof(tsnep_rx_queue_stats));
226 data += TSNEP_RX_QUEUE_STATS_COUNT;
227 }
228
229 for (i = 0; i < tx_count; i++) {
230 memset(&tsnep_tx_queue_stats, 0, sizeof(tsnep_tx_queue_stats));
231 tsnep_tx_queue_stats.tx_packets += adapter->tx[i].packets;
232 tsnep_tx_queue_stats.tx_bytes += adapter->tx[i].bytes;
233 tsnep_tx_queue_stats.tx_dropped += adapter->tx[i].dropped;
234 memcpy(data, &tsnep_tx_queue_stats,
235 sizeof(tsnep_tx_queue_stats));
236 data += TSNEP_TX_QUEUE_STATS_COUNT;
237 }
238 }
239
tsnep_ethtool_get_sset_count(struct net_device * netdev,int sset)240 static int tsnep_ethtool_get_sset_count(struct net_device *netdev, int sset)
241 {
242 struct tsnep_adapter *adapter = netdev_priv(netdev);
243 int rx_count;
244 int tx_count;
245
246 switch (sset) {
247 case ETH_SS_STATS:
248 rx_count = adapter->num_rx_queues;
249 tx_count = adapter->num_tx_queues;
250 return TSNEP_STATS_COUNT +
251 TSNEP_RX_QUEUE_STATS_COUNT * rx_count +
252 TSNEP_TX_QUEUE_STATS_COUNT * tx_count;
253 case ETH_SS_TEST:
254 return tsnep_ethtool_get_test_count();
255 default:
256 return -EOPNOTSUPP;
257 }
258 }
259
tsnep_ethtool_get_rxnfc(struct net_device * netdev,struct ethtool_rxnfc * cmd,u32 * rule_locs)260 static int tsnep_ethtool_get_rxnfc(struct net_device *netdev,
261 struct ethtool_rxnfc *cmd, u32 *rule_locs)
262 {
263 struct tsnep_adapter *adapter = netdev_priv(netdev);
264
265 switch (cmd->cmd) {
266 case ETHTOOL_GRXRINGS:
267 cmd->data = adapter->num_rx_queues;
268 return 0;
269 case ETHTOOL_GRXCLSRLCNT:
270 cmd->rule_cnt = adapter->rxnfc_count;
271 cmd->data = adapter->rxnfc_max;
272 cmd->data |= RX_CLS_LOC_SPECIAL;
273 return 0;
274 case ETHTOOL_GRXCLSRULE:
275 return tsnep_rxnfc_get_rule(adapter, cmd);
276 case ETHTOOL_GRXCLSRLALL:
277 return tsnep_rxnfc_get_all(adapter, cmd, rule_locs);
278 default:
279 return -EOPNOTSUPP;
280 }
281 }
282
tsnep_ethtool_set_rxnfc(struct net_device * netdev,struct ethtool_rxnfc * cmd)283 static int tsnep_ethtool_set_rxnfc(struct net_device *netdev,
284 struct ethtool_rxnfc *cmd)
285 {
286 struct tsnep_adapter *adapter = netdev_priv(netdev);
287
288 switch (cmd->cmd) {
289 case ETHTOOL_SRXCLSRLINS:
290 return tsnep_rxnfc_add_rule(adapter, cmd);
291 case ETHTOOL_SRXCLSRLDEL:
292 return tsnep_rxnfc_del_rule(adapter, cmd);
293 default:
294 return -EOPNOTSUPP;
295 }
296 }
297
tsnep_ethtool_get_channels(struct net_device * netdev,struct ethtool_channels * ch)298 static void tsnep_ethtool_get_channels(struct net_device *netdev,
299 struct ethtool_channels *ch)
300 {
301 struct tsnep_adapter *adapter = netdev_priv(netdev);
302
303 ch->max_combined = adapter->num_queues;
304 ch->combined_count = adapter->num_queues;
305 }
306
tsnep_ethtool_get_ts_info(struct net_device * netdev,struct kernel_ethtool_ts_info * info)307 static int tsnep_ethtool_get_ts_info(struct net_device *netdev,
308 struct kernel_ethtool_ts_info *info)
309 {
310 struct tsnep_adapter *adapter = netdev_priv(netdev);
311
312 info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
313 SOF_TIMESTAMPING_TX_HARDWARE |
314 SOF_TIMESTAMPING_RX_HARDWARE |
315 SOF_TIMESTAMPING_RAW_HARDWARE;
316
317 if (adapter->ptp_clock)
318 info->phc_index = ptp_clock_index(adapter->ptp_clock);
319
320 info->tx_types = BIT(HWTSTAMP_TX_OFF) |
321 BIT(HWTSTAMP_TX_ON);
322 info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
323 BIT(HWTSTAMP_FILTER_ALL);
324
325 return 0;
326 }
327
tsnep_get_queue_with_tx(struct tsnep_adapter * adapter,int index)328 static struct tsnep_queue *tsnep_get_queue_with_tx(struct tsnep_adapter *adapter,
329 int index)
330 {
331 int i;
332
333 for (i = 0; i < adapter->num_queues; i++) {
334 if (adapter->queue[i].tx) {
335 if (index == 0)
336 return &adapter->queue[i];
337
338 index--;
339 }
340 }
341
342 return NULL;
343 }
344
tsnep_get_queue_with_rx(struct tsnep_adapter * adapter,int index)345 static struct tsnep_queue *tsnep_get_queue_with_rx(struct tsnep_adapter *adapter,
346 int index)
347 {
348 int i;
349
350 for (i = 0; i < adapter->num_queues; i++) {
351 if (adapter->queue[i].rx) {
352 if (index == 0)
353 return &adapter->queue[i];
354
355 index--;
356 }
357 }
358
359 return NULL;
360 }
361
tsnep_ethtool_get_coalesce(struct net_device * netdev,struct ethtool_coalesce * ec,struct kernel_ethtool_coalesce * kernel_coal,struct netlink_ext_ack * extack)362 static int tsnep_ethtool_get_coalesce(struct net_device *netdev,
363 struct ethtool_coalesce *ec,
364 struct kernel_ethtool_coalesce *kernel_coal,
365 struct netlink_ext_ack *extack)
366 {
367 struct tsnep_adapter *adapter = netdev_priv(netdev);
368 struct tsnep_queue *queue;
369
370 queue = tsnep_get_queue_with_rx(adapter, 0);
371 if (queue)
372 ec->rx_coalesce_usecs = tsnep_get_irq_coalesce(queue);
373
374 queue = tsnep_get_queue_with_tx(adapter, 0);
375 if (queue)
376 ec->tx_coalesce_usecs = tsnep_get_irq_coalesce(queue);
377
378 return 0;
379 }
380
tsnep_ethtool_set_coalesce(struct net_device * netdev,struct ethtool_coalesce * ec,struct kernel_ethtool_coalesce * kernel_coal,struct netlink_ext_ack * extack)381 static int tsnep_ethtool_set_coalesce(struct net_device *netdev,
382 struct ethtool_coalesce *ec,
383 struct kernel_ethtool_coalesce *kernel_coal,
384 struct netlink_ext_ack *extack)
385 {
386 struct tsnep_adapter *adapter = netdev_priv(netdev);
387 int i;
388 int retval;
389
390 for (i = 0; i < adapter->num_queues; i++) {
391 /* RX coalesce has priority for queues with TX and RX */
392 if (adapter->queue[i].rx)
393 retval = tsnep_set_irq_coalesce(&adapter->queue[i],
394 ec->rx_coalesce_usecs);
395 else
396 retval = tsnep_set_irq_coalesce(&adapter->queue[i],
397 ec->tx_coalesce_usecs);
398 if (retval != 0)
399 return retval;
400 }
401
402 return 0;
403 }
404
tsnep_ethtool_get_per_queue_coalesce(struct net_device * netdev,u32 queue,struct ethtool_coalesce * ec)405 static int tsnep_ethtool_get_per_queue_coalesce(struct net_device *netdev,
406 u32 queue,
407 struct ethtool_coalesce *ec)
408 {
409 struct tsnep_adapter *adapter = netdev_priv(netdev);
410 struct tsnep_queue *queue_with_rx;
411 struct tsnep_queue *queue_with_tx;
412
413 if (queue >= max(adapter->num_tx_queues, adapter->num_rx_queues))
414 return -EINVAL;
415
416 queue_with_rx = tsnep_get_queue_with_rx(adapter, queue);
417 if (queue_with_rx)
418 ec->rx_coalesce_usecs = tsnep_get_irq_coalesce(queue_with_rx);
419
420 queue_with_tx = tsnep_get_queue_with_tx(adapter, queue);
421 if (queue_with_tx)
422 ec->tx_coalesce_usecs = tsnep_get_irq_coalesce(queue_with_tx);
423
424 return 0;
425 }
426
tsnep_ethtool_set_per_queue_coalesce(struct net_device * netdev,u32 queue,struct ethtool_coalesce * ec)427 static int tsnep_ethtool_set_per_queue_coalesce(struct net_device *netdev,
428 u32 queue,
429 struct ethtool_coalesce *ec)
430 {
431 struct tsnep_adapter *adapter = netdev_priv(netdev);
432 struct tsnep_queue *queue_with_rx;
433 struct tsnep_queue *queue_with_tx;
434 int retval;
435
436 if (queue >= max(adapter->num_tx_queues, adapter->num_rx_queues))
437 return -EINVAL;
438
439 queue_with_rx = tsnep_get_queue_with_rx(adapter, queue);
440 if (queue_with_rx) {
441 retval = tsnep_set_irq_coalesce(queue_with_rx, ec->rx_coalesce_usecs);
442 if (retval != 0)
443 return retval;
444 }
445
446 /* RX coalesce has priority for queues with TX and RX */
447 queue_with_tx = tsnep_get_queue_with_tx(adapter, queue);
448 if (queue_with_tx && !queue_with_tx->rx) {
449 retval = tsnep_set_irq_coalesce(queue_with_tx, ec->tx_coalesce_usecs);
450 if (retval != 0)
451 return retval;
452 }
453
454 return 0;
455 }
456
457 const struct ethtool_ops tsnep_ethtool_ops = {
458 .supported_coalesce_params = ETHTOOL_COALESCE_USECS,
459 .get_drvinfo = tsnep_ethtool_get_drvinfo,
460 .get_regs_len = tsnep_ethtool_get_regs_len,
461 .get_regs = tsnep_ethtool_get_regs,
462 .get_msglevel = tsnep_ethtool_get_msglevel,
463 .set_msglevel = tsnep_ethtool_set_msglevel,
464 .nway_reset = phy_ethtool_nway_reset,
465 .get_link = ethtool_op_get_link,
466 .self_test = tsnep_ethtool_self_test,
467 .get_strings = tsnep_ethtool_get_strings,
468 .get_ethtool_stats = tsnep_ethtool_get_ethtool_stats,
469 .get_sset_count = tsnep_ethtool_get_sset_count,
470 .get_rxnfc = tsnep_ethtool_get_rxnfc,
471 .set_rxnfc = tsnep_ethtool_set_rxnfc,
472 .get_channels = tsnep_ethtool_get_channels,
473 .get_ts_info = tsnep_ethtool_get_ts_info,
474 .get_coalesce = tsnep_ethtool_get_coalesce,
475 .set_coalesce = tsnep_ethtool_set_coalesce,
476 .get_per_queue_coalesce = tsnep_ethtool_get_per_queue_coalesce,
477 .set_per_queue_coalesce = tsnep_ethtool_set_per_queue_coalesce,
478 .get_link_ksettings = phy_ethtool_get_link_ksettings,
479 .set_link_ksettings = phy_ethtool_set_link_ksettings,
480 };
481