]> Git Repo - linux.git/blob - drivers/net/ethernet/engleder/tsnep_ethtool.c
Linux 6.14-rc3
[linux.git] / drivers / net / ethernet / engleder / tsnep_ethtool.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2021 Gerhard Engleder <[email protected]> */
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 };
This page took 0.063794 seconds and 4 git commands to generate.