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, 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
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, 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
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