1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com>
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 */
11 struct sja1105_port_status_mac
{
38 struct sja1105_port_status_hl1
{
57 struct sja1105_port_status_hl2
{
62 u64 qlevel_hwm
[8]; /* Only for P/Q/R/S */
63 u64 qlevel
[8]; /* Only for P/Q/R/S */
66 struct sja1105_port_status
{
67 struct sja1105_port_status_mac mac
;
68 struct sja1105_port_status_hl1 hl1
;
69 struct sja1105_port_status_hl2 hl2
;
73 sja1105_port_status_mac_unpack(void *buf
,
74 struct sja1105_port_status_mac
*status
)
76 /* Make pointer arithmetic work on 4 bytes */
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);
106 sja1105_port_status_hl1_unpack(void *buf
,
107 struct sja1105_port_status_hl1
*status
)
109 /* Make pointer arithmetic work on 4 bytes */
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;
135 sja1105_port_status_hl2_unpack(void *buf
,
136 struct sja1105_port_status_hl2
*status
)
138 /* Make pointer arithmetic work on 4 bytes */
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);
148 sja1105pqrs_port_status_qlevel_unpack(void *buf
,
149 struct sja1105_port_status_hl2
*status
)
151 /* Make pointer arithmetic work on 4 bytes */
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);
161 static int sja1105_port_status_get_mac(struct sja1105_private
*priv
,
162 struct sja1105_port_status_mac
*status
,
165 const struct sja1105_regs
*regs
= priv
->info
->regs
;
166 u8 packed_buf
[SJA1105_SIZE_MAC_AREA
] = {0};
170 rc
= sja1105_xfer_buf(priv
, SPI_READ
, regs
->mac
[port
], packed_buf
,
171 SJA1105_SIZE_MAC_AREA
);
175 sja1105_port_status_mac_unpack(packed_buf
, status
);
180 static int sja1105_port_status_get_hl1(struct sja1105_private
*priv
,
181 struct sja1105_port_status_hl1
*status
,
184 const struct sja1105_regs
*regs
= priv
->info
->regs
;
185 u8 packed_buf
[SJA1105_SIZE_HL1_AREA
] = {0};
188 rc
= sja1105_xfer_buf(priv
, SPI_READ
, regs
->mac_hl1
[port
], packed_buf
,
189 SJA1105_SIZE_HL1_AREA
);
193 sja1105_port_status_hl1_unpack(packed_buf
, status
);
198 static int sja1105_port_status_get_hl2(struct sja1105_private
*priv
,
199 struct sja1105_port_status_hl2
*status
,
202 const struct sja1105_regs
*regs
= priv
->info
->regs
;
203 u8 packed_buf
[SJA1105_SIZE_QLEVEL_AREA
] = {0};
206 rc
= sja1105_xfer_buf(priv
, SPI_READ
, regs
->mac_hl2
[port
], packed_buf
,
207 SJA1105_SIZE_HL2_AREA
);
211 sja1105_port_status_hl2_unpack(packed_buf
, status
);
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
)
218 rc
= sja1105_xfer_buf(priv
, SPI_READ
, regs
->qlevel
[port
], packed_buf
,
219 SJA1105_SIZE_QLEVEL_AREA
);
223 sja1105pqrs_port_status_qlevel_unpack(packed_buf
, status
);
228 static int sja1105_port_status_get(struct sja1105_private
*priv
,
229 struct sja1105_port_status
*status
,
234 rc
= sja1105_port_status_get_mac(priv
, &status
->mac
, port
);
237 rc
= sja1105_port_status_get_hl1(priv
, &status
->hl1
, port
);
240 rc
= sja1105_port_status_get_hl2(priv
, &status
->hl2
, port
);
247 static char sja1105_port_stats
[][ETH_GSTRING_LEN
] = {
248 /* MAC-Level Diagnostic Counters */
253 /* MAC-Level Diagnostic Flags */
274 /* High-Level Diagnostic Counters */
293 static char sja1105pqrs_extra_port_stats
[][ETH_GSTRING_LEN
] = {
313 void sja1105_get_ethtool_stats(struct dsa_switch
*ds
, int port
, u64
*data
)
315 struct sja1105_private
*priv
= ds
->priv
;
316 struct sja1105_port_status status
;
319 memset(&status
, 0, sizeof(status
));
321 rc
= sja1105_port_status_get(priv
, &status
, port
);
323 dev_err(ds
->dev
, "Failed to read port %d counters: %d\n",
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
;
369 if (priv
->info
->device_id
== SJA1105E_DEVICE_ID
||
370 priv
->info
->device_id
== SJA1105T_DEVICE_ID
)
373 memset(data
+ k
, 0, ARRAY_SIZE(sja1105pqrs_extra_port_stats
) *
375 for (i
= 0; i
< 8; i
++) {
376 data
[k
++] = status
.hl2
.qlevel_hwm
[i
];
377 data
[k
++] = status
.hl2
.qlevel
[i
];
381 void sja1105_get_strings(struct dsa_switch
*ds
, int port
,
382 u32 stringset
, u8
*data
)
384 struct sja1105_private
*priv
= ds
->priv
;
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
;
394 if (priv
->info
->device_id
== SJA1105E_DEVICE_ID
||
395 priv
->info
->device_id
== SJA1105T_DEVICE_ID
)
397 for (i
= 0; i
< ARRAY_SIZE(sja1105pqrs_extra_port_stats
); i
++) {
398 strlcpy(p
, sja1105pqrs_extra_port_stats
[i
],
400 p
+= ETH_GSTRING_LEN
;
406 int sja1105_get_sset_count(struct dsa_switch
*ds
, int port
, int sset
)
408 int count
= ARRAY_SIZE(sja1105_port_stats
);
409 struct sja1105_private
*priv
= ds
->priv
;
411 if (sset
!= ETH_SS_STATS
)
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
);