xref: /OK3568_Linux_fs/kernel/drivers/net/dsa/sja1105/sja1105_ethtool.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com>
3*4882a593Smuzhiyun  */
4*4882a593Smuzhiyun #include "sja1105.h"
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #define SJA1105_SIZE_MAC_AREA		(0x02 * 4)
7*4882a593Smuzhiyun #define SJA1105_SIZE_HL1_AREA		(0x10 * 4)
8*4882a593Smuzhiyun #define SJA1105_SIZE_HL2_AREA		(0x4 * 4)
9*4882a593Smuzhiyun #define SJA1105_SIZE_QLEVEL_AREA	(0x8 * 4) /* 0x4 to 0xB */
10*4882a593Smuzhiyun #define SJA1105_SIZE_ETHER_AREA		(0x17 * 4)
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun struct sja1105_port_status_mac {
13*4882a593Smuzhiyun 	u64 n_runt;
14*4882a593Smuzhiyun 	u64 n_soferr;
15*4882a593Smuzhiyun 	u64 n_alignerr;
16*4882a593Smuzhiyun 	u64 n_miierr;
17*4882a593Smuzhiyun 	u64 typeerr;
18*4882a593Smuzhiyun 	u64 sizeerr;
19*4882a593Smuzhiyun 	u64 tctimeout;
20*4882a593Smuzhiyun 	u64 priorerr;
21*4882a593Smuzhiyun 	u64 nomaster;
22*4882a593Smuzhiyun 	u64 memov;
23*4882a593Smuzhiyun 	u64 memerr;
24*4882a593Smuzhiyun 	u64 invtyp;
25*4882a593Smuzhiyun 	u64 intcyov;
26*4882a593Smuzhiyun 	u64 domerr;
27*4882a593Smuzhiyun 	u64 pcfbagdrop;
28*4882a593Smuzhiyun 	u64 spcprior;
29*4882a593Smuzhiyun 	u64 ageprior;
30*4882a593Smuzhiyun 	u64 portdrop;
31*4882a593Smuzhiyun 	u64 lendrop;
32*4882a593Smuzhiyun 	u64 bagdrop;
33*4882a593Smuzhiyun 	u64 policeerr;
34*4882a593Smuzhiyun 	u64 drpnona664err;
35*4882a593Smuzhiyun 	u64 spcerr;
36*4882a593Smuzhiyun 	u64 agedrp;
37*4882a593Smuzhiyun };
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun struct sja1105_port_status_hl1 {
40*4882a593Smuzhiyun 	u64 n_n664err;
41*4882a593Smuzhiyun 	u64 n_vlanerr;
42*4882a593Smuzhiyun 	u64 n_unreleased;
43*4882a593Smuzhiyun 	u64 n_sizeerr;
44*4882a593Smuzhiyun 	u64 n_crcerr;
45*4882a593Smuzhiyun 	u64 n_vlnotfound;
46*4882a593Smuzhiyun 	u64 n_ctpolerr;
47*4882a593Smuzhiyun 	u64 n_polerr;
48*4882a593Smuzhiyun 	u64 n_rxfrmsh;
49*4882a593Smuzhiyun 	u64 n_rxfrm;
50*4882a593Smuzhiyun 	u64 n_rxbytesh;
51*4882a593Smuzhiyun 	u64 n_rxbyte;
52*4882a593Smuzhiyun 	u64 n_txfrmsh;
53*4882a593Smuzhiyun 	u64 n_txfrm;
54*4882a593Smuzhiyun 	u64 n_txbytesh;
55*4882a593Smuzhiyun 	u64 n_txbyte;
56*4882a593Smuzhiyun };
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun struct sja1105_port_status_hl2 {
59*4882a593Smuzhiyun 	u64 n_qfull;
60*4882a593Smuzhiyun 	u64 n_part_drop;
61*4882a593Smuzhiyun 	u64 n_egr_disabled;
62*4882a593Smuzhiyun 	u64 n_not_reach;
63*4882a593Smuzhiyun 	u64 qlevel_hwm[8]; /* Only for P/Q/R/S */
64*4882a593Smuzhiyun 	u64 qlevel[8];     /* Only for P/Q/R/S */
65*4882a593Smuzhiyun };
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun struct sja1105_port_status_ether {
68*4882a593Smuzhiyun 	u64 n_drops_nolearn;
69*4882a593Smuzhiyun 	u64 n_drops_noroute;
70*4882a593Smuzhiyun 	u64 n_drops_ill_dtag;
71*4882a593Smuzhiyun 	u64 n_drops_dtag;
72*4882a593Smuzhiyun 	u64 n_drops_sotag;
73*4882a593Smuzhiyun 	u64 n_drops_sitag;
74*4882a593Smuzhiyun 	u64 n_drops_utag;
75*4882a593Smuzhiyun 	u64 n_tx_bytes_1024_2047;
76*4882a593Smuzhiyun 	u64 n_tx_bytes_512_1023;
77*4882a593Smuzhiyun 	u64 n_tx_bytes_256_511;
78*4882a593Smuzhiyun 	u64 n_tx_bytes_128_255;
79*4882a593Smuzhiyun 	u64 n_tx_bytes_65_127;
80*4882a593Smuzhiyun 	u64 n_tx_bytes_64;
81*4882a593Smuzhiyun 	u64 n_tx_mcast;
82*4882a593Smuzhiyun 	u64 n_tx_bcast;
83*4882a593Smuzhiyun 	u64 n_rx_bytes_1024_2047;
84*4882a593Smuzhiyun 	u64 n_rx_bytes_512_1023;
85*4882a593Smuzhiyun 	u64 n_rx_bytes_256_511;
86*4882a593Smuzhiyun 	u64 n_rx_bytes_128_255;
87*4882a593Smuzhiyun 	u64 n_rx_bytes_65_127;
88*4882a593Smuzhiyun 	u64 n_rx_bytes_64;
89*4882a593Smuzhiyun 	u64 n_rx_mcast;
90*4882a593Smuzhiyun 	u64 n_rx_bcast;
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun struct sja1105_port_status {
94*4882a593Smuzhiyun 	struct sja1105_port_status_mac mac;
95*4882a593Smuzhiyun 	struct sja1105_port_status_hl1 hl1;
96*4882a593Smuzhiyun 	struct sja1105_port_status_hl2 hl2;
97*4882a593Smuzhiyun 	struct sja1105_port_status_ether ether;
98*4882a593Smuzhiyun };
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun static void
sja1105_port_status_mac_unpack(void * buf,struct sja1105_port_status_mac * status)101*4882a593Smuzhiyun sja1105_port_status_mac_unpack(void *buf,
102*4882a593Smuzhiyun 			       struct sja1105_port_status_mac *status)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun 	/* Make pointer arithmetic work on 4 bytes */
105*4882a593Smuzhiyun 	u32 *p = buf;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	sja1105_unpack(p + 0x0, &status->n_runt,       31, 24, 4);
108*4882a593Smuzhiyun 	sja1105_unpack(p + 0x0, &status->n_soferr,     23, 16, 4);
109*4882a593Smuzhiyun 	sja1105_unpack(p + 0x0, &status->n_alignerr,   15,  8, 4);
110*4882a593Smuzhiyun 	sja1105_unpack(p + 0x0, &status->n_miierr,      7,  0, 4);
111*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->typeerr,      27, 27, 4);
112*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->sizeerr,      26, 26, 4);
113*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->tctimeout,    25, 25, 4);
114*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->priorerr,     24, 24, 4);
115*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->nomaster,     23, 23, 4);
116*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->memov,        22, 22, 4);
117*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->memerr,       21, 21, 4);
118*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->invtyp,       19, 19, 4);
119*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->intcyov,      18, 18, 4);
120*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->domerr,       17, 17, 4);
121*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->pcfbagdrop,   16, 16, 4);
122*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->spcprior,     15, 12, 4);
123*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->ageprior,     11,  8, 4);
124*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->portdrop,      6,  6, 4);
125*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->lendrop,       5,  5, 4);
126*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->bagdrop,       4,  4, 4);
127*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->policeerr,     3,  3, 4);
128*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->drpnona664err, 2,  2, 4);
129*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->spcerr,        1,  1, 4);
130*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->agedrp,        0,  0, 4);
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun static void
sja1105_port_status_hl1_unpack(void * buf,struct sja1105_port_status_hl1 * status)134*4882a593Smuzhiyun sja1105_port_status_hl1_unpack(void *buf,
135*4882a593Smuzhiyun 			       struct sja1105_port_status_hl1 *status)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	/* Make pointer arithmetic work on 4 bytes */
138*4882a593Smuzhiyun 	u32 *p = buf;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	sja1105_unpack(p + 0xF, &status->n_n664err,    31,  0, 4);
141*4882a593Smuzhiyun 	sja1105_unpack(p + 0xE, &status->n_vlanerr,    31,  0, 4);
142*4882a593Smuzhiyun 	sja1105_unpack(p + 0xD, &status->n_unreleased, 31,  0, 4);
143*4882a593Smuzhiyun 	sja1105_unpack(p + 0xC, &status->n_sizeerr,    31,  0, 4);
144*4882a593Smuzhiyun 	sja1105_unpack(p + 0xB, &status->n_crcerr,     31,  0, 4);
145*4882a593Smuzhiyun 	sja1105_unpack(p + 0xA, &status->n_vlnotfound, 31,  0, 4);
146*4882a593Smuzhiyun 	sja1105_unpack(p + 0x9, &status->n_ctpolerr,   31,  0, 4);
147*4882a593Smuzhiyun 	sja1105_unpack(p + 0x8, &status->n_polerr,     31,  0, 4);
148*4882a593Smuzhiyun 	sja1105_unpack(p + 0x7, &status->n_rxfrmsh,    31,  0, 4);
149*4882a593Smuzhiyun 	sja1105_unpack(p + 0x6, &status->n_rxfrm,      31,  0, 4);
150*4882a593Smuzhiyun 	sja1105_unpack(p + 0x5, &status->n_rxbytesh,   31,  0, 4);
151*4882a593Smuzhiyun 	sja1105_unpack(p + 0x4, &status->n_rxbyte,     31,  0, 4);
152*4882a593Smuzhiyun 	sja1105_unpack(p + 0x3, &status->n_txfrmsh,    31,  0, 4);
153*4882a593Smuzhiyun 	sja1105_unpack(p + 0x2, &status->n_txfrm,      31,  0, 4);
154*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->n_txbytesh,   31,  0, 4);
155*4882a593Smuzhiyun 	sja1105_unpack(p + 0x0, &status->n_txbyte,     31,  0, 4);
156*4882a593Smuzhiyun 	status->n_rxfrm  += status->n_rxfrmsh  << 32;
157*4882a593Smuzhiyun 	status->n_rxbyte += status->n_rxbytesh << 32;
158*4882a593Smuzhiyun 	status->n_txfrm  += status->n_txfrmsh  << 32;
159*4882a593Smuzhiyun 	status->n_txbyte += status->n_txbytesh << 32;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun static void
sja1105_port_status_hl2_unpack(void * buf,struct sja1105_port_status_hl2 * status)163*4882a593Smuzhiyun sja1105_port_status_hl2_unpack(void *buf,
164*4882a593Smuzhiyun 			       struct sja1105_port_status_hl2 *status)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun 	/* Make pointer arithmetic work on 4 bytes */
167*4882a593Smuzhiyun 	u32 *p = buf;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	sja1105_unpack(p + 0x3, &status->n_qfull,        31,  0, 4);
170*4882a593Smuzhiyun 	sja1105_unpack(p + 0x2, &status->n_part_drop,    31,  0, 4);
171*4882a593Smuzhiyun 	sja1105_unpack(p + 0x1, &status->n_egr_disabled, 31,  0, 4);
172*4882a593Smuzhiyun 	sja1105_unpack(p + 0x0, &status->n_not_reach,    31,  0, 4);
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun static void
sja1105pqrs_port_status_qlevel_unpack(void * buf,struct sja1105_port_status_hl2 * status)176*4882a593Smuzhiyun sja1105pqrs_port_status_qlevel_unpack(void *buf,
177*4882a593Smuzhiyun 				      struct sja1105_port_status_hl2 *status)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun 	/* Make pointer arithmetic work on 4 bytes */
180*4882a593Smuzhiyun 	u32 *p = buf;
181*4882a593Smuzhiyun 	int i;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	for (i = 0; i < 8; i++) {
184*4882a593Smuzhiyun 		sja1105_unpack(p + i, &status->qlevel_hwm[i], 24, 16, 4);
185*4882a593Smuzhiyun 		sja1105_unpack(p + i, &status->qlevel[i],      8,  0, 4);
186*4882a593Smuzhiyun 	}
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun static void
sja1105pqrs_port_status_ether_unpack(void * buf,struct sja1105_port_status_ether * status)190*4882a593Smuzhiyun sja1105pqrs_port_status_ether_unpack(void *buf,
191*4882a593Smuzhiyun 				     struct sja1105_port_status_ether *status)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun 	/* Make pointer arithmetic work on 4 bytes */
194*4882a593Smuzhiyun 	u32 *p = buf;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	sja1105_unpack(p + 0x16, &status->n_drops_nolearn,      31, 0, 4);
197*4882a593Smuzhiyun 	sja1105_unpack(p + 0x15, &status->n_drops_noroute,      31, 0, 4);
198*4882a593Smuzhiyun 	sja1105_unpack(p + 0x14, &status->n_drops_ill_dtag,     31, 0, 4);
199*4882a593Smuzhiyun 	sja1105_unpack(p + 0x13, &status->n_drops_dtag,         31, 0, 4);
200*4882a593Smuzhiyun 	sja1105_unpack(p + 0x12, &status->n_drops_sotag,        31, 0, 4);
201*4882a593Smuzhiyun 	sja1105_unpack(p + 0x11, &status->n_drops_sitag,        31, 0, 4);
202*4882a593Smuzhiyun 	sja1105_unpack(p + 0x10, &status->n_drops_utag,         31, 0, 4);
203*4882a593Smuzhiyun 	sja1105_unpack(p + 0x0F, &status->n_tx_bytes_1024_2047, 31, 0, 4);
204*4882a593Smuzhiyun 	sja1105_unpack(p + 0x0E, &status->n_tx_bytes_512_1023,  31, 0, 4);
205*4882a593Smuzhiyun 	sja1105_unpack(p + 0x0D, &status->n_tx_bytes_256_511,   31, 0, 4);
206*4882a593Smuzhiyun 	sja1105_unpack(p + 0x0C, &status->n_tx_bytes_128_255,   31, 0, 4);
207*4882a593Smuzhiyun 	sja1105_unpack(p + 0x0B, &status->n_tx_bytes_65_127,    31, 0, 4);
208*4882a593Smuzhiyun 	sja1105_unpack(p + 0x0A, &status->n_tx_bytes_64,        31, 0, 4);
209*4882a593Smuzhiyun 	sja1105_unpack(p + 0x09, &status->n_tx_mcast,           31, 0, 4);
210*4882a593Smuzhiyun 	sja1105_unpack(p + 0x08, &status->n_tx_bcast,           31, 0, 4);
211*4882a593Smuzhiyun 	sja1105_unpack(p + 0x07, &status->n_rx_bytes_1024_2047, 31, 0, 4);
212*4882a593Smuzhiyun 	sja1105_unpack(p + 0x06, &status->n_rx_bytes_512_1023,  31, 0, 4);
213*4882a593Smuzhiyun 	sja1105_unpack(p + 0x05, &status->n_rx_bytes_256_511,   31, 0, 4);
214*4882a593Smuzhiyun 	sja1105_unpack(p + 0x04, &status->n_rx_bytes_128_255,   31, 0, 4);
215*4882a593Smuzhiyun 	sja1105_unpack(p + 0x03, &status->n_rx_bytes_65_127,    31, 0, 4);
216*4882a593Smuzhiyun 	sja1105_unpack(p + 0x02, &status->n_rx_bytes_64,        31, 0, 4);
217*4882a593Smuzhiyun 	sja1105_unpack(p + 0x01, &status->n_rx_mcast,           31, 0, 4);
218*4882a593Smuzhiyun 	sja1105_unpack(p + 0x00, &status->n_rx_bcast,           31, 0, 4);
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun static int
sja1105pqrs_port_status_get_ether(struct sja1105_private * priv,struct sja1105_port_status_ether * ether,int port)222*4882a593Smuzhiyun sja1105pqrs_port_status_get_ether(struct sja1105_private *priv,
223*4882a593Smuzhiyun 				  struct sja1105_port_status_ether *ether,
224*4882a593Smuzhiyun 				  int port)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun 	const struct sja1105_regs *regs = priv->info->regs;
227*4882a593Smuzhiyun 	u8 packed_buf[SJA1105_SIZE_ETHER_AREA] = {0};
228*4882a593Smuzhiyun 	int rc;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	/* Ethernet statistics area */
231*4882a593Smuzhiyun 	rc = sja1105_xfer_buf(priv, SPI_READ, regs->ether_stats[port],
232*4882a593Smuzhiyun 			      packed_buf, SJA1105_SIZE_ETHER_AREA);
233*4882a593Smuzhiyun 	if (rc < 0)
234*4882a593Smuzhiyun 		return rc;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	sja1105pqrs_port_status_ether_unpack(packed_buf, ether);
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	return 0;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun 
sja1105_port_status_get_mac(struct sja1105_private * priv,struct sja1105_port_status_mac * status,int port)241*4882a593Smuzhiyun static int sja1105_port_status_get_mac(struct sja1105_private *priv,
242*4882a593Smuzhiyun 				       struct sja1105_port_status_mac *status,
243*4882a593Smuzhiyun 				       int port)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun 	const struct sja1105_regs *regs = priv->info->regs;
246*4882a593Smuzhiyun 	u8 packed_buf[SJA1105_SIZE_MAC_AREA] = {0};
247*4882a593Smuzhiyun 	int rc;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	/* MAC area */
250*4882a593Smuzhiyun 	rc = sja1105_xfer_buf(priv, SPI_READ, regs->mac[port], packed_buf,
251*4882a593Smuzhiyun 			      SJA1105_SIZE_MAC_AREA);
252*4882a593Smuzhiyun 	if (rc < 0)
253*4882a593Smuzhiyun 		return rc;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	sja1105_port_status_mac_unpack(packed_buf, status);
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	return 0;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun 
sja1105_port_status_get_hl1(struct sja1105_private * priv,struct sja1105_port_status_hl1 * status,int port)260*4882a593Smuzhiyun static int sja1105_port_status_get_hl1(struct sja1105_private *priv,
261*4882a593Smuzhiyun 				       struct sja1105_port_status_hl1 *status,
262*4882a593Smuzhiyun 				       int port)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun 	const struct sja1105_regs *regs = priv->info->regs;
265*4882a593Smuzhiyun 	u8 packed_buf[SJA1105_SIZE_HL1_AREA] = {0};
266*4882a593Smuzhiyun 	int rc;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	rc = sja1105_xfer_buf(priv, SPI_READ, regs->mac_hl1[port], packed_buf,
269*4882a593Smuzhiyun 			      SJA1105_SIZE_HL1_AREA);
270*4882a593Smuzhiyun 	if (rc < 0)
271*4882a593Smuzhiyun 		return rc;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	sja1105_port_status_hl1_unpack(packed_buf, status);
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	return 0;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
sja1105_port_status_get_hl2(struct sja1105_private * priv,struct sja1105_port_status_hl2 * status,int port)278*4882a593Smuzhiyun static int sja1105_port_status_get_hl2(struct sja1105_private *priv,
279*4882a593Smuzhiyun 				       struct sja1105_port_status_hl2 *status,
280*4882a593Smuzhiyun 				       int port)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun 	const struct sja1105_regs *regs = priv->info->regs;
283*4882a593Smuzhiyun 	u8 packed_buf[SJA1105_SIZE_QLEVEL_AREA] = {0};
284*4882a593Smuzhiyun 	int rc;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	rc = sja1105_xfer_buf(priv, SPI_READ, regs->mac_hl2[port], packed_buf,
287*4882a593Smuzhiyun 			      SJA1105_SIZE_HL2_AREA);
288*4882a593Smuzhiyun 	if (rc < 0)
289*4882a593Smuzhiyun 		return rc;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	sja1105_port_status_hl2_unpack(packed_buf, status);
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	/* Code below is strictly P/Q/R/S specific. */
294*4882a593Smuzhiyun 	if (priv->info->device_id == SJA1105E_DEVICE_ID ||
295*4882a593Smuzhiyun 	    priv->info->device_id == SJA1105T_DEVICE_ID)
296*4882a593Smuzhiyun 		return 0;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	rc = sja1105_xfer_buf(priv, SPI_READ, regs->qlevel[port], packed_buf,
299*4882a593Smuzhiyun 			      SJA1105_SIZE_QLEVEL_AREA);
300*4882a593Smuzhiyun 	if (rc < 0)
301*4882a593Smuzhiyun 		return rc;
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	sja1105pqrs_port_status_qlevel_unpack(packed_buf, status);
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	return 0;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun 
sja1105_port_status_get(struct sja1105_private * priv,struct sja1105_port_status * status,int port)308*4882a593Smuzhiyun static int sja1105_port_status_get(struct sja1105_private *priv,
309*4882a593Smuzhiyun 				   struct sja1105_port_status *status,
310*4882a593Smuzhiyun 				   int port)
311*4882a593Smuzhiyun {
312*4882a593Smuzhiyun 	int rc;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	rc = sja1105_port_status_get_mac(priv, &status->mac, port);
315*4882a593Smuzhiyun 	if (rc < 0)
316*4882a593Smuzhiyun 		return rc;
317*4882a593Smuzhiyun 	rc = sja1105_port_status_get_hl1(priv, &status->hl1, port);
318*4882a593Smuzhiyun 	if (rc < 0)
319*4882a593Smuzhiyun 		return rc;
320*4882a593Smuzhiyun 	rc = sja1105_port_status_get_hl2(priv, &status->hl2, port);
321*4882a593Smuzhiyun 	if (rc < 0)
322*4882a593Smuzhiyun 		return rc;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	if (priv->info->device_id == SJA1105E_DEVICE_ID ||
325*4882a593Smuzhiyun 	    priv->info->device_id == SJA1105T_DEVICE_ID)
326*4882a593Smuzhiyun 		return 0;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	return sja1105pqrs_port_status_get_ether(priv, &status->ether, port);
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun static char sja1105_port_stats[][ETH_GSTRING_LEN] = {
332*4882a593Smuzhiyun 	/* MAC-Level Diagnostic Counters */
333*4882a593Smuzhiyun 	"n_runt",
334*4882a593Smuzhiyun 	"n_soferr",
335*4882a593Smuzhiyun 	"n_alignerr",
336*4882a593Smuzhiyun 	"n_miierr",
337*4882a593Smuzhiyun 	/* MAC-Level Diagnostic Flags */
338*4882a593Smuzhiyun 	"typeerr",
339*4882a593Smuzhiyun 	"sizeerr",
340*4882a593Smuzhiyun 	"tctimeout",
341*4882a593Smuzhiyun 	"priorerr",
342*4882a593Smuzhiyun 	"nomaster",
343*4882a593Smuzhiyun 	"memov",
344*4882a593Smuzhiyun 	"memerr",
345*4882a593Smuzhiyun 	"invtyp",
346*4882a593Smuzhiyun 	"intcyov",
347*4882a593Smuzhiyun 	"domerr",
348*4882a593Smuzhiyun 	"pcfbagdrop",
349*4882a593Smuzhiyun 	"spcprior",
350*4882a593Smuzhiyun 	"ageprior",
351*4882a593Smuzhiyun 	"portdrop",
352*4882a593Smuzhiyun 	"lendrop",
353*4882a593Smuzhiyun 	"bagdrop",
354*4882a593Smuzhiyun 	"policeerr",
355*4882a593Smuzhiyun 	"drpnona664err",
356*4882a593Smuzhiyun 	"spcerr",
357*4882a593Smuzhiyun 	"agedrp",
358*4882a593Smuzhiyun 	/* High-Level Diagnostic Counters */
359*4882a593Smuzhiyun 	"n_n664err",
360*4882a593Smuzhiyun 	"n_vlanerr",
361*4882a593Smuzhiyun 	"n_unreleased",
362*4882a593Smuzhiyun 	"n_sizeerr",
363*4882a593Smuzhiyun 	"n_crcerr",
364*4882a593Smuzhiyun 	"n_vlnotfound",
365*4882a593Smuzhiyun 	"n_ctpolerr",
366*4882a593Smuzhiyun 	"n_polerr",
367*4882a593Smuzhiyun 	"n_rxfrm",
368*4882a593Smuzhiyun 	"n_rxbyte",
369*4882a593Smuzhiyun 	"n_txfrm",
370*4882a593Smuzhiyun 	"n_txbyte",
371*4882a593Smuzhiyun 	"n_qfull",
372*4882a593Smuzhiyun 	"n_part_drop",
373*4882a593Smuzhiyun 	"n_egr_disabled",
374*4882a593Smuzhiyun 	"n_not_reach",
375*4882a593Smuzhiyun };
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun static char sja1105pqrs_extra_port_stats[][ETH_GSTRING_LEN] = {
378*4882a593Smuzhiyun 	/* Queue Levels */
379*4882a593Smuzhiyun 	"qlevel_hwm_0",
380*4882a593Smuzhiyun 	"qlevel_hwm_1",
381*4882a593Smuzhiyun 	"qlevel_hwm_2",
382*4882a593Smuzhiyun 	"qlevel_hwm_3",
383*4882a593Smuzhiyun 	"qlevel_hwm_4",
384*4882a593Smuzhiyun 	"qlevel_hwm_5",
385*4882a593Smuzhiyun 	"qlevel_hwm_6",
386*4882a593Smuzhiyun 	"qlevel_hwm_7",
387*4882a593Smuzhiyun 	"qlevel_0",
388*4882a593Smuzhiyun 	"qlevel_1",
389*4882a593Smuzhiyun 	"qlevel_2",
390*4882a593Smuzhiyun 	"qlevel_3",
391*4882a593Smuzhiyun 	"qlevel_4",
392*4882a593Smuzhiyun 	"qlevel_5",
393*4882a593Smuzhiyun 	"qlevel_6",
394*4882a593Smuzhiyun 	"qlevel_7",
395*4882a593Smuzhiyun 	/* Ether Stats */
396*4882a593Smuzhiyun 	"n_drops_nolearn",
397*4882a593Smuzhiyun 	"n_drops_noroute",
398*4882a593Smuzhiyun 	"n_drops_ill_dtag",
399*4882a593Smuzhiyun 	"n_drops_dtag",
400*4882a593Smuzhiyun 	"n_drops_sotag",
401*4882a593Smuzhiyun 	"n_drops_sitag",
402*4882a593Smuzhiyun 	"n_drops_utag",
403*4882a593Smuzhiyun 	"n_tx_bytes_1024_2047",
404*4882a593Smuzhiyun 	"n_tx_bytes_512_1023",
405*4882a593Smuzhiyun 	"n_tx_bytes_256_511",
406*4882a593Smuzhiyun 	"n_tx_bytes_128_255",
407*4882a593Smuzhiyun 	"n_tx_bytes_65_127",
408*4882a593Smuzhiyun 	"n_tx_bytes_64",
409*4882a593Smuzhiyun 	"n_tx_mcast",
410*4882a593Smuzhiyun 	"n_tx_bcast",
411*4882a593Smuzhiyun 	"n_rx_bytes_1024_2047",
412*4882a593Smuzhiyun 	"n_rx_bytes_512_1023",
413*4882a593Smuzhiyun 	"n_rx_bytes_256_511",
414*4882a593Smuzhiyun 	"n_rx_bytes_128_255",
415*4882a593Smuzhiyun 	"n_rx_bytes_65_127",
416*4882a593Smuzhiyun 	"n_rx_bytes_64",
417*4882a593Smuzhiyun 	"n_rx_mcast",
418*4882a593Smuzhiyun 	"n_rx_bcast",
419*4882a593Smuzhiyun };
420*4882a593Smuzhiyun 
sja1105_get_ethtool_stats(struct dsa_switch * ds,int port,u64 * data)421*4882a593Smuzhiyun void sja1105_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data)
422*4882a593Smuzhiyun {
423*4882a593Smuzhiyun 	struct sja1105_private *priv = ds->priv;
424*4882a593Smuzhiyun 	struct sja1105_port_status *status;
425*4882a593Smuzhiyun 	int rc, i, k = 0;
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	status = kzalloc(sizeof(*status), GFP_KERNEL);
428*4882a593Smuzhiyun 	if (!status)
429*4882a593Smuzhiyun 		goto out;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	rc = sja1105_port_status_get(priv, status, port);
432*4882a593Smuzhiyun 	if (rc < 0) {
433*4882a593Smuzhiyun 		dev_err(ds->dev, "Failed to read port %d counters: %d\n",
434*4882a593Smuzhiyun 			port, rc);
435*4882a593Smuzhiyun 		goto out;
436*4882a593Smuzhiyun 	}
437*4882a593Smuzhiyun 	memset(data, 0, ARRAY_SIZE(sja1105_port_stats) * sizeof(u64));
438*4882a593Smuzhiyun 	data[k++] = status->mac.n_runt;
439*4882a593Smuzhiyun 	data[k++] = status->mac.n_soferr;
440*4882a593Smuzhiyun 	data[k++] = status->mac.n_alignerr;
441*4882a593Smuzhiyun 	data[k++] = status->mac.n_miierr;
442*4882a593Smuzhiyun 	data[k++] = status->mac.typeerr;
443*4882a593Smuzhiyun 	data[k++] = status->mac.sizeerr;
444*4882a593Smuzhiyun 	data[k++] = status->mac.tctimeout;
445*4882a593Smuzhiyun 	data[k++] = status->mac.priorerr;
446*4882a593Smuzhiyun 	data[k++] = status->mac.nomaster;
447*4882a593Smuzhiyun 	data[k++] = status->mac.memov;
448*4882a593Smuzhiyun 	data[k++] = status->mac.memerr;
449*4882a593Smuzhiyun 	data[k++] = status->mac.invtyp;
450*4882a593Smuzhiyun 	data[k++] = status->mac.intcyov;
451*4882a593Smuzhiyun 	data[k++] = status->mac.domerr;
452*4882a593Smuzhiyun 	data[k++] = status->mac.pcfbagdrop;
453*4882a593Smuzhiyun 	data[k++] = status->mac.spcprior;
454*4882a593Smuzhiyun 	data[k++] = status->mac.ageprior;
455*4882a593Smuzhiyun 	data[k++] = status->mac.portdrop;
456*4882a593Smuzhiyun 	data[k++] = status->mac.lendrop;
457*4882a593Smuzhiyun 	data[k++] = status->mac.bagdrop;
458*4882a593Smuzhiyun 	data[k++] = status->mac.policeerr;
459*4882a593Smuzhiyun 	data[k++] = status->mac.drpnona664err;
460*4882a593Smuzhiyun 	data[k++] = status->mac.spcerr;
461*4882a593Smuzhiyun 	data[k++] = status->mac.agedrp;
462*4882a593Smuzhiyun 	data[k++] = status->hl1.n_n664err;
463*4882a593Smuzhiyun 	data[k++] = status->hl1.n_vlanerr;
464*4882a593Smuzhiyun 	data[k++] = status->hl1.n_unreleased;
465*4882a593Smuzhiyun 	data[k++] = status->hl1.n_sizeerr;
466*4882a593Smuzhiyun 	data[k++] = status->hl1.n_crcerr;
467*4882a593Smuzhiyun 	data[k++] = status->hl1.n_vlnotfound;
468*4882a593Smuzhiyun 	data[k++] = status->hl1.n_ctpolerr;
469*4882a593Smuzhiyun 	data[k++] = status->hl1.n_polerr;
470*4882a593Smuzhiyun 	data[k++] = status->hl1.n_rxfrm;
471*4882a593Smuzhiyun 	data[k++] = status->hl1.n_rxbyte;
472*4882a593Smuzhiyun 	data[k++] = status->hl1.n_txfrm;
473*4882a593Smuzhiyun 	data[k++] = status->hl1.n_txbyte;
474*4882a593Smuzhiyun 	data[k++] = status->hl2.n_qfull;
475*4882a593Smuzhiyun 	data[k++] = status->hl2.n_part_drop;
476*4882a593Smuzhiyun 	data[k++] = status->hl2.n_egr_disabled;
477*4882a593Smuzhiyun 	data[k++] = status->hl2.n_not_reach;
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	if (priv->info->device_id == SJA1105E_DEVICE_ID ||
480*4882a593Smuzhiyun 	    priv->info->device_id == SJA1105T_DEVICE_ID)
481*4882a593Smuzhiyun 		goto out;
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	memset(data + k, 0, ARRAY_SIZE(sja1105pqrs_extra_port_stats) *
484*4882a593Smuzhiyun 			sizeof(u64));
485*4882a593Smuzhiyun 	for (i = 0; i < 8; i++) {
486*4882a593Smuzhiyun 		data[k++] = status->hl2.qlevel_hwm[i];
487*4882a593Smuzhiyun 		data[k++] = status->hl2.qlevel[i];
488*4882a593Smuzhiyun 	}
489*4882a593Smuzhiyun 	data[k++] = status->ether.n_drops_nolearn;
490*4882a593Smuzhiyun 	data[k++] = status->ether.n_drops_noroute;
491*4882a593Smuzhiyun 	data[k++] = status->ether.n_drops_ill_dtag;
492*4882a593Smuzhiyun 	data[k++] = status->ether.n_drops_dtag;
493*4882a593Smuzhiyun 	data[k++] = status->ether.n_drops_sotag;
494*4882a593Smuzhiyun 	data[k++] = status->ether.n_drops_sitag;
495*4882a593Smuzhiyun 	data[k++] = status->ether.n_drops_utag;
496*4882a593Smuzhiyun 	data[k++] = status->ether.n_tx_bytes_1024_2047;
497*4882a593Smuzhiyun 	data[k++] = status->ether.n_tx_bytes_512_1023;
498*4882a593Smuzhiyun 	data[k++] = status->ether.n_tx_bytes_256_511;
499*4882a593Smuzhiyun 	data[k++] = status->ether.n_tx_bytes_128_255;
500*4882a593Smuzhiyun 	data[k++] = status->ether.n_tx_bytes_65_127;
501*4882a593Smuzhiyun 	data[k++] = status->ether.n_tx_bytes_64;
502*4882a593Smuzhiyun 	data[k++] = status->ether.n_tx_mcast;
503*4882a593Smuzhiyun 	data[k++] = status->ether.n_tx_bcast;
504*4882a593Smuzhiyun 	data[k++] = status->ether.n_rx_bytes_1024_2047;
505*4882a593Smuzhiyun 	data[k++] = status->ether.n_rx_bytes_512_1023;
506*4882a593Smuzhiyun 	data[k++] = status->ether.n_rx_bytes_256_511;
507*4882a593Smuzhiyun 	data[k++] = status->ether.n_rx_bytes_128_255;
508*4882a593Smuzhiyun 	data[k++] = status->ether.n_rx_bytes_65_127;
509*4882a593Smuzhiyun 	data[k++] = status->ether.n_rx_bytes_64;
510*4882a593Smuzhiyun 	data[k++] = status->ether.n_rx_mcast;
511*4882a593Smuzhiyun 	data[k++] = status->ether.n_rx_bcast;
512*4882a593Smuzhiyun out:
513*4882a593Smuzhiyun 	kfree(status);
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun 
sja1105_get_strings(struct dsa_switch * ds,int port,u32 stringset,u8 * data)516*4882a593Smuzhiyun void sja1105_get_strings(struct dsa_switch *ds, int port,
517*4882a593Smuzhiyun 			 u32 stringset, u8 *data)
518*4882a593Smuzhiyun {
519*4882a593Smuzhiyun 	struct sja1105_private *priv = ds->priv;
520*4882a593Smuzhiyun 	u8 *p = data;
521*4882a593Smuzhiyun 	int i;
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	switch (stringset) {
524*4882a593Smuzhiyun 	case ETH_SS_STATS:
525*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(sja1105_port_stats); i++) {
526*4882a593Smuzhiyun 			strlcpy(p, sja1105_port_stats[i], ETH_GSTRING_LEN);
527*4882a593Smuzhiyun 			p += ETH_GSTRING_LEN;
528*4882a593Smuzhiyun 		}
529*4882a593Smuzhiyun 		if (priv->info->device_id == SJA1105E_DEVICE_ID ||
530*4882a593Smuzhiyun 		    priv->info->device_id == SJA1105T_DEVICE_ID)
531*4882a593Smuzhiyun 			return;
532*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(sja1105pqrs_extra_port_stats); i++) {
533*4882a593Smuzhiyun 			strlcpy(p, sja1105pqrs_extra_port_stats[i],
534*4882a593Smuzhiyun 				ETH_GSTRING_LEN);
535*4882a593Smuzhiyun 			p += ETH_GSTRING_LEN;
536*4882a593Smuzhiyun 		}
537*4882a593Smuzhiyun 		break;
538*4882a593Smuzhiyun 	}
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun 
sja1105_get_sset_count(struct dsa_switch * ds,int port,int sset)541*4882a593Smuzhiyun int sja1105_get_sset_count(struct dsa_switch *ds, int port, int sset)
542*4882a593Smuzhiyun {
543*4882a593Smuzhiyun 	int count = ARRAY_SIZE(sja1105_port_stats);
544*4882a593Smuzhiyun 	struct sja1105_private *priv = ds->priv;
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 	if (sset != ETH_SS_STATS)
547*4882a593Smuzhiyun 		return -EOPNOTSUPP;
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	if (priv->info->device_id == SJA1105PR_DEVICE_ID ||
550*4882a593Smuzhiyun 	    priv->info->device_id == SJA1105QS_DEVICE_ID)
551*4882a593Smuzhiyun 		count += ARRAY_SIZE(sja1105pqrs_extra_port_stats);
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	return count;
554*4882a593Smuzhiyun }
555