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