Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com>
  3 */
  4#include "sja1105.h"
  5
  6#define SJA1105_SIZE_MAC_AREA		(0x02 * 4)
  7#define SJA1105_SIZE_HL1_AREA		(0x10 * 4)
  8#define SJA1105_SIZE_HL2_AREA		(0x4 * 4)
  9#define SJA1105_SIZE_QLEVEL_AREA	(0x8 * 4) /* 0x4 to 0xB */
 10
 11struct sja1105_port_status_mac {
 12	u64 n_runt;
 13	u64 n_soferr;
 14	u64 n_alignerr;
 15	u64 n_miierr;
 16	u64 typeerr;
 17	u64 sizeerr;
 18	u64 tctimeout;
 19	u64 priorerr;
 20	u64 nomaster;
 21	u64 memov;
 22	u64 memerr;
 23	u64 invtyp;
 24	u64 intcyov;
 25	u64 domerr;
 26	u64 pcfbagdrop;
 27	u64 spcprior;
 28	u64 ageprior;
 29	u64 portdrop;
 30	u64 lendrop;
 31	u64 bagdrop;
 32	u64 policeerr;
 33	u64 drpnona664err;
 34	u64 spcerr;
 35	u64 agedrp;
 36};
 37
 38struct sja1105_port_status_hl1 {
 39	u64 n_n664err;
 40	u64 n_vlanerr;
 41	u64 n_unreleased;
 42	u64 n_sizeerr;
 43	u64 n_crcerr;
 44	u64 n_vlnotfound;
 45	u64 n_ctpolerr;
 46	u64 n_polerr;
 47	u64 n_rxfrmsh;
 48	u64 n_rxfrm;
 49	u64 n_rxbytesh;
 50	u64 n_rxbyte;
 51	u64 n_txfrmsh;
 52	u64 n_txfrm;
 53	u64 n_txbytesh;
 54	u64 n_txbyte;
 55};
 56
 57struct sja1105_port_status_hl2 {
 58	u64 n_qfull;
 59	u64 n_part_drop;
 60	u64 n_egr_disabled;
 61	u64 n_not_reach;
 62	u64 qlevel_hwm[8]; /* Only for P/Q/R/S */
 63	u64 qlevel[8];     /* Only for P/Q/R/S */
 64};
 65
 66struct sja1105_port_status {
 67	struct sja1105_port_status_mac mac;
 68	struct sja1105_port_status_hl1 hl1;
 69	struct sja1105_port_status_hl2 hl2;
 70};
 71
 72static void
 73sja1105_port_status_mac_unpack(void *buf,
 74			       struct sja1105_port_status_mac *status)
 75{
 76	/* Make pointer arithmetic work on 4 bytes */
 77	u32 *p = buf;
 78
 79	sja1105_unpack(p + 0x0, &status->n_runt,       31, 24, 4);
 80	sja1105_unpack(p + 0x0, &status->n_soferr,     23, 16, 4);
 81	sja1105_unpack(p + 0x0, &status->n_alignerr,   15,  8, 4);
 82	sja1105_unpack(p + 0x0, &status->n_miierr,      7,  0, 4);
 83	sja1105_unpack(p + 0x1, &status->typeerr,      27, 27, 4);
 84	sja1105_unpack(p + 0x1, &status->sizeerr,      26, 26, 4);
 85	sja1105_unpack(p + 0x1, &status->tctimeout,    25, 25, 4);
 86	sja1105_unpack(p + 0x1, &status->priorerr,     24, 24, 4);
 87	sja1105_unpack(p + 0x1, &status->nomaster,     23, 23, 4);
 88	sja1105_unpack(p + 0x1, &status->memov,        22, 22, 4);
 89	sja1105_unpack(p + 0x1, &status->memerr,       21, 21, 4);
 90	sja1105_unpack(p + 0x1, &status->invtyp,       19, 19, 4);
 91	sja1105_unpack(p + 0x1, &status->intcyov,      18, 18, 4);
 92	sja1105_unpack(p + 0x1, &status->domerr,       17, 17, 4);
 93	sja1105_unpack(p + 0x1, &status->pcfbagdrop,   16, 16, 4);
 94	sja1105_unpack(p + 0x1, &status->spcprior,     15, 12, 4);
 95	sja1105_unpack(p + 0x1, &status->ageprior,     11,  8, 4);
 96	sja1105_unpack(p + 0x1, &status->portdrop,      6,  6, 4);
 97	sja1105_unpack(p + 0x1, &status->lendrop,       5,  5, 4);
 98	sja1105_unpack(p + 0x1, &status->bagdrop,       4,  4, 4);
 99	sja1105_unpack(p + 0x1, &status->policeerr,     3,  3, 4);
100	sja1105_unpack(p + 0x1, &status->drpnona664err, 2,  2, 4);
101	sja1105_unpack(p + 0x1, &status->spcerr,        1,  1, 4);
102	sja1105_unpack(p + 0x1, &status->agedrp,        0,  0, 4);
103}
104
105static void
106sja1105_port_status_hl1_unpack(void *buf,
107			       struct sja1105_port_status_hl1 *status)
108{
109	/* Make pointer arithmetic work on 4 bytes */
110	u32 *p = buf;
111
112	sja1105_unpack(p + 0xF, &status->n_n664err,    31,  0, 4);
113	sja1105_unpack(p + 0xE, &status->n_vlanerr,    31,  0, 4);
114	sja1105_unpack(p + 0xD, &status->n_unreleased, 31,  0, 4);
115	sja1105_unpack(p + 0xC, &status->n_sizeerr,    31,  0, 4);
116	sja1105_unpack(p + 0xB, &status->n_crcerr,     31,  0, 4);
117	sja1105_unpack(p + 0xA, &status->n_vlnotfound, 31,  0, 4);
118	sja1105_unpack(p + 0x9, &status->n_ctpolerr,   31,  0, 4);
119	sja1105_unpack(p + 0x8, &status->n_polerr,     31,  0, 4);
120	sja1105_unpack(p + 0x7, &status->n_rxfrmsh,    31,  0, 4);
121	sja1105_unpack(p + 0x6, &status->n_rxfrm,      31,  0, 4);
122	sja1105_unpack(p + 0x5, &status->n_rxbytesh,   31,  0, 4);
123	sja1105_unpack(p + 0x4, &status->n_rxbyte,     31,  0, 4);
124	sja1105_unpack(p + 0x3, &status->n_txfrmsh,    31,  0, 4);
125	sja1105_unpack(p + 0x2, &status->n_txfrm,      31,  0, 4);
126	sja1105_unpack(p + 0x1, &status->n_txbytesh,   31,  0, 4);
127	sja1105_unpack(p + 0x0, &status->n_txbyte,     31,  0, 4);
128	status->n_rxfrm  += status->n_rxfrmsh  << 32;
129	status->n_rxbyte += status->n_rxbytesh << 32;
130	status->n_txfrm  += status->n_txfrmsh  << 32;
131	status->n_txbyte += status->n_txbytesh << 32;
132}
133
134static void
135sja1105_port_status_hl2_unpack(void *buf,
136			       struct sja1105_port_status_hl2 *status)
137{
138	/* Make pointer arithmetic work on 4 bytes */
139	u32 *p = buf;
140
141	sja1105_unpack(p + 0x3, &status->n_qfull,        31,  0, 4);
142	sja1105_unpack(p + 0x2, &status->n_part_drop,    31,  0, 4);
143	sja1105_unpack(p + 0x1, &status->n_egr_disabled, 31,  0, 4);
144	sja1105_unpack(p + 0x0, &status->n_not_reach,    31,  0, 4);
145}
146
147static void
148sja1105pqrs_port_status_qlevel_unpack(void *buf,
149				      struct sja1105_port_status_hl2 *status)
150{
151	/* Make pointer arithmetic work on 4 bytes */
152	u32 *p = buf;
153	int i;
154
155	for (i = 0; i < 8; i++) {
156		sja1105_unpack(p + i, &status->qlevel_hwm[i], 24, 16, 4);
157		sja1105_unpack(p + i, &status->qlevel[i],      8,  0, 4);
158	}
159}
160
161static int sja1105_port_status_get_mac(struct sja1105_private *priv,
162				       struct sja1105_port_status_mac *status,
163				       int port)
164{
165	const struct sja1105_regs *regs = priv->info->regs;
166	u8 packed_buf[SJA1105_SIZE_MAC_AREA] = {0};
167	int rc;
168
169	/* MAC area */
170	rc = sja1105_spi_send_packed_buf(priv, SPI_READ, regs->mac[port],
171					 packed_buf, SJA1105_SIZE_MAC_AREA);
172	if (rc < 0)
173		return rc;
174
175	sja1105_port_status_mac_unpack(packed_buf, status);
176
177	return 0;
178}
179
180static int sja1105_port_status_get_hl1(struct sja1105_private *priv,
181				       struct sja1105_port_status_hl1 *status,
182				       int port)
183{
184	const struct sja1105_regs *regs = priv->info->regs;
185	u8 packed_buf[SJA1105_SIZE_HL1_AREA] = {0};
186	int rc;
187
188	rc = sja1105_spi_send_packed_buf(priv, SPI_READ, regs->mac_hl1[port],
189					 packed_buf, SJA1105_SIZE_HL1_AREA);
190	if (rc < 0)
191		return rc;
192
193	sja1105_port_status_hl1_unpack(packed_buf, status);
194
195	return 0;
196}
197
198static int sja1105_port_status_get_hl2(struct sja1105_private *priv,
199				       struct sja1105_port_status_hl2 *status,
200				       int port)
201{
202	const struct sja1105_regs *regs = priv->info->regs;
203	u8 packed_buf[SJA1105_SIZE_QLEVEL_AREA] = {0};
204	int rc;
205
206	rc = sja1105_spi_send_packed_buf(priv, SPI_READ, regs->mac_hl2[port],
207					 packed_buf, SJA1105_SIZE_HL2_AREA);
208	if (rc < 0)
209		return rc;
210
211	sja1105_port_status_hl2_unpack(packed_buf, status);
212
213	/* Code below is strictly P/Q/R/S specific. */
214	if (priv->info->device_id == SJA1105E_DEVICE_ID ||
215	    priv->info->device_id == SJA1105T_DEVICE_ID)
216		return 0;
217
218	rc = sja1105_spi_send_packed_buf(priv, SPI_READ, regs->qlevel[port],
219					 packed_buf, SJA1105_SIZE_QLEVEL_AREA);
220	if (rc < 0)
221		return rc;
222
223	sja1105pqrs_port_status_qlevel_unpack(packed_buf, status);
224
225	return 0;
226}
227
228static int sja1105_port_status_get(struct sja1105_private *priv,
229				   struct sja1105_port_status *status,
230				   int port)
231{
232	int rc;
233
234	rc = sja1105_port_status_get_mac(priv, &status->mac, port);
235	if (rc < 0)
236		return rc;
237	rc = sja1105_port_status_get_hl1(priv, &status->hl1, port);
238	if (rc < 0)
239		return rc;
240	rc = sja1105_port_status_get_hl2(priv, &status->hl2, port);
241	if (rc < 0)
242		return rc;
243
244	return 0;
245}
246
247static char sja1105_port_stats[][ETH_GSTRING_LEN] = {
248	/* MAC-Level Diagnostic Counters */
249	"n_runt",
250	"n_soferr",
251	"n_alignerr",
252	"n_miierr",
253	/* MAC-Level Diagnostic Flags */
254	"typeerr",
255	"sizeerr",
256	"tctimeout",
257	"priorerr",
258	"nomaster",
259	"memov",
260	"memerr",
261	"invtyp",
262	"intcyov",
263	"domerr",
264	"pcfbagdrop",
265	"spcprior",
266	"ageprior",
267	"portdrop",
268	"lendrop",
269	"bagdrop",
270	"policeerr",
271	"drpnona664err",
272	"spcerr",
273	"agedrp",
274	/* High-Level Diagnostic Counters */
275	"n_n664err",
276	"n_vlanerr",
277	"n_unreleased",
278	"n_sizeerr",
279	"n_crcerr",
280	"n_vlnotfound",
281	"n_ctpolerr",
282	"n_polerr",
283	"n_rxfrm",
284	"n_rxbyte",
285	"n_txfrm",
286	"n_txbyte",
287	"n_qfull",
288	"n_part_drop",
289	"n_egr_disabled",
290	"n_not_reach",
291};
292
293static char sja1105pqrs_extra_port_stats[][ETH_GSTRING_LEN] = {
294	/* Queue Levels */
295	"qlevel_hwm_0",
296	"qlevel_hwm_1",
297	"qlevel_hwm_2",
298	"qlevel_hwm_3",
299	"qlevel_hwm_4",
300	"qlevel_hwm_5",
301	"qlevel_hwm_6",
302	"qlevel_hwm_7",
303	"qlevel_0",
304	"qlevel_1",
305	"qlevel_2",
306	"qlevel_3",
307	"qlevel_4",
308	"qlevel_5",
309	"qlevel_6",
310	"qlevel_7",
311};
312
313void sja1105_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data)
314{
315	struct sja1105_private *priv = ds->priv;
316	struct sja1105_port_status status;
317	int rc, i, k = 0;
318
319	memset(&status, 0, sizeof(status));
320
321	rc = sja1105_port_status_get(priv, &status, port);
322	if (rc < 0) {
323		dev_err(ds->dev, "Failed to read port %d counters: %d\n",
324			port, rc);
325		return;
326	}
327	memset(data, 0, ARRAY_SIZE(sja1105_port_stats) * sizeof(u64));
328	data[k++] = status.mac.n_runt;
329	data[k++] = status.mac.n_soferr;
330	data[k++] = status.mac.n_alignerr;
331	data[k++] = status.mac.n_miierr;
332	data[k++] = status.mac.typeerr;
333	data[k++] = status.mac.sizeerr;
334	data[k++] = status.mac.tctimeout;
335	data[k++] = status.mac.priorerr;
336	data[k++] = status.mac.nomaster;
337	data[k++] = status.mac.memov;
338	data[k++] = status.mac.memerr;
339	data[k++] = status.mac.invtyp;
340	data[k++] = status.mac.intcyov;
341	data[k++] = status.mac.domerr;
342	data[k++] = status.mac.pcfbagdrop;
343	data[k++] = status.mac.spcprior;
344	data[k++] = status.mac.ageprior;
345	data[k++] = status.mac.portdrop;
346	data[k++] = status.mac.lendrop;
347	data[k++] = status.mac.bagdrop;
348	data[k++] = status.mac.policeerr;
349	data[k++] = status.mac.drpnona664err;
350	data[k++] = status.mac.spcerr;
351	data[k++] = status.mac.agedrp;
352	data[k++] = status.hl1.n_n664err;
353	data[k++] = status.hl1.n_vlanerr;
354	data[k++] = status.hl1.n_unreleased;
355	data[k++] = status.hl1.n_sizeerr;
356	data[k++] = status.hl1.n_crcerr;
357	data[k++] = status.hl1.n_vlnotfound;
358	data[k++] = status.hl1.n_ctpolerr;
359	data[k++] = status.hl1.n_polerr;
360	data[k++] = status.hl1.n_rxfrm;
361	data[k++] = status.hl1.n_rxbyte;
362	data[k++] = status.hl1.n_txfrm;
363	data[k++] = status.hl1.n_txbyte;
364	data[k++] = status.hl2.n_qfull;
365	data[k++] = status.hl2.n_part_drop;
366	data[k++] = status.hl2.n_egr_disabled;
367	data[k++] = status.hl2.n_not_reach;
368
369	if (priv->info->device_id == SJA1105E_DEVICE_ID ||
370	    priv->info->device_id == SJA1105T_DEVICE_ID)
371		return;
372
373	memset(data + k, 0, ARRAY_SIZE(sja1105pqrs_extra_port_stats) *
374			sizeof(u64));
375	for (i = 0; i < 8; i++) {
376		data[k++] = status.hl2.qlevel_hwm[i];
377		data[k++] = status.hl2.qlevel[i];
378	}
379}
380
381void sja1105_get_strings(struct dsa_switch *ds, int port,
382			 u32 stringset, u8 *data)
383{
384	struct sja1105_private *priv = ds->priv;
385	u8 *p = data;
386	int i;
387
388	switch (stringset) {
389	case ETH_SS_STATS:
390		for (i = 0; i < ARRAY_SIZE(sja1105_port_stats); i++) {
391			strlcpy(p, sja1105_port_stats[i], ETH_GSTRING_LEN);
392			p += ETH_GSTRING_LEN;
393		}
394		if (priv->info->device_id == SJA1105E_DEVICE_ID ||
395		    priv->info->device_id == SJA1105T_DEVICE_ID)
396			return;
397		for (i = 0; i < ARRAY_SIZE(sja1105pqrs_extra_port_stats); i++) {
398			strlcpy(p, sja1105pqrs_extra_port_stats[i],
399				ETH_GSTRING_LEN);
400			p += ETH_GSTRING_LEN;
401		}
402		break;
403	}
404}
405
406int sja1105_get_sset_count(struct dsa_switch *ds, int port, int sset)
407{
408	int count = ARRAY_SIZE(sja1105_port_stats);
409	struct sja1105_private *priv = ds->priv;
410
411	if (sset != ETH_SS_STATS)
412		return -EOPNOTSUPP;
413
414	if (priv->info->device_id == SJA1105PR_DEVICE_ID ||
415	    priv->info->device_id == SJA1105QS_DEVICE_ID)
416		count += ARRAY_SIZE(sja1105pqrs_extra_port_stats);
417
418	return count;
419}