1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
2/* Statistics for Ocelot switch family
3 *
4 * Copyright (c) 2017 Microsemi Corporation
5 * Copyright 2022 NXP
6 */
7#include <linux/ethtool_netlink.h>
8#include <linux/spinlock.h>
9#include <linux/mutex.h>
10#include <linux/workqueue.h>
11#include "ocelot.h"
12
13enum ocelot_stat {
14 OCELOT_STAT_RX_OCTETS,
15 OCELOT_STAT_RX_UNICAST,
16 OCELOT_STAT_RX_MULTICAST,
17 OCELOT_STAT_RX_BROADCAST,
18 OCELOT_STAT_RX_SHORTS,
19 OCELOT_STAT_RX_FRAGMENTS,
20 OCELOT_STAT_RX_JABBERS,
21 OCELOT_STAT_RX_CRC_ALIGN_ERRS,
22 OCELOT_STAT_RX_SYM_ERRS,
23 OCELOT_STAT_RX_64,
24 OCELOT_STAT_RX_65_127,
25 OCELOT_STAT_RX_128_255,
26 OCELOT_STAT_RX_256_511,
27 OCELOT_STAT_RX_512_1023,
28 OCELOT_STAT_RX_1024_1526,
29 OCELOT_STAT_RX_1527_MAX,
30 OCELOT_STAT_RX_PAUSE,
31 OCELOT_STAT_RX_CONTROL,
32 OCELOT_STAT_RX_LONGS,
33 OCELOT_STAT_RX_CLASSIFIED_DROPS,
34 OCELOT_STAT_RX_RED_PRIO_0,
35 OCELOT_STAT_RX_RED_PRIO_1,
36 OCELOT_STAT_RX_RED_PRIO_2,
37 OCELOT_STAT_RX_RED_PRIO_3,
38 OCELOT_STAT_RX_RED_PRIO_4,
39 OCELOT_STAT_RX_RED_PRIO_5,
40 OCELOT_STAT_RX_RED_PRIO_6,
41 OCELOT_STAT_RX_RED_PRIO_7,
42 OCELOT_STAT_RX_YELLOW_PRIO_0,
43 OCELOT_STAT_RX_YELLOW_PRIO_1,
44 OCELOT_STAT_RX_YELLOW_PRIO_2,
45 OCELOT_STAT_RX_YELLOW_PRIO_3,
46 OCELOT_STAT_RX_YELLOW_PRIO_4,
47 OCELOT_STAT_RX_YELLOW_PRIO_5,
48 OCELOT_STAT_RX_YELLOW_PRIO_6,
49 OCELOT_STAT_RX_YELLOW_PRIO_7,
50 OCELOT_STAT_RX_GREEN_PRIO_0,
51 OCELOT_STAT_RX_GREEN_PRIO_1,
52 OCELOT_STAT_RX_GREEN_PRIO_2,
53 OCELOT_STAT_RX_GREEN_PRIO_3,
54 OCELOT_STAT_RX_GREEN_PRIO_4,
55 OCELOT_STAT_RX_GREEN_PRIO_5,
56 OCELOT_STAT_RX_GREEN_PRIO_6,
57 OCELOT_STAT_RX_GREEN_PRIO_7,
58 OCELOT_STAT_RX_ASSEMBLY_ERRS,
59 OCELOT_STAT_RX_SMD_ERRS,
60 OCELOT_STAT_RX_ASSEMBLY_OK,
61 OCELOT_STAT_RX_MERGE_FRAGMENTS,
62 OCELOT_STAT_RX_PMAC_OCTETS,
63 OCELOT_STAT_RX_PMAC_UNICAST,
64 OCELOT_STAT_RX_PMAC_MULTICAST,
65 OCELOT_STAT_RX_PMAC_BROADCAST,
66 OCELOT_STAT_RX_PMAC_SHORTS,
67 OCELOT_STAT_RX_PMAC_FRAGMENTS,
68 OCELOT_STAT_RX_PMAC_JABBERS,
69 OCELOT_STAT_RX_PMAC_CRC_ALIGN_ERRS,
70 OCELOT_STAT_RX_PMAC_SYM_ERRS,
71 OCELOT_STAT_RX_PMAC_64,
72 OCELOT_STAT_RX_PMAC_65_127,
73 OCELOT_STAT_RX_PMAC_128_255,
74 OCELOT_STAT_RX_PMAC_256_511,
75 OCELOT_STAT_RX_PMAC_512_1023,
76 OCELOT_STAT_RX_PMAC_1024_1526,
77 OCELOT_STAT_RX_PMAC_1527_MAX,
78 OCELOT_STAT_RX_PMAC_PAUSE,
79 OCELOT_STAT_RX_PMAC_CONTROL,
80 OCELOT_STAT_RX_PMAC_LONGS,
81 OCELOT_STAT_TX_OCTETS,
82 OCELOT_STAT_TX_UNICAST,
83 OCELOT_STAT_TX_MULTICAST,
84 OCELOT_STAT_TX_BROADCAST,
85 OCELOT_STAT_TX_COLLISION,
86 OCELOT_STAT_TX_DROPS,
87 OCELOT_STAT_TX_PAUSE,
88 OCELOT_STAT_TX_64,
89 OCELOT_STAT_TX_65_127,
90 OCELOT_STAT_TX_128_255,
91 OCELOT_STAT_TX_256_511,
92 OCELOT_STAT_TX_512_1023,
93 OCELOT_STAT_TX_1024_1526,
94 OCELOT_STAT_TX_1527_MAX,
95 OCELOT_STAT_TX_YELLOW_PRIO_0,
96 OCELOT_STAT_TX_YELLOW_PRIO_1,
97 OCELOT_STAT_TX_YELLOW_PRIO_2,
98 OCELOT_STAT_TX_YELLOW_PRIO_3,
99 OCELOT_STAT_TX_YELLOW_PRIO_4,
100 OCELOT_STAT_TX_YELLOW_PRIO_5,
101 OCELOT_STAT_TX_YELLOW_PRIO_6,
102 OCELOT_STAT_TX_YELLOW_PRIO_7,
103 OCELOT_STAT_TX_GREEN_PRIO_0,
104 OCELOT_STAT_TX_GREEN_PRIO_1,
105 OCELOT_STAT_TX_GREEN_PRIO_2,
106 OCELOT_STAT_TX_GREEN_PRIO_3,
107 OCELOT_STAT_TX_GREEN_PRIO_4,
108 OCELOT_STAT_TX_GREEN_PRIO_5,
109 OCELOT_STAT_TX_GREEN_PRIO_6,
110 OCELOT_STAT_TX_GREEN_PRIO_7,
111 OCELOT_STAT_TX_AGED,
112 OCELOT_STAT_TX_MM_HOLD,
113 OCELOT_STAT_TX_MERGE_FRAGMENTS,
114 OCELOT_STAT_TX_PMAC_OCTETS,
115 OCELOT_STAT_TX_PMAC_UNICAST,
116 OCELOT_STAT_TX_PMAC_MULTICAST,
117 OCELOT_STAT_TX_PMAC_BROADCAST,
118 OCELOT_STAT_TX_PMAC_PAUSE,
119 OCELOT_STAT_TX_PMAC_64,
120 OCELOT_STAT_TX_PMAC_65_127,
121 OCELOT_STAT_TX_PMAC_128_255,
122 OCELOT_STAT_TX_PMAC_256_511,
123 OCELOT_STAT_TX_PMAC_512_1023,
124 OCELOT_STAT_TX_PMAC_1024_1526,
125 OCELOT_STAT_TX_PMAC_1527_MAX,
126 OCELOT_STAT_DROP_LOCAL,
127 OCELOT_STAT_DROP_TAIL,
128 OCELOT_STAT_DROP_YELLOW_PRIO_0,
129 OCELOT_STAT_DROP_YELLOW_PRIO_1,
130 OCELOT_STAT_DROP_YELLOW_PRIO_2,
131 OCELOT_STAT_DROP_YELLOW_PRIO_3,
132 OCELOT_STAT_DROP_YELLOW_PRIO_4,
133 OCELOT_STAT_DROP_YELLOW_PRIO_5,
134 OCELOT_STAT_DROP_YELLOW_PRIO_6,
135 OCELOT_STAT_DROP_YELLOW_PRIO_7,
136 OCELOT_STAT_DROP_GREEN_PRIO_0,
137 OCELOT_STAT_DROP_GREEN_PRIO_1,
138 OCELOT_STAT_DROP_GREEN_PRIO_2,
139 OCELOT_STAT_DROP_GREEN_PRIO_3,
140 OCELOT_STAT_DROP_GREEN_PRIO_4,
141 OCELOT_STAT_DROP_GREEN_PRIO_5,
142 OCELOT_STAT_DROP_GREEN_PRIO_6,
143 OCELOT_STAT_DROP_GREEN_PRIO_7,
144 OCELOT_NUM_STATS,
145};
146
147struct ocelot_stat_layout {
148 enum ocelot_reg reg;
149 char name[ETH_GSTRING_LEN];
150};
151
152/* 32-bit counter checked for wraparound by ocelot_port_update_stats()
153 * and copied to ocelot->stats.
154 */
155#define OCELOT_STAT(kind) \
156 [OCELOT_STAT_ ## kind] = { .reg = SYS_COUNT_ ## kind }
157/* Same as above, except also exported to ethtool -S. Standard counters should
158 * only be exposed to more specific interfaces rather than by their string name.
159 */
160#define OCELOT_STAT_ETHTOOL(kind, ethtool_name) \
161 [OCELOT_STAT_ ## kind] = { .reg = SYS_COUNT_ ## kind, .name = ethtool_name }
162
163#define OCELOT_COMMON_STATS \
164 OCELOT_STAT_ETHTOOL(RX_OCTETS, "rx_octets"), \
165 OCELOT_STAT_ETHTOOL(RX_UNICAST, "rx_unicast"), \
166 OCELOT_STAT_ETHTOOL(RX_MULTICAST, "rx_multicast"), \
167 OCELOT_STAT_ETHTOOL(RX_BROADCAST, "rx_broadcast"), \
168 OCELOT_STAT_ETHTOOL(RX_SHORTS, "rx_shorts"), \
169 OCELOT_STAT_ETHTOOL(RX_FRAGMENTS, "rx_fragments"), \
170 OCELOT_STAT_ETHTOOL(RX_JABBERS, "rx_jabbers"), \
171 OCELOT_STAT_ETHTOOL(RX_CRC_ALIGN_ERRS, "rx_crc_align_errs"), \
172 OCELOT_STAT_ETHTOOL(RX_SYM_ERRS, "rx_sym_errs"), \
173 OCELOT_STAT_ETHTOOL(RX_64, "rx_frames_below_65_octets"), \
174 OCELOT_STAT_ETHTOOL(RX_65_127, "rx_frames_65_to_127_octets"), \
175 OCELOT_STAT_ETHTOOL(RX_128_255, "rx_frames_128_to_255_octets"), \
176 OCELOT_STAT_ETHTOOL(RX_256_511, "rx_frames_256_to_511_octets"), \
177 OCELOT_STAT_ETHTOOL(RX_512_1023, "rx_frames_512_to_1023_octets"), \
178 OCELOT_STAT_ETHTOOL(RX_1024_1526, "rx_frames_1024_to_1526_octets"), \
179 OCELOT_STAT_ETHTOOL(RX_1527_MAX, "rx_frames_over_1526_octets"), \
180 OCELOT_STAT_ETHTOOL(RX_PAUSE, "rx_pause"), \
181 OCELOT_STAT_ETHTOOL(RX_CONTROL, "rx_control"), \
182 OCELOT_STAT_ETHTOOL(RX_LONGS, "rx_longs"), \
183 OCELOT_STAT_ETHTOOL(RX_CLASSIFIED_DROPS, "rx_classified_drops"), \
184 OCELOT_STAT_ETHTOOL(RX_RED_PRIO_0, "rx_red_prio_0"), \
185 OCELOT_STAT_ETHTOOL(RX_RED_PRIO_1, "rx_red_prio_1"), \
186 OCELOT_STAT_ETHTOOL(RX_RED_PRIO_2, "rx_red_prio_2"), \
187 OCELOT_STAT_ETHTOOL(RX_RED_PRIO_3, "rx_red_prio_3"), \
188 OCELOT_STAT_ETHTOOL(RX_RED_PRIO_4, "rx_red_prio_4"), \
189 OCELOT_STAT_ETHTOOL(RX_RED_PRIO_5, "rx_red_prio_5"), \
190 OCELOT_STAT_ETHTOOL(RX_RED_PRIO_6, "rx_red_prio_6"), \
191 OCELOT_STAT_ETHTOOL(RX_RED_PRIO_7, "rx_red_prio_7"), \
192 OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_0, "rx_yellow_prio_0"), \
193 OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_1, "rx_yellow_prio_1"), \
194 OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_2, "rx_yellow_prio_2"), \
195 OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_3, "rx_yellow_prio_3"), \
196 OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_4, "rx_yellow_prio_4"), \
197 OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_5, "rx_yellow_prio_5"), \
198 OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_6, "rx_yellow_prio_6"), \
199 OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_7, "rx_yellow_prio_7"), \
200 OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_0, "rx_green_prio_0"), \
201 OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_1, "rx_green_prio_1"), \
202 OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_2, "rx_green_prio_2"), \
203 OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_3, "rx_green_prio_3"), \
204 OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_4, "rx_green_prio_4"), \
205 OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_5, "rx_green_prio_5"), \
206 OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_6, "rx_green_prio_6"), \
207 OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_7, "rx_green_prio_7"), \
208 OCELOT_STAT_ETHTOOL(TX_OCTETS, "tx_octets"), \
209 OCELOT_STAT_ETHTOOL(TX_UNICAST, "tx_unicast"), \
210 OCELOT_STAT_ETHTOOL(TX_MULTICAST, "tx_multicast"), \
211 OCELOT_STAT_ETHTOOL(TX_BROADCAST, "tx_broadcast"), \
212 OCELOT_STAT_ETHTOOL(TX_COLLISION, "tx_collision"), \
213 OCELOT_STAT_ETHTOOL(TX_DROPS, "tx_drops"), \
214 OCELOT_STAT_ETHTOOL(TX_PAUSE, "tx_pause"), \
215 OCELOT_STAT_ETHTOOL(TX_64, "tx_frames_below_65_octets"), \
216 OCELOT_STAT_ETHTOOL(TX_65_127, "tx_frames_65_to_127_octets"), \
217 OCELOT_STAT_ETHTOOL(TX_128_255, "tx_frames_128_255_octets"), \
218 OCELOT_STAT_ETHTOOL(TX_256_511, "tx_frames_256_511_octets"), \
219 OCELOT_STAT_ETHTOOL(TX_512_1023, "tx_frames_512_1023_octets"), \
220 OCELOT_STAT_ETHTOOL(TX_1024_1526, "tx_frames_1024_1526_octets"), \
221 OCELOT_STAT_ETHTOOL(TX_1527_MAX, "tx_frames_over_1526_octets"), \
222 OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_0, "tx_yellow_prio_0"), \
223 OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_1, "tx_yellow_prio_1"), \
224 OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_2, "tx_yellow_prio_2"), \
225 OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_3, "tx_yellow_prio_3"), \
226 OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_4, "tx_yellow_prio_4"), \
227 OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_5, "tx_yellow_prio_5"), \
228 OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_6, "tx_yellow_prio_6"), \
229 OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_7, "tx_yellow_prio_7"), \
230 OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_0, "tx_green_prio_0"), \
231 OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_1, "tx_green_prio_1"), \
232 OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_2, "tx_green_prio_2"), \
233 OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_3, "tx_green_prio_3"), \
234 OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_4, "tx_green_prio_4"), \
235 OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_5, "tx_green_prio_5"), \
236 OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_6, "tx_green_prio_6"), \
237 OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_7, "tx_green_prio_7"), \
238 OCELOT_STAT_ETHTOOL(TX_AGED, "tx_aged"), \
239 OCELOT_STAT_ETHTOOL(DROP_LOCAL, "drop_local"), \
240 OCELOT_STAT_ETHTOOL(DROP_TAIL, "drop_tail"), \
241 OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_0, "drop_yellow_prio_0"), \
242 OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_1, "drop_yellow_prio_1"), \
243 OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_2, "drop_yellow_prio_2"), \
244 OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_3, "drop_yellow_prio_3"), \
245 OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_4, "drop_yellow_prio_4"), \
246 OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_5, "drop_yellow_prio_5"), \
247 OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_6, "drop_yellow_prio_6"), \
248 OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_7, "drop_yellow_prio_7"), \
249 OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_0, "drop_green_prio_0"), \
250 OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_1, "drop_green_prio_1"), \
251 OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_2, "drop_green_prio_2"), \
252 OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_3, "drop_green_prio_3"), \
253 OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_4, "drop_green_prio_4"), \
254 OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_5, "drop_green_prio_5"), \
255 OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_6, "drop_green_prio_6"), \
256 OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_7, "drop_green_prio_7")
257
258struct ocelot_stats_region {
259 struct list_head node;
260 enum ocelot_reg base;
261 enum ocelot_stat first_stat;
262 int count;
263 u32 *buf;
264};
265
266static const struct ocelot_stat_layout ocelot_stats_layout[OCELOT_NUM_STATS] = {
267 OCELOT_COMMON_STATS,
268};
269
270static const struct ocelot_stat_layout ocelot_mm_stats_layout[OCELOT_NUM_STATS] = {
271 OCELOT_COMMON_STATS,
272 OCELOT_STAT(RX_ASSEMBLY_ERRS),
273 OCELOT_STAT(RX_SMD_ERRS),
274 OCELOT_STAT(RX_ASSEMBLY_OK),
275 OCELOT_STAT(RX_MERGE_FRAGMENTS),
276 OCELOT_STAT(TX_MERGE_FRAGMENTS),
277 OCELOT_STAT(TX_MM_HOLD),
278 OCELOT_STAT(RX_PMAC_OCTETS),
279 OCELOT_STAT(RX_PMAC_UNICAST),
280 OCELOT_STAT(RX_PMAC_MULTICAST),
281 OCELOT_STAT(RX_PMAC_BROADCAST),
282 OCELOT_STAT(RX_PMAC_SHORTS),
283 OCELOT_STAT(RX_PMAC_FRAGMENTS),
284 OCELOT_STAT(RX_PMAC_JABBERS),
285 OCELOT_STAT(RX_PMAC_CRC_ALIGN_ERRS),
286 OCELOT_STAT(RX_PMAC_SYM_ERRS),
287 OCELOT_STAT(RX_PMAC_64),
288 OCELOT_STAT(RX_PMAC_65_127),
289 OCELOT_STAT(RX_PMAC_128_255),
290 OCELOT_STAT(RX_PMAC_256_511),
291 OCELOT_STAT(RX_PMAC_512_1023),
292 OCELOT_STAT(RX_PMAC_1024_1526),
293 OCELOT_STAT(RX_PMAC_1527_MAX),
294 OCELOT_STAT(RX_PMAC_PAUSE),
295 OCELOT_STAT(RX_PMAC_CONTROL),
296 OCELOT_STAT(RX_PMAC_LONGS),
297 OCELOT_STAT(TX_PMAC_OCTETS),
298 OCELOT_STAT(TX_PMAC_UNICAST),
299 OCELOT_STAT(TX_PMAC_MULTICAST),
300 OCELOT_STAT(TX_PMAC_BROADCAST),
301 OCELOT_STAT(TX_PMAC_PAUSE),
302 OCELOT_STAT(TX_PMAC_64),
303 OCELOT_STAT(TX_PMAC_65_127),
304 OCELOT_STAT(TX_PMAC_128_255),
305 OCELOT_STAT(TX_PMAC_256_511),
306 OCELOT_STAT(TX_PMAC_512_1023),
307 OCELOT_STAT(TX_PMAC_1024_1526),
308 OCELOT_STAT(TX_PMAC_1527_MAX),
309};
310
311static const struct ocelot_stat_layout *
312ocelot_get_stats_layout(struct ocelot *ocelot)
313{
314 if (ocelot->mm_supported)
315 return ocelot_mm_stats_layout;
316
317 return ocelot_stats_layout;
318}
319
320/* Read the counters from hardware and keep them in region->buf.
321 * Caller must hold &ocelot->stat_view_lock.
322 */
323static int ocelot_port_update_stats(struct ocelot *ocelot, int port)
324{
325 struct ocelot_stats_region *region;
326 int err;
327
328 /* Configure the port to read the stats from */
329 ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port), SYS_STAT_CFG);
330
331 list_for_each_entry(region, &ocelot->stats_regions, node) {
332 err = ocelot_bulk_read(ocelot, region->base, region->buf,
333 region->count);
334 if (err)
335 return err;
336 }
337
338 return 0;
339}
340
341/* Transfer the counters from region->buf to ocelot->stats.
342 * Caller must hold &ocelot->stat_view_lock and &ocelot->stats_lock.
343 */
344static void ocelot_port_transfer_stats(struct ocelot *ocelot, int port)
345{
346 struct ocelot_stats_region *region;
347 int j;
348
349 list_for_each_entry(region, &ocelot->stats_regions, node) {
350 unsigned int idx = port * OCELOT_NUM_STATS + region->first_stat;
351
352 for (j = 0; j < region->count; j++) {
353 u64 *stat = &ocelot->stats[idx + j];
354 u64 val = region->buf[j];
355
356 if (val < (*stat & U32_MAX))
357 *stat += (u64)1 << 32;
358
359 *stat = (*stat & ~(u64)U32_MAX) + val;
360 }
361 }
362}
363
364static void ocelot_check_stats_work(struct work_struct *work)
365{
366 struct delayed_work *del_work = to_delayed_work(work);
367 struct ocelot *ocelot = container_of(del_work, struct ocelot,
368 stats_work);
369 int port, err;
370
371 mutex_lock(&ocelot->stat_view_lock);
372
373 for (port = 0; port < ocelot->num_phys_ports; port++) {
374 err = ocelot_port_update_stats(ocelot, port);
375 if (err)
376 break;
377
378 spin_lock(lock: &ocelot->stats_lock);
379 ocelot_port_transfer_stats(ocelot, port);
380 spin_unlock(lock: &ocelot->stats_lock);
381 }
382
383 if (!err && ocelot->ops->update_stats)
384 ocelot->ops->update_stats(ocelot);
385
386 mutex_unlock(lock: &ocelot->stat_view_lock);
387
388 if (err)
389 dev_err(ocelot->dev, "Error %d updating ethtool stats\n", err);
390
391 queue_delayed_work(wq: ocelot->stats_queue, dwork: &ocelot->stats_work,
392 OCELOT_STATS_CHECK_DELAY);
393}
394
395void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data)
396{
397 const struct ocelot_stat_layout *layout;
398 enum ocelot_stat i;
399
400 if (sset != ETH_SS_STATS)
401 return;
402
403 layout = ocelot_get_stats_layout(ocelot);
404
405 for (i = 0; i < OCELOT_NUM_STATS; i++) {
406 if (layout[i].name[0] == '\0')
407 continue;
408
409 memcpy(data, layout[i].name, ETH_GSTRING_LEN);
410 data += ETH_GSTRING_LEN;
411 }
412}
413EXPORT_SYMBOL(ocelot_get_strings);
414
415/* Update ocelot->stats for the given port and run the given callback */
416static void ocelot_port_stats_run(struct ocelot *ocelot, int port, void *priv,
417 void (*cb)(struct ocelot *ocelot, int port,
418 void *priv))
419{
420 int err;
421
422 mutex_lock(&ocelot->stat_view_lock);
423
424 err = ocelot_port_update_stats(ocelot, port);
425 if (err) {
426 dev_err(ocelot->dev, "Failed to update port %d stats: %pe\n",
427 port, ERR_PTR(err));
428 goto out_unlock;
429 }
430
431 spin_lock(lock: &ocelot->stats_lock);
432
433 ocelot_port_transfer_stats(ocelot, port);
434 cb(ocelot, port, priv);
435
436 spin_unlock(lock: &ocelot->stats_lock);
437
438out_unlock:
439 mutex_unlock(lock: &ocelot->stat_view_lock);
440}
441
442int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset)
443{
444 const struct ocelot_stat_layout *layout;
445 enum ocelot_stat i;
446 int num_stats = 0;
447
448 if (sset != ETH_SS_STATS)
449 return -EOPNOTSUPP;
450
451 layout = ocelot_get_stats_layout(ocelot);
452
453 for (i = 0; i < OCELOT_NUM_STATS; i++)
454 if (layout[i].name[0] != '\0')
455 num_stats++;
456
457 return num_stats;
458}
459EXPORT_SYMBOL(ocelot_get_sset_count);
460
461static void ocelot_port_ethtool_stats_cb(struct ocelot *ocelot, int port,
462 void *priv)
463{
464 const struct ocelot_stat_layout *layout;
465 enum ocelot_stat i;
466 u64 *data = priv;
467
468 layout = ocelot_get_stats_layout(ocelot);
469
470 /* Copy all supported counters */
471 for (i = 0; i < OCELOT_NUM_STATS; i++) {
472 int index = port * OCELOT_NUM_STATS + i;
473
474 if (layout[i].name[0] == '\0')
475 continue;
476
477 *data++ = ocelot->stats[index];
478 }
479}
480
481void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
482{
483 ocelot_port_stats_run(ocelot, port, priv: data, cb: ocelot_port_ethtool_stats_cb);
484}
485EXPORT_SYMBOL(ocelot_get_ethtool_stats);
486
487static void ocelot_port_pause_stats_cb(struct ocelot *ocelot, int port, void *priv)
488{
489 u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
490 struct ethtool_pause_stats *pause_stats = priv;
491
492 pause_stats->tx_pause_frames = s[OCELOT_STAT_TX_PAUSE];
493 pause_stats->rx_pause_frames = s[OCELOT_STAT_RX_PAUSE];
494}
495
496static void ocelot_port_pmac_pause_stats_cb(struct ocelot *ocelot, int port,
497 void *priv)
498{
499 u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
500 struct ethtool_pause_stats *pause_stats = priv;
501
502 pause_stats->tx_pause_frames = s[OCELOT_STAT_TX_PMAC_PAUSE];
503 pause_stats->rx_pause_frames = s[OCELOT_STAT_RX_PMAC_PAUSE];
504}
505
506static void ocelot_port_mm_stats_cb(struct ocelot *ocelot, int port,
507 void *priv)
508{
509 u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
510 struct ethtool_mm_stats *stats = priv;
511
512 stats->MACMergeFrameAssErrorCount = s[OCELOT_STAT_RX_ASSEMBLY_ERRS];
513 stats->MACMergeFrameSmdErrorCount = s[OCELOT_STAT_RX_SMD_ERRS];
514 stats->MACMergeFrameAssOkCount = s[OCELOT_STAT_RX_ASSEMBLY_OK];
515 stats->MACMergeFragCountRx = s[OCELOT_STAT_RX_MERGE_FRAGMENTS];
516 stats->MACMergeFragCountTx = s[OCELOT_STAT_TX_MERGE_FRAGMENTS];
517 stats->MACMergeHoldCount = s[OCELOT_STAT_TX_MM_HOLD];
518}
519
520void ocelot_port_get_pause_stats(struct ocelot *ocelot, int port,
521 struct ethtool_pause_stats *pause_stats)
522{
523 struct net_device *dev;
524
525 switch (pause_stats->src) {
526 case ETHTOOL_MAC_STATS_SRC_EMAC:
527 ocelot_port_stats_run(ocelot, port, priv: pause_stats,
528 cb: ocelot_port_pause_stats_cb);
529 break;
530 case ETHTOOL_MAC_STATS_SRC_PMAC:
531 if (ocelot->mm_supported)
532 ocelot_port_stats_run(ocelot, port, priv: pause_stats,
533 cb: ocelot_port_pmac_pause_stats_cb);
534 break;
535 case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
536 dev = ocelot->ops->port_to_netdev(ocelot, port);
537 ethtool_aggregate_pause_stats(dev, pause_stats);
538 break;
539 }
540}
541EXPORT_SYMBOL_GPL(ocelot_port_get_pause_stats);
542
543void ocelot_port_get_mm_stats(struct ocelot *ocelot, int port,
544 struct ethtool_mm_stats *stats)
545{
546 if (!ocelot->mm_supported)
547 return;
548
549 ocelot_port_stats_run(ocelot, port, priv: stats, cb: ocelot_port_mm_stats_cb);
550}
551EXPORT_SYMBOL_GPL(ocelot_port_get_mm_stats);
552
553static const struct ethtool_rmon_hist_range ocelot_rmon_ranges[] = {
554 { 64, 64 },
555 { 65, 127 },
556 { 128, 255 },
557 { 256, 511 },
558 { 512, 1023 },
559 { 1024, 1526 },
560 { 1527, 65535 },
561 {},
562};
563
564static void ocelot_port_rmon_stats_cb(struct ocelot *ocelot, int port, void *priv)
565{
566 u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
567 struct ethtool_rmon_stats *rmon_stats = priv;
568
569 rmon_stats->undersize_pkts = s[OCELOT_STAT_RX_SHORTS];
570 rmon_stats->oversize_pkts = s[OCELOT_STAT_RX_LONGS];
571 rmon_stats->fragments = s[OCELOT_STAT_RX_FRAGMENTS];
572 rmon_stats->jabbers = s[OCELOT_STAT_RX_JABBERS];
573
574 rmon_stats->hist[0] = s[OCELOT_STAT_RX_64];
575 rmon_stats->hist[1] = s[OCELOT_STAT_RX_65_127];
576 rmon_stats->hist[2] = s[OCELOT_STAT_RX_128_255];
577 rmon_stats->hist[3] = s[OCELOT_STAT_RX_256_511];
578 rmon_stats->hist[4] = s[OCELOT_STAT_RX_512_1023];
579 rmon_stats->hist[5] = s[OCELOT_STAT_RX_1024_1526];
580 rmon_stats->hist[6] = s[OCELOT_STAT_RX_1527_MAX];
581
582 rmon_stats->hist_tx[0] = s[OCELOT_STAT_TX_64];
583 rmon_stats->hist_tx[1] = s[OCELOT_STAT_TX_65_127];
584 rmon_stats->hist_tx[2] = s[OCELOT_STAT_TX_128_255];
585 rmon_stats->hist_tx[3] = s[OCELOT_STAT_TX_128_255];
586 rmon_stats->hist_tx[4] = s[OCELOT_STAT_TX_256_511];
587 rmon_stats->hist_tx[5] = s[OCELOT_STAT_TX_512_1023];
588 rmon_stats->hist_tx[6] = s[OCELOT_STAT_TX_1024_1526];
589}
590
591static void ocelot_port_pmac_rmon_stats_cb(struct ocelot *ocelot, int port,
592 void *priv)
593{
594 u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
595 struct ethtool_rmon_stats *rmon_stats = priv;
596
597 rmon_stats->undersize_pkts = s[OCELOT_STAT_RX_PMAC_SHORTS];
598 rmon_stats->oversize_pkts = s[OCELOT_STAT_RX_PMAC_LONGS];
599 rmon_stats->fragments = s[OCELOT_STAT_RX_PMAC_FRAGMENTS];
600 rmon_stats->jabbers = s[OCELOT_STAT_RX_PMAC_JABBERS];
601
602 rmon_stats->hist[0] = s[OCELOT_STAT_RX_PMAC_64];
603 rmon_stats->hist[1] = s[OCELOT_STAT_RX_PMAC_65_127];
604 rmon_stats->hist[2] = s[OCELOT_STAT_RX_PMAC_128_255];
605 rmon_stats->hist[3] = s[OCELOT_STAT_RX_PMAC_256_511];
606 rmon_stats->hist[4] = s[OCELOT_STAT_RX_PMAC_512_1023];
607 rmon_stats->hist[5] = s[OCELOT_STAT_RX_PMAC_1024_1526];
608 rmon_stats->hist[6] = s[OCELOT_STAT_RX_PMAC_1527_MAX];
609
610 rmon_stats->hist_tx[0] = s[OCELOT_STAT_TX_PMAC_64];
611 rmon_stats->hist_tx[1] = s[OCELOT_STAT_TX_PMAC_65_127];
612 rmon_stats->hist_tx[2] = s[OCELOT_STAT_TX_PMAC_128_255];
613 rmon_stats->hist_tx[3] = s[OCELOT_STAT_TX_PMAC_128_255];
614 rmon_stats->hist_tx[4] = s[OCELOT_STAT_TX_PMAC_256_511];
615 rmon_stats->hist_tx[5] = s[OCELOT_STAT_TX_PMAC_512_1023];
616 rmon_stats->hist_tx[6] = s[OCELOT_STAT_TX_PMAC_1024_1526];
617}
618
619void ocelot_port_get_rmon_stats(struct ocelot *ocelot, int port,
620 struct ethtool_rmon_stats *rmon_stats,
621 const struct ethtool_rmon_hist_range **ranges)
622{
623 struct net_device *dev;
624
625 *ranges = ocelot_rmon_ranges;
626
627 switch (rmon_stats->src) {
628 case ETHTOOL_MAC_STATS_SRC_EMAC:
629 ocelot_port_stats_run(ocelot, port, priv: rmon_stats,
630 cb: ocelot_port_rmon_stats_cb);
631 break;
632 case ETHTOOL_MAC_STATS_SRC_PMAC:
633 if (ocelot->mm_supported)
634 ocelot_port_stats_run(ocelot, port, priv: rmon_stats,
635 cb: ocelot_port_pmac_rmon_stats_cb);
636 break;
637 case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
638 dev = ocelot->ops->port_to_netdev(ocelot, port);
639 ethtool_aggregate_rmon_stats(dev, rmon_stats);
640 break;
641 }
642}
643EXPORT_SYMBOL_GPL(ocelot_port_get_rmon_stats);
644
645static void ocelot_port_ctrl_stats_cb(struct ocelot *ocelot, int port, void *priv)
646{
647 u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
648 struct ethtool_eth_ctrl_stats *ctrl_stats = priv;
649
650 ctrl_stats->MACControlFramesReceived = s[OCELOT_STAT_RX_CONTROL];
651}
652
653static void ocelot_port_pmac_ctrl_stats_cb(struct ocelot *ocelot, int port,
654 void *priv)
655{
656 u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
657 struct ethtool_eth_ctrl_stats *ctrl_stats = priv;
658
659 ctrl_stats->MACControlFramesReceived = s[OCELOT_STAT_RX_PMAC_CONTROL];
660}
661
662void ocelot_port_get_eth_ctrl_stats(struct ocelot *ocelot, int port,
663 struct ethtool_eth_ctrl_stats *ctrl_stats)
664{
665 struct net_device *dev;
666
667 switch (ctrl_stats->src) {
668 case ETHTOOL_MAC_STATS_SRC_EMAC:
669 ocelot_port_stats_run(ocelot, port, priv: ctrl_stats,
670 cb: ocelot_port_ctrl_stats_cb);
671 break;
672 case ETHTOOL_MAC_STATS_SRC_PMAC:
673 if (ocelot->mm_supported)
674 ocelot_port_stats_run(ocelot, port, priv: ctrl_stats,
675 cb: ocelot_port_pmac_ctrl_stats_cb);
676 break;
677 case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
678 dev = ocelot->ops->port_to_netdev(ocelot, port);
679 ethtool_aggregate_ctrl_stats(dev, ctrl_stats);
680 break;
681 }
682}
683EXPORT_SYMBOL_GPL(ocelot_port_get_eth_ctrl_stats);
684
685static void ocelot_port_mac_stats_cb(struct ocelot *ocelot, int port, void *priv)
686{
687 u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
688 struct ethtool_eth_mac_stats *mac_stats = priv;
689
690 mac_stats->OctetsTransmittedOK = s[OCELOT_STAT_TX_OCTETS];
691 mac_stats->FramesTransmittedOK = s[OCELOT_STAT_TX_64] +
692 s[OCELOT_STAT_TX_65_127] +
693 s[OCELOT_STAT_TX_128_255] +
694 s[OCELOT_STAT_TX_256_511] +
695 s[OCELOT_STAT_TX_512_1023] +
696 s[OCELOT_STAT_TX_1024_1526] +
697 s[OCELOT_STAT_TX_1527_MAX];
698 mac_stats->OctetsReceivedOK = s[OCELOT_STAT_RX_OCTETS];
699 mac_stats->FramesReceivedOK = s[OCELOT_STAT_RX_GREEN_PRIO_0] +
700 s[OCELOT_STAT_RX_GREEN_PRIO_1] +
701 s[OCELOT_STAT_RX_GREEN_PRIO_2] +
702 s[OCELOT_STAT_RX_GREEN_PRIO_3] +
703 s[OCELOT_STAT_RX_GREEN_PRIO_4] +
704 s[OCELOT_STAT_RX_GREEN_PRIO_5] +
705 s[OCELOT_STAT_RX_GREEN_PRIO_6] +
706 s[OCELOT_STAT_RX_GREEN_PRIO_7] +
707 s[OCELOT_STAT_RX_YELLOW_PRIO_0] +
708 s[OCELOT_STAT_RX_YELLOW_PRIO_1] +
709 s[OCELOT_STAT_RX_YELLOW_PRIO_2] +
710 s[OCELOT_STAT_RX_YELLOW_PRIO_3] +
711 s[OCELOT_STAT_RX_YELLOW_PRIO_4] +
712 s[OCELOT_STAT_RX_YELLOW_PRIO_5] +
713 s[OCELOT_STAT_RX_YELLOW_PRIO_6] +
714 s[OCELOT_STAT_RX_YELLOW_PRIO_7];
715 mac_stats->MulticastFramesXmittedOK = s[OCELOT_STAT_TX_MULTICAST];
716 mac_stats->BroadcastFramesXmittedOK = s[OCELOT_STAT_TX_BROADCAST];
717 mac_stats->MulticastFramesReceivedOK = s[OCELOT_STAT_RX_MULTICAST];
718 mac_stats->BroadcastFramesReceivedOK = s[OCELOT_STAT_RX_BROADCAST];
719 mac_stats->FrameTooLongErrors = s[OCELOT_STAT_RX_LONGS];
720 /* Sadly, C_RX_CRC is the sum of FCS and alignment errors, they are not
721 * counted individually.
722 */
723 mac_stats->FrameCheckSequenceErrors = s[OCELOT_STAT_RX_CRC_ALIGN_ERRS];
724 mac_stats->AlignmentErrors = s[OCELOT_STAT_RX_CRC_ALIGN_ERRS];
725}
726
727static void ocelot_port_pmac_mac_stats_cb(struct ocelot *ocelot, int port,
728 void *priv)
729{
730 u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
731 struct ethtool_eth_mac_stats *mac_stats = priv;
732
733 mac_stats->OctetsTransmittedOK = s[OCELOT_STAT_TX_PMAC_OCTETS];
734 mac_stats->FramesTransmittedOK = s[OCELOT_STAT_TX_PMAC_64] +
735 s[OCELOT_STAT_TX_PMAC_65_127] +
736 s[OCELOT_STAT_TX_PMAC_128_255] +
737 s[OCELOT_STAT_TX_PMAC_256_511] +
738 s[OCELOT_STAT_TX_PMAC_512_1023] +
739 s[OCELOT_STAT_TX_PMAC_1024_1526] +
740 s[OCELOT_STAT_TX_PMAC_1527_MAX];
741 mac_stats->OctetsReceivedOK = s[OCELOT_STAT_RX_PMAC_OCTETS];
742 mac_stats->FramesReceivedOK = s[OCELOT_STAT_RX_PMAC_64] +
743 s[OCELOT_STAT_RX_PMAC_65_127] +
744 s[OCELOT_STAT_RX_PMAC_128_255] +
745 s[OCELOT_STAT_RX_PMAC_256_511] +
746 s[OCELOT_STAT_RX_PMAC_512_1023] +
747 s[OCELOT_STAT_RX_PMAC_1024_1526] +
748 s[OCELOT_STAT_RX_PMAC_1527_MAX];
749 mac_stats->MulticastFramesXmittedOK = s[OCELOT_STAT_TX_PMAC_MULTICAST];
750 mac_stats->BroadcastFramesXmittedOK = s[OCELOT_STAT_TX_PMAC_BROADCAST];
751 mac_stats->MulticastFramesReceivedOK = s[OCELOT_STAT_RX_PMAC_MULTICAST];
752 mac_stats->BroadcastFramesReceivedOK = s[OCELOT_STAT_RX_PMAC_BROADCAST];
753 mac_stats->FrameTooLongErrors = s[OCELOT_STAT_RX_PMAC_LONGS];
754 /* Sadly, C_RX_CRC is the sum of FCS and alignment errors, they are not
755 * counted individually.
756 */
757 mac_stats->FrameCheckSequenceErrors = s[OCELOT_STAT_RX_PMAC_CRC_ALIGN_ERRS];
758 mac_stats->AlignmentErrors = s[OCELOT_STAT_RX_PMAC_CRC_ALIGN_ERRS];
759}
760
761void ocelot_port_get_eth_mac_stats(struct ocelot *ocelot, int port,
762 struct ethtool_eth_mac_stats *mac_stats)
763{
764 struct net_device *dev;
765
766 switch (mac_stats->src) {
767 case ETHTOOL_MAC_STATS_SRC_EMAC:
768 ocelot_port_stats_run(ocelot, port, priv: mac_stats,
769 cb: ocelot_port_mac_stats_cb);
770 break;
771 case ETHTOOL_MAC_STATS_SRC_PMAC:
772 if (ocelot->mm_supported)
773 ocelot_port_stats_run(ocelot, port, priv: mac_stats,
774 cb: ocelot_port_pmac_mac_stats_cb);
775 break;
776 case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
777 dev = ocelot->ops->port_to_netdev(ocelot, port);
778 ethtool_aggregate_mac_stats(dev, mac_stats);
779 break;
780 }
781}
782EXPORT_SYMBOL_GPL(ocelot_port_get_eth_mac_stats);
783
784static void ocelot_port_phy_stats_cb(struct ocelot *ocelot, int port, void *priv)
785{
786 u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
787 struct ethtool_eth_phy_stats *phy_stats = priv;
788
789 phy_stats->SymbolErrorDuringCarrier = s[OCELOT_STAT_RX_SYM_ERRS];
790}
791
792static void ocelot_port_pmac_phy_stats_cb(struct ocelot *ocelot, int port,
793 void *priv)
794{
795 u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
796 struct ethtool_eth_phy_stats *phy_stats = priv;
797
798 phy_stats->SymbolErrorDuringCarrier = s[OCELOT_STAT_RX_PMAC_SYM_ERRS];
799}
800
801void ocelot_port_get_eth_phy_stats(struct ocelot *ocelot, int port,
802 struct ethtool_eth_phy_stats *phy_stats)
803{
804 struct net_device *dev;
805
806 switch (phy_stats->src) {
807 case ETHTOOL_MAC_STATS_SRC_EMAC:
808 ocelot_port_stats_run(ocelot, port, priv: phy_stats,
809 cb: ocelot_port_phy_stats_cb);
810 break;
811 case ETHTOOL_MAC_STATS_SRC_PMAC:
812 if (ocelot->mm_supported)
813 ocelot_port_stats_run(ocelot, port, priv: phy_stats,
814 cb: ocelot_port_pmac_phy_stats_cb);
815 break;
816 case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
817 dev = ocelot->ops->port_to_netdev(ocelot, port);
818 ethtool_aggregate_phy_stats(dev, phy_stats);
819 break;
820 }
821}
822EXPORT_SYMBOL_GPL(ocelot_port_get_eth_phy_stats);
823
824void ocelot_port_get_stats64(struct ocelot *ocelot, int port,
825 struct rtnl_link_stats64 *stats)
826{
827 u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
828
829 spin_lock(lock: &ocelot->stats_lock);
830
831 /* Get Rx stats */
832 stats->rx_bytes = s[OCELOT_STAT_RX_OCTETS];
833 stats->rx_packets = s[OCELOT_STAT_RX_SHORTS] +
834 s[OCELOT_STAT_RX_FRAGMENTS] +
835 s[OCELOT_STAT_RX_JABBERS] +
836 s[OCELOT_STAT_RX_LONGS] +
837 s[OCELOT_STAT_RX_64] +
838 s[OCELOT_STAT_RX_65_127] +
839 s[OCELOT_STAT_RX_128_255] +
840 s[OCELOT_STAT_RX_256_511] +
841 s[OCELOT_STAT_RX_512_1023] +
842 s[OCELOT_STAT_RX_1024_1526] +
843 s[OCELOT_STAT_RX_1527_MAX];
844 stats->multicast = s[OCELOT_STAT_RX_MULTICAST];
845 stats->rx_missed_errors = s[OCELOT_STAT_DROP_TAIL];
846 stats->rx_dropped = s[OCELOT_STAT_RX_RED_PRIO_0] +
847 s[OCELOT_STAT_RX_RED_PRIO_1] +
848 s[OCELOT_STAT_RX_RED_PRIO_2] +
849 s[OCELOT_STAT_RX_RED_PRIO_3] +
850 s[OCELOT_STAT_RX_RED_PRIO_4] +
851 s[OCELOT_STAT_RX_RED_PRIO_5] +
852 s[OCELOT_STAT_RX_RED_PRIO_6] +
853 s[OCELOT_STAT_RX_RED_PRIO_7] +
854 s[OCELOT_STAT_DROP_LOCAL] +
855 s[OCELOT_STAT_DROP_YELLOW_PRIO_0] +
856 s[OCELOT_STAT_DROP_YELLOW_PRIO_1] +
857 s[OCELOT_STAT_DROP_YELLOW_PRIO_2] +
858 s[OCELOT_STAT_DROP_YELLOW_PRIO_3] +
859 s[OCELOT_STAT_DROP_YELLOW_PRIO_4] +
860 s[OCELOT_STAT_DROP_YELLOW_PRIO_5] +
861 s[OCELOT_STAT_DROP_YELLOW_PRIO_6] +
862 s[OCELOT_STAT_DROP_YELLOW_PRIO_7] +
863 s[OCELOT_STAT_DROP_GREEN_PRIO_0] +
864 s[OCELOT_STAT_DROP_GREEN_PRIO_1] +
865 s[OCELOT_STAT_DROP_GREEN_PRIO_2] +
866 s[OCELOT_STAT_DROP_GREEN_PRIO_3] +
867 s[OCELOT_STAT_DROP_GREEN_PRIO_4] +
868 s[OCELOT_STAT_DROP_GREEN_PRIO_5] +
869 s[OCELOT_STAT_DROP_GREEN_PRIO_6] +
870 s[OCELOT_STAT_DROP_GREEN_PRIO_7];
871
872 /* Get Tx stats */
873 stats->tx_bytes = s[OCELOT_STAT_TX_OCTETS];
874 stats->tx_packets = s[OCELOT_STAT_TX_64] +
875 s[OCELOT_STAT_TX_65_127] +
876 s[OCELOT_STAT_TX_128_255] +
877 s[OCELOT_STAT_TX_256_511] +
878 s[OCELOT_STAT_TX_512_1023] +
879 s[OCELOT_STAT_TX_1024_1526] +
880 s[OCELOT_STAT_TX_1527_MAX];
881 stats->tx_dropped = s[OCELOT_STAT_TX_DROPS] +
882 s[OCELOT_STAT_TX_AGED];
883 stats->collisions = s[OCELOT_STAT_TX_COLLISION];
884
885 spin_unlock(lock: &ocelot->stats_lock);
886}
887EXPORT_SYMBOL(ocelot_port_get_stats64);
888
889static int ocelot_prepare_stats_regions(struct ocelot *ocelot)
890{
891 struct ocelot_stats_region *region = NULL;
892 const struct ocelot_stat_layout *layout;
893 enum ocelot_reg last = 0;
894 enum ocelot_stat i;
895
896 INIT_LIST_HEAD(list: &ocelot->stats_regions);
897
898 layout = ocelot_get_stats_layout(ocelot);
899
900 for (i = 0; i < OCELOT_NUM_STATS; i++) {
901 if (!layout[i].reg)
902 continue;
903
904 /* enum ocelot_stat must be kept sorted in the same order
905 * as the addresses behind layout[i].reg in order to have
906 * efficient bulking
907 */
908 if (last) {
909 WARN(ocelot->map[SYS][last & REG_MASK] >= ocelot->map[SYS][layout[i].reg & REG_MASK],
910 "reg 0x%x had address 0x%x but reg 0x%x has address 0x%x, bulking broken!",
911 last, ocelot->map[SYS][last & REG_MASK],
912 layout[i].reg, ocelot->map[SYS][layout[i].reg & REG_MASK]);
913 }
914
915 if (region && ocelot->map[SYS][layout[i].reg & REG_MASK] ==
916 ocelot->map[SYS][last & REG_MASK] + 4) {
917 region->count++;
918 } else {
919 region = devm_kzalloc(dev: ocelot->dev, size: sizeof(*region),
920 GFP_KERNEL);
921 if (!region)
922 return -ENOMEM;
923
924 region->base = layout[i].reg;
925 region->first_stat = i;
926 region->count = 1;
927 list_add_tail(new: &region->node, head: &ocelot->stats_regions);
928 }
929
930 last = layout[i].reg;
931 }
932
933 list_for_each_entry(region, &ocelot->stats_regions, node) {
934 enum ocelot_target target;
935 u32 addr;
936
937 ocelot_reg_to_target_addr(ocelot, reg: region->base, target: &target,
938 addr: &addr);
939
940 dev_dbg(ocelot->dev,
941 "region of %d contiguous counters starting with SYS:STAT:CNT[0x%03x]\n",
942 region->count, addr / 4);
943 region->buf = devm_kcalloc(dev: ocelot->dev, n: region->count,
944 size: sizeof(*region->buf), GFP_KERNEL);
945 if (!region->buf)
946 return -ENOMEM;
947 }
948
949 return 0;
950}
951
952int ocelot_stats_init(struct ocelot *ocelot)
953{
954 char queue_name[32];
955 int ret;
956
957 ocelot->stats = devm_kcalloc(dev: ocelot->dev,
958 n: ocelot->num_phys_ports * OCELOT_NUM_STATS,
959 size: sizeof(u64), GFP_KERNEL);
960 if (!ocelot->stats)
961 return -ENOMEM;
962
963 snprintf(buf: queue_name, size: sizeof(queue_name), fmt: "%s-stats",
964 dev_name(dev: ocelot->dev));
965 ocelot->stats_queue = create_singlethread_workqueue(queue_name);
966 if (!ocelot->stats_queue)
967 return -ENOMEM;
968
969 spin_lock_init(&ocelot->stats_lock);
970 mutex_init(&ocelot->stat_view_lock);
971
972 ret = ocelot_prepare_stats_regions(ocelot);
973 if (ret) {
974 destroy_workqueue(wq: ocelot->stats_queue);
975 return ret;
976 }
977
978 INIT_DELAYED_WORK(&ocelot->stats_work, ocelot_check_stats_work);
979 queue_delayed_work(wq: ocelot->stats_queue, dwork: &ocelot->stats_work,
980 OCELOT_STATS_CHECK_DELAY);
981
982 return 0;
983}
984
985void ocelot_stats_deinit(struct ocelot *ocelot)
986{
987 cancel_delayed_work(dwork: &ocelot->stats_work);
988 destroy_workqueue(wq: ocelot->stats_queue);
989}
990

source code of linux/drivers/net/ethernet/mscc/ocelot_stats.c