xref: /openbmc/linux/drivers/net/dsa/sja1105/sja1105_ethtool.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
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  
sja1105_port_counter_read(struct sja1105_private * priv,int port,enum sja1105_counter_index idx,u64 * ctr)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  
sja1105_get_ethtool_stats(struct dsa_switch * ds,int port,u64 * data)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  
sja1105_get_strings(struct dsa_switch * ds,int port,u32 stringset,u8 * data)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  
sja1105_get_sset_count(struct dsa_switch * ds,int port,int sset)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