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 *
ocelot_get_stats_layout(struct ocelot * ocelot)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  */
ocelot_port_update_stats(struct ocelot * ocelot,int port)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  */
ocelot_port_transfer_stats(struct ocelot * ocelot,int port)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 
ocelot_check_stats_work(struct work_struct * work)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 
ocelot_get_strings(struct ocelot * ocelot,int port,u32 sset,u8 * data)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 */
ocelot_port_stats_run(struct ocelot * ocelot,int port,void * priv,void (* cb)(struct ocelot * ocelot,int port,void * priv))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 
ocelot_get_sset_count(struct ocelot * ocelot,int port,int sset)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 
ocelot_port_ethtool_stats_cb(struct ocelot * ocelot,int port,void * priv)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 
ocelot_get_ethtool_stats(struct ocelot * ocelot,int port,u64 * data)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 
ocelot_port_pause_stats_cb(struct ocelot * ocelot,int port,void * priv)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 
ocelot_port_pmac_pause_stats_cb(struct ocelot * ocelot,int port,void * priv)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 
ocelot_port_mm_stats_cb(struct ocelot * ocelot,int port,void * priv)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 
ocelot_port_get_pause_stats(struct ocelot * ocelot,int port,struct ethtool_pause_stats * pause_stats)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 
ocelot_port_get_mm_stats(struct ocelot * ocelot,int port,struct ethtool_mm_stats * stats)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 
ocelot_port_rmon_stats_cb(struct ocelot * ocelot,int port,void * priv)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_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 
ocelot_port_pmac_rmon_stats_cb(struct ocelot * ocelot,int port,void * priv)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_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 
ocelot_port_get_rmon_stats(struct ocelot * ocelot,int port,struct ethtool_rmon_stats * rmon_stats,const struct ethtool_rmon_hist_range ** ranges)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 
ocelot_port_ctrl_stats_cb(struct ocelot * ocelot,int port,void * priv)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 
ocelot_port_pmac_ctrl_stats_cb(struct ocelot * ocelot,int port,void * priv)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 
ocelot_port_get_eth_ctrl_stats(struct ocelot * ocelot,int port,struct ethtool_eth_ctrl_stats * ctrl_stats)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 
ocelot_port_mac_stats_cb(struct ocelot * ocelot,int port,void * priv)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 
ocelot_port_pmac_mac_stats_cb(struct ocelot * ocelot,int port,void * priv)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 
ocelot_port_get_eth_mac_stats(struct ocelot * ocelot,int port,struct ethtool_eth_mac_stats * mac_stats)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 
ocelot_port_phy_stats_cb(struct ocelot * ocelot,int port,void * priv)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 
ocelot_port_pmac_phy_stats_cb(struct ocelot * ocelot,int port,void * priv)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 
ocelot_port_get_eth_phy_stats(struct ocelot * ocelot,int port,struct ethtool_eth_phy_stats * phy_stats)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 
ocelot_port_get_stats64(struct ocelot * ocelot,int port,struct rtnl_link_stats64 * stats)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 
ocelot_prepare_stats_regions(struct ocelot * ocelot)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 
ocelot_stats_init(struct ocelot * ocelot)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 
ocelot_stats_deinit(struct ocelot * ocelot)985 void ocelot_stats_deinit(struct ocelot *ocelot)
986 {
987 	cancel_delayed_work(&ocelot->stats_work);
988 	destroy_workqueue(ocelot->stats_queue);
989 }
990