Merge tag 'x86-asm-2024-01-08' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
[linux-2.6-microblaze.git] / drivers / net / ethernet / mscc / ocelot_stats.c
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
13 enum 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
147 struct 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
258 struct 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
266 static const struct ocelot_stat_layout ocelot_stats_layout[OCELOT_NUM_STATS] = {
267         OCELOT_COMMON_STATS,
268 };
269
270 static 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
311 static const struct ocelot_stat_layout *
312 ocelot_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  */
323 static 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  */
344 static 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
364 static 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(&ocelot->stats_lock);
379                 ocelot_port_transfer_stats(ocelot, port);
380                 spin_unlock(&ocelot->stats_lock);
381         }
382
383         if (!err && ocelot->ops->update_stats)
384                 ocelot->ops->update_stats(ocelot);
385
386         mutex_unlock(&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(ocelot->stats_queue, &ocelot->stats_work,
392                            OCELOT_STATS_CHECK_DELAY);
393 }
394
395 void 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 }
413 EXPORT_SYMBOL(ocelot_get_strings);
414
415 /* Update ocelot->stats for the given port and run the given callback */
416 static 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(&ocelot->stats_lock);
432
433         ocelot_port_transfer_stats(ocelot, port);
434         cb(ocelot, port, priv);
435
436         spin_unlock(&ocelot->stats_lock);
437
438 out_unlock:
439         mutex_unlock(&ocelot->stat_view_lock);
440 }
441
442 int 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 }
459 EXPORT_SYMBOL(ocelot_get_sset_count);
460
461 static 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
481 void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
482 {
483         ocelot_port_stats_run(ocelot, port, data, ocelot_port_ethtool_stats_cb);
484 }
485 EXPORT_SYMBOL(ocelot_get_ethtool_stats);
486
487 static 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
496 static 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
506 static 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
520 void 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, pause_stats,
528                                       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, pause_stats,
533                                               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 }
541 EXPORT_SYMBOL_GPL(ocelot_port_get_pause_stats);
542
543 void 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, stats, ocelot_port_mm_stats_cb);
550 }
551 EXPORT_SYMBOL_GPL(ocelot_port_get_mm_stats);
552
553 static 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
564 static 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_256_511];
586         rmon_stats->hist_tx[4] = s[OCELOT_STAT_TX_512_1023];
587         rmon_stats->hist_tx[5] = s[OCELOT_STAT_TX_1024_1526];
588         rmon_stats->hist_tx[6] = s[OCELOT_STAT_TX_1527_MAX];
589 }
590
591 static 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_256_511];
614         rmon_stats->hist_tx[4] = s[OCELOT_STAT_TX_PMAC_512_1023];
615         rmon_stats->hist_tx[5] = s[OCELOT_STAT_TX_PMAC_1024_1526];
616         rmon_stats->hist_tx[6] = s[OCELOT_STAT_TX_PMAC_1527_MAX];
617 }
618
619 void 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, rmon_stats,
630                                       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, rmon_stats,
635                                               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 }
643 EXPORT_SYMBOL_GPL(ocelot_port_get_rmon_stats);
644
645 static 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
653 static 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
662 void 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, ctrl_stats,
670                                       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, ctrl_stats,
675                                               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 }
683 EXPORT_SYMBOL_GPL(ocelot_port_get_eth_ctrl_stats);
684
685 static 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
727 static 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
761 void 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, mac_stats,
769                                       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, mac_stats,
774                                               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 }
782 EXPORT_SYMBOL_GPL(ocelot_port_get_eth_mac_stats);
783
784 static 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
792 static 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
801 void 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, phy_stats,
809                                       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, phy_stats,
814                                               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 }
822 EXPORT_SYMBOL_GPL(ocelot_port_get_eth_phy_stats);
823
824 void 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(&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(&ocelot->stats_lock);
886 }
887 EXPORT_SYMBOL(ocelot_port_get_stats64);
888
889 static 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(&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(ocelot->dev, 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(&region->node, &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, region->base, &target,
938                                           &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(ocelot->dev, region->count,
944                                            sizeof(*region->buf), GFP_KERNEL);
945                 if (!region->buf)
946                         return -ENOMEM;
947         }
948
949         return 0;
950 }
951
952 int ocelot_stats_init(struct ocelot *ocelot)
953 {
954         char queue_name[32];
955         int ret;
956
957         ocelot->stats = devm_kcalloc(ocelot->dev,
958                                      ocelot->num_phys_ports * OCELOT_NUM_STATS,
959                                      sizeof(u64), GFP_KERNEL);
960         if (!ocelot->stats)
961                 return -ENOMEM;
962
963         snprintf(queue_name, sizeof(queue_name), "%s-stats",
964                  dev_name(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(ocelot->stats_queue);
975                 return ret;
976         }
977
978         INIT_DELAYED_WORK(&ocelot->stats_work, ocelot_check_stats_work);
979         queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
980                            OCELOT_STATS_CHECK_DELAY);
981
982         return 0;
983 }
984
985 void ocelot_stats_deinit(struct ocelot *ocelot)
986 {
987         cancel_delayed_work(&ocelot->stats_work);
988         destroy_workqueue(ocelot->stats_queue);
989 }