1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com>
3 */
4#include "sja1105.h"
5
6enum sja1105_counter_index {
7 __SJA1105_COUNTER_UNUSED,
8 /* MAC */
9 N_RUNT,
10 N_SOFERR,
11 N_ALIGNERR,
12 N_MIIERR,
13 TYPEERR,
14 SIZEERR,
15 TCTIMEOUT,
16 PRIORERR,
17 NOMASTER,
18 MEMOV,
19 MEMERR,
20 INVTYP,
21 INTCYOV,
22 DOMERR,
23 PCFBAGDROP,
24 SPCPRIOR,
25 AGEPRIOR,
26 PORTDROP,
27 LENDROP,
28 BAGDROP,
29 POLICEERR,
30 DRPNONA664ERR,
31 SPCERR,
32 AGEDRP,
33 /* HL1 */
34 N_N664ERR,
35 N_VLANERR,
36 N_UNRELEASED,
37 N_SIZEERR,
38 N_CRCERR,
39 N_VLNOTFOUND,
40 N_CTPOLERR,
41 N_POLERR,
42 N_RXFRM,
43 N_RXBYTE,
44 N_TXFRM,
45 N_TXBYTE,
46 /* HL2 */
47 N_QFULL,
48 N_PART_DROP,
49 N_EGR_DISABLED,
50 N_NOT_REACH,
51 __MAX_SJA1105ET_PORT_COUNTER,
52 /* P/Q/R/S only */
53 /* ETHER */
54 N_DROPS_NOLEARN = __MAX_SJA1105ET_PORT_COUNTER,
55 N_DROPS_NOROUTE,
56 N_DROPS_ILL_DTAG,
57 N_DROPS_DTAG,
58 N_DROPS_SOTAG,
59 N_DROPS_SITAG,
60 N_DROPS_UTAG,
61 N_TX_BYTES_1024_2047,
62 N_TX_BYTES_512_1023,
63 N_TX_BYTES_256_511,
64 N_TX_BYTES_128_255,
65 N_TX_BYTES_65_127,
66 N_TX_BYTES_64,
67 N_TX_MCAST,
68 N_TX_BCAST,
69 N_RX_BYTES_1024_2047,
70 N_RX_BYTES_512_1023,
71 N_RX_BYTES_256_511,
72 N_RX_BYTES_128_255,
73 N_RX_BYTES_65_127,
74 N_RX_BYTES_64,
75 N_RX_MCAST,
76 N_RX_BCAST,
77 __MAX_SJA1105PQRS_PORT_COUNTER,
78};
79
80struct sja1105_port_counter {
81 enum sja1105_stats_area area;
82 const char name[ETH_GSTRING_LEN];
83 int offset;
84 int start;
85 int end;
86 bool is_64bit;
87};
88
89static const struct sja1105_port_counter sja1105_port_counters[] = {
90 /* MAC-Level Diagnostic Counters */
91 [N_RUNT] = {
92 .area = MAC,
93 .name = "n_runt",
94 .offset = 0,
95 .start = 31,
96 .end = 24,
97 },
98 [N_SOFERR] = {
99 .area = MAC,
100 .name = "n_soferr",
101 .offset = 0x0,
102 .start = 23,
103 .end = 16,
104 },
105 [N_ALIGNERR] = {
106 .area = MAC,
107 .name = "n_alignerr",
108 .offset = 0x0,
109 .start = 15,
110 .end = 8,
111 },
112 [N_MIIERR] = {
113 .area = MAC,
114 .name = "n_miierr",
115 .offset = 0x0,
116 .start = 7,
117 .end = 0,
118 },
119 /* MAC-Level Diagnostic Flags */
120 [TYPEERR] = {
121 .area = MAC,
122 .name = "typeerr",
123 .offset = 0x1,
124 .start = 27,
125 .end = 27,
126 },
127 [SIZEERR] = {
128 .area = MAC,
129 .name = "sizeerr",
130 .offset = 0x1,
131 .start = 26,
132 .end = 26,
133 },
134 [TCTIMEOUT] = {
135 .area = MAC,
136 .name = "tctimeout",
137 .offset = 0x1,
138 .start = 25,
139 .end = 25,
140 },
141 [PRIORERR] = {
142 .area = MAC,
143 .name = "priorerr",
144 .offset = 0x1,
145 .start = 24,
146 .end = 24,
147 },
148 [NOMASTER] = {
149 .area = MAC,
150 .name = "nomaster",
151 .offset = 0x1,
152 .start = 23,
153 .end = 23,
154 },
155 [MEMOV] = {
156 .area = MAC,
157 .name = "memov",
158 .offset = 0x1,
159 .start = 22,
160 .end = 22,
161 },
162 [MEMERR] = {
163 .area = MAC,
164 .name = "memerr",
165 .offset = 0x1,
166 .start = 21,
167 .end = 21,
168 },
169 [INVTYP] = {
170 .area = MAC,
171 .name = "invtyp",
172 .offset = 0x1,
173 .start = 19,
174 .end = 19,
175 },
176 [INTCYOV] = {
177 .area = MAC,
178 .name = "intcyov",
179 .offset = 0x1,
180 .start = 18,
181 .end = 18,
182 },
183 [DOMERR] = {
184 .area = MAC,
185 .name = "domerr",
186 .offset = 0x1,
187 .start = 17,
188 .end = 17,
189 },
190 [PCFBAGDROP] = {
191 .area = MAC,
192 .name = "pcfbagdrop",
193 .offset = 0x1,
194 .start = 16,
195 .end = 16,
196 },
197 [SPCPRIOR] = {
198 .area = MAC,
199 .name = "spcprior",
200 .offset = 0x1,
201 .start = 15,
202 .end = 12,
203 },
204 [AGEPRIOR] = {
205 .area = MAC,
206 .name = "ageprior",
207 .offset = 0x1,
208 .start = 11,
209 .end = 8,
210 },
211 [PORTDROP] = {
212 .area = MAC,
213 .name = "portdrop",
214 .offset = 0x1,
215 .start = 6,
216 .end = 6,
217 },
218 [LENDROP] = {
219 .area = MAC,
220 .name = "lendrop",
221 .offset = 0x1,
222 .start = 5,
223 .end = 5,
224 },
225 [BAGDROP] = {
226 .area = MAC,
227 .name = "bagdrop",
228 .offset = 0x1,
229 .start = 4,
230 .end = 4,
231 },
232 [POLICEERR] = {
233 .area = MAC,
234 .name = "policeerr",
235 .offset = 0x1,
236 .start = 3,
237 .end = 3,
238 },
239 [DRPNONA664ERR] = {
240 .area = MAC,
241 .name = "drpnona664err",
242 .offset = 0x1,
243 .start = 2,
244 .end = 2,
245 },
246 [SPCERR] = {
247 .area = MAC,
248 .name = "spcerr",
249 .offset = 0x1,
250 .start = 1,
251 .end = 1,
252 },
253 [AGEDRP] = {
254 .area = MAC,
255 .name = "agedrp",
256 .offset = 0x1,
257 .start = 0,
258 .end = 0,
259 },
260 /* High-Level Diagnostic Counters */
261 [N_N664ERR] = {
262 .area = HL1,
263 .name = "n_n664err",
264 .offset = 0xF,
265 .start = 31,
266 .end = 0,
267 },
268 [N_VLANERR] = {
269 .area = HL1,
270 .name = "n_vlanerr",
271 .offset = 0xE,
272 .start = 31,
273 .end = 0,
274 },
275 [N_UNRELEASED] = {
276 .area = HL1,
277 .name = "n_unreleased",
278 .offset = 0xD,
279 .start = 31,
280 .end = 0,
281 },
282 [N_SIZEERR] = {
283 .area = HL1,
284 .name = "n_sizeerr",
285 .offset = 0xC,
286 .start = 31,
287 .end = 0,
288 },
289 [N_CRCERR] = {
290 .area = HL1,
291 .name = "n_crcerr",
292 .offset = 0xB,
293 .start = 31,
294 .end = 0,
295 },
296 [N_VLNOTFOUND] = {
297 .area = HL1,
298 .name = "n_vlnotfound",
299 .offset = 0xA,
300 .start = 31,
301 .end = 0,
302 },
303 [N_CTPOLERR] = {
304 .area = HL1,
305 .name = "n_ctpolerr",
306 .offset = 0x9,
307 .start = 31,
308 .end = 0,
309 },
310 [N_POLERR] = {
311 .area = HL1,
312 .name = "n_polerr",
313 .offset = 0x8,
314 .start = 31,
315 .end = 0,
316 },
317 [N_RXFRM] = {
318 .area = HL1,
319 .name = "n_rxfrm",
320 .offset = 0x6,
321 .start = 31,
322 .end = 0,
323 .is_64bit = true,
324 },
325 [N_RXBYTE] = {
326 .area = HL1,
327 .name = "n_rxbyte",
328 .offset = 0x4,
329 .start = 31,
330 .end = 0,
331 .is_64bit = true,
332 },
333 [N_TXFRM] = {
334 .area = HL1,
335 .name = "n_txfrm",
336 .offset = 0x2,
337 .start = 31,
338 .end = 0,
339 .is_64bit = true,
340 },
341 [N_TXBYTE] = {
342 .area = HL1,
343 .name = "n_txbyte",
344 .offset = 0x0,
345 .start = 31,
346 .end = 0,
347 .is_64bit = true,
348 },
349 [N_QFULL] = {
350 .area = HL2,
351 .name = "n_qfull",
352 .offset = 0x3,
353 .start = 31,
354 .end = 0,
355 },
356 [N_PART_DROP] = {
357 .area = HL2,
358 .name = "n_part_drop",
359 .offset = 0x2,
360 .start = 31,
361 .end = 0,
362 },
363 [N_EGR_DISABLED] = {
364 .area = HL2,
365 .name = "n_egr_disabled",
366 .offset = 0x1,
367 .start = 31,
368 .end = 0,
369 },
370 [N_NOT_REACH] = {
371 .area = HL2,
372 .name = "n_not_reach",
373 .offset = 0x0,
374 .start = 31,
375 .end = 0,
376 },
377 /* Ether Stats */
378 [N_DROPS_NOLEARN] = {
379 .area = ETHER,
380 .name = "n_drops_nolearn",
381 .offset = 0x16,
382 .start = 31,
383 .end = 0,
384 },
385 [N_DROPS_NOROUTE] = {
386 .area = ETHER,
387 .name = "n_drops_noroute",
388 .offset = 0x15,
389 .start = 31,
390 .end = 0,
391 },
392 [N_DROPS_ILL_DTAG] = {
393 .area = ETHER,
394 .name = "n_drops_ill_dtag",
395 .offset = 0x14,
396 .start = 31,
397 .end = 0,
398 },
399 [N_DROPS_DTAG] = {
400 .area = ETHER,
401 .name = "n_drops_dtag",
402 .offset = 0x13,
403 .start = 31,
404 .end = 0,
405 },
406 [N_DROPS_SOTAG] = {
407 .area = ETHER,
408 .name = "n_drops_sotag",
409 .offset = 0x12,
410 .start = 31,
411 .end = 0,
412 },
413 [N_DROPS_SITAG] = {
414 .area = ETHER,
415 .name = "n_drops_sitag",
416 .offset = 0x11,
417 .start = 31,
418 .end = 0,
419 },
420 [N_DROPS_UTAG] = {
421 .area = ETHER,
422 .name = "n_drops_utag",
423 .offset = 0x10,
424 .start = 31,
425 .end = 0,
426 },
427 [N_TX_BYTES_1024_2047] = {
428 .area = ETHER,
429 .name = "n_tx_bytes_1024_2047",
430 .offset = 0x0F,
431 .start = 31,
432 .end = 0,
433 },
434 [N_TX_BYTES_512_1023] = {
435 .area = ETHER,
436 .name = "n_tx_bytes_512_1023",
437 .offset = 0x0E,
438 .start = 31,
439 .end = 0,
440 },
441 [N_TX_BYTES_256_511] = {
442 .area = ETHER,
443 .name = "n_tx_bytes_256_511",
444 .offset = 0x0D,
445 .start = 31,
446 .end = 0,
447 },
448 [N_TX_BYTES_128_255] = {
449 .area = ETHER,
450 .name = "n_tx_bytes_128_255",
451 .offset = 0x0C,
452 .start = 31,
453 .end = 0,
454 },
455 [N_TX_BYTES_65_127] = {
456 .area = ETHER,
457 .name = "n_tx_bytes_65_127",
458 .offset = 0x0B,
459 .start = 31,
460 .end = 0,
461 },
462 [N_TX_BYTES_64] = {
463 .area = ETHER,
464 .name = "n_tx_bytes_64",
465 .offset = 0x0A,
466 .start = 31,
467 .end = 0,
468 },
469 [N_TX_MCAST] = {
470 .area = ETHER,
471 .name = "n_tx_mcast",
472 .offset = 0x09,
473 .start = 31,
474 .end = 0,
475 },
476 [N_TX_BCAST] = {
477 .area = ETHER,
478 .name = "n_tx_bcast",
479 .offset = 0x08,
480 .start = 31,
481 .end = 0,
482 },
483 [N_RX_BYTES_1024_2047] = {
484 .area = ETHER,
485 .name = "n_rx_bytes_1024_2047",
486 .offset = 0x07,
487 .start = 31,
488 .end = 0,
489 },
490 [N_RX_BYTES_512_1023] = {
491 .area = ETHER,
492 .name = "n_rx_bytes_512_1023",
493 .offset = 0x06,
494 .start = 31,
495 .end = 0,
496 },
497 [N_RX_BYTES_256_511] = {
498 .area = ETHER,
499 .name = "n_rx_bytes_256_511",
500 .offset = 0x05,
501 .start = 31,
502 .end = 0,
503 },
504 [N_RX_BYTES_128_255] = {
505 .area = ETHER,
506 .name = "n_rx_bytes_128_255",
507 .offset = 0x04,
508 .start = 31,
509 .end = 0,
510 },
511 [N_RX_BYTES_65_127] = {
512 .area = ETHER,
513 .name = "n_rx_bytes_65_127",
514 .offset = 0x03,
515 .start = 31,
516 .end = 0,
517 },
518 [N_RX_BYTES_64] = {
519 .area = ETHER,
520 .name = "n_rx_bytes_64",
521 .offset = 0x02,
522 .start = 31,
523 .end = 0,
524 },
525 [N_RX_MCAST] = {
526 .area = ETHER,
527 .name = "n_rx_mcast",
528 .offset = 0x01,
529 .start = 31,
530 .end = 0,
531 },
532 [N_RX_BCAST] = {
533 .area = ETHER,
534 .name = "n_rx_bcast",
535 .offset = 0x00,
536 .start = 31,
537 .end = 0,
538 },
539};
540
541static int sja1105_port_counter_read(struct sja1105_private *priv, int port,
542 enum sja1105_counter_index idx, u64 *ctr)
543{
544 const struct sja1105_port_counter *c = &sja1105_port_counters[idx];
545 size_t size = c->is_64bit ? 8 : 4;
546 u8 buf[8] = {0};
547 u64 regs;
548 int rc;
549
550 regs = priv->info->regs->stats[c->area][port];
551
552 rc = sja1105_xfer_buf(priv, rw: SPI_READ, reg_addr: regs + c->offset, buf, len: size);
553 if (rc)
554 return rc;
555
556 sja1105_unpack(buf, val: ctr, start: c->start, end: c->end, len: size);
557
558 return 0;
559}
560
561void sja1105_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data)
562{
563 struct sja1105_private *priv = ds->priv;
564 enum sja1105_counter_index max_ctr, i;
565 int rc, k = 0;
566
567 if (priv->info->device_id == SJA1105E_DEVICE_ID ||
568 priv->info->device_id == SJA1105T_DEVICE_ID)
569 max_ctr = __MAX_SJA1105ET_PORT_COUNTER;
570 else
571 max_ctr = __MAX_SJA1105PQRS_PORT_COUNTER;
572
573 for (i = 0; i < max_ctr; i++) {
574 rc = sja1105_port_counter_read(priv, port, idx: i, ctr: &data[k++]);
575 if (rc) {
576 dev_err(ds->dev,
577 "Failed to read port %d counters: %d\n",
578 port, rc);
579 break;
580 }
581 }
582}
583
584void sja1105_get_strings(struct dsa_switch *ds, int port,
585 u32 stringset, u8 *data)
586{
587 struct sja1105_private *priv = ds->priv;
588 enum sja1105_counter_index max_ctr, i;
589 char *p = data;
590
591 if (stringset != ETH_SS_STATS)
592 return;
593
594 if (priv->info->device_id == SJA1105E_DEVICE_ID ||
595 priv->info->device_id == SJA1105T_DEVICE_ID)
596 max_ctr = __MAX_SJA1105ET_PORT_COUNTER;
597 else
598 max_ctr = __MAX_SJA1105PQRS_PORT_COUNTER;
599
600 for (i = 0; i < max_ctr; i++) {
601 strscpy(p, sja1105_port_counters[i].name, ETH_GSTRING_LEN);
602 p += ETH_GSTRING_LEN;
603 }
604}
605
606int sja1105_get_sset_count(struct dsa_switch *ds, int port, int sset)
607{
608 struct sja1105_private *priv = ds->priv;
609 enum sja1105_counter_index max_ctr, i;
610 int sset_count = 0;
611
612 if (sset != ETH_SS_STATS)
613 return -EOPNOTSUPP;
614
615 if (priv->info->device_id == SJA1105E_DEVICE_ID ||
616 priv->info->device_id == SJA1105T_DEVICE_ID)
617 max_ctr = __MAX_SJA1105ET_PORT_COUNTER;
618 else
619 max_ctr = __MAX_SJA1105PQRS_PORT_COUNTER;
620
621 for (i = 0; i < max_ctr; i++) {
622 if (!strlen(sja1105_port_counters[i].name))
623 continue;
624
625 sset_count++;
626 }
627
628 return sset_count;
629}
630

source code of linux/drivers/net/dsa/sja1105/sja1105_ethtool.c