Linux Audio

Check our new training course

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