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/spinlock.h>
8 #include <linux/mutex.h>
9 #include <linux/workqueue.h>
10 #include "ocelot.h"
11 
12 enum ocelot_stat {
13 	OCELOT_STAT_RX_OCTETS,
14 	OCELOT_STAT_RX_UNICAST,
15 	OCELOT_STAT_RX_MULTICAST,
16 	OCELOT_STAT_RX_BROADCAST,
17 	OCELOT_STAT_RX_SHORTS,
18 	OCELOT_STAT_RX_FRAGMENTS,
19 	OCELOT_STAT_RX_JABBERS,
20 	OCELOT_STAT_RX_CRC_ALIGN_ERRS,
21 	OCELOT_STAT_RX_SYM_ERRS,
22 	OCELOT_STAT_RX_64,
23 	OCELOT_STAT_RX_65_127,
24 	OCELOT_STAT_RX_128_255,
25 	OCELOT_STAT_RX_256_511,
26 	OCELOT_STAT_RX_512_1023,
27 	OCELOT_STAT_RX_1024_1526,
28 	OCELOT_STAT_RX_1527_MAX,
29 	OCELOT_STAT_RX_PAUSE,
30 	OCELOT_STAT_RX_CONTROL,
31 	OCELOT_STAT_RX_LONGS,
32 	OCELOT_STAT_RX_CLASSIFIED_DROPS,
33 	OCELOT_STAT_RX_RED_PRIO_0,
34 	OCELOT_STAT_RX_RED_PRIO_1,
35 	OCELOT_STAT_RX_RED_PRIO_2,
36 	OCELOT_STAT_RX_RED_PRIO_3,
37 	OCELOT_STAT_RX_RED_PRIO_4,
38 	OCELOT_STAT_RX_RED_PRIO_5,
39 	OCELOT_STAT_RX_RED_PRIO_6,
40 	OCELOT_STAT_RX_RED_PRIO_7,
41 	OCELOT_STAT_RX_YELLOW_PRIO_0,
42 	OCELOT_STAT_RX_YELLOW_PRIO_1,
43 	OCELOT_STAT_RX_YELLOW_PRIO_2,
44 	OCELOT_STAT_RX_YELLOW_PRIO_3,
45 	OCELOT_STAT_RX_YELLOW_PRIO_4,
46 	OCELOT_STAT_RX_YELLOW_PRIO_5,
47 	OCELOT_STAT_RX_YELLOW_PRIO_6,
48 	OCELOT_STAT_RX_YELLOW_PRIO_7,
49 	OCELOT_STAT_RX_GREEN_PRIO_0,
50 	OCELOT_STAT_RX_GREEN_PRIO_1,
51 	OCELOT_STAT_RX_GREEN_PRIO_2,
52 	OCELOT_STAT_RX_GREEN_PRIO_3,
53 	OCELOT_STAT_RX_GREEN_PRIO_4,
54 	OCELOT_STAT_RX_GREEN_PRIO_5,
55 	OCELOT_STAT_RX_GREEN_PRIO_6,
56 	OCELOT_STAT_RX_GREEN_PRIO_7,
57 	OCELOT_STAT_TX_OCTETS,
58 	OCELOT_STAT_TX_UNICAST,
59 	OCELOT_STAT_TX_MULTICAST,
60 	OCELOT_STAT_TX_BROADCAST,
61 	OCELOT_STAT_TX_COLLISION,
62 	OCELOT_STAT_TX_DROPS,
63 	OCELOT_STAT_TX_PAUSE,
64 	OCELOT_STAT_TX_64,
65 	OCELOT_STAT_TX_65_127,
66 	OCELOT_STAT_TX_128_255,
67 	OCELOT_STAT_TX_256_511,
68 	OCELOT_STAT_TX_512_1023,
69 	OCELOT_STAT_TX_1024_1526,
70 	OCELOT_STAT_TX_1527_MAX,
71 	OCELOT_STAT_TX_YELLOW_PRIO_0,
72 	OCELOT_STAT_TX_YELLOW_PRIO_1,
73 	OCELOT_STAT_TX_YELLOW_PRIO_2,
74 	OCELOT_STAT_TX_YELLOW_PRIO_3,
75 	OCELOT_STAT_TX_YELLOW_PRIO_4,
76 	OCELOT_STAT_TX_YELLOW_PRIO_5,
77 	OCELOT_STAT_TX_YELLOW_PRIO_6,
78 	OCELOT_STAT_TX_YELLOW_PRIO_7,
79 	OCELOT_STAT_TX_GREEN_PRIO_0,
80 	OCELOT_STAT_TX_GREEN_PRIO_1,
81 	OCELOT_STAT_TX_GREEN_PRIO_2,
82 	OCELOT_STAT_TX_GREEN_PRIO_3,
83 	OCELOT_STAT_TX_GREEN_PRIO_4,
84 	OCELOT_STAT_TX_GREEN_PRIO_5,
85 	OCELOT_STAT_TX_GREEN_PRIO_6,
86 	OCELOT_STAT_TX_GREEN_PRIO_7,
87 	OCELOT_STAT_TX_AGED,
88 	OCELOT_STAT_DROP_LOCAL,
89 	OCELOT_STAT_DROP_TAIL,
90 	OCELOT_STAT_DROP_YELLOW_PRIO_0,
91 	OCELOT_STAT_DROP_YELLOW_PRIO_1,
92 	OCELOT_STAT_DROP_YELLOW_PRIO_2,
93 	OCELOT_STAT_DROP_YELLOW_PRIO_3,
94 	OCELOT_STAT_DROP_YELLOW_PRIO_4,
95 	OCELOT_STAT_DROP_YELLOW_PRIO_5,
96 	OCELOT_STAT_DROP_YELLOW_PRIO_6,
97 	OCELOT_STAT_DROP_YELLOW_PRIO_7,
98 	OCELOT_STAT_DROP_GREEN_PRIO_0,
99 	OCELOT_STAT_DROP_GREEN_PRIO_1,
100 	OCELOT_STAT_DROP_GREEN_PRIO_2,
101 	OCELOT_STAT_DROP_GREEN_PRIO_3,
102 	OCELOT_STAT_DROP_GREEN_PRIO_4,
103 	OCELOT_STAT_DROP_GREEN_PRIO_5,
104 	OCELOT_STAT_DROP_GREEN_PRIO_6,
105 	OCELOT_STAT_DROP_GREEN_PRIO_7,
106 	OCELOT_NUM_STATS,
107 };
108 
109 struct ocelot_stat_layout {
110 	u32 reg;
111 	char name[ETH_GSTRING_LEN];
112 };
113 
114 /* 32-bit counter checked for wraparound by ocelot_port_update_stats()
115  * and copied to ocelot->stats.
116  */
117 #define OCELOT_STAT(kind) \
118 	[OCELOT_STAT_ ## kind] = { .reg = SYS_COUNT_ ## kind }
119 /* Same as above, except also exported to ethtool -S. Standard counters should
120  * only be exposed to more specific interfaces rather than by their string name.
121  */
122 #define OCELOT_STAT_ETHTOOL(kind, ethtool_name) \
123 	[OCELOT_STAT_ ## kind] = { .reg = SYS_COUNT_ ## kind, .name = ethtool_name }
124 
125 #define OCELOT_COMMON_STATS \
126 	OCELOT_STAT_ETHTOOL(RX_OCTETS, "rx_octets"), \
127 	OCELOT_STAT_ETHTOOL(RX_UNICAST, "rx_unicast"), \
128 	OCELOT_STAT_ETHTOOL(RX_MULTICAST, "rx_multicast"), \
129 	OCELOT_STAT_ETHTOOL(RX_BROADCAST, "rx_broadcast"), \
130 	OCELOT_STAT_ETHTOOL(RX_SHORTS, "rx_shorts"), \
131 	OCELOT_STAT_ETHTOOL(RX_FRAGMENTS, "rx_fragments"), \
132 	OCELOT_STAT_ETHTOOL(RX_JABBERS, "rx_jabbers"), \
133 	OCELOT_STAT_ETHTOOL(RX_CRC_ALIGN_ERRS, "rx_crc_align_errs"), \
134 	OCELOT_STAT_ETHTOOL(RX_SYM_ERRS, "rx_sym_errs"), \
135 	OCELOT_STAT_ETHTOOL(RX_64, "rx_frames_below_65_octets"), \
136 	OCELOT_STAT_ETHTOOL(RX_65_127, "rx_frames_65_to_127_octets"), \
137 	OCELOT_STAT_ETHTOOL(RX_128_255, "rx_frames_128_to_255_octets"), \
138 	OCELOT_STAT_ETHTOOL(RX_256_511, "rx_frames_256_to_511_octets"), \
139 	OCELOT_STAT_ETHTOOL(RX_512_1023, "rx_frames_512_to_1023_octets"), \
140 	OCELOT_STAT_ETHTOOL(RX_1024_1526, "rx_frames_1024_to_1526_octets"), \
141 	OCELOT_STAT_ETHTOOL(RX_1527_MAX, "rx_frames_over_1526_octets"), \
142 	OCELOT_STAT_ETHTOOL(RX_PAUSE, "rx_pause"), \
143 	OCELOT_STAT_ETHTOOL(RX_CONTROL, "rx_control"), \
144 	OCELOT_STAT_ETHTOOL(RX_LONGS, "rx_longs"), \
145 	OCELOT_STAT_ETHTOOL(RX_CLASSIFIED_DROPS, "rx_classified_drops"), \
146 	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_0, "rx_red_prio_0"), \
147 	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_1, "rx_red_prio_1"), \
148 	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_2, "rx_red_prio_2"), \
149 	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_3, "rx_red_prio_3"), \
150 	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_4, "rx_red_prio_4"), \
151 	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_5, "rx_red_prio_5"), \
152 	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_6, "rx_red_prio_6"), \
153 	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_7, "rx_red_prio_7"), \
154 	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_0, "rx_yellow_prio_0"), \
155 	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_1, "rx_yellow_prio_1"), \
156 	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_2, "rx_yellow_prio_2"), \
157 	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_3, "rx_yellow_prio_3"), \
158 	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_4, "rx_yellow_prio_4"), \
159 	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_5, "rx_yellow_prio_5"), \
160 	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_6, "rx_yellow_prio_6"), \
161 	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_7, "rx_yellow_prio_7"), \
162 	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_0, "rx_green_prio_0"), \
163 	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_1, "rx_green_prio_1"), \
164 	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_2, "rx_green_prio_2"), \
165 	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_3, "rx_green_prio_3"), \
166 	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_4, "rx_green_prio_4"), \
167 	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_5, "rx_green_prio_5"), \
168 	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_6, "rx_green_prio_6"), \
169 	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_7, "rx_green_prio_7"), \
170 	OCELOT_STAT_ETHTOOL(TX_OCTETS, "tx_octets"), \
171 	OCELOT_STAT_ETHTOOL(TX_UNICAST, "tx_unicast"), \
172 	OCELOT_STAT_ETHTOOL(TX_MULTICAST, "tx_multicast"), \
173 	OCELOT_STAT_ETHTOOL(TX_BROADCAST, "tx_broadcast"), \
174 	OCELOT_STAT_ETHTOOL(TX_COLLISION, "tx_collision"), \
175 	OCELOT_STAT_ETHTOOL(TX_DROPS, "tx_drops"), \
176 	OCELOT_STAT_ETHTOOL(TX_PAUSE, "tx_pause"), \
177 	OCELOT_STAT_ETHTOOL(TX_64, "tx_frames_below_65_octets"), \
178 	OCELOT_STAT_ETHTOOL(TX_65_127, "tx_frames_65_to_127_octets"), \
179 	OCELOT_STAT_ETHTOOL(TX_128_255, "tx_frames_128_255_octets"), \
180 	OCELOT_STAT_ETHTOOL(TX_256_511, "tx_frames_256_511_octets"), \
181 	OCELOT_STAT_ETHTOOL(TX_512_1023, "tx_frames_512_1023_octets"), \
182 	OCELOT_STAT_ETHTOOL(TX_1024_1526, "tx_frames_1024_1526_octets"), \
183 	OCELOT_STAT_ETHTOOL(TX_1527_MAX, "tx_frames_over_1526_octets"), \
184 	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_0, "tx_yellow_prio_0"), \
185 	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_1, "tx_yellow_prio_1"), \
186 	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_2, "tx_yellow_prio_2"), \
187 	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_3, "tx_yellow_prio_3"), \
188 	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_4, "tx_yellow_prio_4"), \
189 	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_5, "tx_yellow_prio_5"), \
190 	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_6, "tx_yellow_prio_6"), \
191 	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_7, "tx_yellow_prio_7"), \
192 	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_0, "tx_green_prio_0"), \
193 	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_1, "tx_green_prio_1"), \
194 	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_2, "tx_green_prio_2"), \
195 	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_3, "tx_green_prio_3"), \
196 	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_4, "tx_green_prio_4"), \
197 	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_5, "tx_green_prio_5"), \
198 	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_6, "tx_green_prio_6"), \
199 	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_7, "tx_green_prio_7"), \
200 	OCELOT_STAT_ETHTOOL(TX_AGED, "tx_aged"), \
201 	OCELOT_STAT_ETHTOOL(DROP_LOCAL, "drop_local"), \
202 	OCELOT_STAT_ETHTOOL(DROP_TAIL, "drop_tail"), \
203 	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_0, "drop_yellow_prio_0"), \
204 	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_1, "drop_yellow_prio_1"), \
205 	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_2, "drop_yellow_prio_2"), \
206 	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_3, "drop_yellow_prio_3"), \
207 	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_4, "drop_yellow_prio_4"), \
208 	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_5, "drop_yellow_prio_5"), \
209 	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_6, "drop_yellow_prio_6"), \
210 	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_7, "drop_yellow_prio_7"), \
211 	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_0, "drop_green_prio_0"), \
212 	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_1, "drop_green_prio_1"), \
213 	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_2, "drop_green_prio_2"), \
214 	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_3, "drop_green_prio_3"), \
215 	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_4, "drop_green_prio_4"), \
216 	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_5, "drop_green_prio_5"), \
217 	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_6, "drop_green_prio_6"), \
218 	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_7, "drop_green_prio_7")
219 
220 struct ocelot_stats_region {
221 	struct list_head node;
222 	u32 base;
223 	int count;
224 	u32 *buf;
225 };
226 
227 static const struct ocelot_stat_layout ocelot_stats_layout[OCELOT_NUM_STATS] = {
228 	OCELOT_COMMON_STATS,
229 };
230 
231 /* Read the counters from hardware and keep them in region->buf.
232  * Caller must hold &ocelot->stat_view_lock.
233  */
234 static int ocelot_port_update_stats(struct ocelot *ocelot, int port)
235 {
236 	struct ocelot_stats_region *region;
237 	int err;
238 
239 	/* Configure the port to read the stats from */
240 	ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port), SYS_STAT_CFG);
241 
242 	list_for_each_entry(region, &ocelot->stats_regions, node) {
243 		err = ocelot_bulk_read(ocelot, region->base, region->buf,
244 				       region->count);
245 		if (err)
246 			return err;
247 	}
248 
249 	return 0;
250 }
251 
252 /* Transfer the counters from region->buf to ocelot->stats.
253  * Caller must hold &ocelot->stat_view_lock and &ocelot->stats_lock.
254  */
255 static void ocelot_port_transfer_stats(struct ocelot *ocelot, int port)
256 {
257 	unsigned int idx = port * OCELOT_NUM_STATS;
258 	struct ocelot_stats_region *region;
259 	int j;
260 
261 	list_for_each_entry(region, &ocelot->stats_regions, node) {
262 		for (j = 0; j < region->count; j++) {
263 			u64 *stat = &ocelot->stats[idx + j];
264 			u64 val = region->buf[j];
265 
266 			if (val < (*stat & U32_MAX))
267 				*stat += (u64)1 << 32;
268 
269 			*stat = (*stat & ~(u64)U32_MAX) + val;
270 		}
271 
272 		idx += region->count;
273 	}
274 }
275 
276 static void ocelot_check_stats_work(struct work_struct *work)
277 {
278 	struct delayed_work *del_work = to_delayed_work(work);
279 	struct ocelot *ocelot = container_of(del_work, struct ocelot,
280 					     stats_work);
281 	int port, err;
282 
283 	mutex_lock(&ocelot->stat_view_lock);
284 
285 	for (port = 0; port < ocelot->num_phys_ports; port++) {
286 		err = ocelot_port_update_stats(ocelot, port);
287 		if (err)
288 			break;
289 
290 		spin_lock(&ocelot->stats_lock);
291 		ocelot_port_transfer_stats(ocelot, port);
292 		spin_unlock(&ocelot->stats_lock);
293 	}
294 
295 	if (!err && ocelot->ops->update_stats)
296 		ocelot->ops->update_stats(ocelot);
297 
298 	mutex_unlock(&ocelot->stat_view_lock);
299 
300 	if (err)
301 		dev_err(ocelot->dev, "Error %d updating ethtool stats\n",  err);
302 
303 	queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
304 			   OCELOT_STATS_CHECK_DELAY);
305 }
306 
307 void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data)
308 {
309 	int i;
310 
311 	if (sset != ETH_SS_STATS)
312 		return;
313 
314 	for (i = 0; i < OCELOT_NUM_STATS; i++) {
315 		if (ocelot_stats_layout[i].name[0] == '\0')
316 			continue;
317 
318 		memcpy(data + i * ETH_GSTRING_LEN, ocelot_stats_layout[i].name,
319 		       ETH_GSTRING_LEN);
320 	}
321 }
322 EXPORT_SYMBOL(ocelot_get_strings);
323 
324 /* Update ocelot->stats for the given port and run the given callback */
325 static void ocelot_port_stats_run(struct ocelot *ocelot, int port, void *priv,
326 				  void (*cb)(struct ocelot *ocelot, int port,
327 					     void *priv))
328 {
329 	int err;
330 
331 	mutex_lock(&ocelot->stat_view_lock);
332 
333 	err = ocelot_port_update_stats(ocelot, port);
334 	if (err) {
335 		dev_err(ocelot->dev, "Failed to update port %d stats: %pe\n",
336 			port, ERR_PTR(err));
337 		goto out_unlock;
338 	}
339 
340 	spin_lock(&ocelot->stats_lock);
341 
342 	ocelot_port_transfer_stats(ocelot, port);
343 	cb(ocelot, port, priv);
344 
345 	spin_unlock(&ocelot->stats_lock);
346 
347 out_unlock:
348 	mutex_unlock(&ocelot->stat_view_lock);
349 }
350 
351 int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset)
352 {
353 	int i, num_stats = 0;
354 
355 	if (sset != ETH_SS_STATS)
356 		return -EOPNOTSUPP;
357 
358 	for (i = 0; i < OCELOT_NUM_STATS; i++)
359 		if (ocelot_stats_layout[i].name[0] != '\0')
360 			num_stats++;
361 
362 	return num_stats;
363 }
364 EXPORT_SYMBOL(ocelot_get_sset_count);
365 
366 static void ocelot_port_ethtool_stats_cb(struct ocelot *ocelot, int port,
367 					 void *priv)
368 {
369 	u64 *data = priv;
370 	int i;
371 
372 	/* Copy all supported counters */
373 	for (i = 0; i < OCELOT_NUM_STATS; i++) {
374 		int index = port * OCELOT_NUM_STATS + i;
375 
376 		if (ocelot_stats_layout[i].name[0] == '\0')
377 			continue;
378 
379 		*data++ = ocelot->stats[index];
380 	}
381 }
382 
383 void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
384 {
385 	ocelot_port_stats_run(ocelot, port, data, ocelot_port_ethtool_stats_cb);
386 }
387 EXPORT_SYMBOL(ocelot_get_ethtool_stats);
388 
389 static void ocelot_port_pause_stats_cb(struct ocelot *ocelot, int port, void *priv)
390 {
391 	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
392 	struct ethtool_pause_stats *pause_stats = priv;
393 
394 	pause_stats->tx_pause_frames = s[OCELOT_STAT_TX_PAUSE];
395 	pause_stats->rx_pause_frames = s[OCELOT_STAT_RX_PAUSE];
396 }
397 
398 void ocelot_port_get_pause_stats(struct ocelot *ocelot, int port,
399 				 struct ethtool_pause_stats *pause_stats)
400 {
401 	ocelot_port_stats_run(ocelot, port, pause_stats,
402 			      ocelot_port_pause_stats_cb);
403 }
404 EXPORT_SYMBOL_GPL(ocelot_port_get_pause_stats);
405 
406 static const struct ethtool_rmon_hist_range ocelot_rmon_ranges[] = {
407 	{   64,    64 },
408 	{   65,   127 },
409 	{  128,   255 },
410 	{  256,   511 },
411 	{  512,  1023 },
412 	{ 1024,  1526 },
413 	{ 1527, 65535 },
414 	{},
415 };
416 
417 static void ocelot_port_rmon_stats_cb(struct ocelot *ocelot, int port, void *priv)
418 {
419 	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
420 	struct ethtool_rmon_stats *rmon_stats = priv;
421 
422 	rmon_stats->undersize_pkts = s[OCELOT_STAT_RX_SHORTS];
423 	rmon_stats->oversize_pkts = s[OCELOT_STAT_RX_LONGS];
424 	rmon_stats->fragments = s[OCELOT_STAT_RX_FRAGMENTS];
425 	rmon_stats->jabbers = s[OCELOT_STAT_RX_JABBERS];
426 
427 	rmon_stats->hist[0] = s[OCELOT_STAT_RX_64];
428 	rmon_stats->hist[1] = s[OCELOT_STAT_RX_65_127];
429 	rmon_stats->hist[2] = s[OCELOT_STAT_RX_128_255];
430 	rmon_stats->hist[3] = s[OCELOT_STAT_RX_256_511];
431 	rmon_stats->hist[4] = s[OCELOT_STAT_RX_512_1023];
432 	rmon_stats->hist[5] = s[OCELOT_STAT_RX_1024_1526];
433 	rmon_stats->hist[6] = s[OCELOT_STAT_RX_1527_MAX];
434 
435 	rmon_stats->hist_tx[0] = s[OCELOT_STAT_TX_64];
436 	rmon_stats->hist_tx[1] = s[OCELOT_STAT_TX_65_127];
437 	rmon_stats->hist_tx[2] = s[OCELOT_STAT_TX_128_255];
438 	rmon_stats->hist_tx[3] = s[OCELOT_STAT_TX_128_255];
439 	rmon_stats->hist_tx[4] = s[OCELOT_STAT_TX_256_511];
440 	rmon_stats->hist_tx[5] = s[OCELOT_STAT_TX_512_1023];
441 	rmon_stats->hist_tx[6] = s[OCELOT_STAT_TX_1024_1526];
442 }
443 
444 void ocelot_port_get_rmon_stats(struct ocelot *ocelot, int port,
445 				struct ethtool_rmon_stats *rmon_stats,
446 				const struct ethtool_rmon_hist_range **ranges)
447 {
448 	*ranges = ocelot_rmon_ranges;
449 
450 	ocelot_port_stats_run(ocelot, port, rmon_stats,
451 			      ocelot_port_rmon_stats_cb);
452 }
453 EXPORT_SYMBOL_GPL(ocelot_port_get_rmon_stats);
454 
455 static void ocelot_port_ctrl_stats_cb(struct ocelot *ocelot, int port, void *priv)
456 {
457 	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
458 	struct ethtool_eth_ctrl_stats *ctrl_stats = priv;
459 
460 	ctrl_stats->MACControlFramesReceived = s[OCELOT_STAT_RX_CONTROL];
461 }
462 
463 void ocelot_port_get_eth_ctrl_stats(struct ocelot *ocelot, int port,
464 				    struct ethtool_eth_ctrl_stats *ctrl_stats)
465 {
466 	ocelot_port_stats_run(ocelot, port, ctrl_stats,
467 			      ocelot_port_ctrl_stats_cb);
468 }
469 EXPORT_SYMBOL_GPL(ocelot_port_get_eth_ctrl_stats);
470 
471 static void ocelot_port_mac_stats_cb(struct ocelot *ocelot, int port, void *priv)
472 {
473 	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
474 	struct ethtool_eth_mac_stats *mac_stats = priv;
475 
476 	mac_stats->OctetsTransmittedOK = s[OCELOT_STAT_TX_OCTETS];
477 	mac_stats->FramesTransmittedOK = s[OCELOT_STAT_TX_64] +
478 					 s[OCELOT_STAT_TX_65_127] +
479 					 s[OCELOT_STAT_TX_128_255] +
480 					 s[OCELOT_STAT_TX_256_511] +
481 					 s[OCELOT_STAT_TX_512_1023] +
482 					 s[OCELOT_STAT_TX_1024_1526] +
483 					 s[OCELOT_STAT_TX_1527_MAX];
484 	mac_stats->OctetsReceivedOK = s[OCELOT_STAT_RX_OCTETS];
485 	mac_stats->FramesReceivedOK = s[OCELOT_STAT_RX_GREEN_PRIO_0] +
486 				      s[OCELOT_STAT_RX_GREEN_PRIO_1] +
487 				      s[OCELOT_STAT_RX_GREEN_PRIO_2] +
488 				      s[OCELOT_STAT_RX_GREEN_PRIO_3] +
489 				      s[OCELOT_STAT_RX_GREEN_PRIO_4] +
490 				      s[OCELOT_STAT_RX_GREEN_PRIO_5] +
491 				      s[OCELOT_STAT_RX_GREEN_PRIO_6] +
492 				      s[OCELOT_STAT_RX_GREEN_PRIO_7] +
493 				      s[OCELOT_STAT_RX_YELLOW_PRIO_0] +
494 				      s[OCELOT_STAT_RX_YELLOW_PRIO_1] +
495 				      s[OCELOT_STAT_RX_YELLOW_PRIO_2] +
496 				      s[OCELOT_STAT_RX_YELLOW_PRIO_3] +
497 				      s[OCELOT_STAT_RX_YELLOW_PRIO_4] +
498 				      s[OCELOT_STAT_RX_YELLOW_PRIO_5] +
499 				      s[OCELOT_STAT_RX_YELLOW_PRIO_6] +
500 				      s[OCELOT_STAT_RX_YELLOW_PRIO_7];
501 	mac_stats->MulticastFramesXmittedOK = s[OCELOT_STAT_TX_MULTICAST];
502 	mac_stats->BroadcastFramesXmittedOK = s[OCELOT_STAT_TX_BROADCAST];
503 	mac_stats->MulticastFramesReceivedOK = s[OCELOT_STAT_RX_MULTICAST];
504 	mac_stats->BroadcastFramesReceivedOK = s[OCELOT_STAT_RX_BROADCAST];
505 	mac_stats->FrameTooLongErrors = s[OCELOT_STAT_RX_LONGS];
506 	/* Sadly, C_RX_CRC is the sum of FCS and alignment errors, they are not
507 	 * counted individually.
508 	 */
509 	mac_stats->FrameCheckSequenceErrors = s[OCELOT_STAT_RX_CRC_ALIGN_ERRS];
510 	mac_stats->AlignmentErrors = s[OCELOT_STAT_RX_CRC_ALIGN_ERRS];
511 }
512 
513 void ocelot_port_get_eth_mac_stats(struct ocelot *ocelot, int port,
514 				   struct ethtool_eth_mac_stats *mac_stats)
515 {
516 	ocelot_port_stats_run(ocelot, port, mac_stats,
517 			      ocelot_port_mac_stats_cb);
518 }
519 EXPORT_SYMBOL_GPL(ocelot_port_get_eth_mac_stats);
520 
521 static void ocelot_port_phy_stats_cb(struct ocelot *ocelot, int port, void *priv)
522 {
523 	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
524 	struct ethtool_eth_phy_stats *phy_stats = priv;
525 
526 	phy_stats->SymbolErrorDuringCarrier = s[OCELOT_STAT_RX_SYM_ERRS];
527 }
528 
529 void ocelot_port_get_eth_phy_stats(struct ocelot *ocelot, int port,
530 				   struct ethtool_eth_phy_stats *phy_stats)
531 {
532 	ocelot_port_stats_run(ocelot, port, phy_stats,
533 			      ocelot_port_phy_stats_cb);
534 }
535 EXPORT_SYMBOL_GPL(ocelot_port_get_eth_phy_stats);
536 
537 void ocelot_port_get_stats64(struct ocelot *ocelot, int port,
538 			     struct rtnl_link_stats64 *stats)
539 {
540 	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
541 
542 	spin_lock(&ocelot->stats_lock);
543 
544 	/* Get Rx stats */
545 	stats->rx_bytes = s[OCELOT_STAT_RX_OCTETS];
546 	stats->rx_packets = s[OCELOT_STAT_RX_SHORTS] +
547 			    s[OCELOT_STAT_RX_FRAGMENTS] +
548 			    s[OCELOT_STAT_RX_JABBERS] +
549 			    s[OCELOT_STAT_RX_LONGS] +
550 			    s[OCELOT_STAT_RX_64] +
551 			    s[OCELOT_STAT_RX_65_127] +
552 			    s[OCELOT_STAT_RX_128_255] +
553 			    s[OCELOT_STAT_RX_256_511] +
554 			    s[OCELOT_STAT_RX_512_1023] +
555 			    s[OCELOT_STAT_RX_1024_1526] +
556 			    s[OCELOT_STAT_RX_1527_MAX];
557 	stats->multicast = s[OCELOT_STAT_RX_MULTICAST];
558 	stats->rx_missed_errors = s[OCELOT_STAT_DROP_TAIL];
559 	stats->rx_dropped = s[OCELOT_STAT_RX_RED_PRIO_0] +
560 			    s[OCELOT_STAT_RX_RED_PRIO_1] +
561 			    s[OCELOT_STAT_RX_RED_PRIO_2] +
562 			    s[OCELOT_STAT_RX_RED_PRIO_3] +
563 			    s[OCELOT_STAT_RX_RED_PRIO_4] +
564 			    s[OCELOT_STAT_RX_RED_PRIO_5] +
565 			    s[OCELOT_STAT_RX_RED_PRIO_6] +
566 			    s[OCELOT_STAT_RX_RED_PRIO_7] +
567 			    s[OCELOT_STAT_DROP_LOCAL] +
568 			    s[OCELOT_STAT_DROP_YELLOW_PRIO_0] +
569 			    s[OCELOT_STAT_DROP_YELLOW_PRIO_1] +
570 			    s[OCELOT_STAT_DROP_YELLOW_PRIO_2] +
571 			    s[OCELOT_STAT_DROP_YELLOW_PRIO_3] +
572 			    s[OCELOT_STAT_DROP_YELLOW_PRIO_4] +
573 			    s[OCELOT_STAT_DROP_YELLOW_PRIO_5] +
574 			    s[OCELOT_STAT_DROP_YELLOW_PRIO_6] +
575 			    s[OCELOT_STAT_DROP_YELLOW_PRIO_7] +
576 			    s[OCELOT_STAT_DROP_GREEN_PRIO_0] +
577 			    s[OCELOT_STAT_DROP_GREEN_PRIO_1] +
578 			    s[OCELOT_STAT_DROP_GREEN_PRIO_2] +
579 			    s[OCELOT_STAT_DROP_GREEN_PRIO_3] +
580 			    s[OCELOT_STAT_DROP_GREEN_PRIO_4] +
581 			    s[OCELOT_STAT_DROP_GREEN_PRIO_5] +
582 			    s[OCELOT_STAT_DROP_GREEN_PRIO_6] +
583 			    s[OCELOT_STAT_DROP_GREEN_PRIO_7];
584 
585 	/* Get Tx stats */
586 	stats->tx_bytes = s[OCELOT_STAT_TX_OCTETS];
587 	stats->tx_packets = s[OCELOT_STAT_TX_64] +
588 			    s[OCELOT_STAT_TX_65_127] +
589 			    s[OCELOT_STAT_TX_128_255] +
590 			    s[OCELOT_STAT_TX_256_511] +
591 			    s[OCELOT_STAT_TX_512_1023] +
592 			    s[OCELOT_STAT_TX_1024_1526] +
593 			    s[OCELOT_STAT_TX_1527_MAX];
594 	stats->tx_dropped = s[OCELOT_STAT_TX_DROPS] +
595 			    s[OCELOT_STAT_TX_AGED];
596 	stats->collisions = s[OCELOT_STAT_TX_COLLISION];
597 
598 	spin_unlock(&ocelot->stats_lock);
599 }
600 EXPORT_SYMBOL(ocelot_port_get_stats64);
601 
602 static int ocelot_prepare_stats_regions(struct ocelot *ocelot)
603 {
604 	struct ocelot_stats_region *region = NULL;
605 	unsigned int last = 0;
606 	int i;
607 
608 	INIT_LIST_HEAD(&ocelot->stats_regions);
609 
610 	for (i = 0; i < OCELOT_NUM_STATS; i++) {
611 		if (!ocelot_stats_layout[i].reg)
612 			continue;
613 
614 		if (region && ocelot_stats_layout[i].reg == last + 4) {
615 			region->count++;
616 		} else {
617 			region = devm_kzalloc(ocelot->dev, sizeof(*region),
618 					      GFP_KERNEL);
619 			if (!region)
620 				return -ENOMEM;
621 
622 			/* enum ocelot_stat must be kept sorted in the same
623 			 * order as ocelot_stats_layout[i].reg in order to have
624 			 * efficient bulking
625 			 */
626 			WARN_ON(last >= ocelot_stats_layout[i].reg);
627 
628 			region->base = ocelot_stats_layout[i].reg;
629 			region->count = 1;
630 			list_add_tail(&region->node, &ocelot->stats_regions);
631 		}
632 
633 		last = ocelot_stats_layout[i].reg;
634 	}
635 
636 	list_for_each_entry(region, &ocelot->stats_regions, node) {
637 		region->buf = devm_kcalloc(ocelot->dev, region->count,
638 					   sizeof(*region->buf), GFP_KERNEL);
639 		if (!region->buf)
640 			return -ENOMEM;
641 	}
642 
643 	return 0;
644 }
645 
646 int ocelot_stats_init(struct ocelot *ocelot)
647 {
648 	char queue_name[32];
649 	int ret;
650 
651 	ocelot->stats = devm_kcalloc(ocelot->dev,
652 				     ocelot->num_phys_ports * OCELOT_NUM_STATS,
653 				     sizeof(u64), GFP_KERNEL);
654 	if (!ocelot->stats)
655 		return -ENOMEM;
656 
657 	snprintf(queue_name, sizeof(queue_name), "%s-stats",
658 		 dev_name(ocelot->dev));
659 	ocelot->stats_queue = create_singlethread_workqueue(queue_name);
660 	if (!ocelot->stats_queue)
661 		return -ENOMEM;
662 
663 	spin_lock_init(&ocelot->stats_lock);
664 	mutex_init(&ocelot->stat_view_lock);
665 
666 	ret = ocelot_prepare_stats_regions(ocelot);
667 	if (ret) {
668 		destroy_workqueue(ocelot->stats_queue);
669 		return ret;
670 	}
671 
672 	INIT_DELAYED_WORK(&ocelot->stats_work, ocelot_check_stats_work);
673 	queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
674 			   OCELOT_STATS_CHECK_DELAY);
675 
676 	return 0;
677 }
678 
679 void ocelot_stats_deinit(struct ocelot *ocelot)
680 {
681 	cancel_delayed_work(&ocelot->stats_work);
682 	destroy_workqueue(ocelot->stats_queue);
683 }
684 
685