1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | |
3 | #include <linux/netdevice.h> |
4 | |
5 | #include "lan966x_main.h" |
6 | |
7 | /* Number of traffic classes */ |
8 | #define LAN966X_NUM_TC 8 |
9 | #define LAN966X_STATS_CHECK_DELAY (2 * HZ) |
10 | |
11 | static const struct lan966x_stat_layout lan966x_stats_layout[] = { |
12 | { .name = "rx_octets" , .offset = 0x00, }, |
13 | { .name = "rx_unicast" , .offset = 0x01, }, |
14 | { .name = "rx_multicast" , .offset = 0x02 }, |
15 | { .name = "rx_broadcast" , .offset = 0x03 }, |
16 | { .name = "rx_short" , .offset = 0x04 }, |
17 | { .name = "rx_frag" , .offset = 0x05 }, |
18 | { .name = "rx_jabber" , .offset = 0x06 }, |
19 | { .name = "rx_crc" , .offset = 0x07 }, |
20 | { .name = "rx_symbol_err" , .offset = 0x08 }, |
21 | { .name = "rx_sz_64" , .offset = 0x09 }, |
22 | { .name = "rx_sz_65_127" , .offset = 0x0a}, |
23 | { .name = "rx_sz_128_255" , .offset = 0x0b}, |
24 | { .name = "rx_sz_256_511" , .offset = 0x0c }, |
25 | { .name = "rx_sz_512_1023" , .offset = 0x0d }, |
26 | { .name = "rx_sz_1024_1526" , .offset = 0x0e }, |
27 | { .name = "rx_sz_jumbo" , .offset = 0x0f }, |
28 | { .name = "rx_pause" , .offset = 0x10 }, |
29 | { .name = "rx_control" , .offset = 0x11 }, |
30 | { .name = "rx_long" , .offset = 0x12 }, |
31 | { .name = "rx_cat_drop" , .offset = 0x13 }, |
32 | { .name = "rx_red_prio_0" , .offset = 0x14 }, |
33 | { .name = "rx_red_prio_1" , .offset = 0x15 }, |
34 | { .name = "rx_red_prio_2" , .offset = 0x16 }, |
35 | { .name = "rx_red_prio_3" , .offset = 0x17 }, |
36 | { .name = "rx_red_prio_4" , .offset = 0x18 }, |
37 | { .name = "rx_red_prio_5" , .offset = 0x19 }, |
38 | { .name = "rx_red_prio_6" , .offset = 0x1a }, |
39 | { .name = "rx_red_prio_7" , .offset = 0x1b }, |
40 | { .name = "rx_yellow_prio_0" , .offset = 0x1c }, |
41 | { .name = "rx_yellow_prio_1" , .offset = 0x1d }, |
42 | { .name = "rx_yellow_prio_2" , .offset = 0x1e }, |
43 | { .name = "rx_yellow_prio_3" , .offset = 0x1f }, |
44 | { .name = "rx_yellow_prio_4" , .offset = 0x20 }, |
45 | { .name = "rx_yellow_prio_5" , .offset = 0x21 }, |
46 | { .name = "rx_yellow_prio_6" , .offset = 0x22 }, |
47 | { .name = "rx_yellow_prio_7" , .offset = 0x23 }, |
48 | { .name = "rx_green_prio_0" , .offset = 0x24 }, |
49 | { .name = "rx_green_prio_1" , .offset = 0x25 }, |
50 | { .name = "rx_green_prio_2" , .offset = 0x26 }, |
51 | { .name = "rx_green_prio_3" , .offset = 0x27 }, |
52 | { .name = "rx_green_prio_4" , .offset = 0x28 }, |
53 | { .name = "rx_green_prio_5" , .offset = 0x29 }, |
54 | { .name = "rx_green_prio_6" , .offset = 0x2a }, |
55 | { .name = "rx_green_prio_7" , .offset = 0x2b }, |
56 | { .name = "rx_assembly_err" , .offset = 0x2c }, |
57 | { .name = "rx_smd_err" , .offset = 0x2d }, |
58 | { .name = "rx_assembly_ok" , .offset = 0x2e }, |
59 | { .name = "rx_merge_frag" , .offset = 0x2f }, |
60 | { .name = "rx_pmac_octets" , .offset = 0x30, }, |
61 | { .name = "rx_pmac_unicast" , .offset = 0x31, }, |
62 | { .name = "rx_pmac_multicast" , .offset = 0x32 }, |
63 | { .name = "rx_pmac_broadcast" , .offset = 0x33 }, |
64 | { .name = "rx_pmac_short" , .offset = 0x34 }, |
65 | { .name = "rx_pmac_frag" , .offset = 0x35 }, |
66 | { .name = "rx_pmac_jabber" , .offset = 0x36 }, |
67 | { .name = "rx_pmac_crc" , .offset = 0x37 }, |
68 | { .name = "rx_pmac_symbol_err" , .offset = 0x38 }, |
69 | { .name = "rx_pmac_sz_64" , .offset = 0x39 }, |
70 | { .name = "rx_pmac_sz_65_127" , .offset = 0x3a }, |
71 | { .name = "rx_pmac_sz_128_255" , .offset = 0x3b }, |
72 | { .name = "rx_pmac_sz_256_511" , .offset = 0x3c }, |
73 | { .name = "rx_pmac_sz_512_1023" , .offset = 0x3d }, |
74 | { .name = "rx_pmac_sz_1024_1526" , .offset = 0x3e }, |
75 | { .name = "rx_pmac_sz_jumbo" , .offset = 0x3f }, |
76 | { .name = "rx_pmac_pause" , .offset = 0x40 }, |
77 | { .name = "rx_pmac_control" , .offset = 0x41 }, |
78 | { .name = "rx_pmac_long" , .offset = 0x42 }, |
79 | |
80 | { .name = "tx_octets" , .offset = 0x80, }, |
81 | { .name = "tx_unicast" , .offset = 0x81, }, |
82 | { .name = "tx_multicast" , .offset = 0x82 }, |
83 | { .name = "tx_broadcast" , .offset = 0x83 }, |
84 | { .name = "tx_col" , .offset = 0x84 }, |
85 | { .name = "tx_drop" , .offset = 0x85 }, |
86 | { .name = "tx_pause" , .offset = 0x86 }, |
87 | { .name = "tx_sz_64" , .offset = 0x87 }, |
88 | { .name = "tx_sz_65_127" , .offset = 0x88 }, |
89 | { .name = "tx_sz_128_255" , .offset = 0x89 }, |
90 | { .name = "tx_sz_256_511" , .offset = 0x8a }, |
91 | { .name = "tx_sz_512_1023" , .offset = 0x8b }, |
92 | { .name = "tx_sz_1024_1526" , .offset = 0x8c }, |
93 | { .name = "tx_sz_jumbo" , .offset = 0x8d }, |
94 | { .name = "tx_yellow_prio_0" , .offset = 0x8e }, |
95 | { .name = "tx_yellow_prio_1" , .offset = 0x8f }, |
96 | { .name = "tx_yellow_prio_2" , .offset = 0x90 }, |
97 | { .name = "tx_yellow_prio_3" , .offset = 0x91 }, |
98 | { .name = "tx_yellow_prio_4" , .offset = 0x92 }, |
99 | { .name = "tx_yellow_prio_5" , .offset = 0x93 }, |
100 | { .name = "tx_yellow_prio_6" , .offset = 0x94 }, |
101 | { .name = "tx_yellow_prio_7" , .offset = 0x95 }, |
102 | { .name = "tx_green_prio_0" , .offset = 0x96 }, |
103 | { .name = "tx_green_prio_1" , .offset = 0x97 }, |
104 | { .name = "tx_green_prio_2" , .offset = 0x98 }, |
105 | { .name = "tx_green_prio_3" , .offset = 0x99 }, |
106 | { .name = "tx_green_prio_4" , .offset = 0x9a }, |
107 | { .name = "tx_green_prio_5" , .offset = 0x9b }, |
108 | { .name = "tx_green_prio_6" , .offset = 0x9c }, |
109 | { .name = "tx_green_prio_7" , .offset = 0x9d }, |
110 | { .name = "tx_aged" , .offset = 0x9e }, |
111 | { .name = "tx_llct" , .offset = 0x9f }, |
112 | { .name = "tx_ct" , .offset = 0xa0 }, |
113 | { .name = "tx_mm_hold" , .offset = 0xa1 }, |
114 | { .name = "tx_merge_frag" , .offset = 0xa2 }, |
115 | { .name = "tx_pmac_octets" , .offset = 0xa3, }, |
116 | { .name = "tx_pmac_unicast" , .offset = 0xa4, }, |
117 | { .name = "tx_pmac_multicast" , .offset = 0xa5 }, |
118 | { .name = "tx_pmac_broadcast" , .offset = 0xa6 }, |
119 | { .name = "tx_pmac_pause" , .offset = 0xa7 }, |
120 | { .name = "tx_pmac_sz_64" , .offset = 0xa8 }, |
121 | { .name = "tx_pmac_sz_65_127" , .offset = 0xa9 }, |
122 | { .name = "tx_pmac_sz_128_255" , .offset = 0xaa }, |
123 | { .name = "tx_pmac_sz_256_511" , .offset = 0xab }, |
124 | { .name = "tx_pmac_sz_512_1023" , .offset = 0xac }, |
125 | { .name = "tx_pmac_sz_1024_1526" , .offset = 0xad }, |
126 | { .name = "tx_pmac_sz_jumbo" , .offset = 0xae }, |
127 | |
128 | { .name = "dr_local" , .offset = 0x100 }, |
129 | { .name = "dr_tail" , .offset = 0x101 }, |
130 | { .name = "dr_yellow_prio_0" , .offset = 0x102 }, |
131 | { .name = "dr_yellow_prio_1" , .offset = 0x103 }, |
132 | { .name = "dr_yellow_prio_2" , .offset = 0x104 }, |
133 | { .name = "dr_yellow_prio_3" , .offset = 0x105 }, |
134 | { .name = "dr_yellow_prio_4" , .offset = 0x106 }, |
135 | { .name = "dr_yellow_prio_5" , .offset = 0x107 }, |
136 | { .name = "dr_yellow_prio_6" , .offset = 0x108 }, |
137 | { .name = "dr_yellow_prio_7" , .offset = 0x109 }, |
138 | { .name = "dr_green_prio_0" , .offset = 0x10a }, |
139 | { .name = "dr_green_prio_1" , .offset = 0x10b }, |
140 | { .name = "dr_green_prio_2" , .offset = 0x10c }, |
141 | { .name = "dr_green_prio_3" , .offset = 0x10d }, |
142 | { .name = "dr_green_prio_4" , .offset = 0x10e }, |
143 | { .name = "dr_green_prio_5" , .offset = 0x10f }, |
144 | { .name = "dr_green_prio_6" , .offset = 0x110 }, |
145 | { .name = "dr_green_prio_7" , .offset = 0x111 }, |
146 | }; |
147 | |
148 | /* The following numbers are indexes into lan966x_stats_layout[] */ |
149 | #define SYS_COUNT_RX_OCT 0 |
150 | #define SYS_COUNT_RX_UC 1 |
151 | #define SYS_COUNT_RX_MC 2 |
152 | #define SYS_COUNT_RX_BC 3 |
153 | #define SYS_COUNT_RX_SHORT 4 |
154 | #define SYS_COUNT_RX_FRAG 5 |
155 | #define SYS_COUNT_RX_JABBER 6 |
156 | #define SYS_COUNT_RX_CRC 7 |
157 | #define SYS_COUNT_RX_SYMBOL_ERR 8 |
158 | #define SYS_COUNT_RX_SZ_64 9 |
159 | #define SYS_COUNT_RX_SZ_65_127 10 |
160 | #define SYS_COUNT_RX_SZ_128_255 11 |
161 | #define SYS_COUNT_RX_SZ_256_511 12 |
162 | #define SYS_COUNT_RX_SZ_512_1023 13 |
163 | #define SYS_COUNT_RX_SZ_1024_1526 14 |
164 | #define SYS_COUNT_RX_SZ_JUMBO 15 |
165 | #define SYS_COUNT_RX_PAUSE 16 |
166 | #define SYS_COUNT_RX_CONTROL 17 |
167 | #define SYS_COUNT_RX_LONG 18 |
168 | #define SYS_COUNT_RX_CAT_DROP 19 |
169 | #define SYS_COUNT_RX_RED_PRIO_0 20 |
170 | #define SYS_COUNT_RX_RED_PRIO_1 21 |
171 | #define SYS_COUNT_RX_RED_PRIO_2 22 |
172 | #define SYS_COUNT_RX_RED_PRIO_3 23 |
173 | #define SYS_COUNT_RX_RED_PRIO_4 24 |
174 | #define SYS_COUNT_RX_RED_PRIO_5 25 |
175 | #define SYS_COUNT_RX_RED_PRIO_6 26 |
176 | #define SYS_COUNT_RX_RED_PRIO_7 27 |
177 | #define SYS_COUNT_RX_YELLOW_PRIO_0 28 |
178 | #define SYS_COUNT_RX_YELLOW_PRIO_1 29 |
179 | #define SYS_COUNT_RX_YELLOW_PRIO_2 30 |
180 | #define SYS_COUNT_RX_YELLOW_PRIO_3 31 |
181 | #define SYS_COUNT_RX_YELLOW_PRIO_4 32 |
182 | #define SYS_COUNT_RX_YELLOW_PRIO_5 33 |
183 | #define SYS_COUNT_RX_YELLOW_PRIO_6 34 |
184 | #define SYS_COUNT_RX_YELLOW_PRIO_7 35 |
185 | #define SYS_COUNT_RX_GREEN_PRIO_0 36 |
186 | #define SYS_COUNT_RX_GREEN_PRIO_1 37 |
187 | #define SYS_COUNT_RX_GREEN_PRIO_2 38 |
188 | #define SYS_COUNT_RX_GREEN_PRIO_3 39 |
189 | #define SYS_COUNT_RX_GREEN_PRIO_4 40 |
190 | #define SYS_COUNT_RX_GREEN_PRIO_5 41 |
191 | #define SYS_COUNT_RX_GREEN_PRIO_6 42 |
192 | #define SYS_COUNT_RX_GREEN_PRIO_7 43 |
193 | #define SYS_COUNT_RX_ASSEMBLY_ERR 44 |
194 | #define SYS_COUNT_RX_SMD_ERR 45 |
195 | #define SYS_COUNT_RX_ASSEMBLY_OK 46 |
196 | #define SYS_COUNT_RX_MERGE_FRAG 47 |
197 | #define SYS_COUNT_RX_PMAC_OCT 48 |
198 | #define SYS_COUNT_RX_PMAC_UC 49 |
199 | #define SYS_COUNT_RX_PMAC_MC 50 |
200 | #define SYS_COUNT_RX_PMAC_BC 51 |
201 | #define SYS_COUNT_RX_PMAC_SHORT 52 |
202 | #define SYS_COUNT_RX_PMAC_FRAG 53 |
203 | #define SYS_COUNT_RX_PMAC_JABBER 54 |
204 | #define SYS_COUNT_RX_PMAC_CRC 55 |
205 | #define SYS_COUNT_RX_PMAC_SYMBOL_ERR 56 |
206 | #define SYS_COUNT_RX_PMAC_SZ_64 57 |
207 | #define SYS_COUNT_RX_PMAC_SZ_65_127 58 |
208 | #define SYS_COUNT_RX_PMAC_SZ_128_255 59 |
209 | #define SYS_COUNT_RX_PMAC_SZ_256_511 60 |
210 | #define SYS_COUNT_RX_PMAC_SZ_512_1023 61 |
211 | #define SYS_COUNT_RX_PMAC_SZ_1024_1526 62 |
212 | #define SYS_COUNT_RX_PMAC_SZ_JUMBO 63 |
213 | #define SYS_COUNT_RX_PMAC_PAUSE 64 |
214 | #define SYS_COUNT_RX_PMAC_CONTROL 65 |
215 | #define SYS_COUNT_RX_PMAC_LONG 66 |
216 | |
217 | #define SYS_COUNT_TX_OCT 67 |
218 | #define SYS_COUNT_TX_UC 68 |
219 | #define SYS_COUNT_TX_MC 69 |
220 | #define SYS_COUNT_TX_BC 70 |
221 | #define SYS_COUNT_TX_COL 71 |
222 | #define SYS_COUNT_TX_DROP 72 |
223 | #define SYS_COUNT_TX_PAUSE 73 |
224 | #define SYS_COUNT_TX_SZ_64 74 |
225 | #define SYS_COUNT_TX_SZ_65_127 75 |
226 | #define SYS_COUNT_TX_SZ_128_255 76 |
227 | #define SYS_COUNT_TX_SZ_256_511 77 |
228 | #define SYS_COUNT_TX_SZ_512_1023 78 |
229 | #define SYS_COUNT_TX_SZ_1024_1526 79 |
230 | #define SYS_COUNT_TX_SZ_JUMBO 80 |
231 | #define SYS_COUNT_TX_YELLOW_PRIO_0 81 |
232 | #define SYS_COUNT_TX_YELLOW_PRIO_1 82 |
233 | #define SYS_COUNT_TX_YELLOW_PRIO_2 83 |
234 | #define SYS_COUNT_TX_YELLOW_PRIO_3 84 |
235 | #define SYS_COUNT_TX_YELLOW_PRIO_4 85 |
236 | #define SYS_COUNT_TX_YELLOW_PRIO_5 86 |
237 | #define SYS_COUNT_TX_YELLOW_PRIO_6 87 |
238 | #define SYS_COUNT_TX_YELLOW_PRIO_7 88 |
239 | #define SYS_COUNT_TX_GREEN_PRIO_0 89 |
240 | #define SYS_COUNT_TX_GREEN_PRIO_1 90 |
241 | #define SYS_COUNT_TX_GREEN_PRIO_2 91 |
242 | #define SYS_COUNT_TX_GREEN_PRIO_3 92 |
243 | #define SYS_COUNT_TX_GREEN_PRIO_4 93 |
244 | #define SYS_COUNT_TX_GREEN_PRIO_5 94 |
245 | #define SYS_COUNT_TX_GREEN_PRIO_6 95 |
246 | #define SYS_COUNT_TX_GREEN_PRIO_7 96 |
247 | #define SYS_COUNT_TX_AGED 97 |
248 | #define SYS_COUNT_TX_LLCT 98 |
249 | #define SYS_COUNT_TX_CT 99 |
250 | #define SYS_COUNT_TX_MM_HOLD 100 |
251 | #define SYS_COUNT_TX_MERGE_FRAG 101 |
252 | #define SYS_COUNT_TX_PMAC_OCT 102 |
253 | #define SYS_COUNT_TX_PMAC_UC 103 |
254 | #define SYS_COUNT_TX_PMAC_MC 104 |
255 | #define SYS_COUNT_TX_PMAC_BC 105 |
256 | #define SYS_COUNT_TX_PMAC_PAUSE 106 |
257 | #define SYS_COUNT_TX_PMAC_SZ_64 107 |
258 | #define SYS_COUNT_TX_PMAC_SZ_65_127 108 |
259 | #define SYS_COUNT_TX_PMAC_SZ_128_255 109 |
260 | #define SYS_COUNT_TX_PMAC_SZ_256_511 110 |
261 | #define SYS_COUNT_TX_PMAC_SZ_512_1023 111 |
262 | #define SYS_COUNT_TX_PMAC_SZ_1024_1526 112 |
263 | #define SYS_COUNT_TX_PMAC_SZ_JUMBO 113 |
264 | |
265 | #define SYS_COUNT_DR_LOCAL 114 |
266 | #define SYS_COUNT_DR_TAIL 115 |
267 | #define SYS_COUNT_DR_YELLOW_PRIO_0 116 |
268 | #define SYS_COUNT_DR_YELLOW_PRIO_1 117 |
269 | #define SYS_COUNT_DR_YELLOW_PRIO_2 118 |
270 | #define SYS_COUNT_DR_YELLOW_PRIO_3 119 |
271 | #define SYS_COUNT_DR_YELLOW_PRIO_4 120 |
272 | #define SYS_COUNT_DR_YELLOW_PRIO_5 121 |
273 | #define SYS_COUNT_DR_YELLOW_PRIO_6 122 |
274 | #define SYS_COUNT_DR_YELLOW_PRIO_7 123 |
275 | #define SYS_COUNT_DR_GREEN_PRIO_0 124 |
276 | #define SYS_COUNT_DR_GREEN_PRIO_1 125 |
277 | #define SYS_COUNT_DR_GREEN_PRIO_2 126 |
278 | #define SYS_COUNT_DR_GREEN_PRIO_3 127 |
279 | #define SYS_COUNT_DR_GREEN_PRIO_4 128 |
280 | #define SYS_COUNT_DR_GREEN_PRIO_5 129 |
281 | #define SYS_COUNT_DR_GREEN_PRIO_6 130 |
282 | #define SYS_COUNT_DR_GREEN_PRIO_7 131 |
283 | |
284 | /* Add a possibly wrapping 32 bit value to a 64 bit counter */ |
285 | static void lan966x_add_cnt(u64 *cnt, u32 val) |
286 | { |
287 | if (val < (*cnt & U32_MAX)) |
288 | *cnt += (u64)1 << 32; /* value has wrapped */ |
289 | |
290 | *cnt = (*cnt & ~(u64)U32_MAX) + val; |
291 | } |
292 | |
293 | static void lan966x_stats_update(struct lan966x *lan966x) |
294 | { |
295 | int i, j; |
296 | |
297 | mutex_lock(&lan966x->stats_lock); |
298 | |
299 | for (i = 0; i < lan966x->num_phys_ports; i++) { |
300 | uint idx = i * lan966x->num_stats; |
301 | |
302 | lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(i), |
303 | lan966x, SYS_STAT_CFG); |
304 | |
305 | for (j = 0; j < lan966x->num_stats; j++) { |
306 | u32 offset = lan966x->stats_layout[j].offset; |
307 | |
308 | lan966x_add_cnt(cnt: &lan966x->stats[idx++], |
309 | val: lan_rd(lan966x, SYS_CNT(offset))); |
310 | } |
311 | } |
312 | |
313 | mutex_unlock(lock: &lan966x->stats_lock); |
314 | } |
315 | |
316 | static int lan966x_get_sset_count(struct net_device *dev, int sset) |
317 | { |
318 | struct lan966x_port *port = netdev_priv(dev); |
319 | struct lan966x *lan966x = port->lan966x; |
320 | |
321 | if (sset != ETH_SS_STATS) |
322 | return -EOPNOTSUPP; |
323 | |
324 | return lan966x->num_stats; |
325 | } |
326 | |
327 | static void lan966x_get_strings(struct net_device *netdev, u32 sset, u8 *data) |
328 | { |
329 | struct lan966x_port *port = netdev_priv(dev: netdev); |
330 | struct lan966x *lan966x = port->lan966x; |
331 | int i; |
332 | |
333 | if (sset != ETH_SS_STATS) |
334 | return; |
335 | |
336 | for (i = 0; i < lan966x->num_stats; i++) |
337 | memcpy(data + i * ETH_GSTRING_LEN, |
338 | lan966x->stats_layout[i].name, ETH_GSTRING_LEN); |
339 | } |
340 | |
341 | static void lan966x_get_ethtool_stats(struct net_device *dev, |
342 | struct ethtool_stats *stats, u64 *data) |
343 | { |
344 | struct lan966x_port *port = netdev_priv(dev); |
345 | struct lan966x *lan966x = port->lan966x; |
346 | int i; |
347 | |
348 | /* check and update now */ |
349 | lan966x_stats_update(lan966x); |
350 | |
351 | /* Copy all counters */ |
352 | for (i = 0; i < lan966x->num_stats; i++) |
353 | *data++ = lan966x->stats[port->chip_port * |
354 | lan966x->num_stats + i]; |
355 | } |
356 | |
357 | static void lan966x_get_eth_mac_stats(struct net_device *dev, |
358 | struct ethtool_eth_mac_stats *mac_stats) |
359 | { |
360 | struct lan966x_port *port = netdev_priv(dev); |
361 | struct lan966x *lan966x = port->lan966x; |
362 | u32 idx; |
363 | |
364 | lan966x_stats_update(lan966x); |
365 | |
366 | idx = port->chip_port * lan966x->num_stats; |
367 | |
368 | mutex_lock(&lan966x->stats_lock); |
369 | |
370 | mac_stats->FramesTransmittedOK = |
371 | lan966x->stats[idx + SYS_COUNT_TX_UC] + |
372 | lan966x->stats[idx + SYS_COUNT_TX_MC] + |
373 | lan966x->stats[idx + SYS_COUNT_TX_BC] + |
374 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_UC] + |
375 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_MC] + |
376 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_BC]; |
377 | mac_stats->SingleCollisionFrames = |
378 | lan966x->stats[idx + SYS_COUNT_TX_COL]; |
379 | mac_stats->MultipleCollisionFrames = 0; |
380 | mac_stats->FramesReceivedOK = |
381 | lan966x->stats[idx + SYS_COUNT_RX_UC] + |
382 | lan966x->stats[idx + SYS_COUNT_RX_MC] + |
383 | lan966x->stats[idx + SYS_COUNT_RX_BC]; |
384 | mac_stats->FrameCheckSequenceErrors = |
385 | lan966x->stats[idx + SYS_COUNT_RX_CRC] + |
386 | lan966x->stats[idx + SYS_COUNT_RX_CRC]; |
387 | mac_stats->AlignmentErrors = 0; |
388 | mac_stats->OctetsTransmittedOK = |
389 | lan966x->stats[idx + SYS_COUNT_TX_OCT] + |
390 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_OCT]; |
391 | mac_stats->FramesWithDeferredXmissions = |
392 | lan966x->stats[idx + SYS_COUNT_TX_MM_HOLD]; |
393 | mac_stats->LateCollisions = 0; |
394 | mac_stats->FramesAbortedDueToXSColls = 0; |
395 | mac_stats->FramesLostDueToIntMACXmitError = 0; |
396 | mac_stats->CarrierSenseErrors = 0; |
397 | mac_stats->OctetsReceivedOK = |
398 | lan966x->stats[idx + SYS_COUNT_RX_OCT]; |
399 | mac_stats->FramesLostDueToIntMACRcvError = 0; |
400 | mac_stats->MulticastFramesXmittedOK = |
401 | lan966x->stats[idx + SYS_COUNT_TX_MC] + |
402 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_MC]; |
403 | mac_stats->BroadcastFramesXmittedOK = |
404 | lan966x->stats[idx + SYS_COUNT_TX_BC] + |
405 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_BC]; |
406 | mac_stats->FramesWithExcessiveDeferral = 0; |
407 | mac_stats->MulticastFramesReceivedOK = |
408 | lan966x->stats[idx + SYS_COUNT_RX_MC]; |
409 | mac_stats->BroadcastFramesReceivedOK = |
410 | lan966x->stats[idx + SYS_COUNT_RX_BC]; |
411 | mac_stats->InRangeLengthErrors = |
412 | lan966x->stats[idx + SYS_COUNT_RX_FRAG] + |
413 | lan966x->stats[idx + SYS_COUNT_RX_JABBER] + |
414 | lan966x->stats[idx + SYS_COUNT_RX_CRC] + |
415 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_FRAG] + |
416 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_JABBER] + |
417 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_CRC]; |
418 | mac_stats->OutOfRangeLengthField = |
419 | lan966x->stats[idx + SYS_COUNT_RX_SHORT] + |
420 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_SHORT] + |
421 | lan966x->stats[idx + SYS_COUNT_RX_LONG] + |
422 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_LONG]; |
423 | mac_stats->FrameTooLongErrors = |
424 | lan966x->stats[idx + SYS_COUNT_RX_LONG] + |
425 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_LONG]; |
426 | |
427 | mutex_unlock(lock: &lan966x->stats_lock); |
428 | } |
429 | |
430 | static const struct ethtool_rmon_hist_range lan966x_rmon_ranges[] = { |
431 | { 0, 64 }, |
432 | { 65, 127 }, |
433 | { 128, 255 }, |
434 | { 256, 511 }, |
435 | { 512, 1023 }, |
436 | { 1024, 1518 }, |
437 | { 1519, 10239 }, |
438 | {} |
439 | }; |
440 | |
441 | static void lan966x_get_eth_rmon_stats(struct net_device *dev, |
442 | struct ethtool_rmon_stats *rmon_stats, |
443 | const struct ethtool_rmon_hist_range **ranges) |
444 | { |
445 | struct lan966x_port *port = netdev_priv(dev); |
446 | struct lan966x *lan966x = port->lan966x; |
447 | u32 idx; |
448 | |
449 | lan966x_stats_update(lan966x); |
450 | |
451 | idx = port->chip_port * lan966x->num_stats; |
452 | |
453 | mutex_lock(&lan966x->stats_lock); |
454 | |
455 | rmon_stats->undersize_pkts = |
456 | lan966x->stats[idx + SYS_COUNT_RX_SHORT] + |
457 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_SHORT]; |
458 | rmon_stats->oversize_pkts = |
459 | lan966x->stats[idx + SYS_COUNT_RX_LONG] + |
460 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_LONG]; |
461 | rmon_stats->fragments = |
462 | lan966x->stats[idx + SYS_COUNT_RX_FRAG] + |
463 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_FRAG]; |
464 | rmon_stats->jabbers = |
465 | lan966x->stats[idx + SYS_COUNT_RX_JABBER] + |
466 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_JABBER]; |
467 | rmon_stats->hist[0] = |
468 | lan966x->stats[idx + SYS_COUNT_RX_SZ_64] + |
469 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_64]; |
470 | rmon_stats->hist[1] = |
471 | lan966x->stats[idx + SYS_COUNT_RX_SZ_65_127] + |
472 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_65_127]; |
473 | rmon_stats->hist[2] = |
474 | lan966x->stats[idx + SYS_COUNT_RX_SZ_128_255] + |
475 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_128_255]; |
476 | rmon_stats->hist[3] = |
477 | lan966x->stats[idx + SYS_COUNT_RX_SZ_256_511] + |
478 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_256_511]; |
479 | rmon_stats->hist[4] = |
480 | lan966x->stats[idx + SYS_COUNT_RX_SZ_512_1023] + |
481 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_512_1023]; |
482 | rmon_stats->hist[5] = |
483 | lan966x->stats[idx + SYS_COUNT_RX_SZ_1024_1526] + |
484 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_1024_1526]; |
485 | rmon_stats->hist[6] = |
486 | lan966x->stats[idx + SYS_COUNT_RX_SZ_1024_1526] + |
487 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_1024_1526]; |
488 | |
489 | rmon_stats->hist_tx[0] = |
490 | lan966x->stats[idx + SYS_COUNT_TX_SZ_64] + |
491 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_64]; |
492 | rmon_stats->hist_tx[1] = |
493 | lan966x->stats[idx + SYS_COUNT_TX_SZ_65_127] + |
494 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_65_127]; |
495 | rmon_stats->hist_tx[2] = |
496 | lan966x->stats[idx + SYS_COUNT_TX_SZ_128_255] + |
497 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_128_255]; |
498 | rmon_stats->hist_tx[3] = |
499 | lan966x->stats[idx + SYS_COUNT_TX_SZ_256_511] + |
500 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_256_511]; |
501 | rmon_stats->hist_tx[4] = |
502 | lan966x->stats[idx + SYS_COUNT_TX_SZ_512_1023] + |
503 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_512_1023]; |
504 | rmon_stats->hist_tx[5] = |
505 | lan966x->stats[idx + SYS_COUNT_TX_SZ_1024_1526] + |
506 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_1024_1526]; |
507 | rmon_stats->hist_tx[6] = |
508 | lan966x->stats[idx + SYS_COUNT_TX_SZ_1024_1526] + |
509 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_1024_1526]; |
510 | |
511 | mutex_unlock(lock: &lan966x->stats_lock); |
512 | |
513 | *ranges = lan966x_rmon_ranges; |
514 | } |
515 | |
516 | static int lan966x_get_link_ksettings(struct net_device *ndev, |
517 | struct ethtool_link_ksettings *cmd) |
518 | { |
519 | struct lan966x_port *port = netdev_priv(dev: ndev); |
520 | |
521 | return phylink_ethtool_ksettings_get(port->phylink, cmd); |
522 | } |
523 | |
524 | static int lan966x_set_link_ksettings(struct net_device *ndev, |
525 | const struct ethtool_link_ksettings *cmd) |
526 | { |
527 | struct lan966x_port *port = netdev_priv(dev: ndev); |
528 | |
529 | return phylink_ethtool_ksettings_set(port->phylink, cmd); |
530 | } |
531 | |
532 | static void lan966x_get_pauseparam(struct net_device *dev, |
533 | struct ethtool_pauseparam *pause) |
534 | { |
535 | struct lan966x_port *port = netdev_priv(dev); |
536 | |
537 | phylink_ethtool_get_pauseparam(port->phylink, pause); |
538 | } |
539 | |
540 | static int lan966x_set_pauseparam(struct net_device *dev, |
541 | struct ethtool_pauseparam *pause) |
542 | { |
543 | struct lan966x_port *port = netdev_priv(dev); |
544 | |
545 | return phylink_ethtool_set_pauseparam(port->phylink, pause); |
546 | } |
547 | |
548 | static int lan966x_get_ts_info(struct net_device *dev, |
549 | struct ethtool_ts_info *info) |
550 | { |
551 | struct lan966x_port *port = netdev_priv(dev); |
552 | struct lan966x *lan966x = port->lan966x; |
553 | struct lan966x_phc *phc; |
554 | |
555 | if (!lan966x->ptp) |
556 | return ethtool_op_get_ts_info(dev, eti: info); |
557 | |
558 | phc = &lan966x->phc[LAN966X_PHC_PORT]; |
559 | |
560 | info->phc_index = phc->clock ? ptp_clock_index(ptp: phc->clock) : -1; |
561 | if (info->phc_index == -1) { |
562 | info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE | |
563 | SOF_TIMESTAMPING_RX_SOFTWARE | |
564 | SOF_TIMESTAMPING_SOFTWARE; |
565 | return 0; |
566 | } |
567 | info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE | |
568 | SOF_TIMESTAMPING_RX_SOFTWARE | |
569 | SOF_TIMESTAMPING_SOFTWARE | |
570 | SOF_TIMESTAMPING_TX_HARDWARE | |
571 | SOF_TIMESTAMPING_RX_HARDWARE | |
572 | SOF_TIMESTAMPING_RAW_HARDWARE; |
573 | info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON) | |
574 | BIT(HWTSTAMP_TX_ONESTEP_SYNC); |
575 | info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | |
576 | BIT(HWTSTAMP_FILTER_ALL); |
577 | |
578 | return 0; |
579 | } |
580 | |
581 | const struct ethtool_ops lan966x_ethtool_ops = { |
582 | .get_link_ksettings = lan966x_get_link_ksettings, |
583 | .set_link_ksettings = lan966x_set_link_ksettings, |
584 | .get_pauseparam = lan966x_get_pauseparam, |
585 | .set_pauseparam = lan966x_set_pauseparam, |
586 | .get_sset_count = lan966x_get_sset_count, |
587 | .get_strings = lan966x_get_strings, |
588 | .get_ethtool_stats = lan966x_get_ethtool_stats, |
589 | .get_eth_mac_stats = lan966x_get_eth_mac_stats, |
590 | .get_rmon_stats = lan966x_get_eth_rmon_stats, |
591 | .get_link = ethtool_op_get_link, |
592 | .get_ts_info = lan966x_get_ts_info, |
593 | }; |
594 | |
595 | static void lan966x_check_stats_work(struct work_struct *work) |
596 | { |
597 | struct delayed_work *del_work = to_delayed_work(work); |
598 | struct lan966x *lan966x = container_of(del_work, struct lan966x, |
599 | stats_work); |
600 | |
601 | lan966x_stats_update(lan966x); |
602 | |
603 | queue_delayed_work(wq: lan966x->stats_queue, dwork: &lan966x->stats_work, |
604 | LAN966X_STATS_CHECK_DELAY); |
605 | } |
606 | |
607 | void lan966x_stats_get(struct net_device *dev, |
608 | struct rtnl_link_stats64 *stats) |
609 | { |
610 | struct lan966x_port *port = netdev_priv(dev); |
611 | struct lan966x *lan966x = port->lan966x; |
612 | u32 idx; |
613 | int i; |
614 | |
615 | idx = port->chip_port * lan966x->num_stats; |
616 | |
617 | mutex_lock(&lan966x->stats_lock); |
618 | |
619 | stats->rx_bytes = lan966x->stats[idx + SYS_COUNT_RX_OCT] + |
620 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_OCT]; |
621 | |
622 | stats->rx_packets = lan966x->stats[idx + SYS_COUNT_RX_SHORT] + |
623 | lan966x->stats[idx + SYS_COUNT_RX_FRAG] + |
624 | lan966x->stats[idx + SYS_COUNT_RX_JABBER] + |
625 | lan966x->stats[idx + SYS_COUNT_RX_CRC] + |
626 | lan966x->stats[idx + SYS_COUNT_RX_SYMBOL_ERR] + |
627 | lan966x->stats[idx + SYS_COUNT_RX_SZ_64] + |
628 | lan966x->stats[idx + SYS_COUNT_RX_SZ_65_127] + |
629 | lan966x->stats[idx + SYS_COUNT_RX_SZ_128_255] + |
630 | lan966x->stats[idx + SYS_COUNT_RX_SZ_256_511] + |
631 | lan966x->stats[idx + SYS_COUNT_RX_SZ_512_1023] + |
632 | lan966x->stats[idx + SYS_COUNT_RX_SZ_1024_1526] + |
633 | lan966x->stats[idx + SYS_COUNT_RX_SZ_JUMBO] + |
634 | lan966x->stats[idx + SYS_COUNT_RX_LONG] + |
635 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_SHORT] + |
636 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_FRAG] + |
637 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_JABBER] + |
638 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_64] + |
639 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_65_127] + |
640 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_128_255] + |
641 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_256_511] + |
642 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_512_1023] + |
643 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_1024_1526] + |
644 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_JUMBO]; |
645 | |
646 | stats->multicast = lan966x->stats[idx + SYS_COUNT_RX_MC] + |
647 | lan966x->stats[idx + SYS_COUNT_RX_PMAC_MC]; |
648 | |
649 | stats->rx_errors = lan966x->stats[idx + SYS_COUNT_RX_SHORT] + |
650 | lan966x->stats[idx + SYS_COUNT_RX_FRAG] + |
651 | lan966x->stats[idx + SYS_COUNT_RX_JABBER] + |
652 | lan966x->stats[idx + SYS_COUNT_RX_CRC] + |
653 | lan966x->stats[idx + SYS_COUNT_RX_SYMBOL_ERR] + |
654 | lan966x->stats[idx + SYS_COUNT_RX_LONG]; |
655 | |
656 | stats->rx_dropped = dev->stats.rx_dropped + |
657 | lan966x->stats[idx + SYS_COUNT_RX_LONG] + |
658 | lan966x->stats[idx + SYS_COUNT_DR_LOCAL] + |
659 | lan966x->stats[idx + SYS_COUNT_DR_TAIL] + |
660 | lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_0] + |
661 | lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_1] + |
662 | lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_2] + |
663 | lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_3] + |
664 | lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_4] + |
665 | lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_5] + |
666 | lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_6] + |
667 | lan966x->stats[idx + SYS_COUNT_RX_RED_PRIO_7]; |
668 | |
669 | for (i = 0; i < LAN966X_NUM_TC; i++) { |
670 | stats->rx_dropped += |
671 | (lan966x->stats[idx + SYS_COUNT_DR_YELLOW_PRIO_0 + i] + |
672 | lan966x->stats[idx + SYS_COUNT_DR_GREEN_PRIO_0 + i]); |
673 | } |
674 | |
675 | /* Get Tx stats */ |
676 | stats->tx_bytes = lan966x->stats[idx + SYS_COUNT_TX_OCT] + |
677 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_OCT]; |
678 | |
679 | stats->tx_packets = lan966x->stats[idx + SYS_COUNT_TX_SZ_64] + |
680 | lan966x->stats[idx + SYS_COUNT_TX_SZ_65_127] + |
681 | lan966x->stats[idx + SYS_COUNT_TX_SZ_128_255] + |
682 | lan966x->stats[idx + SYS_COUNT_TX_SZ_256_511] + |
683 | lan966x->stats[idx + SYS_COUNT_TX_SZ_512_1023] + |
684 | lan966x->stats[idx + SYS_COUNT_TX_SZ_1024_1526] + |
685 | lan966x->stats[idx + SYS_COUNT_TX_SZ_JUMBO] + |
686 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_64] + |
687 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_65_127] + |
688 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_128_255] + |
689 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_256_511] + |
690 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_512_1023] + |
691 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_1024_1526] + |
692 | lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_JUMBO]; |
693 | |
694 | stats->tx_dropped = lan966x->stats[idx + SYS_COUNT_TX_DROP] + |
695 | lan966x->stats[idx + SYS_COUNT_TX_AGED]; |
696 | |
697 | stats->collisions = lan966x->stats[idx + SYS_COUNT_TX_COL]; |
698 | |
699 | mutex_unlock(lock: &lan966x->stats_lock); |
700 | } |
701 | |
702 | int lan966x_stats_init(struct lan966x *lan966x) |
703 | { |
704 | char queue_name[32]; |
705 | |
706 | lan966x->stats_layout = lan966x_stats_layout; |
707 | lan966x->num_stats = ARRAY_SIZE(lan966x_stats_layout); |
708 | lan966x->stats = devm_kcalloc(dev: lan966x->dev, n: lan966x->num_phys_ports * |
709 | lan966x->num_stats, |
710 | size: sizeof(u64), GFP_KERNEL); |
711 | if (!lan966x->stats) |
712 | return -ENOMEM; |
713 | |
714 | /* Init stats worker */ |
715 | mutex_init(&lan966x->stats_lock); |
716 | snprintf(buf: queue_name, size: sizeof(queue_name), fmt: "%s-stats" , |
717 | dev_name(dev: lan966x->dev)); |
718 | lan966x->stats_queue = create_singlethread_workqueue(queue_name); |
719 | if (!lan966x->stats_queue) |
720 | return -ENOMEM; |
721 | |
722 | INIT_DELAYED_WORK(&lan966x->stats_work, lan966x_check_stats_work); |
723 | queue_delayed_work(wq: lan966x->stats_queue, dwork: &lan966x->stats_work, |
724 | LAN966X_STATS_CHECK_DELAY); |
725 | |
726 | return 0; |
727 | } |
728 | |