1// SPDX-License-Identifier: GPL-2.0+
2
3#include <linux/netdevice.h>
4
5#include "lan966x_main.h"
6
7/* Number of traffic classes */
8#define LAN966X_NUM_TC 8
9#define LAN966X_STATS_CHECK_DELAY (2 * HZ)
10
11static const struct lan966x_stat_layout lan966x_stats_layout[] = {
12 { .name = "rx_octets", .offset = 0x00, },
13 { .name = "rx_unicast", .offset = 0x01, },
14 { .name = "rx_multicast", .offset = 0x02 },
15 { .name = "rx_broadcast", .offset = 0x03 },
16 { .name = "rx_short", .offset = 0x04 },
17 { .name = "rx_frag", .offset = 0x05 },
18 { .name = "rx_jabber", .offset = 0x06 },
19 { .name = "rx_crc", .offset = 0x07 },
20 { .name = "rx_symbol_err", .offset = 0x08 },
21 { .name = "rx_sz_64", .offset = 0x09 },
22 { .name = "rx_sz_65_127", .offset = 0x0a},
23 { .name = "rx_sz_128_255", .offset = 0x0b},
24 { .name = "rx_sz_256_511", .offset = 0x0c },
25 { .name = "rx_sz_512_1023", .offset = 0x0d },
26 { .name = "rx_sz_1024_1526", .offset = 0x0e },
27 { .name = "rx_sz_jumbo", .offset = 0x0f },
28 { .name = "rx_pause", .offset = 0x10 },
29 { .name = "rx_control", .offset = 0x11 },
30 { .name = "rx_long", .offset = 0x12 },
31 { .name = "rx_cat_drop", .offset = 0x13 },
32 { .name = "rx_red_prio_0", .offset = 0x14 },
33 { .name = "rx_red_prio_1", .offset = 0x15 },
34 { .name = "rx_red_prio_2", .offset = 0x16 },
35 { .name = "rx_red_prio_3", .offset = 0x17 },
36 { .name = "rx_red_prio_4", .offset = 0x18 },
37 { .name = "rx_red_prio_5", .offset = 0x19 },
38 { .name = "rx_red_prio_6", .offset = 0x1a },
39 { .name = "rx_red_prio_7", .offset = 0x1b },
40 { .name = "rx_yellow_prio_0", .offset = 0x1c },
41 { .name = "rx_yellow_prio_1", .offset = 0x1d },
42 { .name = "rx_yellow_prio_2", .offset = 0x1e },
43 { .name = "rx_yellow_prio_3", .offset = 0x1f },
44 { .name = "rx_yellow_prio_4", .offset = 0x20 },
45 { .name = "rx_yellow_prio_5", .offset = 0x21 },
46 { .name = "rx_yellow_prio_6", .offset = 0x22 },
47 { .name = "rx_yellow_prio_7", .offset = 0x23 },
48 { .name = "rx_green_prio_0", .offset = 0x24 },
49 { .name = "rx_green_prio_1", .offset = 0x25 },
50 { .name = "rx_green_prio_2", .offset = 0x26 },
51 { .name = "rx_green_prio_3", .offset = 0x27 },
52 { .name = "rx_green_prio_4", .offset = 0x28 },
53 { .name = "rx_green_prio_5", .offset = 0x29 },
54 { .name = "rx_green_prio_6", .offset = 0x2a },
55 { .name = "rx_green_prio_7", .offset = 0x2b },
56 { .name = "rx_assembly_err", .offset = 0x2c },
57 { .name = "rx_smd_err", .offset = 0x2d },
58 { .name = "rx_assembly_ok", .offset = 0x2e },
59 { .name = "rx_merge_frag", .offset = 0x2f },
60 { .name = "rx_pmac_octets", .offset = 0x30, },
61 { .name = "rx_pmac_unicast", .offset = 0x31, },
62 { .name = "rx_pmac_multicast", .offset = 0x32 },
63 { .name = "rx_pmac_broadcast", .offset = 0x33 },
64 { .name = "rx_pmac_short", .offset = 0x34 },
65 { .name = "rx_pmac_frag", .offset = 0x35 },
66 { .name = "rx_pmac_jabber", .offset = 0x36 },
67 { .name = "rx_pmac_crc", .offset = 0x37 },
68 { .name = "rx_pmac_symbol_err", .offset = 0x38 },
69 { .name = "rx_pmac_sz_64", .offset = 0x39 },
70 { .name = "rx_pmac_sz_65_127", .offset = 0x3a },
71 { .name = "rx_pmac_sz_128_255", .offset = 0x3b },
72 { .name = "rx_pmac_sz_256_511", .offset = 0x3c },
73 { .name = "rx_pmac_sz_512_1023", .offset = 0x3d },
74 { .name = "rx_pmac_sz_1024_1526", .offset = 0x3e },
75 { .name = "rx_pmac_sz_jumbo", .offset = 0x3f },
76 { .name = "rx_pmac_pause", .offset = 0x40 },
77 { .name = "rx_pmac_control", .offset = 0x41 },
78 { .name = "rx_pmac_long", .offset = 0x42 },
79
80 { .name = "tx_octets", .offset = 0x80, },
81 { .name = "tx_unicast", .offset = 0x81, },
82 { .name = "tx_multicast", .offset = 0x82 },
83 { .name = "tx_broadcast", .offset = 0x83 },
84 { .name = "tx_col", .offset = 0x84 },
85 { .name = "tx_drop", .offset = 0x85 },
86 { .name = "tx_pause", .offset = 0x86 },
87 { .name = "tx_sz_64", .offset = 0x87 },
88 { .name = "tx_sz_65_127", .offset = 0x88 },
89 { .name = "tx_sz_128_255", .offset = 0x89 },
90 { .name = "tx_sz_256_511", .offset = 0x8a },
91 { .name = "tx_sz_512_1023", .offset = 0x8b },
92 { .name = "tx_sz_1024_1526", .offset = 0x8c },
93 { .name = "tx_sz_jumbo", .offset = 0x8d },
94 { .name = "tx_yellow_prio_0", .offset = 0x8e },
95 { .name = "tx_yellow_prio_1", .offset = 0x8f },
96 { .name = "tx_yellow_prio_2", .offset = 0x90 },
97 { .name = "tx_yellow_prio_3", .offset = 0x91 },
98 { .name = "tx_yellow_prio_4", .offset = 0x92 },
99 { .name = "tx_yellow_prio_5", .offset = 0x93 },
100 { .name = "tx_yellow_prio_6", .offset = 0x94 },
101 { .name = "tx_yellow_prio_7", .offset = 0x95 },
102 { .name = "tx_green_prio_0", .offset = 0x96 },
103 { .name = "tx_green_prio_1", .offset = 0x97 },
104 { .name = "tx_green_prio_2", .offset = 0x98 },
105 { .name = "tx_green_prio_3", .offset = 0x99 },
106 { .name = "tx_green_prio_4", .offset = 0x9a },
107 { .name = "tx_green_prio_5", .offset = 0x9b },
108 { .name = "tx_green_prio_6", .offset = 0x9c },
109 { .name = "tx_green_prio_7", .offset = 0x9d },
110 { .name = "tx_aged", .offset = 0x9e },
111 { .name = "tx_llct", .offset = 0x9f },
112 { .name = "tx_ct", .offset = 0xa0 },
113 { .name = "tx_mm_hold", .offset = 0xa1 },
114 { .name = "tx_merge_frag", .offset = 0xa2 },
115 { .name = "tx_pmac_octets", .offset = 0xa3, },
116 { .name = "tx_pmac_unicast", .offset = 0xa4, },
117 { .name = "tx_pmac_multicast", .offset = 0xa5 },
118 { .name = "tx_pmac_broadcast", .offset = 0xa6 },
119 { .name = "tx_pmac_pause", .offset = 0xa7 },
120 { .name = "tx_pmac_sz_64", .offset = 0xa8 },
121 { .name = "tx_pmac_sz_65_127", .offset = 0xa9 },
122 { .name = "tx_pmac_sz_128_255", .offset = 0xaa },
123 { .name = "tx_pmac_sz_256_511", .offset = 0xab },
124 { .name = "tx_pmac_sz_512_1023", .offset = 0xac },
125 { .name = "tx_pmac_sz_1024_1526", .offset = 0xad },
126 { .name = "tx_pmac_sz_jumbo", .offset = 0xae },
127
128 { .name = "dr_local", .offset = 0x100 },
129 { .name = "dr_tail", .offset = 0x101 },
130 { .name = "dr_yellow_prio_0", .offset = 0x102 },
131 { .name = "dr_yellow_prio_1", .offset = 0x103 },
132 { .name = "dr_yellow_prio_2", .offset = 0x104 },
133 { .name = "dr_yellow_prio_3", .offset = 0x105 },
134 { .name = "dr_yellow_prio_4", .offset = 0x106 },
135 { .name = "dr_yellow_prio_5", .offset = 0x107 },
136 { .name = "dr_yellow_prio_6", .offset = 0x108 },
137 { .name = "dr_yellow_prio_7", .offset = 0x109 },
138 { .name = "dr_green_prio_0", .offset = 0x10a },
139 { .name = "dr_green_prio_1", .offset = 0x10b },
140 { .name = "dr_green_prio_2", .offset = 0x10c },
141 { .name = "dr_green_prio_3", .offset = 0x10d },
142 { .name = "dr_green_prio_4", .offset = 0x10e },
143 { .name = "dr_green_prio_5", .offset = 0x10f },
144 { .name = "dr_green_prio_6", .offset = 0x110 },
145 { .name = "dr_green_prio_7", .offset = 0x111 },
146};
147
148/* The following numbers are indexes into lan966x_stats_layout[] */
149#define SYS_COUNT_RX_OCT 0
150#define SYS_COUNT_RX_UC 1
151#define SYS_COUNT_RX_MC 2
152#define SYS_COUNT_RX_BC 3
153#define SYS_COUNT_RX_SHORT 4
154#define SYS_COUNT_RX_FRAG 5
155#define SYS_COUNT_RX_JABBER 6
156#define SYS_COUNT_RX_CRC 7
157#define SYS_COUNT_RX_SYMBOL_ERR 8
158#define SYS_COUNT_RX_SZ_64 9
159#define SYS_COUNT_RX_SZ_65_127 10
160#define SYS_COUNT_RX_SZ_128_255 11
161#define SYS_COUNT_RX_SZ_256_511 12
162#define SYS_COUNT_RX_SZ_512_1023 13
163#define SYS_COUNT_RX_SZ_1024_1526 14
164#define SYS_COUNT_RX_SZ_JUMBO 15
165#define SYS_COUNT_RX_PAUSE 16
166#define SYS_COUNT_RX_CONTROL 17
167#define SYS_COUNT_RX_LONG 18
168#define SYS_COUNT_RX_CAT_DROP 19
169#define SYS_COUNT_RX_RED_PRIO_0 20
170#define SYS_COUNT_RX_RED_PRIO_1 21
171#define SYS_COUNT_RX_RED_PRIO_2 22
172#define SYS_COUNT_RX_RED_PRIO_3 23
173#define SYS_COUNT_RX_RED_PRIO_4 24
174#define SYS_COUNT_RX_RED_PRIO_5 25
175#define SYS_COUNT_RX_RED_PRIO_6 26
176#define SYS_COUNT_RX_RED_PRIO_7 27
177#define SYS_COUNT_RX_YELLOW_PRIO_0 28
178#define SYS_COUNT_RX_YELLOW_PRIO_1 29
179#define SYS_COUNT_RX_YELLOW_PRIO_2 30
180#define SYS_COUNT_RX_YELLOW_PRIO_3 31
181#define SYS_COUNT_RX_YELLOW_PRIO_4 32
182#define SYS_COUNT_RX_YELLOW_PRIO_5 33
183#define SYS_COUNT_RX_YELLOW_PRIO_6 34
184#define SYS_COUNT_RX_YELLOW_PRIO_7 35
185#define SYS_COUNT_RX_GREEN_PRIO_0 36
186#define SYS_COUNT_RX_GREEN_PRIO_1 37
187#define SYS_COUNT_RX_GREEN_PRIO_2 38
188#define SYS_COUNT_RX_GREEN_PRIO_3 39
189#define SYS_COUNT_RX_GREEN_PRIO_4 40
190#define SYS_COUNT_RX_GREEN_PRIO_5 41
191#define SYS_COUNT_RX_GREEN_PRIO_6 42
192#define SYS_COUNT_RX_GREEN_PRIO_7 43
193#define SYS_COUNT_RX_ASSEMBLY_ERR 44
194#define SYS_COUNT_RX_SMD_ERR 45
195#define SYS_COUNT_RX_ASSEMBLY_OK 46
196#define SYS_COUNT_RX_MERGE_FRAG 47
197#define SYS_COUNT_RX_PMAC_OCT 48
198#define SYS_COUNT_RX_PMAC_UC 49
199#define SYS_COUNT_RX_PMAC_MC 50
200#define SYS_COUNT_RX_PMAC_BC 51
201#define SYS_COUNT_RX_PMAC_SHORT 52
202#define SYS_COUNT_RX_PMAC_FRAG 53
203#define SYS_COUNT_RX_PMAC_JABBER 54
204#define SYS_COUNT_RX_PMAC_CRC 55
205#define SYS_COUNT_RX_PMAC_SYMBOL_ERR 56
206#define SYS_COUNT_RX_PMAC_SZ_64 57
207#define SYS_COUNT_RX_PMAC_SZ_65_127 58
208#define SYS_COUNT_RX_PMAC_SZ_128_255 59
209#define SYS_COUNT_RX_PMAC_SZ_256_511 60
210#define SYS_COUNT_RX_PMAC_SZ_512_1023 61
211#define SYS_COUNT_RX_PMAC_SZ_1024_1526 62
212#define SYS_COUNT_RX_PMAC_SZ_JUMBO 63
213#define SYS_COUNT_RX_PMAC_PAUSE 64
214#define SYS_COUNT_RX_PMAC_CONTROL 65
215#define SYS_COUNT_RX_PMAC_LONG 66
216
217#define SYS_COUNT_TX_OCT 67
218#define SYS_COUNT_TX_UC 68
219#define SYS_COUNT_TX_MC 69
220#define SYS_COUNT_TX_BC 70
221#define SYS_COUNT_TX_COL 71
222#define SYS_COUNT_TX_DROP 72
223#define SYS_COUNT_TX_PAUSE 73
224#define SYS_COUNT_TX_SZ_64 74
225#define SYS_COUNT_TX_SZ_65_127 75
226#define SYS_COUNT_TX_SZ_128_255 76
227#define SYS_COUNT_TX_SZ_256_511 77
228#define SYS_COUNT_TX_SZ_512_1023 78
229#define SYS_COUNT_TX_SZ_1024_1526 79
230#define SYS_COUNT_TX_SZ_JUMBO 80
231#define SYS_COUNT_TX_YELLOW_PRIO_0 81
232#define SYS_COUNT_TX_YELLOW_PRIO_1 82
233#define SYS_COUNT_TX_YELLOW_PRIO_2 83
234#define SYS_COUNT_TX_YELLOW_PRIO_3 84
235#define SYS_COUNT_TX_YELLOW_PRIO_4 85
236#define SYS_COUNT_TX_YELLOW_PRIO_5 86
237#define SYS_COUNT_TX_YELLOW_PRIO_6 87
238#define SYS_COUNT_TX_YELLOW_PRIO_7 88
239#define SYS_COUNT_TX_GREEN_PRIO_0 89
240#define SYS_COUNT_TX_GREEN_PRIO_1 90
241#define SYS_COUNT_TX_GREEN_PRIO_2 91
242#define SYS_COUNT_TX_GREEN_PRIO_3 92
243#define SYS_COUNT_TX_GREEN_PRIO_4 93
244#define SYS_COUNT_TX_GREEN_PRIO_5 94
245#define SYS_COUNT_TX_GREEN_PRIO_6 95
246#define SYS_COUNT_TX_GREEN_PRIO_7 96
247#define SYS_COUNT_TX_AGED 97
248#define SYS_COUNT_TX_LLCT 98
249#define SYS_COUNT_TX_CT 99
250#define SYS_COUNT_TX_MM_HOLD 100
251#define SYS_COUNT_TX_MERGE_FRAG 101
252#define SYS_COUNT_TX_PMAC_OCT 102
253#define SYS_COUNT_TX_PMAC_UC 103
254#define SYS_COUNT_TX_PMAC_MC 104
255#define SYS_COUNT_TX_PMAC_BC 105
256#define SYS_COUNT_TX_PMAC_PAUSE 106
257#define SYS_COUNT_TX_PMAC_SZ_64 107
258#define SYS_COUNT_TX_PMAC_SZ_65_127 108
259#define SYS_COUNT_TX_PMAC_SZ_128_255 109
260#define SYS_COUNT_TX_PMAC_SZ_256_511 110
261#define SYS_COUNT_TX_PMAC_SZ_512_1023 111
262#define SYS_COUNT_TX_PMAC_SZ_1024_1526 112
263#define SYS_COUNT_TX_PMAC_SZ_JUMBO 113
264
265#define SYS_COUNT_DR_LOCAL 114
266#define SYS_COUNT_DR_TAIL 115
267#define SYS_COUNT_DR_YELLOW_PRIO_0 116
268#define SYS_COUNT_DR_YELLOW_PRIO_1 117
269#define SYS_COUNT_DR_YELLOW_PRIO_2 118
270#define SYS_COUNT_DR_YELLOW_PRIO_3 119
271#define SYS_COUNT_DR_YELLOW_PRIO_4 120
272#define SYS_COUNT_DR_YELLOW_PRIO_5 121
273#define SYS_COUNT_DR_YELLOW_PRIO_6 122
274#define SYS_COUNT_DR_YELLOW_PRIO_7 123
275#define SYS_COUNT_DR_GREEN_PRIO_0 124
276#define SYS_COUNT_DR_GREEN_PRIO_1 125
277#define SYS_COUNT_DR_GREEN_PRIO_2 126
278#define SYS_COUNT_DR_GREEN_PRIO_3 127
279#define SYS_COUNT_DR_GREEN_PRIO_4 128
280#define SYS_COUNT_DR_GREEN_PRIO_5 129
281#define SYS_COUNT_DR_GREEN_PRIO_6 130
282#define SYS_COUNT_DR_GREEN_PRIO_7 131
283
284/* Add a possibly wrapping 32 bit value to a 64 bit counter */
285static void lan966x_add_cnt(u64 *cnt, u32 val)
286{
287 if (val < (*cnt & U32_MAX))
288 *cnt += (u64)1 << 32; /* value has wrapped */
289
290 *cnt = (*cnt & ~(u64)U32_MAX) + val;
291}
292
293static void lan966x_stats_update(struct lan966x *lan966x)
294{
295 int i, j;
296
297 mutex_lock(&lan966x->stats_lock);
298
299 for (i = 0; i < lan966x->num_phys_ports; i++) {
300 uint idx = i * lan966x->num_stats;
301
302 lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(i),
303 lan966x, SYS_STAT_CFG);
304
305 for (j = 0; j < lan966x->num_stats; j++) {
306 u32 offset = lan966x->stats_layout[j].offset;
307
308 lan966x_add_cnt(cnt: &lan966x->stats[idx++],
309 val: lan_rd(lan966x, SYS_CNT(offset)));
310 }
311 }
312
313 mutex_unlock(lock: &lan966x->stats_lock);
314}
315
316static int lan966x_get_sset_count(struct net_device *dev, int sset)
317{
318 struct lan966x_port *port = netdev_priv(dev);
319 struct lan966x *lan966x = port->lan966x;
320
321 if (sset != ETH_SS_STATS)
322 return -EOPNOTSUPP;
323
324 return lan966x->num_stats;
325}
326
327static void lan966x_get_strings(struct net_device *netdev, u32 sset, u8 *data)
328{
329 struct lan966x_port *port = netdev_priv(dev: netdev);
330 struct lan966x *lan966x = port->lan966x;
331 int i;
332
333 if (sset != ETH_SS_STATS)
334 return;
335
336 for (i = 0; i < lan966x->num_stats; i++)
337 memcpy(data + i * ETH_GSTRING_LEN,
338 lan966x->stats_layout[i].name, ETH_GSTRING_LEN);
339}
340
341static void lan966x_get_ethtool_stats(struct net_device *dev,
342 struct ethtool_stats *stats, u64 *data)
343{
344 struct lan966x_port *port = netdev_priv(dev);
345 struct lan966x *lan966x = port->lan966x;
346 int i;
347
348 /* check and update now */
349 lan966x_stats_update(lan966x);
350
351 /* Copy all counters */
352 for (i = 0; i < lan966x->num_stats; i++)
353 *data++ = lan966x->stats[port->chip_port *
354 lan966x->num_stats + i];
355}
356
357static void lan966x_get_eth_mac_stats(struct net_device *dev,
358 struct ethtool_eth_mac_stats *mac_stats)
359{
360 struct lan966x_port *port = netdev_priv(dev);
361 struct lan966x *lan966x = port->lan966x;
362 u32 idx;
363
364 lan966x_stats_update(lan966x);
365
366 idx = port->chip_port * lan966x->num_stats;
367
368 mutex_lock(&lan966x->stats_lock);
369
370 mac_stats->FramesTransmittedOK =
371 lan966x->stats[idx + SYS_COUNT_TX_UC] +
372 lan966x->stats[idx + SYS_COUNT_TX_MC] +
373 lan966x->stats[idx + SYS_COUNT_TX_BC] +
374 lan966x->stats[idx + SYS_COUNT_TX_PMAC_UC] +
375 lan966x->stats[idx + SYS_COUNT_TX_PMAC_MC] +
376 lan966x->stats[idx + SYS_COUNT_TX_PMAC_BC];
377 mac_stats->SingleCollisionFrames =
378 lan966x->stats[idx + SYS_COUNT_TX_COL];
379 mac_stats->MultipleCollisionFrames = 0;
380 mac_stats->FramesReceivedOK =
381 lan966x->stats[idx + SYS_COUNT_RX_UC] +
382 lan966x->stats[idx + SYS_COUNT_RX_MC] +
383 lan966x->stats[idx + SYS_COUNT_RX_BC];
384 mac_stats->FrameCheckSequenceErrors =
385 lan966x->stats[idx + SYS_COUNT_RX_CRC] +
386 lan966x->stats[idx + SYS_COUNT_RX_CRC];
387 mac_stats->AlignmentErrors = 0;
388 mac_stats->OctetsTransmittedOK =
389 lan966x->stats[idx + SYS_COUNT_TX_OCT] +
390 lan966x->stats[idx + SYS_COUNT_TX_PMAC_OCT];
391 mac_stats->FramesWithDeferredXmissions =
392 lan966x->stats[idx + SYS_COUNT_TX_MM_HOLD];
393 mac_stats->LateCollisions = 0;
394 mac_stats->FramesAbortedDueToXSColls = 0;
395 mac_stats->FramesLostDueToIntMACXmitError = 0;
396 mac_stats->CarrierSenseErrors = 0;
397 mac_stats->OctetsReceivedOK =
398 lan966x->stats[idx + SYS_COUNT_RX_OCT];
399 mac_stats->FramesLostDueToIntMACRcvError = 0;
400 mac_stats->MulticastFramesXmittedOK =
401 lan966x->stats[idx + SYS_COUNT_TX_MC] +
402 lan966x->stats[idx + SYS_COUNT_TX_PMAC_MC];
403 mac_stats->BroadcastFramesXmittedOK =
404 lan966x->stats[idx + SYS_COUNT_TX_BC] +
405 lan966x->stats[idx + SYS_COUNT_TX_PMAC_BC];
406 mac_stats->FramesWithExcessiveDeferral = 0;
407 mac_stats->MulticastFramesReceivedOK =
408 lan966x->stats[idx + SYS_COUNT_RX_MC];
409 mac_stats->BroadcastFramesReceivedOK =
410 lan966x->stats[idx + SYS_COUNT_RX_BC];
411 mac_stats->InRangeLengthErrors =
412 lan966x->stats[idx + SYS_COUNT_RX_FRAG] +
413 lan966x->stats[idx + SYS_COUNT_RX_JABBER] +
414 lan966x->stats[idx + SYS_COUNT_RX_CRC] +
415 lan966x->stats[idx + SYS_COUNT_RX_PMAC_FRAG] +
416 lan966x->stats[idx + SYS_COUNT_RX_PMAC_JABBER] +
417 lan966x->stats[idx + SYS_COUNT_RX_PMAC_CRC];
418 mac_stats->OutOfRangeLengthField =
419 lan966x->stats[idx + SYS_COUNT_RX_SHORT] +
420 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SHORT] +
421 lan966x->stats[idx + SYS_COUNT_RX_LONG] +
422 lan966x->stats[idx + SYS_COUNT_RX_PMAC_LONG];
423 mac_stats->FrameTooLongErrors =
424 lan966x->stats[idx + SYS_COUNT_RX_LONG] +
425 lan966x->stats[idx + SYS_COUNT_RX_PMAC_LONG];
426
427 mutex_unlock(lock: &lan966x->stats_lock);
428}
429
430static const struct ethtool_rmon_hist_range lan966x_rmon_ranges[] = {
431 { 0, 64 },
432 { 65, 127 },
433 { 128, 255 },
434 { 256, 511 },
435 { 512, 1023 },
436 { 1024, 1518 },
437 { 1519, 10239 },
438 {}
439};
440
441static void lan966x_get_eth_rmon_stats(struct net_device *dev,
442 struct ethtool_rmon_stats *rmon_stats,
443 const struct ethtool_rmon_hist_range **ranges)
444{
445 struct lan966x_port *port = netdev_priv(dev);
446 struct lan966x *lan966x = port->lan966x;
447 u32 idx;
448
449 lan966x_stats_update(lan966x);
450
451 idx = port->chip_port * lan966x->num_stats;
452
453 mutex_lock(&lan966x->stats_lock);
454
455 rmon_stats->undersize_pkts =
456 lan966x->stats[idx + SYS_COUNT_RX_SHORT] +
457 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SHORT];
458 rmon_stats->oversize_pkts =
459 lan966x->stats[idx + SYS_COUNT_RX_LONG] +
460 lan966x->stats[idx + SYS_COUNT_RX_PMAC_LONG];
461 rmon_stats->fragments =
462 lan966x->stats[idx + SYS_COUNT_RX_FRAG] +
463 lan966x->stats[idx + SYS_COUNT_RX_PMAC_FRAG];
464 rmon_stats->jabbers =
465 lan966x->stats[idx + SYS_COUNT_RX_JABBER] +
466 lan966x->stats[idx + SYS_COUNT_RX_PMAC_JABBER];
467 rmon_stats->hist[0] =
468 lan966x->stats[idx + SYS_COUNT_RX_SZ_64] +
469 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_64];
470 rmon_stats->hist[1] =
471 lan966x->stats[idx + SYS_COUNT_RX_SZ_65_127] +
472 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_65_127];
473 rmon_stats->hist[2] =
474 lan966x->stats[idx + SYS_COUNT_RX_SZ_128_255] +
475 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_128_255];
476 rmon_stats->hist[3] =
477 lan966x->stats[idx + SYS_COUNT_RX_SZ_256_511] +
478 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_256_511];
479 rmon_stats->hist[4] =
480 lan966x->stats[idx + SYS_COUNT_RX_SZ_512_1023] +
481 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_512_1023];
482 rmon_stats->hist[5] =
483 lan966x->stats[idx + SYS_COUNT_RX_SZ_1024_1526] +
484 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_1024_1526];
485 rmon_stats->hist[6] =
486 lan966x->stats[idx + SYS_COUNT_RX_SZ_1024_1526] +
487 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_1024_1526];
488
489 rmon_stats->hist_tx[0] =
490 lan966x->stats[idx + SYS_COUNT_TX_SZ_64] +
491 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_64];
492 rmon_stats->hist_tx[1] =
493 lan966x->stats[idx + SYS_COUNT_TX_SZ_65_127] +
494 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_65_127];
495 rmon_stats->hist_tx[2] =
496 lan966x->stats[idx + SYS_COUNT_TX_SZ_128_255] +
497 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_128_255];
498 rmon_stats->hist_tx[3] =
499 lan966x->stats[idx + SYS_COUNT_TX_SZ_256_511] +
500 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_256_511];
501 rmon_stats->hist_tx[4] =
502 lan966x->stats[idx + SYS_COUNT_TX_SZ_512_1023] +
503 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_512_1023];
504 rmon_stats->hist_tx[5] =
505 lan966x->stats[idx + SYS_COUNT_TX_SZ_1024_1526] +
506 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_1024_1526];
507 rmon_stats->hist_tx[6] =
508 lan966x->stats[idx + SYS_COUNT_TX_SZ_1024_1526] +
509 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_1024_1526];
510
511 mutex_unlock(lock: &lan966x->stats_lock);
512
513 *ranges = lan966x_rmon_ranges;
514}
515
516static int lan966x_get_link_ksettings(struct net_device *ndev,
517 struct ethtool_link_ksettings *cmd)
518{
519 struct lan966x_port *port = netdev_priv(dev: ndev);
520
521 return phylink_ethtool_ksettings_get(port->phylink, cmd);
522}
523
524static int lan966x_set_link_ksettings(struct net_device *ndev,
525 const struct ethtool_link_ksettings *cmd)
526{
527 struct lan966x_port *port = netdev_priv(dev: ndev);
528
529 return phylink_ethtool_ksettings_set(port->phylink, cmd);
530}
531
532static void lan966x_get_pauseparam(struct net_device *dev,
533 struct ethtool_pauseparam *pause)
534{
535 struct lan966x_port *port = netdev_priv(dev);
536
537 phylink_ethtool_get_pauseparam(port->phylink, pause);
538}
539
540static int lan966x_set_pauseparam(struct net_device *dev,
541 struct ethtool_pauseparam *pause)
542{
543 struct lan966x_port *port = netdev_priv(dev);
544
545 return phylink_ethtool_set_pauseparam(port->phylink, pause);
546}
547
548static int lan966x_get_ts_info(struct net_device *dev,
549 struct ethtool_ts_info *info)
550{
551 struct lan966x_port *port = netdev_priv(dev);
552 struct lan966x *lan966x = port->lan966x;
553 struct lan966x_phc *phc;
554
555 if (!lan966x->ptp)
556 return ethtool_op_get_ts_info(dev, eti: info);
557
558 phc = &lan966x->phc[LAN966X_PHC_PORT];
559
560 info->phc_index = phc->clock ? ptp_clock_index(ptp: phc->clock) : -1;
561 if (info->phc_index == -1) {
562 info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE |
563 SOF_TIMESTAMPING_RX_SOFTWARE |
564 SOF_TIMESTAMPING_SOFTWARE;
565 return 0;
566 }
567 info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE |
568 SOF_TIMESTAMPING_RX_SOFTWARE |
569 SOF_TIMESTAMPING_SOFTWARE |
570 SOF_TIMESTAMPING_TX_HARDWARE |
571 SOF_TIMESTAMPING_RX_HARDWARE |
572 SOF_TIMESTAMPING_RAW_HARDWARE;
573 info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON) |
574 BIT(HWTSTAMP_TX_ONESTEP_SYNC);
575 info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
576 BIT(HWTSTAMP_FILTER_ALL);
577
578 return 0;
579}
580
581const struct ethtool_ops lan966x_ethtool_ops = {
582 .get_link_ksettings = lan966x_get_link_ksettings,
583 .set_link_ksettings = lan966x_set_link_ksettings,
584 .get_pauseparam = lan966x_get_pauseparam,
585 .set_pauseparam = lan966x_set_pauseparam,
586 .get_sset_count = lan966x_get_sset_count,
587 .get_strings = lan966x_get_strings,
588 .get_ethtool_stats = lan966x_get_ethtool_stats,
589 .get_eth_mac_stats = lan966x_get_eth_mac_stats,
590 .get_rmon_stats = lan966x_get_eth_rmon_stats,
591 .get_link = ethtool_op_get_link,
592 .get_ts_info = lan966x_get_ts_info,
593};
594
595static void lan966x_check_stats_work(struct work_struct *work)
596{
597 struct delayed_work *del_work = to_delayed_work(work);
598 struct lan966x *lan966x = container_of(del_work, struct lan966x,
599 stats_work);
600
601 lan966x_stats_update(lan966x);
602
603 queue_delayed_work(wq: lan966x->stats_queue, dwork: &lan966x->stats_work,
604 LAN966X_STATS_CHECK_DELAY);
605}
606
607void lan966x_stats_get(struct net_device *dev,
608 struct rtnl_link_stats64 *stats)
609{
610 struct lan966x_port *port = netdev_priv(dev);
611 struct lan966x *lan966x = port->lan966x;
612 u32 idx;
613 int i;
614
615 idx = port->chip_port * lan966x->num_stats;
616
617 mutex_lock(&lan966x->stats_lock);
618
619 stats->rx_bytes = lan966x->stats[idx + SYS_COUNT_RX_OCT] +
620 lan966x->stats[idx + SYS_COUNT_RX_PMAC_OCT];
621
622 stats->rx_packets = lan966x->stats[idx + SYS_COUNT_RX_SHORT] +
623 lan966x->stats[idx + SYS_COUNT_RX_FRAG] +
624 lan966x->stats[idx + SYS_COUNT_RX_JABBER] +
625 lan966x->stats[idx + SYS_COUNT_RX_CRC] +
626 lan966x->stats[idx + SYS_COUNT_RX_SYMBOL_ERR] +
627 lan966x->stats[idx + SYS_COUNT_RX_SZ_64] +
628 lan966x->stats[idx + SYS_COUNT_RX_SZ_65_127] +
629 lan966x->stats[idx + SYS_COUNT_RX_SZ_128_255] +
630 lan966x->stats[idx + SYS_COUNT_RX_SZ_256_511] +
631 lan966x->stats[idx + SYS_COUNT_RX_SZ_512_1023] +
632 lan966x->stats[idx + SYS_COUNT_RX_SZ_1024_1526] +
633 lan966x->stats[idx + SYS_COUNT_RX_SZ_JUMBO] +
634 lan966x->stats[idx + SYS_COUNT_RX_LONG] +
635 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SHORT] +
636 lan966x->stats[idx + SYS_COUNT_RX_PMAC_FRAG] +
637 lan966x->stats[idx + SYS_COUNT_RX_PMAC_JABBER] +
638 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_64] +
639 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_65_127] +
640 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_128_255] +
641 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_256_511] +
642 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_512_1023] +
643 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_1024_1526] +
644 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_JUMBO];
645
646 stats->multicast = lan966x->stats[idx + SYS_COUNT_RX_MC] +
647 lan966x->stats[idx + SYS_COUNT_RX_PMAC_MC];
648
649 stats->rx_errors = lan966x->stats[idx + SYS_COUNT_RX_SHORT] +
650 lan966x->stats[idx + SYS_COUNT_RX_FRAG] +
651 lan966x->stats[idx + SYS_COUNT_RX_JABBER] +
652 lan966x->stats[idx + SYS_COUNT_RX_CRC] +
653 lan966x->stats[idx + SYS_COUNT_RX_SYMBOL_ERR] +
654 lan966x->stats[idx + SYS_COUNT_RX_LONG];
655
656 stats->rx_dropped = dev->stats.rx_dropped +
657 lan966x->stats[idx + SYS_COUNT_RX_LONG] +
658 lan966x->stats[idx + SYS_COUNT_DR_LOCAL] +
659 lan966x->stats[idx + SYS_COUNT_DR_TAIL] +
660 lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_0] +
661 lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_1] +
662 lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_2] +
663 lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_3] +
664 lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_4] +
665 lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_5] +
666 lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_6] +
667 lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_7];
668
669 for (i = 0; i < LAN966X_NUM_TC; i++) {
670 stats->rx_dropped +=
671 (lan966x->stats[idx + SYS_COUNT_DR_YELLOW_PRIO_0 + i] +
672 lan966x->stats[idx + SYS_COUNT_DR_GREEN_PRIO_0 + i]);
673 }
674
675 /* Get Tx stats */
676 stats->tx_bytes = lan966x->stats[idx + SYS_COUNT_TX_OCT] +
677 lan966x->stats[idx + SYS_COUNT_TX_PMAC_OCT];
678
679 stats->tx_packets = lan966x->stats[idx + SYS_COUNT_TX_SZ_64] +
680 lan966x->stats[idx + SYS_COUNT_TX_SZ_65_127] +
681 lan966x->stats[idx + SYS_COUNT_TX_SZ_128_255] +
682 lan966x->stats[idx + SYS_COUNT_TX_SZ_256_511] +
683 lan966x->stats[idx + SYS_COUNT_TX_SZ_512_1023] +
684 lan966x->stats[idx + SYS_COUNT_TX_SZ_1024_1526] +
685 lan966x->stats[idx + SYS_COUNT_TX_SZ_JUMBO] +
686 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_64] +
687 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_65_127] +
688 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_128_255] +
689 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_256_511] +
690 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_512_1023] +
691 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_1024_1526] +
692 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_JUMBO];
693
694 stats->tx_dropped = lan966x->stats[idx + SYS_COUNT_TX_DROP] +
695 lan966x->stats[idx + SYS_COUNT_TX_AGED];
696
697 stats->collisions = lan966x->stats[idx + SYS_COUNT_TX_COL];
698
699 mutex_unlock(lock: &lan966x->stats_lock);
700}
701
702int lan966x_stats_init(struct lan966x *lan966x)
703{
704 char queue_name[32];
705
706 lan966x->stats_layout = lan966x_stats_layout;
707 lan966x->num_stats = ARRAY_SIZE(lan966x_stats_layout);
708 lan966x->stats = devm_kcalloc(dev: lan966x->dev, n: lan966x->num_phys_ports *
709 lan966x->num_stats,
710 size: sizeof(u64), GFP_KERNEL);
711 if (!lan966x->stats)
712 return -ENOMEM;
713
714 /* Init stats worker */
715 mutex_init(&lan966x->stats_lock);
716 snprintf(buf: queue_name, size: sizeof(queue_name), fmt: "%s-stats",
717 dev_name(dev: lan966x->dev));
718 lan966x->stats_queue = create_singlethread_workqueue(queue_name);
719 if (!lan966x->stats_queue)
720 return -ENOMEM;
721
722 INIT_DELAYED_WORK(&lan966x->stats_work, lan966x_check_stats_work);
723 queue_delayed_work(wq: lan966x->stats_queue, dwork: &lan966x->stats_work,
724 LAN966X_STATS_CHECK_DELAY);
725
726 return 0;
727}
728

source code of linux/drivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c