xref: /linux/drivers/net/dsa/sja1105/sja1105_ethtool.c (revision e7d759f31ca295d589f7420719c311870bb3166f)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com>
3  */
4 #include "sja1105.h"
5 
6 enum 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 
80 struct 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 
89 static 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 
541 static 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, SPI_READ, regs + c->offset, buf, size);
553 	if (rc)
554 		return rc;
555 
556 	sja1105_unpack(buf, ctr, c->start, c->end, size);
557 
558 	return 0;
559 }
560 
561 void 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, i, &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 
584 void 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 
606 int 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