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 */
79179f5feSVladimir Oltean #include <linux/ethtool_netlink.h>
8fe90104cSVladimir Oltean #include <linux/spinlock.h>
9fe90104cSVladimir Oltean #include <linux/mutex.h>
10fe90104cSVladimir Oltean #include <linux/workqueue.h>
11fe90104cSVladimir Oltean #include "ocelot.h"
12fe90104cSVladimir Oltean
13a3bb8f52SColin Foster enum ocelot_stat {
14a3bb8f52SColin Foster OCELOT_STAT_RX_OCTETS,
15a3bb8f52SColin Foster OCELOT_STAT_RX_UNICAST,
16a3bb8f52SColin Foster OCELOT_STAT_RX_MULTICAST,
17a3bb8f52SColin Foster OCELOT_STAT_RX_BROADCAST,
18a3bb8f52SColin Foster OCELOT_STAT_RX_SHORTS,
19a3bb8f52SColin Foster OCELOT_STAT_RX_FRAGMENTS,
20a3bb8f52SColin Foster OCELOT_STAT_RX_JABBERS,
21a3bb8f52SColin Foster OCELOT_STAT_RX_CRC_ALIGN_ERRS,
22a3bb8f52SColin Foster OCELOT_STAT_RX_SYM_ERRS,
23a3bb8f52SColin Foster OCELOT_STAT_RX_64,
24a3bb8f52SColin Foster OCELOT_STAT_RX_65_127,
25a3bb8f52SColin Foster OCELOT_STAT_RX_128_255,
26a3bb8f52SColin Foster OCELOT_STAT_RX_256_511,
27a3bb8f52SColin Foster OCELOT_STAT_RX_512_1023,
28a3bb8f52SColin Foster OCELOT_STAT_RX_1024_1526,
29a3bb8f52SColin Foster OCELOT_STAT_RX_1527_MAX,
30a3bb8f52SColin Foster OCELOT_STAT_RX_PAUSE,
31a3bb8f52SColin Foster OCELOT_STAT_RX_CONTROL,
32a3bb8f52SColin Foster OCELOT_STAT_RX_LONGS,
33a3bb8f52SColin Foster OCELOT_STAT_RX_CLASSIFIED_DROPS,
34a3bb8f52SColin Foster OCELOT_STAT_RX_RED_PRIO_0,
35a3bb8f52SColin Foster OCELOT_STAT_RX_RED_PRIO_1,
36a3bb8f52SColin Foster OCELOT_STAT_RX_RED_PRIO_2,
37a3bb8f52SColin Foster OCELOT_STAT_RX_RED_PRIO_3,
38a3bb8f52SColin Foster OCELOT_STAT_RX_RED_PRIO_4,
39a3bb8f52SColin Foster OCELOT_STAT_RX_RED_PRIO_5,
40a3bb8f52SColin Foster OCELOT_STAT_RX_RED_PRIO_6,
41a3bb8f52SColin Foster OCELOT_STAT_RX_RED_PRIO_7,
42a3bb8f52SColin Foster OCELOT_STAT_RX_YELLOW_PRIO_0,
43a3bb8f52SColin Foster OCELOT_STAT_RX_YELLOW_PRIO_1,
44a3bb8f52SColin Foster OCELOT_STAT_RX_YELLOW_PRIO_2,
45a3bb8f52SColin Foster OCELOT_STAT_RX_YELLOW_PRIO_3,
46a3bb8f52SColin Foster OCELOT_STAT_RX_YELLOW_PRIO_4,
47a3bb8f52SColin Foster OCELOT_STAT_RX_YELLOW_PRIO_5,
48a3bb8f52SColin Foster OCELOT_STAT_RX_YELLOW_PRIO_6,
49a3bb8f52SColin Foster OCELOT_STAT_RX_YELLOW_PRIO_7,
50a3bb8f52SColin Foster OCELOT_STAT_RX_GREEN_PRIO_0,
51a3bb8f52SColin Foster OCELOT_STAT_RX_GREEN_PRIO_1,
52a3bb8f52SColin Foster OCELOT_STAT_RX_GREEN_PRIO_2,
53a3bb8f52SColin Foster OCELOT_STAT_RX_GREEN_PRIO_3,
54a3bb8f52SColin Foster OCELOT_STAT_RX_GREEN_PRIO_4,
55a3bb8f52SColin Foster OCELOT_STAT_RX_GREEN_PRIO_5,
56a3bb8f52SColin Foster OCELOT_STAT_RX_GREEN_PRIO_6,
57a3bb8f52SColin Foster OCELOT_STAT_RX_GREEN_PRIO_7,
58ab3f97a9SVladimir Oltean OCELOT_STAT_RX_ASSEMBLY_ERRS,
59ab3f97a9SVladimir Oltean OCELOT_STAT_RX_SMD_ERRS,
60ab3f97a9SVladimir Oltean OCELOT_STAT_RX_ASSEMBLY_OK,
61ab3f97a9SVladimir Oltean OCELOT_STAT_RX_MERGE_FRAGMENTS,
62ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_OCTETS,
63ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_UNICAST,
64ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_MULTICAST,
65ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_BROADCAST,
66ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_SHORTS,
67ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_FRAGMENTS,
68ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_JABBERS,
69ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_CRC_ALIGN_ERRS,
70ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_SYM_ERRS,
71ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_64,
72ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_65_127,
73ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_128_255,
74ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_256_511,
75ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_512_1023,
76ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_1024_1526,
77ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_1527_MAX,
78ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_PAUSE,
79ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_CONTROL,
80ab3f97a9SVladimir Oltean OCELOT_STAT_RX_PMAC_LONGS,
81a3bb8f52SColin Foster OCELOT_STAT_TX_OCTETS,
82a3bb8f52SColin Foster OCELOT_STAT_TX_UNICAST,
83a3bb8f52SColin Foster OCELOT_STAT_TX_MULTICAST,
84a3bb8f52SColin Foster OCELOT_STAT_TX_BROADCAST,
85a3bb8f52SColin Foster OCELOT_STAT_TX_COLLISION,
86a3bb8f52SColin Foster OCELOT_STAT_TX_DROPS,
87a3bb8f52SColin Foster OCELOT_STAT_TX_PAUSE,
88a3bb8f52SColin Foster OCELOT_STAT_TX_64,
89a3bb8f52SColin Foster OCELOT_STAT_TX_65_127,
90a3bb8f52SColin Foster OCELOT_STAT_TX_128_255,
91a3bb8f52SColin Foster OCELOT_STAT_TX_256_511,
92a3bb8f52SColin Foster OCELOT_STAT_TX_512_1023,
93a3bb8f52SColin Foster OCELOT_STAT_TX_1024_1526,
94a3bb8f52SColin Foster OCELOT_STAT_TX_1527_MAX,
95a3bb8f52SColin Foster OCELOT_STAT_TX_YELLOW_PRIO_0,
96a3bb8f52SColin Foster OCELOT_STAT_TX_YELLOW_PRIO_1,
97a3bb8f52SColin Foster OCELOT_STAT_TX_YELLOW_PRIO_2,
98a3bb8f52SColin Foster OCELOT_STAT_TX_YELLOW_PRIO_3,
99a3bb8f52SColin Foster OCELOT_STAT_TX_YELLOW_PRIO_4,
100a3bb8f52SColin Foster OCELOT_STAT_TX_YELLOW_PRIO_5,
101a3bb8f52SColin Foster OCELOT_STAT_TX_YELLOW_PRIO_6,
102a3bb8f52SColin Foster OCELOT_STAT_TX_YELLOW_PRIO_7,
103a3bb8f52SColin Foster OCELOT_STAT_TX_GREEN_PRIO_0,
104a3bb8f52SColin Foster OCELOT_STAT_TX_GREEN_PRIO_1,
105a3bb8f52SColin Foster OCELOT_STAT_TX_GREEN_PRIO_2,
106a3bb8f52SColin Foster OCELOT_STAT_TX_GREEN_PRIO_3,
107a3bb8f52SColin Foster OCELOT_STAT_TX_GREEN_PRIO_4,
108a3bb8f52SColin Foster OCELOT_STAT_TX_GREEN_PRIO_5,
109a3bb8f52SColin Foster OCELOT_STAT_TX_GREEN_PRIO_6,
110a3bb8f52SColin Foster OCELOT_STAT_TX_GREEN_PRIO_7,
111a3bb8f52SColin Foster OCELOT_STAT_TX_AGED,
112ab3f97a9SVladimir Oltean OCELOT_STAT_TX_MM_HOLD,
113ab3f97a9SVladimir Oltean OCELOT_STAT_TX_MERGE_FRAGMENTS,
114ab3f97a9SVladimir Oltean OCELOT_STAT_TX_PMAC_OCTETS,
115ab3f97a9SVladimir Oltean OCELOT_STAT_TX_PMAC_UNICAST,
116ab3f97a9SVladimir Oltean OCELOT_STAT_TX_PMAC_MULTICAST,
117ab3f97a9SVladimir Oltean OCELOT_STAT_TX_PMAC_BROADCAST,
118ab3f97a9SVladimir Oltean OCELOT_STAT_TX_PMAC_PAUSE,
119ab3f97a9SVladimir Oltean OCELOT_STAT_TX_PMAC_64,
120ab3f97a9SVladimir Oltean OCELOT_STAT_TX_PMAC_65_127,
121ab3f97a9SVladimir Oltean OCELOT_STAT_TX_PMAC_128_255,
122ab3f97a9SVladimir Oltean OCELOT_STAT_TX_PMAC_256_511,
123ab3f97a9SVladimir Oltean OCELOT_STAT_TX_PMAC_512_1023,
124ab3f97a9SVladimir Oltean OCELOT_STAT_TX_PMAC_1024_1526,
125ab3f97a9SVladimir Oltean OCELOT_STAT_TX_PMAC_1527_MAX,
126a3bb8f52SColin Foster OCELOT_STAT_DROP_LOCAL,
127a3bb8f52SColin Foster OCELOT_STAT_DROP_TAIL,
128a3bb8f52SColin Foster OCELOT_STAT_DROP_YELLOW_PRIO_0,
129a3bb8f52SColin Foster OCELOT_STAT_DROP_YELLOW_PRIO_1,
130a3bb8f52SColin Foster OCELOT_STAT_DROP_YELLOW_PRIO_2,
131a3bb8f52SColin Foster OCELOT_STAT_DROP_YELLOW_PRIO_3,
132a3bb8f52SColin Foster OCELOT_STAT_DROP_YELLOW_PRIO_4,
133a3bb8f52SColin Foster OCELOT_STAT_DROP_YELLOW_PRIO_5,
134a3bb8f52SColin Foster OCELOT_STAT_DROP_YELLOW_PRIO_6,
135a3bb8f52SColin Foster OCELOT_STAT_DROP_YELLOW_PRIO_7,
136a3bb8f52SColin Foster OCELOT_STAT_DROP_GREEN_PRIO_0,
137a3bb8f52SColin Foster OCELOT_STAT_DROP_GREEN_PRIO_1,
138a3bb8f52SColin Foster OCELOT_STAT_DROP_GREEN_PRIO_2,
139a3bb8f52SColin Foster OCELOT_STAT_DROP_GREEN_PRIO_3,
140a3bb8f52SColin Foster OCELOT_STAT_DROP_GREEN_PRIO_4,
141a3bb8f52SColin Foster OCELOT_STAT_DROP_GREEN_PRIO_5,
142a3bb8f52SColin Foster OCELOT_STAT_DROP_GREEN_PRIO_6,
143a3bb8f52SColin Foster OCELOT_STAT_DROP_GREEN_PRIO_7,
144a3bb8f52SColin Foster OCELOT_NUM_STATS,
145a3bb8f52SColin Foster };
146a3bb8f52SColin Foster
147a3bb8f52SColin Foster struct ocelot_stat_layout {
148eae0b9d1SVladimir Oltean enum ocelot_reg reg;
149a3bb8f52SColin Foster char name[ETH_GSTRING_LEN];
150a3bb8f52SColin Foster };
151a3bb8f52SColin Foster
152a3bb8f52SColin Foster /* 32-bit counter checked for wraparound by ocelot_port_update_stats()
153a3bb8f52SColin Foster * and copied to ocelot->stats.
154a3bb8f52SColin Foster */
155a3bb8f52SColin Foster #define OCELOT_STAT(kind) \
156a3bb8f52SColin Foster [OCELOT_STAT_ ## kind] = { .reg = SYS_COUNT_ ## kind }
157a3bb8f52SColin Foster /* Same as above, except also exported to ethtool -S. Standard counters should
158a3bb8f52SColin Foster * only be exposed to more specific interfaces rather than by their string name.
159a3bb8f52SColin Foster */
160a3bb8f52SColin Foster #define OCELOT_STAT_ETHTOOL(kind, ethtool_name) \
161a3bb8f52SColin Foster [OCELOT_STAT_ ## kind] = { .reg = SYS_COUNT_ ## kind, .name = ethtool_name }
162a3bb8f52SColin Foster
163a3bb8f52SColin Foster #define OCELOT_COMMON_STATS \
164a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_OCTETS, "rx_octets"), \
165a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_UNICAST, "rx_unicast"), \
166a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_MULTICAST, "rx_multicast"), \
167a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_BROADCAST, "rx_broadcast"), \
168a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_SHORTS, "rx_shorts"), \
169a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_FRAGMENTS, "rx_fragments"), \
170a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_JABBERS, "rx_jabbers"), \
171a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_CRC_ALIGN_ERRS, "rx_crc_align_errs"), \
172a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_SYM_ERRS, "rx_sym_errs"), \
173a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_64, "rx_frames_below_65_octets"), \
174a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_65_127, "rx_frames_65_to_127_octets"), \
175a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_128_255, "rx_frames_128_to_255_octets"), \
176a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_256_511, "rx_frames_256_to_511_octets"), \
177a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_512_1023, "rx_frames_512_to_1023_octets"), \
178a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_1024_1526, "rx_frames_1024_to_1526_octets"), \
179a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_1527_MAX, "rx_frames_over_1526_octets"), \
180a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_PAUSE, "rx_pause"), \
181a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_CONTROL, "rx_control"), \
182a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_LONGS, "rx_longs"), \
183a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_CLASSIFIED_DROPS, "rx_classified_drops"), \
184a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_RED_PRIO_0, "rx_red_prio_0"), \
185a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_RED_PRIO_1, "rx_red_prio_1"), \
186a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_RED_PRIO_2, "rx_red_prio_2"), \
187a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_RED_PRIO_3, "rx_red_prio_3"), \
188a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_RED_PRIO_4, "rx_red_prio_4"), \
189a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_RED_PRIO_5, "rx_red_prio_5"), \
190a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_RED_PRIO_6, "rx_red_prio_6"), \
191a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_RED_PRIO_7, "rx_red_prio_7"), \
192a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_0, "rx_yellow_prio_0"), \
193a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_1, "rx_yellow_prio_1"), \
194a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_2, "rx_yellow_prio_2"), \
195a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_3, "rx_yellow_prio_3"), \
196a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_4, "rx_yellow_prio_4"), \
197a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_5, "rx_yellow_prio_5"), \
198a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_6, "rx_yellow_prio_6"), \
199a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_7, "rx_yellow_prio_7"), \
200a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_0, "rx_green_prio_0"), \
201a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_1, "rx_green_prio_1"), \
202a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_2, "rx_green_prio_2"), \
203a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_3, "rx_green_prio_3"), \
204a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_4, "rx_green_prio_4"), \
205a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_5, "rx_green_prio_5"), \
206a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_6, "rx_green_prio_6"), \
207a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_7, "rx_green_prio_7"), \
208a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_OCTETS, "tx_octets"), \
209a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_UNICAST, "tx_unicast"), \
210a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_MULTICAST, "tx_multicast"), \
211a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_BROADCAST, "tx_broadcast"), \
212a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_COLLISION, "tx_collision"), \
213a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_DROPS, "tx_drops"), \
214a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_PAUSE, "tx_pause"), \
215a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_64, "tx_frames_below_65_octets"), \
216a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_65_127, "tx_frames_65_to_127_octets"), \
217a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_128_255, "tx_frames_128_255_octets"), \
218a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_256_511, "tx_frames_256_511_octets"), \
219a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_512_1023, "tx_frames_512_1023_octets"), \
220a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_1024_1526, "tx_frames_1024_1526_octets"), \
221a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_1527_MAX, "tx_frames_over_1526_octets"), \
222a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_0, "tx_yellow_prio_0"), \
223a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_1, "tx_yellow_prio_1"), \
224a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_2, "tx_yellow_prio_2"), \
225a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_3, "tx_yellow_prio_3"), \
226a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_4, "tx_yellow_prio_4"), \
227a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_5, "tx_yellow_prio_5"), \
228a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_6, "tx_yellow_prio_6"), \
229a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_7, "tx_yellow_prio_7"), \
230a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_0, "tx_green_prio_0"), \
231a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_1, "tx_green_prio_1"), \
232a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_2, "tx_green_prio_2"), \
233a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_3, "tx_green_prio_3"), \
234a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_4, "tx_green_prio_4"), \
235a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_5, "tx_green_prio_5"), \
236a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_6, "tx_green_prio_6"), \
237a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_7, "tx_green_prio_7"), \
238a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(TX_AGED, "tx_aged"), \
239a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(DROP_LOCAL, "drop_local"), \
240a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(DROP_TAIL, "drop_tail"), \
241a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_0, "drop_yellow_prio_0"), \
242a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_1, "drop_yellow_prio_1"), \
243a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_2, "drop_yellow_prio_2"), \
244a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_3, "drop_yellow_prio_3"), \
245a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_4, "drop_yellow_prio_4"), \
246a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_5, "drop_yellow_prio_5"), \
247a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_6, "drop_yellow_prio_6"), \
248a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_7, "drop_yellow_prio_7"), \
249a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_0, "drop_green_prio_0"), \
250a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_1, "drop_green_prio_1"), \
251a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_2, "drop_green_prio_2"), \
252a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_3, "drop_green_prio_3"), \
253a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_4, "drop_green_prio_4"), \
254a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_5, "drop_green_prio_5"), \
255a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_6, "drop_green_prio_6"), \
256a3bb8f52SColin Foster OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_7, "drop_green_prio_7")
257a3bb8f52SColin Foster
258a3bb8f52SColin Foster struct ocelot_stats_region {
259a3bb8f52SColin Foster struct list_head node;
260eae0b9d1SVladimir Oltean enum ocelot_reg base;
26117dfd210SVladimir Oltean enum ocelot_stat first_stat;
262a3bb8f52SColin Foster int count;
263a3bb8f52SColin Foster u32 *buf;
264a3bb8f52SColin Foster };
265a3bb8f52SColin Foster
26633d5eeb9SColin Foster static const struct ocelot_stat_layout ocelot_stats_layout[OCELOT_NUM_STATS] = {
26733d5eeb9SColin Foster OCELOT_COMMON_STATS,
26833d5eeb9SColin Foster };
26933d5eeb9SColin Foster
270ab3f97a9SVladimir Oltean static const struct ocelot_stat_layout ocelot_mm_stats_layout[OCELOT_NUM_STATS] = {
271ab3f97a9SVladimir Oltean OCELOT_COMMON_STATS,
272ab3f97a9SVladimir Oltean OCELOT_STAT(RX_ASSEMBLY_ERRS),
273ab3f97a9SVladimir Oltean OCELOT_STAT(RX_SMD_ERRS),
274ab3f97a9SVladimir Oltean OCELOT_STAT(RX_ASSEMBLY_OK),
275ab3f97a9SVladimir Oltean OCELOT_STAT(RX_MERGE_FRAGMENTS),
276ab3f97a9SVladimir Oltean OCELOT_STAT(TX_MERGE_FRAGMENTS),
2775291099eSVladimir Oltean OCELOT_STAT(TX_MM_HOLD),
278ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_OCTETS),
279ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_UNICAST),
280ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_MULTICAST),
281ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_BROADCAST),
282ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_SHORTS),
283ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_FRAGMENTS),
284ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_JABBERS),
285ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_CRC_ALIGN_ERRS),
286ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_SYM_ERRS),
287ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_64),
288ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_65_127),
289ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_128_255),
290ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_256_511),
291ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_512_1023),
292ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_1024_1526),
293ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_1527_MAX),
294ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_PAUSE),
295ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_CONTROL),
296ab3f97a9SVladimir Oltean OCELOT_STAT(RX_PMAC_LONGS),
297ab3f97a9SVladimir Oltean OCELOT_STAT(TX_PMAC_OCTETS),
298ab3f97a9SVladimir Oltean OCELOT_STAT(TX_PMAC_UNICAST),
299ab3f97a9SVladimir Oltean OCELOT_STAT(TX_PMAC_MULTICAST),
300ab3f97a9SVladimir Oltean OCELOT_STAT(TX_PMAC_BROADCAST),
301ab3f97a9SVladimir Oltean OCELOT_STAT(TX_PMAC_PAUSE),
302ab3f97a9SVladimir Oltean OCELOT_STAT(TX_PMAC_64),
303ab3f97a9SVladimir Oltean OCELOT_STAT(TX_PMAC_65_127),
304ab3f97a9SVladimir Oltean OCELOT_STAT(TX_PMAC_128_255),
305ab3f97a9SVladimir Oltean OCELOT_STAT(TX_PMAC_256_511),
306ab3f97a9SVladimir Oltean OCELOT_STAT(TX_PMAC_512_1023),
307ab3f97a9SVladimir Oltean OCELOT_STAT(TX_PMAC_1024_1526),
308ab3f97a9SVladimir Oltean OCELOT_STAT(TX_PMAC_1527_MAX),
309ab3f97a9SVladimir Oltean };
310ab3f97a9SVladimir Oltean
311497eea9fSVladimir Oltean static const struct ocelot_stat_layout *
ocelot_get_stats_layout(struct ocelot * ocelot)312497eea9fSVladimir Oltean ocelot_get_stats_layout(struct ocelot *ocelot)
313497eea9fSVladimir Oltean {
314ab3f97a9SVladimir Oltean if (ocelot->mm_supported)
315ab3f97a9SVladimir Oltean return ocelot_mm_stats_layout;
316ab3f97a9SVladimir Oltean
317497eea9fSVladimir Oltean return ocelot_stats_layout;
318497eea9fSVladimir Oltean }
319497eea9fSVladimir Oltean
320fe90104cSVladimir Oltean /* Read the counters from hardware and keep them in region->buf.
321fe90104cSVladimir Oltean * Caller must hold &ocelot->stat_view_lock.
322fe90104cSVladimir Oltean */
ocelot_port_update_stats(struct ocelot * ocelot,int port)323fe90104cSVladimir Oltean static int ocelot_port_update_stats(struct ocelot *ocelot, int port)
324fe90104cSVladimir Oltean {
325fe90104cSVladimir Oltean struct ocelot_stats_region *region;
326fe90104cSVladimir Oltean int err;
327fe90104cSVladimir Oltean
328fe90104cSVladimir Oltean /* Configure the port to read the stats from */
329fe90104cSVladimir Oltean ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port), SYS_STAT_CFG);
330fe90104cSVladimir Oltean
331fe90104cSVladimir Oltean list_for_each_entry(region, &ocelot->stats_regions, node) {
332fe90104cSVladimir Oltean err = ocelot_bulk_read(ocelot, region->base, region->buf,
333fe90104cSVladimir Oltean region->count);
334fe90104cSVladimir Oltean if (err)
335fe90104cSVladimir Oltean return err;
336fe90104cSVladimir Oltean }
337fe90104cSVladimir Oltean
338fe90104cSVladimir Oltean return 0;
339fe90104cSVladimir Oltean }
340fe90104cSVladimir Oltean
341fe90104cSVladimir Oltean /* Transfer the counters from region->buf to ocelot->stats.
342fe90104cSVladimir Oltean * Caller must hold &ocelot->stat_view_lock and &ocelot->stats_lock.
343fe90104cSVladimir Oltean */
ocelot_port_transfer_stats(struct ocelot * ocelot,int port)344fe90104cSVladimir Oltean static void ocelot_port_transfer_stats(struct ocelot *ocelot, int port)
345fe90104cSVladimir Oltean {
346fe90104cSVladimir Oltean struct ocelot_stats_region *region;
347fe90104cSVladimir Oltean int j;
348fe90104cSVladimir Oltean
349fe90104cSVladimir Oltean list_for_each_entry(region, &ocelot->stats_regions, node) {
35017dfd210SVladimir Oltean unsigned int idx = port * OCELOT_NUM_STATS + region->first_stat;
35117dfd210SVladimir Oltean
352fe90104cSVladimir Oltean for (j = 0; j < region->count; j++) {
353fe90104cSVladimir Oltean u64 *stat = &ocelot->stats[idx + j];
354fe90104cSVladimir Oltean u64 val = region->buf[j];
355fe90104cSVladimir Oltean
356fe90104cSVladimir Oltean if (val < (*stat & U32_MAX))
357fe90104cSVladimir Oltean *stat += (u64)1 << 32;
358fe90104cSVladimir Oltean
359fe90104cSVladimir Oltean *stat = (*stat & ~(u64)U32_MAX) + val;
360fe90104cSVladimir Oltean }
361fe90104cSVladimir Oltean }
362fe90104cSVladimir Oltean }
363fe90104cSVladimir Oltean
ocelot_check_stats_work(struct work_struct * work)364fe90104cSVladimir Oltean static void ocelot_check_stats_work(struct work_struct *work)
365fe90104cSVladimir Oltean {
366fe90104cSVladimir Oltean struct delayed_work *del_work = to_delayed_work(work);
367fe90104cSVladimir Oltean struct ocelot *ocelot = container_of(del_work, struct ocelot,
368fe90104cSVladimir Oltean stats_work);
369fe90104cSVladimir Oltean int port, err;
370fe90104cSVladimir Oltean
371fe90104cSVladimir Oltean mutex_lock(&ocelot->stat_view_lock);
372fe90104cSVladimir Oltean
373fe90104cSVladimir Oltean for (port = 0; port < ocelot->num_phys_ports; port++) {
374fe90104cSVladimir Oltean err = ocelot_port_update_stats(ocelot, port);
375fe90104cSVladimir Oltean if (err)
376fe90104cSVladimir Oltean break;
377fe90104cSVladimir Oltean
378fe90104cSVladimir Oltean spin_lock(&ocelot->stats_lock);
379fe90104cSVladimir Oltean ocelot_port_transfer_stats(ocelot, port);
380fe90104cSVladimir Oltean spin_unlock(&ocelot->stats_lock);
381fe90104cSVladimir Oltean }
382fe90104cSVladimir Oltean
383fe90104cSVladimir Oltean if (!err && ocelot->ops->update_stats)
384fe90104cSVladimir Oltean ocelot->ops->update_stats(ocelot);
385fe90104cSVladimir Oltean
386fe90104cSVladimir Oltean mutex_unlock(&ocelot->stat_view_lock);
387fe90104cSVladimir Oltean
388fe90104cSVladimir Oltean if (err)
389fe90104cSVladimir Oltean dev_err(ocelot->dev, "Error %d updating ethtool stats\n", err);
390fe90104cSVladimir Oltean
391fe90104cSVladimir Oltean queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
392fe90104cSVladimir Oltean OCELOT_STATS_CHECK_DELAY);
393fe90104cSVladimir Oltean }
394fe90104cSVladimir Oltean
ocelot_get_strings(struct ocelot * ocelot,int port,u32 sset,u8 * data)395fe90104cSVladimir Oltean void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data)
396fe90104cSVladimir Oltean {
397497eea9fSVladimir Oltean const struct ocelot_stat_layout *layout;
3986663c01eSVladimir Oltean enum ocelot_stat i;
399fe90104cSVladimir Oltean
400fe90104cSVladimir Oltean if (sset != ETH_SS_STATS)
401fe90104cSVladimir Oltean return;
402fe90104cSVladimir Oltean
403497eea9fSVladimir Oltean layout = ocelot_get_stats_layout(ocelot);
404497eea9fSVladimir Oltean
405fe90104cSVladimir Oltean for (i = 0; i < OCELOT_NUM_STATS; i++) {
406497eea9fSVladimir Oltean if (layout[i].name[0] == '\0')
407fe90104cSVladimir Oltean continue;
408fe90104cSVladimir Oltean
409497eea9fSVladimir Oltean memcpy(data, layout[i].name, ETH_GSTRING_LEN);
4101a733bbdSVladimir Oltean data += ETH_GSTRING_LEN;
411fe90104cSVladimir Oltean }
412fe90104cSVladimir Oltean }
413fe90104cSVladimir Oltean EXPORT_SYMBOL(ocelot_get_strings);
414fe90104cSVladimir Oltean
415e32036e1SVladimir Oltean /* Update ocelot->stats for the given port and run the given callback */
ocelot_port_stats_run(struct ocelot * ocelot,int port,void * priv,void (* cb)(struct ocelot * ocelot,int port,void * priv))416e32036e1SVladimir Oltean static void ocelot_port_stats_run(struct ocelot *ocelot, int port, void *priv,
417e32036e1SVladimir Oltean void (*cb)(struct ocelot *ocelot, int port,
418e32036e1SVladimir Oltean void *priv))
419fe90104cSVladimir Oltean {
420e32036e1SVladimir Oltean int err;
421fe90104cSVladimir Oltean
422fe90104cSVladimir Oltean mutex_lock(&ocelot->stat_view_lock);
423fe90104cSVladimir Oltean
424fe90104cSVladimir Oltean err = ocelot_port_update_stats(ocelot, port);
425e32036e1SVladimir Oltean if (err) {
426e32036e1SVladimir Oltean dev_err(ocelot->dev, "Failed to update port %d stats: %pe\n",
427e32036e1SVladimir Oltean port, ERR_PTR(err));
428e32036e1SVladimir Oltean goto out_unlock;
429e32036e1SVladimir Oltean }
430fe90104cSVladimir Oltean
431fe90104cSVladimir Oltean spin_lock(&ocelot->stats_lock);
432fe90104cSVladimir Oltean
433fe90104cSVladimir Oltean ocelot_port_transfer_stats(ocelot, port);
434e32036e1SVladimir Oltean cb(ocelot, port, priv);
435fe90104cSVladimir Oltean
436fe90104cSVladimir Oltean spin_unlock(&ocelot->stats_lock);
437fe90104cSVladimir Oltean
438e32036e1SVladimir Oltean out_unlock:
439fe90104cSVladimir Oltean mutex_unlock(&ocelot->stat_view_lock);
440fe90104cSVladimir Oltean }
441fe90104cSVladimir Oltean
ocelot_get_sset_count(struct ocelot * ocelot,int port,int sset)442fe90104cSVladimir Oltean int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset)
443fe90104cSVladimir Oltean {
444497eea9fSVladimir Oltean const struct ocelot_stat_layout *layout;
4456663c01eSVladimir Oltean enum ocelot_stat i;
4466663c01eSVladimir Oltean int num_stats = 0;
447fe90104cSVladimir Oltean
448fe90104cSVladimir Oltean if (sset != ETH_SS_STATS)
449fe90104cSVladimir Oltean return -EOPNOTSUPP;
450fe90104cSVladimir Oltean
451497eea9fSVladimir Oltean layout = ocelot_get_stats_layout(ocelot);
452497eea9fSVladimir Oltean
453fe90104cSVladimir Oltean for (i = 0; i < OCELOT_NUM_STATS; i++)
454497eea9fSVladimir Oltean if (layout[i].name[0] != '\0')
455fe90104cSVladimir Oltean num_stats++;
456fe90104cSVladimir Oltean
457fe90104cSVladimir Oltean return num_stats;
458fe90104cSVladimir Oltean }
459fe90104cSVladimir Oltean EXPORT_SYMBOL(ocelot_get_sset_count);
460fe90104cSVladimir Oltean
ocelot_port_ethtool_stats_cb(struct ocelot * ocelot,int port,void * priv)461e32036e1SVladimir Oltean static void ocelot_port_ethtool_stats_cb(struct ocelot *ocelot, int port,
462e32036e1SVladimir Oltean void *priv)
463e32036e1SVladimir Oltean {
464497eea9fSVladimir Oltean const struct ocelot_stat_layout *layout;
4656663c01eSVladimir Oltean enum ocelot_stat i;
466e32036e1SVladimir Oltean u64 *data = priv;
467e32036e1SVladimir Oltean
468497eea9fSVladimir Oltean layout = ocelot_get_stats_layout(ocelot);
469497eea9fSVladimir Oltean
470e32036e1SVladimir Oltean /* Copy all supported counters */
471e32036e1SVladimir Oltean for (i = 0; i < OCELOT_NUM_STATS; i++) {
472e32036e1SVladimir Oltean int index = port * OCELOT_NUM_STATS + i;
473e32036e1SVladimir Oltean
474497eea9fSVladimir Oltean if (layout[i].name[0] == '\0')
475e32036e1SVladimir Oltean continue;
476e32036e1SVladimir Oltean
477e32036e1SVladimir Oltean *data++ = ocelot->stats[index];
478e32036e1SVladimir Oltean }
479e32036e1SVladimir Oltean }
480e32036e1SVladimir Oltean
ocelot_get_ethtool_stats(struct ocelot * ocelot,int port,u64 * data)481e32036e1SVladimir Oltean void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
482e32036e1SVladimir Oltean {
483e32036e1SVladimir Oltean ocelot_port_stats_run(ocelot, port, data, ocelot_port_ethtool_stats_cb);
484e32036e1SVladimir Oltean }
485e32036e1SVladimir Oltean EXPORT_SYMBOL(ocelot_get_ethtool_stats);
486e32036e1SVladimir Oltean
ocelot_port_pause_stats_cb(struct ocelot * ocelot,int port,void * priv)487e32036e1SVladimir Oltean static void ocelot_port_pause_stats_cb(struct ocelot *ocelot, int port, void *priv)
488e32036e1SVladimir Oltean {
489e32036e1SVladimir Oltean u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
490e32036e1SVladimir Oltean struct ethtool_pause_stats *pause_stats = priv;
491e32036e1SVladimir Oltean
492e32036e1SVladimir Oltean pause_stats->tx_pause_frames = s[OCELOT_STAT_TX_PAUSE];
493e32036e1SVladimir Oltean pause_stats->rx_pause_frames = s[OCELOT_STAT_RX_PAUSE];
494e32036e1SVladimir Oltean }
495e32036e1SVladimir Oltean
ocelot_port_pmac_pause_stats_cb(struct ocelot * ocelot,int port,void * priv)496ab3f97a9SVladimir Oltean static void ocelot_port_pmac_pause_stats_cb(struct ocelot *ocelot, int port,
497ab3f97a9SVladimir Oltean void *priv)
498ab3f97a9SVladimir Oltean {
499ab3f97a9SVladimir Oltean u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
500ab3f97a9SVladimir Oltean struct ethtool_pause_stats *pause_stats = priv;
501ab3f97a9SVladimir Oltean
502ab3f97a9SVladimir Oltean pause_stats->tx_pause_frames = s[OCELOT_STAT_TX_PMAC_PAUSE];
503ab3f97a9SVladimir Oltean pause_stats->rx_pause_frames = s[OCELOT_STAT_RX_PMAC_PAUSE];
504ab3f97a9SVladimir Oltean }
505ab3f97a9SVladimir Oltean
ocelot_port_mm_stats_cb(struct ocelot * ocelot,int port,void * priv)506ab3f97a9SVladimir Oltean static void ocelot_port_mm_stats_cb(struct ocelot *ocelot, int port,
507ab3f97a9SVladimir Oltean void *priv)
508ab3f97a9SVladimir Oltean {
509ab3f97a9SVladimir Oltean u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
510ab3f97a9SVladimir Oltean struct ethtool_mm_stats *stats = priv;
511ab3f97a9SVladimir Oltean
512ab3f97a9SVladimir Oltean stats->MACMergeFrameAssErrorCount = s[OCELOT_STAT_RX_ASSEMBLY_ERRS];
513ab3f97a9SVladimir Oltean stats->MACMergeFrameSmdErrorCount = s[OCELOT_STAT_RX_SMD_ERRS];
514ab3f97a9SVladimir Oltean stats->MACMergeFrameAssOkCount = s[OCELOT_STAT_RX_ASSEMBLY_OK];
515ab3f97a9SVladimir Oltean stats->MACMergeFragCountRx = s[OCELOT_STAT_RX_MERGE_FRAGMENTS];
516ab3f97a9SVladimir Oltean stats->MACMergeFragCountTx = s[OCELOT_STAT_TX_MERGE_FRAGMENTS];
517ab3f97a9SVladimir Oltean stats->MACMergeHoldCount = s[OCELOT_STAT_TX_MM_HOLD];
518ab3f97a9SVladimir Oltean }
519ab3f97a9SVladimir Oltean
ocelot_port_get_pause_stats(struct ocelot * ocelot,int port,struct ethtool_pause_stats * pause_stats)520e32036e1SVladimir Oltean void ocelot_port_get_pause_stats(struct ocelot *ocelot, int port,
521e32036e1SVladimir Oltean struct ethtool_pause_stats *pause_stats)
522e32036e1SVladimir Oltean {
523ab3f97a9SVladimir Oltean struct net_device *dev;
524ab3f97a9SVladimir Oltean
525ab3f97a9SVladimir Oltean switch (pause_stats->src) {
526ab3f97a9SVladimir Oltean case ETHTOOL_MAC_STATS_SRC_EMAC:
527e32036e1SVladimir Oltean ocelot_port_stats_run(ocelot, port, pause_stats,
528e32036e1SVladimir Oltean ocelot_port_pause_stats_cb);
529ab3f97a9SVladimir Oltean break;
530ab3f97a9SVladimir Oltean case ETHTOOL_MAC_STATS_SRC_PMAC:
531ab3f97a9SVladimir Oltean if (ocelot->mm_supported)
532ab3f97a9SVladimir Oltean ocelot_port_stats_run(ocelot, port, pause_stats,
533ab3f97a9SVladimir Oltean ocelot_port_pmac_pause_stats_cb);
534ab3f97a9SVladimir Oltean break;
535ab3f97a9SVladimir Oltean case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
536ab3f97a9SVladimir Oltean dev = ocelot->ops->port_to_netdev(ocelot, port);
537ab3f97a9SVladimir Oltean ethtool_aggregate_pause_stats(dev, pause_stats);
538ab3f97a9SVladimir Oltean break;
539ab3f97a9SVladimir Oltean }
540e32036e1SVladimir Oltean }
541e32036e1SVladimir Oltean EXPORT_SYMBOL_GPL(ocelot_port_get_pause_stats);
542e32036e1SVladimir Oltean
ocelot_port_get_mm_stats(struct ocelot * ocelot,int port,struct ethtool_mm_stats * stats)543ab3f97a9SVladimir Oltean void ocelot_port_get_mm_stats(struct ocelot *ocelot, int port,
544ab3f97a9SVladimir Oltean struct ethtool_mm_stats *stats)
545ab3f97a9SVladimir Oltean {
546ab3f97a9SVladimir Oltean if (!ocelot->mm_supported)
547ab3f97a9SVladimir Oltean return;
548ab3f97a9SVladimir Oltean
549ab3f97a9SVladimir Oltean ocelot_port_stats_run(ocelot, port, stats, ocelot_port_mm_stats_cb);
550ab3f97a9SVladimir Oltean }
551ab3f97a9SVladimir Oltean EXPORT_SYMBOL_GPL(ocelot_port_get_mm_stats);
552ab3f97a9SVladimir Oltean
553e32036e1SVladimir Oltean static const struct ethtool_rmon_hist_range ocelot_rmon_ranges[] = {
554e32036e1SVladimir Oltean { 64, 64 },
555e32036e1SVladimir Oltean { 65, 127 },
556e32036e1SVladimir Oltean { 128, 255 },
557e32036e1SVladimir Oltean { 256, 511 },
558e32036e1SVladimir Oltean { 512, 1023 },
559e32036e1SVladimir Oltean { 1024, 1526 },
560e32036e1SVladimir Oltean { 1527, 65535 },
561e32036e1SVladimir Oltean {},
562e32036e1SVladimir Oltean };
563e32036e1SVladimir Oltean
ocelot_port_rmon_stats_cb(struct ocelot * ocelot,int port,void * priv)564e32036e1SVladimir Oltean static void ocelot_port_rmon_stats_cb(struct ocelot *ocelot, int port, void *priv)
565e32036e1SVladimir Oltean {
566e32036e1SVladimir Oltean u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
567e32036e1SVladimir Oltean struct ethtool_rmon_stats *rmon_stats = priv;
568e32036e1SVladimir Oltean
569e32036e1SVladimir Oltean rmon_stats->undersize_pkts = s[OCELOT_STAT_RX_SHORTS];
570e32036e1SVladimir Oltean rmon_stats->oversize_pkts = s[OCELOT_STAT_RX_LONGS];
571e32036e1SVladimir Oltean rmon_stats->fragments = s[OCELOT_STAT_RX_FRAGMENTS];
572e32036e1SVladimir Oltean rmon_stats->jabbers = s[OCELOT_STAT_RX_JABBERS];
573e32036e1SVladimir Oltean
574e32036e1SVladimir Oltean rmon_stats->hist[0] = s[OCELOT_STAT_RX_64];
575e32036e1SVladimir Oltean rmon_stats->hist[1] = s[OCELOT_STAT_RX_65_127];
576e32036e1SVladimir Oltean rmon_stats->hist[2] = s[OCELOT_STAT_RX_128_255];
577e32036e1SVladimir Oltean rmon_stats->hist[3] = s[OCELOT_STAT_RX_256_511];
578e32036e1SVladimir Oltean rmon_stats->hist[4] = s[OCELOT_STAT_RX_512_1023];
579e32036e1SVladimir Oltean rmon_stats->hist[5] = s[OCELOT_STAT_RX_1024_1526];
580e32036e1SVladimir Oltean rmon_stats->hist[6] = s[OCELOT_STAT_RX_1527_MAX];
581e32036e1SVladimir Oltean
582e32036e1SVladimir Oltean rmon_stats->hist_tx[0] = s[OCELOT_STAT_TX_64];
583e32036e1SVladimir Oltean rmon_stats->hist_tx[1] = s[OCELOT_STAT_TX_65_127];
584e32036e1SVladimir Oltean rmon_stats->hist_tx[2] = s[OCELOT_STAT_TX_128_255];
58530108546SVladimir Oltean rmon_stats->hist_tx[3] = s[OCELOT_STAT_TX_256_511];
58630108546SVladimir Oltean rmon_stats->hist_tx[4] = s[OCELOT_STAT_TX_512_1023];
58730108546SVladimir Oltean rmon_stats->hist_tx[5] = s[OCELOT_STAT_TX_1024_1526];
58830108546SVladimir Oltean rmon_stats->hist_tx[6] = s[OCELOT_STAT_TX_1527_MAX];
589e32036e1SVladimir Oltean }
590e32036e1SVladimir Oltean
ocelot_port_pmac_rmon_stats_cb(struct ocelot * ocelot,int port,void * priv)591ab3f97a9SVladimir Oltean static void ocelot_port_pmac_rmon_stats_cb(struct ocelot *ocelot, int port,
592ab3f97a9SVladimir Oltean void *priv)
593ab3f97a9SVladimir Oltean {
594ab3f97a9SVladimir Oltean u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
595ab3f97a9SVladimir Oltean struct ethtool_rmon_stats *rmon_stats = priv;
596ab3f97a9SVladimir Oltean
597ab3f97a9SVladimir Oltean rmon_stats->undersize_pkts = s[OCELOT_STAT_RX_PMAC_SHORTS];
598ab3f97a9SVladimir Oltean rmon_stats->oversize_pkts = s[OCELOT_STAT_RX_PMAC_LONGS];
599ab3f97a9SVladimir Oltean rmon_stats->fragments = s[OCELOT_STAT_RX_PMAC_FRAGMENTS];
600ab3f97a9SVladimir Oltean rmon_stats->jabbers = s[OCELOT_STAT_RX_PMAC_JABBERS];
601ab3f97a9SVladimir Oltean
602ab3f97a9SVladimir Oltean rmon_stats->hist[0] = s[OCELOT_STAT_RX_PMAC_64];
603ab3f97a9SVladimir Oltean rmon_stats->hist[1] = s[OCELOT_STAT_RX_PMAC_65_127];
604ab3f97a9SVladimir Oltean rmon_stats->hist[2] = s[OCELOT_STAT_RX_PMAC_128_255];
605ab3f97a9SVladimir Oltean rmon_stats->hist[3] = s[OCELOT_STAT_RX_PMAC_256_511];
606ab3f97a9SVladimir Oltean rmon_stats->hist[4] = s[OCELOT_STAT_RX_PMAC_512_1023];
607ab3f97a9SVladimir Oltean rmon_stats->hist[5] = s[OCELOT_STAT_RX_PMAC_1024_1526];
608ab3f97a9SVladimir Oltean rmon_stats->hist[6] = s[OCELOT_STAT_RX_PMAC_1527_MAX];
609ab3f97a9SVladimir Oltean
610ab3f97a9SVladimir Oltean rmon_stats->hist_tx[0] = s[OCELOT_STAT_TX_PMAC_64];
611ab3f97a9SVladimir Oltean rmon_stats->hist_tx[1] = s[OCELOT_STAT_TX_PMAC_65_127];
612ab3f97a9SVladimir Oltean rmon_stats->hist_tx[2] = s[OCELOT_STAT_TX_PMAC_128_255];
613*fd0f5c1aSVladimir Oltean rmon_stats->hist_tx[3] = s[OCELOT_STAT_TX_PMAC_256_511];
614*fd0f5c1aSVladimir Oltean rmon_stats->hist_tx[4] = s[OCELOT_STAT_TX_PMAC_512_1023];
615*fd0f5c1aSVladimir Oltean rmon_stats->hist_tx[5] = s[OCELOT_STAT_TX_PMAC_1024_1526];
616*fd0f5c1aSVladimir Oltean rmon_stats->hist_tx[6] = s[OCELOT_STAT_TX_PMAC_1527_MAX];
617ab3f97a9SVladimir Oltean }
618ab3f97a9SVladimir Oltean
ocelot_port_get_rmon_stats(struct ocelot * ocelot,int port,struct ethtool_rmon_stats * rmon_stats,const struct ethtool_rmon_hist_range ** ranges)619e32036e1SVladimir Oltean void ocelot_port_get_rmon_stats(struct ocelot *ocelot, int port,
620e32036e1SVladimir Oltean struct ethtool_rmon_stats *rmon_stats,
621e32036e1SVladimir Oltean const struct ethtool_rmon_hist_range **ranges)
622e32036e1SVladimir Oltean {
623ab3f97a9SVladimir Oltean struct net_device *dev;
624ab3f97a9SVladimir Oltean
625e32036e1SVladimir Oltean *ranges = ocelot_rmon_ranges;
626e32036e1SVladimir Oltean
627ab3f97a9SVladimir Oltean switch (rmon_stats->src) {
628ab3f97a9SVladimir Oltean case ETHTOOL_MAC_STATS_SRC_EMAC:
629e32036e1SVladimir Oltean ocelot_port_stats_run(ocelot, port, rmon_stats,
630e32036e1SVladimir Oltean ocelot_port_rmon_stats_cb);
631ab3f97a9SVladimir Oltean break;
632ab3f97a9SVladimir Oltean case ETHTOOL_MAC_STATS_SRC_PMAC:
633ab3f97a9SVladimir Oltean if (ocelot->mm_supported)
634ab3f97a9SVladimir Oltean ocelot_port_stats_run(ocelot, port, rmon_stats,
635ab3f97a9SVladimir Oltean ocelot_port_pmac_rmon_stats_cb);
636ab3f97a9SVladimir Oltean break;
637ab3f97a9SVladimir Oltean case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
638ab3f97a9SVladimir Oltean dev = ocelot->ops->port_to_netdev(ocelot, port);
639ab3f97a9SVladimir Oltean ethtool_aggregate_rmon_stats(dev, rmon_stats);
640ab3f97a9SVladimir Oltean break;
641ab3f97a9SVladimir Oltean }
642e32036e1SVladimir Oltean }
643e32036e1SVladimir Oltean EXPORT_SYMBOL_GPL(ocelot_port_get_rmon_stats);
644e32036e1SVladimir Oltean
ocelot_port_ctrl_stats_cb(struct ocelot * ocelot,int port,void * priv)645e32036e1SVladimir Oltean static void ocelot_port_ctrl_stats_cb(struct ocelot *ocelot, int port, void *priv)
646e32036e1SVladimir Oltean {
647e32036e1SVladimir Oltean u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
648e32036e1SVladimir Oltean struct ethtool_eth_ctrl_stats *ctrl_stats = priv;
649e32036e1SVladimir Oltean
650e32036e1SVladimir Oltean ctrl_stats->MACControlFramesReceived = s[OCELOT_STAT_RX_CONTROL];
651e32036e1SVladimir Oltean }
652e32036e1SVladimir Oltean
ocelot_port_pmac_ctrl_stats_cb(struct ocelot * ocelot,int port,void * priv)653ab3f97a9SVladimir Oltean static void ocelot_port_pmac_ctrl_stats_cb(struct ocelot *ocelot, int port,
654ab3f97a9SVladimir Oltean void *priv)
655ab3f97a9SVladimir Oltean {
656ab3f97a9SVladimir Oltean u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
657ab3f97a9SVladimir Oltean struct ethtool_eth_ctrl_stats *ctrl_stats = priv;
658ab3f97a9SVladimir Oltean
659ab3f97a9SVladimir Oltean ctrl_stats->MACControlFramesReceived = s[OCELOT_STAT_RX_PMAC_CONTROL];
660ab3f97a9SVladimir Oltean }
661ab3f97a9SVladimir Oltean
ocelot_port_get_eth_ctrl_stats(struct ocelot * ocelot,int port,struct ethtool_eth_ctrl_stats * ctrl_stats)662e32036e1SVladimir Oltean void ocelot_port_get_eth_ctrl_stats(struct ocelot *ocelot, int port,
663e32036e1SVladimir Oltean struct ethtool_eth_ctrl_stats *ctrl_stats)
664e32036e1SVladimir Oltean {
665ab3f97a9SVladimir Oltean struct net_device *dev;
666ab3f97a9SVladimir Oltean
667ab3f97a9SVladimir Oltean switch (ctrl_stats->src) {
668ab3f97a9SVladimir Oltean case ETHTOOL_MAC_STATS_SRC_EMAC:
669e32036e1SVladimir Oltean ocelot_port_stats_run(ocelot, port, ctrl_stats,
670e32036e1SVladimir Oltean ocelot_port_ctrl_stats_cb);
671ab3f97a9SVladimir Oltean break;
672ab3f97a9SVladimir Oltean case ETHTOOL_MAC_STATS_SRC_PMAC:
673ab3f97a9SVladimir Oltean if (ocelot->mm_supported)
674ab3f97a9SVladimir Oltean ocelot_port_stats_run(ocelot, port, ctrl_stats,
675ab3f97a9SVladimir Oltean ocelot_port_pmac_ctrl_stats_cb);
676ab3f97a9SVladimir Oltean break;
677ab3f97a9SVladimir Oltean case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
678ab3f97a9SVladimir Oltean dev = ocelot->ops->port_to_netdev(ocelot, port);
679ab3f97a9SVladimir Oltean ethtool_aggregate_ctrl_stats(dev, ctrl_stats);
680ab3f97a9SVladimir Oltean break;
681ab3f97a9SVladimir Oltean }
682e32036e1SVladimir Oltean }
683e32036e1SVladimir Oltean EXPORT_SYMBOL_GPL(ocelot_port_get_eth_ctrl_stats);
684e32036e1SVladimir Oltean
ocelot_port_mac_stats_cb(struct ocelot * ocelot,int port,void * priv)685e32036e1SVladimir Oltean static void ocelot_port_mac_stats_cb(struct ocelot *ocelot, int port, void *priv)
686e32036e1SVladimir Oltean {
687e32036e1SVladimir Oltean u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
688e32036e1SVladimir Oltean struct ethtool_eth_mac_stats *mac_stats = priv;
689e32036e1SVladimir Oltean
690e32036e1SVladimir Oltean mac_stats->OctetsTransmittedOK = s[OCELOT_STAT_TX_OCTETS];
691e32036e1SVladimir Oltean mac_stats->FramesTransmittedOK = s[OCELOT_STAT_TX_64] +
692e32036e1SVladimir Oltean s[OCELOT_STAT_TX_65_127] +
693e32036e1SVladimir Oltean s[OCELOT_STAT_TX_128_255] +
694e32036e1SVladimir Oltean s[OCELOT_STAT_TX_256_511] +
695e32036e1SVladimir Oltean s[OCELOT_STAT_TX_512_1023] +
696e32036e1SVladimir Oltean s[OCELOT_STAT_TX_1024_1526] +
697e32036e1SVladimir Oltean s[OCELOT_STAT_TX_1527_MAX];
698e32036e1SVladimir Oltean mac_stats->OctetsReceivedOK = s[OCELOT_STAT_RX_OCTETS];
699e32036e1SVladimir Oltean mac_stats->FramesReceivedOK = s[OCELOT_STAT_RX_GREEN_PRIO_0] +
700e32036e1SVladimir Oltean s[OCELOT_STAT_RX_GREEN_PRIO_1] +
701e32036e1SVladimir Oltean s[OCELOT_STAT_RX_GREEN_PRIO_2] +
702e32036e1SVladimir Oltean s[OCELOT_STAT_RX_GREEN_PRIO_3] +
703e32036e1SVladimir Oltean s[OCELOT_STAT_RX_GREEN_PRIO_4] +
704e32036e1SVladimir Oltean s[OCELOT_STAT_RX_GREEN_PRIO_5] +
705e32036e1SVladimir Oltean s[OCELOT_STAT_RX_GREEN_PRIO_6] +
706e32036e1SVladimir Oltean s[OCELOT_STAT_RX_GREEN_PRIO_7] +
707e32036e1SVladimir Oltean s[OCELOT_STAT_RX_YELLOW_PRIO_0] +
708e32036e1SVladimir Oltean s[OCELOT_STAT_RX_YELLOW_PRIO_1] +
709e32036e1SVladimir Oltean s[OCELOT_STAT_RX_YELLOW_PRIO_2] +
710e32036e1SVladimir Oltean s[OCELOT_STAT_RX_YELLOW_PRIO_3] +
711e32036e1SVladimir Oltean s[OCELOT_STAT_RX_YELLOW_PRIO_4] +
712e32036e1SVladimir Oltean s[OCELOT_STAT_RX_YELLOW_PRIO_5] +
713e32036e1SVladimir Oltean s[OCELOT_STAT_RX_YELLOW_PRIO_6] +
714e32036e1SVladimir Oltean s[OCELOT_STAT_RX_YELLOW_PRIO_7];
715e32036e1SVladimir Oltean mac_stats->MulticastFramesXmittedOK = s[OCELOT_STAT_TX_MULTICAST];
716e32036e1SVladimir Oltean mac_stats->BroadcastFramesXmittedOK = s[OCELOT_STAT_TX_BROADCAST];
717e32036e1SVladimir Oltean mac_stats->MulticastFramesReceivedOK = s[OCELOT_STAT_RX_MULTICAST];
718e32036e1SVladimir Oltean mac_stats->BroadcastFramesReceivedOK = s[OCELOT_STAT_RX_BROADCAST];
719e32036e1SVladimir Oltean mac_stats->FrameTooLongErrors = s[OCELOT_STAT_RX_LONGS];
720e32036e1SVladimir Oltean /* Sadly, C_RX_CRC is the sum of FCS and alignment errors, they are not
721e32036e1SVladimir Oltean * counted individually.
722e32036e1SVladimir Oltean */
723e32036e1SVladimir Oltean mac_stats->FrameCheckSequenceErrors = s[OCELOT_STAT_RX_CRC_ALIGN_ERRS];
724e32036e1SVladimir Oltean mac_stats->AlignmentErrors = s[OCELOT_STAT_RX_CRC_ALIGN_ERRS];
725e32036e1SVladimir Oltean }
726e32036e1SVladimir Oltean
ocelot_port_pmac_mac_stats_cb(struct ocelot * ocelot,int port,void * priv)727ab3f97a9SVladimir Oltean static void ocelot_port_pmac_mac_stats_cb(struct ocelot *ocelot, int port,
728ab3f97a9SVladimir Oltean void *priv)
729ab3f97a9SVladimir Oltean {
730ab3f97a9SVladimir Oltean u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
731ab3f97a9SVladimir Oltean struct ethtool_eth_mac_stats *mac_stats = priv;
732ab3f97a9SVladimir Oltean
733ab3f97a9SVladimir Oltean mac_stats->OctetsTransmittedOK = s[OCELOT_STAT_TX_PMAC_OCTETS];
734ab3f97a9SVladimir Oltean mac_stats->FramesTransmittedOK = s[OCELOT_STAT_TX_PMAC_64] +
735ab3f97a9SVladimir Oltean s[OCELOT_STAT_TX_PMAC_65_127] +
736ab3f97a9SVladimir Oltean s[OCELOT_STAT_TX_PMAC_128_255] +
737ab3f97a9SVladimir Oltean s[OCELOT_STAT_TX_PMAC_256_511] +
738ab3f97a9SVladimir Oltean s[OCELOT_STAT_TX_PMAC_512_1023] +
739ab3f97a9SVladimir Oltean s[OCELOT_STAT_TX_PMAC_1024_1526] +
740ab3f97a9SVladimir Oltean s[OCELOT_STAT_TX_PMAC_1527_MAX];
741ab3f97a9SVladimir Oltean mac_stats->OctetsReceivedOK = s[OCELOT_STAT_RX_PMAC_OCTETS];
742ab3f97a9SVladimir Oltean mac_stats->FramesReceivedOK = s[OCELOT_STAT_RX_PMAC_64] +
743ab3f97a9SVladimir Oltean s[OCELOT_STAT_RX_PMAC_65_127] +
744ab3f97a9SVladimir Oltean s[OCELOT_STAT_RX_PMAC_128_255] +
745ab3f97a9SVladimir Oltean s[OCELOT_STAT_RX_PMAC_256_511] +
746ab3f97a9SVladimir Oltean s[OCELOT_STAT_RX_PMAC_512_1023] +
747ab3f97a9SVladimir Oltean s[OCELOT_STAT_RX_PMAC_1024_1526] +
748ab3f97a9SVladimir Oltean s[OCELOT_STAT_RX_PMAC_1527_MAX];
749ab3f97a9SVladimir Oltean mac_stats->MulticastFramesXmittedOK = s[OCELOT_STAT_TX_PMAC_MULTICAST];
750ab3f97a9SVladimir Oltean mac_stats->BroadcastFramesXmittedOK = s[OCELOT_STAT_TX_PMAC_BROADCAST];
751ab3f97a9SVladimir Oltean mac_stats->MulticastFramesReceivedOK = s[OCELOT_STAT_RX_PMAC_MULTICAST];
752ab3f97a9SVladimir Oltean mac_stats->BroadcastFramesReceivedOK = s[OCELOT_STAT_RX_PMAC_BROADCAST];
753ab3f97a9SVladimir Oltean mac_stats->FrameTooLongErrors = s[OCELOT_STAT_RX_PMAC_LONGS];
754ab3f97a9SVladimir Oltean /* Sadly, C_RX_CRC is the sum of FCS and alignment errors, they are not
755ab3f97a9SVladimir Oltean * counted individually.
756ab3f97a9SVladimir Oltean */
757ab3f97a9SVladimir Oltean mac_stats->FrameCheckSequenceErrors = s[OCELOT_STAT_RX_PMAC_CRC_ALIGN_ERRS];
758ab3f97a9SVladimir Oltean mac_stats->AlignmentErrors = s[OCELOT_STAT_RX_PMAC_CRC_ALIGN_ERRS];
759ab3f97a9SVladimir Oltean }
760ab3f97a9SVladimir Oltean
ocelot_port_get_eth_mac_stats(struct ocelot * ocelot,int port,struct ethtool_eth_mac_stats * mac_stats)761e32036e1SVladimir Oltean void ocelot_port_get_eth_mac_stats(struct ocelot *ocelot, int port,
762e32036e1SVladimir Oltean struct ethtool_eth_mac_stats *mac_stats)
763e32036e1SVladimir Oltean {
764ab3f97a9SVladimir Oltean struct net_device *dev;
765ab3f97a9SVladimir Oltean
766ab3f97a9SVladimir Oltean switch (mac_stats->src) {
767ab3f97a9SVladimir Oltean case ETHTOOL_MAC_STATS_SRC_EMAC:
768e32036e1SVladimir Oltean ocelot_port_stats_run(ocelot, port, mac_stats,
769e32036e1SVladimir Oltean ocelot_port_mac_stats_cb);
770ab3f97a9SVladimir Oltean break;
771ab3f97a9SVladimir Oltean case ETHTOOL_MAC_STATS_SRC_PMAC:
772ab3f97a9SVladimir Oltean if (ocelot->mm_supported)
773ab3f97a9SVladimir Oltean ocelot_port_stats_run(ocelot, port, mac_stats,
774ab3f97a9SVladimir Oltean ocelot_port_pmac_mac_stats_cb);
775ab3f97a9SVladimir Oltean break;
776ab3f97a9SVladimir Oltean case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
777ab3f97a9SVladimir Oltean dev = ocelot->ops->port_to_netdev(ocelot, port);
778ab3f97a9SVladimir Oltean ethtool_aggregate_mac_stats(dev, mac_stats);
779ab3f97a9SVladimir Oltean break;
780ab3f97a9SVladimir Oltean }
781e32036e1SVladimir Oltean }
782e32036e1SVladimir Oltean EXPORT_SYMBOL_GPL(ocelot_port_get_eth_mac_stats);
783e32036e1SVladimir Oltean
ocelot_port_phy_stats_cb(struct ocelot * ocelot,int port,void * priv)784e32036e1SVladimir Oltean static void ocelot_port_phy_stats_cb(struct ocelot *ocelot, int port, void *priv)
785e32036e1SVladimir Oltean {
786e32036e1SVladimir Oltean u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
787e32036e1SVladimir Oltean struct ethtool_eth_phy_stats *phy_stats = priv;
788e32036e1SVladimir Oltean
789e32036e1SVladimir Oltean phy_stats->SymbolErrorDuringCarrier = s[OCELOT_STAT_RX_SYM_ERRS];
790e32036e1SVladimir Oltean }
791e32036e1SVladimir Oltean
ocelot_port_pmac_phy_stats_cb(struct ocelot * ocelot,int port,void * priv)792ab3f97a9SVladimir Oltean static void ocelot_port_pmac_phy_stats_cb(struct ocelot *ocelot, int port,
793ab3f97a9SVladimir Oltean void *priv)
794ab3f97a9SVladimir Oltean {
795ab3f97a9SVladimir Oltean u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
796ab3f97a9SVladimir Oltean struct ethtool_eth_phy_stats *phy_stats = priv;
797ab3f97a9SVladimir Oltean
798ab3f97a9SVladimir Oltean phy_stats->SymbolErrorDuringCarrier = s[OCELOT_STAT_RX_PMAC_SYM_ERRS];
799ab3f97a9SVladimir Oltean }
800ab3f97a9SVladimir Oltean
ocelot_port_get_eth_phy_stats(struct ocelot * ocelot,int port,struct ethtool_eth_phy_stats * phy_stats)801e32036e1SVladimir Oltean void ocelot_port_get_eth_phy_stats(struct ocelot *ocelot, int port,
802e32036e1SVladimir Oltean struct ethtool_eth_phy_stats *phy_stats)
803e32036e1SVladimir Oltean {
804ab3f97a9SVladimir Oltean struct net_device *dev;
805ab3f97a9SVladimir Oltean
806ab3f97a9SVladimir Oltean switch (phy_stats->src) {
807ab3f97a9SVladimir Oltean case ETHTOOL_MAC_STATS_SRC_EMAC:
808e32036e1SVladimir Oltean ocelot_port_stats_run(ocelot, port, phy_stats,
809e32036e1SVladimir Oltean ocelot_port_phy_stats_cb);
810ab3f97a9SVladimir Oltean break;
811ab3f97a9SVladimir Oltean case ETHTOOL_MAC_STATS_SRC_PMAC:
812ab3f97a9SVladimir Oltean if (ocelot->mm_supported)
813ab3f97a9SVladimir Oltean ocelot_port_stats_run(ocelot, port, phy_stats,
814ab3f97a9SVladimir Oltean ocelot_port_pmac_phy_stats_cb);
815ab3f97a9SVladimir Oltean break;
816ab3f97a9SVladimir Oltean case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
817ab3f97a9SVladimir Oltean dev = ocelot->ops->port_to_netdev(ocelot, port);
818ab3f97a9SVladimir Oltean ethtool_aggregate_phy_stats(dev, phy_stats);
819ab3f97a9SVladimir Oltean break;
820ab3f97a9SVladimir Oltean }
821e32036e1SVladimir Oltean }
822e32036e1SVladimir Oltean EXPORT_SYMBOL_GPL(ocelot_port_get_eth_phy_stats);
823e32036e1SVladimir Oltean
ocelot_port_get_stats64(struct ocelot * ocelot,int port,struct rtnl_link_stats64 * stats)824776b71e5SVladimir Oltean void ocelot_port_get_stats64(struct ocelot *ocelot, int port,
825776b71e5SVladimir Oltean struct rtnl_link_stats64 *stats)
826776b71e5SVladimir Oltean {
827776b71e5SVladimir Oltean u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
828776b71e5SVladimir Oltean
829776b71e5SVladimir Oltean spin_lock(&ocelot->stats_lock);
830776b71e5SVladimir Oltean
831776b71e5SVladimir Oltean /* Get Rx stats */
832776b71e5SVladimir Oltean stats->rx_bytes = s[OCELOT_STAT_RX_OCTETS];
833776b71e5SVladimir Oltean stats->rx_packets = s[OCELOT_STAT_RX_SHORTS] +
834776b71e5SVladimir Oltean s[OCELOT_STAT_RX_FRAGMENTS] +
835776b71e5SVladimir Oltean s[OCELOT_STAT_RX_JABBERS] +
836776b71e5SVladimir Oltean s[OCELOT_STAT_RX_LONGS] +
837776b71e5SVladimir Oltean s[OCELOT_STAT_RX_64] +
838776b71e5SVladimir Oltean s[OCELOT_STAT_RX_65_127] +
839776b71e5SVladimir Oltean s[OCELOT_STAT_RX_128_255] +
840776b71e5SVladimir Oltean s[OCELOT_STAT_RX_256_511] +
841776b71e5SVladimir Oltean s[OCELOT_STAT_RX_512_1023] +
842776b71e5SVladimir Oltean s[OCELOT_STAT_RX_1024_1526] +
843776b71e5SVladimir Oltean s[OCELOT_STAT_RX_1527_MAX];
844776b71e5SVladimir Oltean stats->multicast = s[OCELOT_STAT_RX_MULTICAST];
845776b71e5SVladimir Oltean stats->rx_missed_errors = s[OCELOT_STAT_DROP_TAIL];
846776b71e5SVladimir Oltean stats->rx_dropped = s[OCELOT_STAT_RX_RED_PRIO_0] +
847776b71e5SVladimir Oltean s[OCELOT_STAT_RX_RED_PRIO_1] +
848776b71e5SVladimir Oltean s[OCELOT_STAT_RX_RED_PRIO_2] +
849776b71e5SVladimir Oltean s[OCELOT_STAT_RX_RED_PRIO_3] +
850776b71e5SVladimir Oltean s[OCELOT_STAT_RX_RED_PRIO_4] +
851776b71e5SVladimir Oltean s[OCELOT_STAT_RX_RED_PRIO_5] +
852776b71e5SVladimir Oltean s[OCELOT_STAT_RX_RED_PRIO_6] +
853776b71e5SVladimir Oltean s[OCELOT_STAT_RX_RED_PRIO_7] +
854776b71e5SVladimir Oltean s[OCELOT_STAT_DROP_LOCAL] +
855776b71e5SVladimir Oltean s[OCELOT_STAT_DROP_YELLOW_PRIO_0] +
856776b71e5SVladimir Oltean s[OCELOT_STAT_DROP_YELLOW_PRIO_1] +
857776b71e5SVladimir Oltean s[OCELOT_STAT_DROP_YELLOW_PRIO_2] +
858776b71e5SVladimir Oltean s[OCELOT_STAT_DROP_YELLOW_PRIO_3] +
859776b71e5SVladimir Oltean s[OCELOT_STAT_DROP_YELLOW_PRIO_4] +
860776b71e5SVladimir Oltean s[OCELOT_STAT_DROP_YELLOW_PRIO_5] +
861776b71e5SVladimir Oltean s[OCELOT_STAT_DROP_YELLOW_PRIO_6] +
862776b71e5SVladimir Oltean s[OCELOT_STAT_DROP_YELLOW_PRIO_7] +
863776b71e5SVladimir Oltean s[OCELOT_STAT_DROP_GREEN_PRIO_0] +
864776b71e5SVladimir Oltean s[OCELOT_STAT_DROP_GREEN_PRIO_1] +
865776b71e5SVladimir Oltean s[OCELOT_STAT_DROP_GREEN_PRIO_2] +
866776b71e5SVladimir Oltean s[OCELOT_STAT_DROP_GREEN_PRIO_3] +
867776b71e5SVladimir Oltean s[OCELOT_STAT_DROP_GREEN_PRIO_4] +
868776b71e5SVladimir Oltean s[OCELOT_STAT_DROP_GREEN_PRIO_5] +
869776b71e5SVladimir Oltean s[OCELOT_STAT_DROP_GREEN_PRIO_6] +
870776b71e5SVladimir Oltean s[OCELOT_STAT_DROP_GREEN_PRIO_7];
871776b71e5SVladimir Oltean
872776b71e5SVladimir Oltean /* Get Tx stats */
873776b71e5SVladimir Oltean stats->tx_bytes = s[OCELOT_STAT_TX_OCTETS];
874776b71e5SVladimir Oltean stats->tx_packets = s[OCELOT_STAT_TX_64] +
875776b71e5SVladimir Oltean s[OCELOT_STAT_TX_65_127] +
876776b71e5SVladimir Oltean s[OCELOT_STAT_TX_128_255] +
877776b71e5SVladimir Oltean s[OCELOT_STAT_TX_256_511] +
878776b71e5SVladimir Oltean s[OCELOT_STAT_TX_512_1023] +
879776b71e5SVladimir Oltean s[OCELOT_STAT_TX_1024_1526] +
880776b71e5SVladimir Oltean s[OCELOT_STAT_TX_1527_MAX];
881776b71e5SVladimir Oltean stats->tx_dropped = s[OCELOT_STAT_TX_DROPS] +
882776b71e5SVladimir Oltean s[OCELOT_STAT_TX_AGED];
883776b71e5SVladimir Oltean stats->collisions = s[OCELOT_STAT_TX_COLLISION];
884776b71e5SVladimir Oltean
885776b71e5SVladimir Oltean spin_unlock(&ocelot->stats_lock);
886776b71e5SVladimir Oltean }
887776b71e5SVladimir Oltean EXPORT_SYMBOL(ocelot_port_get_stats64);
888776b71e5SVladimir Oltean
ocelot_prepare_stats_regions(struct ocelot * ocelot)889fe90104cSVladimir Oltean static int ocelot_prepare_stats_regions(struct ocelot *ocelot)
890fe90104cSVladimir Oltean {
891fe90104cSVladimir Oltean struct ocelot_stats_region *region = NULL;
892497eea9fSVladimir Oltean const struct ocelot_stat_layout *layout;
893eae0b9d1SVladimir Oltean enum ocelot_reg last = 0;
8946663c01eSVladimir Oltean enum ocelot_stat i;
895fe90104cSVladimir Oltean
896fe90104cSVladimir Oltean INIT_LIST_HEAD(&ocelot->stats_regions);
897fe90104cSVladimir Oltean
898497eea9fSVladimir Oltean layout = ocelot_get_stats_layout(ocelot);
899497eea9fSVladimir Oltean
900fe90104cSVladimir Oltean for (i = 0; i < OCELOT_NUM_STATS; i++) {
901497eea9fSVladimir Oltean if (!layout[i].reg)
902fe90104cSVladimir Oltean continue;
903fe90104cSVladimir Oltean
904a291399eSVladimir Oltean /* enum ocelot_stat must be kept sorted in the same order
905a291399eSVladimir Oltean * as the addresses behind layout[i].reg in order to have
906a291399eSVladimir Oltean * efficient bulking
907a291399eSVladimir Oltean */
908a291399eSVladimir Oltean if (last) {
909a291399eSVladimir Oltean WARN(ocelot->map[SYS][last & REG_MASK] >= ocelot->map[SYS][layout[i].reg & REG_MASK],
910a291399eSVladimir Oltean "reg 0x%x had address 0x%x but reg 0x%x has address 0x%x, bulking broken!",
911a291399eSVladimir Oltean last, ocelot->map[SYS][last & REG_MASK],
912a291399eSVladimir Oltean layout[i].reg, ocelot->map[SYS][layout[i].reg & REG_MASK]);
913a291399eSVladimir Oltean }
914a291399eSVladimir Oltean
9156acc72a4SVladimir Oltean if (region && ocelot->map[SYS][layout[i].reg & REG_MASK] ==
9166acc72a4SVladimir Oltean ocelot->map[SYS][last & REG_MASK] + 4) {
917fe90104cSVladimir Oltean region->count++;
918fe90104cSVladimir Oltean } else {
919fe90104cSVladimir Oltean region = devm_kzalloc(ocelot->dev, sizeof(*region),
920fe90104cSVladimir Oltean GFP_KERNEL);
921fe90104cSVladimir Oltean if (!region)
922fe90104cSVladimir Oltean return -ENOMEM;
923fe90104cSVladimir Oltean
924497eea9fSVladimir Oltean region->base = layout[i].reg;
92517dfd210SVladimir Oltean region->first_stat = i;
926fe90104cSVladimir Oltean region->count = 1;
927fe90104cSVladimir Oltean list_add_tail(®ion->node, &ocelot->stats_regions);
928fe90104cSVladimir Oltean }
929fe90104cSVladimir Oltean
930497eea9fSVladimir Oltean last = layout[i].reg;
931fe90104cSVladimir Oltean }
932fe90104cSVladimir Oltean
933fe90104cSVladimir Oltean list_for_each_entry(region, &ocelot->stats_regions, node) {
93407de3265SVladimir Oltean enum ocelot_target target;
93507de3265SVladimir Oltean u32 addr;
93607de3265SVladimir Oltean
93707de3265SVladimir Oltean ocelot_reg_to_target_addr(ocelot, region->base, &target,
93807de3265SVladimir Oltean &addr);
93907de3265SVladimir Oltean
94007de3265SVladimir Oltean dev_dbg(ocelot->dev,
94107de3265SVladimir Oltean "region of %d contiguous counters starting with SYS:STAT:CNT[0x%03x]\n",
94207de3265SVladimir Oltean region->count, addr / 4);
943fe90104cSVladimir Oltean region->buf = devm_kcalloc(ocelot->dev, region->count,
944fe90104cSVladimir Oltean sizeof(*region->buf), GFP_KERNEL);
945fe90104cSVladimir Oltean if (!region->buf)
946fe90104cSVladimir Oltean return -ENOMEM;
947fe90104cSVladimir Oltean }
948fe90104cSVladimir Oltean
949fe90104cSVladimir Oltean return 0;
950fe90104cSVladimir Oltean }
951fe90104cSVladimir Oltean
ocelot_stats_init(struct ocelot * ocelot)952fe90104cSVladimir Oltean int ocelot_stats_init(struct ocelot *ocelot)
953fe90104cSVladimir Oltean {
954fe90104cSVladimir Oltean char queue_name[32];
955fe90104cSVladimir Oltean int ret;
956fe90104cSVladimir Oltean
957fe90104cSVladimir Oltean ocelot->stats = devm_kcalloc(ocelot->dev,
958fe90104cSVladimir Oltean ocelot->num_phys_ports * OCELOT_NUM_STATS,
959fe90104cSVladimir Oltean sizeof(u64), GFP_KERNEL);
960fe90104cSVladimir Oltean if (!ocelot->stats)
961fe90104cSVladimir Oltean return -ENOMEM;
962fe90104cSVladimir Oltean
963fe90104cSVladimir Oltean snprintf(queue_name, sizeof(queue_name), "%s-stats",
964fe90104cSVladimir Oltean dev_name(ocelot->dev));
965fe90104cSVladimir Oltean ocelot->stats_queue = create_singlethread_workqueue(queue_name);
966fe90104cSVladimir Oltean if (!ocelot->stats_queue)
967fe90104cSVladimir Oltean return -ENOMEM;
968fe90104cSVladimir Oltean
969fe90104cSVladimir Oltean spin_lock_init(&ocelot->stats_lock);
970fe90104cSVladimir Oltean mutex_init(&ocelot->stat_view_lock);
971fe90104cSVladimir Oltean
972fe90104cSVladimir Oltean ret = ocelot_prepare_stats_regions(ocelot);
973fe90104cSVladimir Oltean if (ret) {
974fe90104cSVladimir Oltean destroy_workqueue(ocelot->stats_queue);
975fe90104cSVladimir Oltean return ret;
976fe90104cSVladimir Oltean }
977fe90104cSVladimir Oltean
978fe90104cSVladimir Oltean INIT_DELAYED_WORK(&ocelot->stats_work, ocelot_check_stats_work);
979fe90104cSVladimir Oltean queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
980fe90104cSVladimir Oltean OCELOT_STATS_CHECK_DELAY);
981fe90104cSVladimir Oltean
982fe90104cSVladimir Oltean return 0;
983fe90104cSVladimir Oltean }
984fe90104cSVladimir Oltean
ocelot_stats_deinit(struct ocelot * ocelot)985fe90104cSVladimir Oltean void ocelot_stats_deinit(struct ocelot *ocelot)
986fe90104cSVladimir Oltean {
987fe90104cSVladimir Oltean cancel_delayed_work(&ocelot->stats_work);
988fe90104cSVladimir Oltean destroy_workqueue(ocelot->stats_queue);
989fe90104cSVladimir Oltean }
990