powerpc/mm: Avoid calling arch_enter/leave_lazy_mmu() in set_ptes
[platform/kernel/linux-starfive.git] / drivers / net / ethernet / engleder / tsnep_ethtool.c
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
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_rx = adapter->num_rx_queues;
304         ch->max_tx = adapter->num_tx_queues;
305         ch->rx_count = adapter->num_rx_queues;
306         ch->tx_count = adapter->num_tx_queues;
307 }
308
309 static int tsnep_ethtool_get_ts_info(struct net_device *netdev,
310                                      struct ethtool_ts_info *info)
311 {
312         struct tsnep_adapter *adapter = netdev_priv(netdev);
313
314         info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
315                                 SOF_TIMESTAMPING_RX_SOFTWARE |
316                                 SOF_TIMESTAMPING_SOFTWARE |
317                                 SOF_TIMESTAMPING_TX_HARDWARE |
318                                 SOF_TIMESTAMPING_RX_HARDWARE |
319                                 SOF_TIMESTAMPING_RAW_HARDWARE;
320
321         if (adapter->ptp_clock)
322                 info->phc_index = ptp_clock_index(adapter->ptp_clock);
323         else
324                 info->phc_index = -1;
325
326         info->tx_types = BIT(HWTSTAMP_TX_OFF) |
327                          BIT(HWTSTAMP_TX_ON);
328         info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
329                            BIT(HWTSTAMP_FILTER_ALL);
330
331         return 0;
332 }
333
334 static struct tsnep_queue *tsnep_get_queue_with_tx(struct tsnep_adapter *adapter,
335                                                    int index)
336 {
337         int i;
338
339         for (i = 0; i < adapter->num_queues; i++) {
340                 if (adapter->queue[i].tx) {
341                         if (index == 0)
342                                 return &adapter->queue[i];
343
344                         index--;
345                 }
346         }
347
348         return NULL;
349 }
350
351 static struct tsnep_queue *tsnep_get_queue_with_rx(struct tsnep_adapter *adapter,
352                                                    int index)
353 {
354         int i;
355
356         for (i = 0; i < adapter->num_queues; i++) {
357                 if (adapter->queue[i].rx) {
358                         if (index == 0)
359                                 return &adapter->queue[i];
360
361                         index--;
362                 }
363         }
364
365         return NULL;
366 }
367
368 static int tsnep_ethtool_get_coalesce(struct net_device *netdev,
369                                       struct ethtool_coalesce *ec,
370                                       struct kernel_ethtool_coalesce *kernel_coal,
371                                       struct netlink_ext_ack *extack)
372 {
373         struct tsnep_adapter *adapter = netdev_priv(netdev);
374         struct tsnep_queue *queue;
375
376         queue = tsnep_get_queue_with_rx(adapter, 0);
377         if (queue)
378                 ec->rx_coalesce_usecs = tsnep_get_irq_coalesce(queue);
379
380         queue = tsnep_get_queue_with_tx(adapter, 0);
381         if (queue)
382                 ec->tx_coalesce_usecs = tsnep_get_irq_coalesce(queue);
383
384         return 0;
385 }
386
387 static int tsnep_ethtool_set_coalesce(struct net_device *netdev,
388                                       struct ethtool_coalesce *ec,
389                                       struct kernel_ethtool_coalesce *kernel_coal,
390                                       struct netlink_ext_ack *extack)
391 {
392         struct tsnep_adapter *adapter = netdev_priv(netdev);
393         int i;
394         int retval;
395
396         for (i = 0; i < adapter->num_queues; i++) {
397                 /* RX coalesce has priority for queues with TX and RX */
398                 if (adapter->queue[i].rx)
399                         retval = tsnep_set_irq_coalesce(&adapter->queue[i],
400                                                         ec->rx_coalesce_usecs);
401                 else
402                         retval = tsnep_set_irq_coalesce(&adapter->queue[i],
403                                                         ec->tx_coalesce_usecs);
404                 if (retval != 0)
405                         return retval;
406         }
407
408         return 0;
409 }
410
411 static int tsnep_ethtool_get_per_queue_coalesce(struct net_device *netdev,
412                                                 u32 queue,
413                                                 struct ethtool_coalesce *ec)
414 {
415         struct tsnep_adapter *adapter = netdev_priv(netdev);
416         struct tsnep_queue *queue_with_rx;
417         struct tsnep_queue *queue_with_tx;
418
419         if (queue >= max(adapter->num_tx_queues, adapter->num_rx_queues))
420                 return -EINVAL;
421
422         queue_with_rx = tsnep_get_queue_with_rx(adapter, queue);
423         if (queue_with_rx)
424                 ec->rx_coalesce_usecs = tsnep_get_irq_coalesce(queue_with_rx);
425
426         queue_with_tx = tsnep_get_queue_with_tx(adapter, queue);
427         if (queue_with_tx)
428                 ec->tx_coalesce_usecs = tsnep_get_irq_coalesce(queue_with_tx);
429
430         return 0;
431 }
432
433 static int tsnep_ethtool_set_per_queue_coalesce(struct net_device *netdev,
434                                                 u32 queue,
435                                                 struct ethtool_coalesce *ec)
436 {
437         struct tsnep_adapter *adapter = netdev_priv(netdev);
438         struct tsnep_queue *queue_with_rx;
439         struct tsnep_queue *queue_with_tx;
440         int retval;
441
442         if (queue >= max(adapter->num_tx_queues, adapter->num_rx_queues))
443                 return -EINVAL;
444
445         queue_with_rx = tsnep_get_queue_with_rx(adapter, queue);
446         if (queue_with_rx) {
447                 retval = tsnep_set_irq_coalesce(queue_with_rx, ec->rx_coalesce_usecs);
448                 if (retval != 0)
449                         return retval;
450         }
451
452         /* RX coalesce has priority for queues with TX and RX */
453         queue_with_tx = tsnep_get_queue_with_tx(adapter, queue);
454         if (queue_with_tx && !queue_with_tx->rx) {
455                 retval = tsnep_set_irq_coalesce(queue_with_tx, ec->tx_coalesce_usecs);
456                 if (retval != 0)
457                         return retval;
458         }
459
460         return 0;
461 }
462
463 const struct ethtool_ops tsnep_ethtool_ops = {
464         .supported_coalesce_params = ETHTOOL_COALESCE_USECS,
465         .get_drvinfo = tsnep_ethtool_get_drvinfo,
466         .get_regs_len = tsnep_ethtool_get_regs_len,
467         .get_regs = tsnep_ethtool_get_regs,
468         .get_msglevel = tsnep_ethtool_get_msglevel,
469         .set_msglevel = tsnep_ethtool_set_msglevel,
470         .nway_reset = phy_ethtool_nway_reset,
471         .get_link = ethtool_op_get_link,
472         .self_test = tsnep_ethtool_self_test,
473         .get_strings = tsnep_ethtool_get_strings,
474         .get_ethtool_stats = tsnep_ethtool_get_ethtool_stats,
475         .get_sset_count = tsnep_ethtool_get_sset_count,
476         .get_rxnfc = tsnep_ethtool_get_rxnfc,
477         .set_rxnfc = tsnep_ethtool_set_rxnfc,
478         .get_channels = tsnep_ethtool_get_channels,
479         .get_ts_info = tsnep_ethtool_get_ts_info,
480         .get_coalesce = tsnep_ethtool_get_coalesce,
481         .set_coalesce = tsnep_ethtool_set_coalesce,
482         .get_per_queue_coalesce = tsnep_ethtool_get_per_queue_coalesce,
483         .set_per_queue_coalesce = tsnep_ethtool_set_per_queue_coalesce,
484         .get_link_ksettings = phy_ethtool_get_link_ksettings,
485         .set_link_ksettings = phy_ethtool_set_link_ksettings,
486 };