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