1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Texas Instruments K3 AM65 Ethernet Switch SubSystem Driver ethtool ops |
3 | * |
4 | * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ |
5 | * |
6 | */ |
7 | |
8 | #include <linux/net_tstamp.h> |
9 | #include <linux/phylink.h> |
10 | #include <linux/platform_device.h> |
11 | #include <linux/pm_runtime.h> |
12 | |
13 | #include "am65-cpsw-nuss.h" |
14 | #include "am65-cpsw-qos.h" |
15 | #include "cpsw_ale.h" |
16 | #include "am65-cpts.h" |
17 | |
18 | #define AM65_CPSW_REGDUMP_VER 0x1 |
19 | |
20 | enum { |
21 | AM65_CPSW_REGDUMP_MOD_NUSS = 1, |
22 | AM65_CPSW_REGDUMP_MOD_RGMII_STATUS = 2, |
23 | AM65_CPSW_REGDUMP_MOD_MDIO = 3, |
24 | AM65_CPSW_REGDUMP_MOD_CPSW = 4, |
25 | AM65_CPSW_REGDUMP_MOD_CPSW_P0 = 5, |
26 | AM65_CPSW_REGDUMP_MOD_CPSW_P1 = 6, |
27 | AM65_CPSW_REGDUMP_MOD_CPSW_CPTS = 7, |
28 | AM65_CPSW_REGDUMP_MOD_CPSW_ALE = 8, |
29 | AM65_CPSW_REGDUMP_MOD_CPSW_ALE_TBL = 9, |
30 | AM65_CPSW_REGDUMP_MOD_LAST, |
31 | }; |
32 | |
33 | /** |
34 | * struct am65_cpsw_regdump_hdr - regdump record header |
35 | * |
36 | * @module_id: CPSW module ID |
37 | * @len: CPSW module registers space length in u32 |
38 | */ |
39 | |
40 | struct am65_cpsw_regdump_hdr { |
41 | u32 module_id; |
42 | u32 len; |
43 | }; |
44 | |
45 | /** |
46 | * struct am65_cpsw_regdump_item - regdump module description |
47 | * |
48 | * @hdr: CPSW module header |
49 | * @start_ofs: CPSW module registers start addr |
50 | * @end_ofs: CPSW module registers end addr |
51 | * |
52 | * Registers dump provided in the format: |
53 | * u32 : module ID |
54 | * u32 : dump length |
55 | * u32[..len]: registers values |
56 | */ |
57 | struct am65_cpsw_regdump_item { |
58 | struct am65_cpsw_regdump_hdr hdr; |
59 | u32 start_ofs; |
60 | u32 end_ofs; |
61 | }; |
62 | |
63 | #define AM65_CPSW_REGDUMP_REC(mod, start, end) { \ |
64 | .hdr.module_id = (mod), \ |
65 | .hdr.len = (end + 4 - start) * 2 + \ |
66 | sizeof(struct am65_cpsw_regdump_hdr), \ |
67 | .start_ofs = (start), \ |
68 | .end_ofs = end, \ |
69 | } |
70 | |
71 | static const struct am65_cpsw_regdump_item am65_cpsw_regdump[] = { |
72 | AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_NUSS, 0x0, 0x1c), |
73 | AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_RGMII_STATUS, 0x30, 0x4c), |
74 | AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_MDIO, 0xf00, 0xffc), |
75 | AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW, 0x20000, 0x2011c), |
76 | AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_P0, 0x21000, 0x21320), |
77 | AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_P1, 0x22000, 0x223a4), |
78 | AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_CPTS, |
79 | 0x3d000, 0x3d048), |
80 | AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_ALE, 0x3e000, 0x3e13c), |
81 | AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_ALE_TBL, 0, 0), |
82 | }; |
83 | |
84 | struct am65_cpsw_stats_regs { |
85 | u32 rx_good_frames; |
86 | u32 rx_broadcast_frames; |
87 | u32 rx_multicast_frames; |
88 | u32 rx_pause_frames; /* slave */ |
89 | u32 rx_crc_errors; |
90 | u32 rx_align_code_errors; /* slave */ |
91 | u32 rx_oversized_frames; |
92 | u32 rx_jabber_frames; /* slave */ |
93 | u32 rx_undersized_frames; |
94 | u32 rx_fragments; /* slave */ |
95 | u32 ale_drop; |
96 | u32 ale_overrun_drop; |
97 | u32 rx_octets; |
98 | u32 tx_good_frames; |
99 | u32 tx_broadcast_frames; |
100 | u32 tx_multicast_frames; |
101 | u32 tx_pause_frames; /* slave */ |
102 | u32 tx_deferred_frames; /* slave */ |
103 | u32 tx_collision_frames; /* slave */ |
104 | u32 tx_single_coll_frames; /* slave */ |
105 | u32 tx_mult_coll_frames; /* slave */ |
106 | u32 tx_excessive_collisions; /* slave */ |
107 | u32 tx_late_collisions; /* slave */ |
108 | u32 rx_ipg_error; /* slave 10G only */ |
109 | u32 tx_carrier_sense_errors; /* slave */ |
110 | u32 tx_octets; |
111 | u32 tx_64B_frames; |
112 | u32 tx_65_to_127B_frames; |
113 | u32 tx_128_to_255B_frames; |
114 | u32 tx_256_to_511B_frames; |
115 | u32 tx_512_to_1023B_frames; |
116 | u32 tx_1024B_frames; |
117 | u32 net_octets; |
118 | u32 rx_bottom_fifo_drop; |
119 | u32 rx_port_mask_drop; |
120 | u32 rx_top_fifo_drop; |
121 | u32 ale_rate_limit_drop; |
122 | u32 ale_vid_ingress_drop; |
123 | u32 ale_da_eq_sa_drop; |
124 | u32 ale_block_drop; /* K3 */ |
125 | u32 ale_secure_drop; /* K3 */ |
126 | u32 ale_auth_drop; /* K3 */ |
127 | u32 ale_unknown_ucast; |
128 | u32 ale_unknown_ucast_bytes; |
129 | u32 ale_unknown_mcast; |
130 | u32 ale_unknown_mcast_bytes; |
131 | u32 ale_unknown_bcast; |
132 | u32 ale_unknown_bcast_bytes; |
133 | u32 ale_pol_match; |
134 | u32 ale_pol_match_red; |
135 | u32 ale_pol_match_yellow; |
136 | u32 ale_mcast_sa_drop; /* K3 */ |
137 | u32 ale_dual_vlan_drop; /* K3 */ |
138 | u32 ale_len_err_drop; /* K3 */ |
139 | u32 ale_ip_next_hdr_drop; /* K3 */ |
140 | u32 ale_ipv4_frag_drop; /* K3 */ |
141 | u32 __rsvd_1[24]; |
142 | u32 iet_rx_assembly_err; /* K3 slave */ |
143 | u32 iet_rx_assembly_ok; /* K3 slave */ |
144 | u32 iet_rx_smd_err; /* K3 slave */ |
145 | u32 iet_rx_frag; /* K3 slave */ |
146 | u32 iet_tx_hold; /* K3 slave */ |
147 | u32 iet_tx_frag; /* K3 slave */ |
148 | u32 __rsvd_2[9]; |
149 | u32 tx_mem_protect_err; |
150 | /* following NU only */ |
151 | u32 tx_pri0; |
152 | u32 tx_pri1; |
153 | u32 tx_pri2; |
154 | u32 tx_pri3; |
155 | u32 tx_pri4; |
156 | u32 tx_pri5; |
157 | u32 tx_pri6; |
158 | u32 tx_pri7; |
159 | u32 tx_pri0_bcnt; |
160 | u32 tx_pri1_bcnt; |
161 | u32 tx_pri2_bcnt; |
162 | u32 tx_pri3_bcnt; |
163 | u32 tx_pri4_bcnt; |
164 | u32 tx_pri5_bcnt; |
165 | u32 tx_pri6_bcnt; |
166 | u32 tx_pri7_bcnt; |
167 | u32 tx_pri0_drop; |
168 | u32 tx_pri1_drop; |
169 | u32 tx_pri2_drop; |
170 | u32 tx_pri3_drop; |
171 | u32 tx_pri4_drop; |
172 | u32 tx_pri5_drop; |
173 | u32 tx_pri6_drop; |
174 | u32 tx_pri7_drop; |
175 | u32 tx_pri0_drop_bcnt; |
176 | u32 tx_pri1_drop_bcnt; |
177 | u32 tx_pri2_drop_bcnt; |
178 | u32 tx_pri3_drop_bcnt; |
179 | u32 tx_pri4_drop_bcnt; |
180 | u32 tx_pri5_drop_bcnt; |
181 | u32 tx_pri6_drop_bcnt; |
182 | u32 tx_pri7_drop_bcnt; |
183 | }; |
184 | |
185 | struct am65_cpsw_ethtool_stat { |
186 | char desc[ETH_GSTRING_LEN]; |
187 | int offset; |
188 | }; |
189 | |
190 | #define AM65_CPSW_STATS(prefix, field) \ |
191 | { \ |
192 | #prefix#field, \ |
193 | offsetof(struct am65_cpsw_stats_regs, field) \ |
194 | } |
195 | |
196 | static const struct am65_cpsw_ethtool_stat am65_host_stats[] = { |
197 | AM65_CPSW_STATS(p0_, rx_good_frames), |
198 | AM65_CPSW_STATS(p0_, rx_broadcast_frames), |
199 | AM65_CPSW_STATS(p0_, rx_multicast_frames), |
200 | AM65_CPSW_STATS(p0_, rx_crc_errors), |
201 | AM65_CPSW_STATS(p0_, rx_oversized_frames), |
202 | AM65_CPSW_STATS(p0_, rx_undersized_frames), |
203 | AM65_CPSW_STATS(p0_, ale_drop), |
204 | AM65_CPSW_STATS(p0_, ale_overrun_drop), |
205 | AM65_CPSW_STATS(p0_, rx_octets), |
206 | AM65_CPSW_STATS(p0_, tx_good_frames), |
207 | AM65_CPSW_STATS(p0_, tx_broadcast_frames), |
208 | AM65_CPSW_STATS(p0_, tx_multicast_frames), |
209 | AM65_CPSW_STATS(p0_, tx_octets), |
210 | AM65_CPSW_STATS(p0_, tx_64B_frames), |
211 | AM65_CPSW_STATS(p0_, tx_65_to_127B_frames), |
212 | AM65_CPSW_STATS(p0_, tx_128_to_255B_frames), |
213 | AM65_CPSW_STATS(p0_, tx_256_to_511B_frames), |
214 | AM65_CPSW_STATS(p0_, tx_512_to_1023B_frames), |
215 | AM65_CPSW_STATS(p0_, tx_1024B_frames), |
216 | AM65_CPSW_STATS(p0_, net_octets), |
217 | AM65_CPSW_STATS(p0_, rx_bottom_fifo_drop), |
218 | AM65_CPSW_STATS(p0_, rx_port_mask_drop), |
219 | AM65_CPSW_STATS(p0_, rx_top_fifo_drop), |
220 | AM65_CPSW_STATS(p0_, ale_rate_limit_drop), |
221 | AM65_CPSW_STATS(p0_, ale_vid_ingress_drop), |
222 | AM65_CPSW_STATS(p0_, ale_da_eq_sa_drop), |
223 | AM65_CPSW_STATS(p0_, ale_block_drop), |
224 | AM65_CPSW_STATS(p0_, ale_secure_drop), |
225 | AM65_CPSW_STATS(p0_, ale_auth_drop), |
226 | AM65_CPSW_STATS(p0_, ale_unknown_ucast), |
227 | AM65_CPSW_STATS(p0_, ale_unknown_ucast_bytes), |
228 | AM65_CPSW_STATS(p0_, ale_unknown_mcast), |
229 | AM65_CPSW_STATS(p0_, ale_unknown_mcast_bytes), |
230 | AM65_CPSW_STATS(p0_, ale_unknown_bcast), |
231 | AM65_CPSW_STATS(p0_, ale_unknown_bcast_bytes), |
232 | AM65_CPSW_STATS(p0_, ale_pol_match), |
233 | AM65_CPSW_STATS(p0_, ale_pol_match_red), |
234 | AM65_CPSW_STATS(p0_, ale_pol_match_yellow), |
235 | AM65_CPSW_STATS(p0_, ale_mcast_sa_drop), |
236 | AM65_CPSW_STATS(p0_, ale_dual_vlan_drop), |
237 | AM65_CPSW_STATS(p0_, ale_len_err_drop), |
238 | AM65_CPSW_STATS(p0_, ale_ip_next_hdr_drop), |
239 | AM65_CPSW_STATS(p0_, ale_ipv4_frag_drop), |
240 | AM65_CPSW_STATS(p0_, tx_mem_protect_err), |
241 | AM65_CPSW_STATS(p0_, tx_pri0), |
242 | AM65_CPSW_STATS(p0_, tx_pri1), |
243 | AM65_CPSW_STATS(p0_, tx_pri2), |
244 | AM65_CPSW_STATS(p0_, tx_pri3), |
245 | AM65_CPSW_STATS(p0_, tx_pri4), |
246 | AM65_CPSW_STATS(p0_, tx_pri5), |
247 | AM65_CPSW_STATS(p0_, tx_pri6), |
248 | AM65_CPSW_STATS(p0_, tx_pri7), |
249 | AM65_CPSW_STATS(p0_, tx_pri0_bcnt), |
250 | AM65_CPSW_STATS(p0_, tx_pri1_bcnt), |
251 | AM65_CPSW_STATS(p0_, tx_pri2_bcnt), |
252 | AM65_CPSW_STATS(p0_, tx_pri3_bcnt), |
253 | AM65_CPSW_STATS(p0_, tx_pri4_bcnt), |
254 | AM65_CPSW_STATS(p0_, tx_pri5_bcnt), |
255 | AM65_CPSW_STATS(p0_, tx_pri6_bcnt), |
256 | AM65_CPSW_STATS(p0_, tx_pri7_bcnt), |
257 | AM65_CPSW_STATS(p0_, tx_pri0_drop), |
258 | AM65_CPSW_STATS(p0_, tx_pri1_drop), |
259 | AM65_CPSW_STATS(p0_, tx_pri2_drop), |
260 | AM65_CPSW_STATS(p0_, tx_pri3_drop), |
261 | AM65_CPSW_STATS(p0_, tx_pri4_drop), |
262 | AM65_CPSW_STATS(p0_, tx_pri5_drop), |
263 | AM65_CPSW_STATS(p0_, tx_pri6_drop), |
264 | AM65_CPSW_STATS(p0_, tx_pri7_drop), |
265 | AM65_CPSW_STATS(p0_, tx_pri0_drop_bcnt), |
266 | AM65_CPSW_STATS(p0_, tx_pri1_drop_bcnt), |
267 | AM65_CPSW_STATS(p0_, tx_pri2_drop_bcnt), |
268 | AM65_CPSW_STATS(p0_, tx_pri3_drop_bcnt), |
269 | AM65_CPSW_STATS(p0_, tx_pri4_drop_bcnt), |
270 | AM65_CPSW_STATS(p0_, tx_pri5_drop_bcnt), |
271 | AM65_CPSW_STATS(p0_, tx_pri6_drop_bcnt), |
272 | AM65_CPSW_STATS(p0_, tx_pri7_drop_bcnt), |
273 | }; |
274 | |
275 | static const struct am65_cpsw_ethtool_stat am65_slave_stats[] = { |
276 | AM65_CPSW_STATS(, rx_good_frames), |
277 | AM65_CPSW_STATS(, rx_broadcast_frames), |
278 | AM65_CPSW_STATS(, rx_multicast_frames), |
279 | AM65_CPSW_STATS(, rx_pause_frames), |
280 | AM65_CPSW_STATS(, rx_crc_errors), |
281 | AM65_CPSW_STATS(, rx_align_code_errors), |
282 | AM65_CPSW_STATS(, rx_oversized_frames), |
283 | AM65_CPSW_STATS(, rx_jabber_frames), |
284 | AM65_CPSW_STATS(, rx_undersized_frames), |
285 | AM65_CPSW_STATS(, rx_fragments), |
286 | AM65_CPSW_STATS(, ale_drop), |
287 | AM65_CPSW_STATS(, ale_overrun_drop), |
288 | AM65_CPSW_STATS(, rx_octets), |
289 | AM65_CPSW_STATS(, tx_good_frames), |
290 | AM65_CPSW_STATS(, tx_broadcast_frames), |
291 | AM65_CPSW_STATS(, tx_multicast_frames), |
292 | AM65_CPSW_STATS(, tx_pause_frames), |
293 | AM65_CPSW_STATS(, tx_deferred_frames), |
294 | AM65_CPSW_STATS(, tx_collision_frames), |
295 | AM65_CPSW_STATS(, tx_single_coll_frames), |
296 | AM65_CPSW_STATS(, tx_mult_coll_frames), |
297 | AM65_CPSW_STATS(, tx_excessive_collisions), |
298 | AM65_CPSW_STATS(, tx_late_collisions), |
299 | AM65_CPSW_STATS(, rx_ipg_error), |
300 | AM65_CPSW_STATS(, tx_carrier_sense_errors), |
301 | AM65_CPSW_STATS(, tx_octets), |
302 | AM65_CPSW_STATS(, tx_64B_frames), |
303 | AM65_CPSW_STATS(, tx_65_to_127B_frames), |
304 | AM65_CPSW_STATS(, tx_128_to_255B_frames), |
305 | AM65_CPSW_STATS(, tx_256_to_511B_frames), |
306 | AM65_CPSW_STATS(, tx_512_to_1023B_frames), |
307 | AM65_CPSW_STATS(, tx_1024B_frames), |
308 | AM65_CPSW_STATS(, net_octets), |
309 | AM65_CPSW_STATS(, rx_bottom_fifo_drop), |
310 | AM65_CPSW_STATS(, rx_port_mask_drop), |
311 | AM65_CPSW_STATS(, rx_top_fifo_drop), |
312 | AM65_CPSW_STATS(, ale_rate_limit_drop), |
313 | AM65_CPSW_STATS(, ale_vid_ingress_drop), |
314 | AM65_CPSW_STATS(, ale_da_eq_sa_drop), |
315 | AM65_CPSW_STATS(, ale_block_drop), |
316 | AM65_CPSW_STATS(, ale_secure_drop), |
317 | AM65_CPSW_STATS(, ale_auth_drop), |
318 | AM65_CPSW_STATS(, ale_unknown_ucast), |
319 | AM65_CPSW_STATS(, ale_unknown_ucast_bytes), |
320 | AM65_CPSW_STATS(, ale_unknown_mcast), |
321 | AM65_CPSW_STATS(, ale_unknown_mcast_bytes), |
322 | AM65_CPSW_STATS(, ale_unknown_bcast), |
323 | AM65_CPSW_STATS(, ale_unknown_bcast_bytes), |
324 | AM65_CPSW_STATS(, ale_pol_match), |
325 | AM65_CPSW_STATS(, ale_pol_match_red), |
326 | AM65_CPSW_STATS(, ale_pol_match_yellow), |
327 | AM65_CPSW_STATS(, ale_mcast_sa_drop), |
328 | AM65_CPSW_STATS(, ale_dual_vlan_drop), |
329 | AM65_CPSW_STATS(, ale_len_err_drop), |
330 | AM65_CPSW_STATS(, ale_ip_next_hdr_drop), |
331 | AM65_CPSW_STATS(, ale_ipv4_frag_drop), |
332 | AM65_CPSW_STATS(, iet_rx_assembly_err), |
333 | AM65_CPSW_STATS(, iet_rx_assembly_ok), |
334 | AM65_CPSW_STATS(, iet_rx_smd_err), |
335 | AM65_CPSW_STATS(, iet_rx_frag), |
336 | AM65_CPSW_STATS(, iet_tx_hold), |
337 | AM65_CPSW_STATS(, iet_tx_frag), |
338 | AM65_CPSW_STATS(, tx_mem_protect_err), |
339 | AM65_CPSW_STATS(, tx_pri0), |
340 | AM65_CPSW_STATS(, tx_pri1), |
341 | AM65_CPSW_STATS(, tx_pri2), |
342 | AM65_CPSW_STATS(, tx_pri3), |
343 | AM65_CPSW_STATS(, tx_pri4), |
344 | AM65_CPSW_STATS(, tx_pri5), |
345 | AM65_CPSW_STATS(, tx_pri6), |
346 | AM65_CPSW_STATS(, tx_pri7), |
347 | AM65_CPSW_STATS(, tx_pri0_bcnt), |
348 | AM65_CPSW_STATS(, tx_pri1_bcnt), |
349 | AM65_CPSW_STATS(, tx_pri2_bcnt), |
350 | AM65_CPSW_STATS(, tx_pri3_bcnt), |
351 | AM65_CPSW_STATS(, tx_pri4_bcnt), |
352 | AM65_CPSW_STATS(, tx_pri5_bcnt), |
353 | AM65_CPSW_STATS(, tx_pri6_bcnt), |
354 | AM65_CPSW_STATS(, tx_pri7_bcnt), |
355 | AM65_CPSW_STATS(, tx_pri0_drop), |
356 | AM65_CPSW_STATS(, tx_pri1_drop), |
357 | AM65_CPSW_STATS(, tx_pri2_drop), |
358 | AM65_CPSW_STATS(, tx_pri3_drop), |
359 | AM65_CPSW_STATS(, tx_pri4_drop), |
360 | AM65_CPSW_STATS(, tx_pri5_drop), |
361 | AM65_CPSW_STATS(, tx_pri6_drop), |
362 | AM65_CPSW_STATS(, tx_pri7_drop), |
363 | AM65_CPSW_STATS(, tx_pri0_drop_bcnt), |
364 | AM65_CPSW_STATS(, tx_pri1_drop_bcnt), |
365 | AM65_CPSW_STATS(, tx_pri2_drop_bcnt), |
366 | AM65_CPSW_STATS(, tx_pri3_drop_bcnt), |
367 | AM65_CPSW_STATS(, tx_pri4_drop_bcnt), |
368 | AM65_CPSW_STATS(, tx_pri5_drop_bcnt), |
369 | AM65_CPSW_STATS(, tx_pri6_drop_bcnt), |
370 | AM65_CPSW_STATS(, tx_pri7_drop_bcnt), |
371 | }; |
372 | |
373 | /* Ethtool priv_flags */ |
374 | static const char am65_cpsw_ethtool_priv_flags[][ETH_GSTRING_LEN] = { |
375 | #define AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN BIT(0) |
376 | "p0-rx-ptype-rrobin" , |
377 | }; |
378 | |
379 | static int am65_cpsw_ethtool_op_begin(struct net_device *ndev) |
380 | { |
381 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); |
382 | int ret; |
383 | |
384 | ret = pm_runtime_resume_and_get(dev: common->dev); |
385 | if (ret < 0) |
386 | dev_err(common->dev, "ethtool begin failed %d\n" , ret); |
387 | |
388 | return ret; |
389 | } |
390 | |
391 | static void am65_cpsw_ethtool_op_complete(struct net_device *ndev) |
392 | { |
393 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); |
394 | int ret; |
395 | |
396 | ret = pm_runtime_put(dev: common->dev); |
397 | if (ret < 0 && ret != -EBUSY) |
398 | dev_err(common->dev, "ethtool complete failed %d\n" , ret); |
399 | } |
400 | |
401 | static void am65_cpsw_get_drvinfo(struct net_device *ndev, |
402 | struct ethtool_drvinfo *info) |
403 | { |
404 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); |
405 | |
406 | strscpy(info->driver, dev_driver_string(common->dev), |
407 | sizeof(info->driver)); |
408 | strscpy(info->bus_info, dev_name(common->dev), sizeof(info->bus_info)); |
409 | } |
410 | |
411 | static u32 am65_cpsw_get_msglevel(struct net_device *ndev) |
412 | { |
413 | struct am65_cpsw_ndev_priv *priv = am65_ndev_to_priv(ndev); |
414 | |
415 | return priv->msg_enable; |
416 | } |
417 | |
418 | static void am65_cpsw_set_msglevel(struct net_device *ndev, u32 value) |
419 | { |
420 | struct am65_cpsw_ndev_priv *priv = am65_ndev_to_priv(ndev); |
421 | |
422 | priv->msg_enable = value; |
423 | } |
424 | |
425 | static void am65_cpsw_get_channels(struct net_device *ndev, |
426 | struct ethtool_channels *ch) |
427 | { |
428 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); |
429 | |
430 | ch->max_rx = AM65_CPSW_MAX_RX_QUEUES; |
431 | ch->max_tx = AM65_CPSW_MAX_TX_QUEUES; |
432 | ch->rx_count = AM65_CPSW_MAX_RX_QUEUES; |
433 | ch->tx_count = common->tx_ch_num; |
434 | } |
435 | |
436 | static int am65_cpsw_set_channels(struct net_device *ndev, |
437 | struct ethtool_channels *chs) |
438 | { |
439 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); |
440 | |
441 | if (!chs->rx_count || !chs->tx_count) |
442 | return -EINVAL; |
443 | |
444 | /* Check if interface is up. Can change the num queues when |
445 | * the interface is down. |
446 | */ |
447 | if (common->usage_count) |
448 | return -EBUSY; |
449 | |
450 | am65_cpsw_nuss_remove_tx_chns(common); |
451 | |
452 | return am65_cpsw_nuss_update_tx_chns(common, num_tx: chs->tx_count); |
453 | } |
454 | |
455 | static void |
456 | am65_cpsw_get_ringparam(struct net_device *ndev, |
457 | struct ethtool_ringparam *ering, |
458 | struct kernel_ethtool_ringparam *kernel_ering, |
459 | struct netlink_ext_ack *extack) |
460 | { |
461 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); |
462 | |
463 | /* not supported */ |
464 | ering->tx_pending = common->tx_chns[0].descs_num; |
465 | ering->rx_pending = common->rx_chns.descs_num; |
466 | } |
467 | |
468 | static void am65_cpsw_get_pauseparam(struct net_device *ndev, |
469 | struct ethtool_pauseparam *pause) |
470 | { |
471 | struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); |
472 | |
473 | phylink_ethtool_get_pauseparam(salve->phylink, pause); |
474 | } |
475 | |
476 | static int am65_cpsw_set_pauseparam(struct net_device *ndev, |
477 | struct ethtool_pauseparam *pause) |
478 | { |
479 | struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); |
480 | |
481 | return phylink_ethtool_set_pauseparam(salve->phylink, pause); |
482 | } |
483 | |
484 | static void am65_cpsw_get_wol(struct net_device *ndev, |
485 | struct ethtool_wolinfo *wol) |
486 | { |
487 | struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); |
488 | |
489 | phylink_ethtool_get_wol(salve->phylink, wol); |
490 | } |
491 | |
492 | static int am65_cpsw_set_wol(struct net_device *ndev, |
493 | struct ethtool_wolinfo *wol) |
494 | { |
495 | struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); |
496 | |
497 | return phylink_ethtool_set_wol(salve->phylink, wol); |
498 | } |
499 | |
500 | static int am65_cpsw_get_link_ksettings(struct net_device *ndev, |
501 | struct ethtool_link_ksettings *ecmd) |
502 | { |
503 | struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); |
504 | |
505 | return phylink_ethtool_ksettings_get(salve->phylink, ecmd); |
506 | } |
507 | |
508 | static int |
509 | am65_cpsw_set_link_ksettings(struct net_device *ndev, |
510 | const struct ethtool_link_ksettings *ecmd) |
511 | { |
512 | struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); |
513 | |
514 | return phylink_ethtool_ksettings_set(salve->phylink, ecmd); |
515 | } |
516 | |
517 | static int am65_cpsw_get_eee(struct net_device *ndev, struct ethtool_keee *edata) |
518 | { |
519 | struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); |
520 | |
521 | return phylink_ethtool_get_eee(link: salve->phylink, eee: edata); |
522 | } |
523 | |
524 | static int am65_cpsw_set_eee(struct net_device *ndev, struct ethtool_keee *edata) |
525 | { |
526 | struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); |
527 | |
528 | return phylink_ethtool_set_eee(link: salve->phylink, eee: edata); |
529 | } |
530 | |
531 | static int am65_cpsw_nway_reset(struct net_device *ndev) |
532 | { |
533 | struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); |
534 | |
535 | return phylink_ethtool_nway_reset(salve->phylink); |
536 | } |
537 | |
538 | static int am65_cpsw_get_regs_len(struct net_device *ndev) |
539 | { |
540 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); |
541 | u32 ale_entries, i, regdump_len = 0; |
542 | |
543 | ale_entries = cpsw_ale_get_num_entries(ale: common->ale); |
544 | for (i = 0; i < ARRAY_SIZE(am65_cpsw_regdump); i++) { |
545 | if (am65_cpsw_regdump[i].hdr.module_id == |
546 | AM65_CPSW_REGDUMP_MOD_CPSW_ALE_TBL) { |
547 | regdump_len += sizeof(struct am65_cpsw_regdump_hdr); |
548 | regdump_len += ale_entries * |
549 | ALE_ENTRY_WORDS * sizeof(u32); |
550 | continue; |
551 | } |
552 | regdump_len += am65_cpsw_regdump[i].hdr.len; |
553 | } |
554 | |
555 | return regdump_len; |
556 | } |
557 | |
558 | static void am65_cpsw_get_regs(struct net_device *ndev, |
559 | struct ethtool_regs *regs, void *p) |
560 | { |
561 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); |
562 | u32 ale_entries, i, j, pos, *reg = p; |
563 | |
564 | /* update CPSW IP version */ |
565 | regs->version = AM65_CPSW_REGDUMP_VER; |
566 | ale_entries = cpsw_ale_get_num_entries(ale: common->ale); |
567 | |
568 | pos = 0; |
569 | for (i = 0; i < ARRAY_SIZE(am65_cpsw_regdump); i++) { |
570 | reg[pos++] = am65_cpsw_regdump[i].hdr.module_id; |
571 | |
572 | if (am65_cpsw_regdump[i].hdr.module_id == |
573 | AM65_CPSW_REGDUMP_MOD_CPSW_ALE_TBL) { |
574 | u32 ale_tbl_len = ale_entries * |
575 | ALE_ENTRY_WORDS * sizeof(u32) + |
576 | sizeof(struct am65_cpsw_regdump_hdr); |
577 | reg[pos++] = ale_tbl_len; |
578 | cpsw_ale_dump(ale: common->ale, data: ®[pos]); |
579 | pos += ale_tbl_len; |
580 | continue; |
581 | } |
582 | |
583 | reg[pos++] = am65_cpsw_regdump[i].hdr.len; |
584 | |
585 | j = am65_cpsw_regdump[i].start_ofs; |
586 | do { |
587 | reg[pos++] = j; |
588 | reg[pos++] = readl_relaxed(common->ss_base + j); |
589 | j += sizeof(u32); |
590 | } while (j <= am65_cpsw_regdump[i].end_ofs); |
591 | } |
592 | } |
593 | |
594 | static int am65_cpsw_get_sset_count(struct net_device *ndev, int sset) |
595 | { |
596 | switch (sset) { |
597 | case ETH_SS_STATS: |
598 | return ARRAY_SIZE(am65_host_stats) + |
599 | ARRAY_SIZE(am65_slave_stats); |
600 | case ETH_SS_PRIV_FLAGS: |
601 | return ARRAY_SIZE(am65_cpsw_ethtool_priv_flags); |
602 | default: |
603 | return -EOPNOTSUPP; |
604 | } |
605 | } |
606 | |
607 | static void am65_cpsw_get_strings(struct net_device *ndev, |
608 | u32 stringset, u8 *data) |
609 | { |
610 | const struct am65_cpsw_ethtool_stat *hw_stats; |
611 | u32 i, num_stats; |
612 | u8 *p = data; |
613 | |
614 | switch (stringset) { |
615 | case ETH_SS_STATS: |
616 | num_stats = ARRAY_SIZE(am65_host_stats); |
617 | hw_stats = am65_host_stats; |
618 | for (i = 0; i < num_stats; i++) { |
619 | memcpy(p, hw_stats[i].desc, ETH_GSTRING_LEN); |
620 | p += ETH_GSTRING_LEN; |
621 | } |
622 | |
623 | num_stats = ARRAY_SIZE(am65_slave_stats); |
624 | hw_stats = am65_slave_stats; |
625 | for (i = 0; i < num_stats; i++) { |
626 | memcpy(p, hw_stats[i].desc, ETH_GSTRING_LEN); |
627 | p += ETH_GSTRING_LEN; |
628 | } |
629 | break; |
630 | case ETH_SS_PRIV_FLAGS: |
631 | num_stats = ARRAY_SIZE(am65_cpsw_ethtool_priv_flags); |
632 | |
633 | for (i = 0; i < num_stats; i++) { |
634 | memcpy(p, am65_cpsw_ethtool_priv_flags[i], |
635 | ETH_GSTRING_LEN); |
636 | p += ETH_GSTRING_LEN; |
637 | } |
638 | break; |
639 | } |
640 | } |
641 | |
642 | static void am65_cpsw_get_ethtool_stats(struct net_device *ndev, |
643 | struct ethtool_stats *stats, u64 *data) |
644 | { |
645 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); |
646 | const struct am65_cpsw_ethtool_stat *hw_stats; |
647 | struct am65_cpsw_host *host_p; |
648 | struct am65_cpsw_port *port; |
649 | u32 i, num_stats; |
650 | |
651 | host_p = am65_common_get_host(common); |
652 | port = am65_ndev_to_port(ndev); |
653 | num_stats = ARRAY_SIZE(am65_host_stats); |
654 | hw_stats = am65_host_stats; |
655 | for (i = 0; i < num_stats; i++) |
656 | *data++ = readl_relaxed(host_p->stat_base + |
657 | hw_stats[i].offset); |
658 | |
659 | num_stats = ARRAY_SIZE(am65_slave_stats); |
660 | hw_stats = am65_slave_stats; |
661 | for (i = 0; i < num_stats; i++) |
662 | *data++ = readl_relaxed(port->stat_base + |
663 | hw_stats[i].offset); |
664 | } |
665 | |
666 | static void am65_cpsw_get_eth_mac_stats(struct net_device *ndev, |
667 | struct ethtool_eth_mac_stats *s) |
668 | { |
669 | struct am65_cpsw_port *port = am65_ndev_to_port(ndev); |
670 | struct am65_cpsw_stats_regs __iomem *stats; |
671 | |
672 | stats = port->stat_base; |
673 | |
674 | if (s->src != ETHTOOL_MAC_STATS_SRC_AGGREGATE) |
675 | return; |
676 | |
677 | s->FramesTransmittedOK = readl_relaxed(&stats->tx_good_frames); |
678 | s->SingleCollisionFrames = readl_relaxed(&stats->tx_single_coll_frames); |
679 | s->MultipleCollisionFrames = readl_relaxed(&stats->tx_mult_coll_frames); |
680 | s->FramesReceivedOK = readl_relaxed(&stats->rx_good_frames); |
681 | s->FrameCheckSequenceErrors = readl_relaxed(&stats->rx_crc_errors); |
682 | s->AlignmentErrors = readl_relaxed(&stats->rx_align_code_errors); |
683 | s->OctetsTransmittedOK = readl_relaxed(&stats->tx_octets); |
684 | s->FramesWithDeferredXmissions = readl_relaxed(&stats->tx_deferred_frames); |
685 | s->LateCollisions = readl_relaxed(&stats->tx_late_collisions); |
686 | s->CarrierSenseErrors = readl_relaxed(&stats->tx_carrier_sense_errors); |
687 | s->OctetsReceivedOK = readl_relaxed(&stats->rx_octets); |
688 | s->MulticastFramesXmittedOK = readl_relaxed(&stats->tx_multicast_frames); |
689 | s->BroadcastFramesXmittedOK = readl_relaxed(&stats->tx_broadcast_frames); |
690 | s->MulticastFramesReceivedOK = readl_relaxed(&stats->rx_multicast_frames); |
691 | s->BroadcastFramesReceivedOK = readl_relaxed(&stats->rx_broadcast_frames); |
692 | }; |
693 | |
694 | static int am65_cpsw_get_ethtool_ts_info(struct net_device *ndev, |
695 | struct ethtool_ts_info *info) |
696 | { |
697 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); |
698 | |
699 | if (!IS_ENABLED(CONFIG_TI_K3_AM65_CPTS)) |
700 | return ethtool_op_get_ts_info(dev: ndev, eti: info); |
701 | |
702 | info->so_timestamping = |
703 | SOF_TIMESTAMPING_TX_HARDWARE | |
704 | SOF_TIMESTAMPING_TX_SOFTWARE | |
705 | SOF_TIMESTAMPING_RX_HARDWARE | |
706 | SOF_TIMESTAMPING_RX_SOFTWARE | |
707 | SOF_TIMESTAMPING_SOFTWARE | |
708 | SOF_TIMESTAMPING_RAW_HARDWARE; |
709 | info->phc_index = am65_cpts_phc_index(cpts: common->cpts); |
710 | info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON); |
711 | info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL); |
712 | return 0; |
713 | } |
714 | |
715 | static u32 am65_cpsw_get_ethtool_priv_flags(struct net_device *ndev) |
716 | { |
717 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); |
718 | u32 priv_flags = 0; |
719 | |
720 | if (common->pf_p0_rx_ptype_rrobin) |
721 | priv_flags |= AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN; |
722 | |
723 | return priv_flags; |
724 | } |
725 | |
726 | static int am65_cpsw_set_ethtool_priv_flags(struct net_device *ndev, u32 flags) |
727 | { |
728 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); |
729 | int rrobin; |
730 | |
731 | rrobin = !!(flags & AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN); |
732 | |
733 | if (common->usage_count) |
734 | return -EBUSY; |
735 | |
736 | if (common->est_enabled && rrobin) { |
737 | netdev_err(dev: ndev, |
738 | format: "p0-rx-ptype-rrobin flag conflicts with QOS\n" ); |
739 | return -EINVAL; |
740 | } |
741 | |
742 | common->pf_p0_rx_ptype_rrobin = rrobin; |
743 | |
744 | return 0; |
745 | } |
746 | |
747 | static void am65_cpsw_port_iet_rx_enable(struct am65_cpsw_port *port, bool enable) |
748 | { |
749 | u32 val; |
750 | |
751 | val = readl(addr: port->port_base + AM65_CPSW_PN_REG_CTL); |
752 | if (enable) |
753 | val |= AM65_CPSW_PN_CTL_IET_PORT_EN; |
754 | else |
755 | val &= ~AM65_CPSW_PN_CTL_IET_PORT_EN; |
756 | |
757 | writel(val, addr: port->port_base + AM65_CPSW_PN_REG_CTL); |
758 | am65_cpsw_iet_common_enable(common: port->common); |
759 | } |
760 | |
761 | static void am65_cpsw_port_iet_tx_enable(struct am65_cpsw_port *port, bool enable) |
762 | { |
763 | u32 val; |
764 | |
765 | val = readl(addr: port->port_base + AM65_CPSW_PN_REG_IET_CTRL); |
766 | if (enable) |
767 | val |= AM65_CPSW_PN_IET_MAC_PENABLE; |
768 | else |
769 | val &= ~AM65_CPSW_PN_IET_MAC_PENABLE; |
770 | |
771 | writel(val, addr: port->port_base + AM65_CPSW_PN_REG_IET_CTRL); |
772 | } |
773 | |
774 | static int am65_cpsw_get_mm(struct net_device *ndev, struct ethtool_mm_state *state) |
775 | { |
776 | struct am65_cpsw_port *port = am65_ndev_to_port(ndev); |
777 | struct am65_cpsw_ndev_priv *priv = netdev_priv(dev: ndev); |
778 | u32 port_ctrl, iet_ctrl, iet_status; |
779 | u32 add_frag_size; |
780 | |
781 | if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_QOS)) |
782 | return -EOPNOTSUPP; |
783 | |
784 | mutex_lock(&priv->mm_lock); |
785 | |
786 | iet_ctrl = readl(addr: port->port_base + AM65_CPSW_PN_REG_IET_CTRL); |
787 | port_ctrl = readl(addr: port->port_base + AM65_CPSW_PN_REG_CTL); |
788 | |
789 | state->tx_enabled = !!(iet_ctrl & AM65_CPSW_PN_IET_MAC_PENABLE); |
790 | state->pmac_enabled = !!(port_ctrl & AM65_CPSW_PN_CTL_IET_PORT_EN); |
791 | |
792 | iet_status = readl(addr: port->port_base + AM65_CPSW_PN_REG_IET_STATUS); |
793 | |
794 | if (iet_ctrl & AM65_CPSW_PN_IET_MAC_DISABLEVERIFY) |
795 | state->verify_status = ETHTOOL_MM_VERIFY_STATUS_DISABLED; |
796 | else if (iet_status & AM65_CPSW_PN_MAC_VERIFIED) |
797 | state->verify_status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED; |
798 | else if (iet_status & AM65_CPSW_PN_MAC_VERIFY_FAIL) |
799 | state->verify_status = ETHTOOL_MM_VERIFY_STATUS_FAILED; |
800 | else |
801 | state->verify_status = ETHTOOL_MM_VERIFY_STATUS_UNKNOWN; |
802 | |
803 | add_frag_size = AM65_CPSW_PN_IET_MAC_GET_ADDFRAGSIZE(iet_ctrl); |
804 | state->tx_min_frag_size = ethtool_mm_frag_size_add_to_min(val_add: add_frag_size); |
805 | |
806 | /* Errata i2208: RX min fragment size cannot be less than 124 */ |
807 | state->rx_min_frag_size = 124; |
808 | |
809 | /* FPE active if common tx_enabled and verification success or disabled (forced) */ |
810 | state->tx_active = state->tx_enabled && |
811 | (state->verify_status == ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED || |
812 | state->verify_status == ETHTOOL_MM_VERIFY_STATUS_DISABLED); |
813 | state->verify_enabled = !(iet_ctrl & AM65_CPSW_PN_IET_MAC_DISABLEVERIFY); |
814 | |
815 | state->verify_time = port->qos.iet.verify_time_ms; |
816 | |
817 | /* 802.3-2018 clause 30.14.1.6, says that the aMACMergeVerifyTime |
818 | * variable has a range between 1 and 128 ms inclusive. Limit to that. |
819 | */ |
820 | state->max_verify_time = 128; |
821 | |
822 | mutex_unlock(lock: &priv->mm_lock); |
823 | |
824 | return 0; |
825 | } |
826 | |
827 | static int am65_cpsw_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg, |
828 | struct netlink_ext_ack *extack) |
829 | { |
830 | struct am65_cpsw_port *port = am65_ndev_to_port(ndev); |
831 | struct am65_cpsw_ndev_priv *priv = netdev_priv(dev: ndev); |
832 | struct am65_cpsw_iet *iet = &port->qos.iet; |
833 | u32 val, add_frag_size; |
834 | int err; |
835 | |
836 | if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_QOS)) |
837 | return -EOPNOTSUPP; |
838 | |
839 | err = ethtool_mm_frag_size_min_to_add(val_min: cfg->tx_min_frag_size, val_add: &add_frag_size, extack); |
840 | if (err) |
841 | return err; |
842 | |
843 | mutex_lock(&priv->mm_lock); |
844 | |
845 | if (cfg->pmac_enabled) { |
846 | /* change TX & RX FIFO MAX_BLKS as per TRM recommendation */ |
847 | if (!iet->original_max_blks) |
848 | iet->original_max_blks = readl(addr: port->port_base + AM65_CPSW_PN_REG_MAX_BLKS); |
849 | |
850 | writel(AM65_CPSW_PN_TX_RX_MAX_BLKS_IET, |
851 | addr: port->port_base + AM65_CPSW_PN_REG_MAX_BLKS); |
852 | } else if (iet->original_max_blks) { |
853 | /* restore RX & TX FIFO MAX_BLKS */ |
854 | writel(val: iet->original_max_blks, |
855 | addr: port->port_base + AM65_CPSW_PN_REG_MAX_BLKS); |
856 | } |
857 | |
858 | am65_cpsw_port_iet_rx_enable(port, enable: cfg->pmac_enabled); |
859 | am65_cpsw_port_iet_tx_enable(port, enable: cfg->tx_enabled); |
860 | |
861 | val = readl(addr: port->port_base + AM65_CPSW_PN_REG_IET_CTRL); |
862 | if (cfg->verify_enabled) { |
863 | val &= ~AM65_CPSW_PN_IET_MAC_DISABLEVERIFY; |
864 | /* Reset Verify state machine. Verification won't start here. |
865 | * Verification will be done once link-up. |
866 | */ |
867 | val |= AM65_CPSW_PN_IET_MAC_LINKFAIL; |
868 | } else { |
869 | val |= AM65_CPSW_PN_IET_MAC_DISABLEVERIFY; |
870 | /* Clear LINKFAIL to allow verify/response packets */ |
871 | val &= ~AM65_CPSW_PN_IET_MAC_LINKFAIL; |
872 | } |
873 | |
874 | val &= ~AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_MASK; |
875 | val |= AM65_CPSW_PN_IET_MAC_SET_ADDFRAGSIZE(add_frag_size); |
876 | writel(val, addr: port->port_base + AM65_CPSW_PN_REG_IET_CTRL); |
877 | |
878 | /* verify_timeout_count can only be set at valid link */ |
879 | port->qos.iet.verify_time_ms = cfg->verify_time; |
880 | |
881 | /* enable/disable preemption based on link status */ |
882 | am65_cpsw_iet_commit_preemptible_tcs(port); |
883 | |
884 | mutex_unlock(lock: &priv->mm_lock); |
885 | |
886 | return 0; |
887 | } |
888 | |
889 | static void am65_cpsw_get_mm_stats(struct net_device *ndev, |
890 | struct ethtool_mm_stats *s) |
891 | { |
892 | struct am65_cpsw_port *port = am65_ndev_to_port(ndev); |
893 | void __iomem *base = port->stat_base; |
894 | |
895 | s->MACMergeFrameAssOkCount = readl(addr: base + AM65_CPSW_STATN_IET_RX_ASSEMBLY_OK); |
896 | s->MACMergeFrameAssErrorCount = readl(addr: base + AM65_CPSW_STATN_IET_RX_ASSEMBLY_ERROR); |
897 | s->MACMergeFrameSmdErrorCount = readl(addr: base + AM65_CPSW_STATN_IET_RX_SMD_ERROR); |
898 | /* CPSW Functional Spec states: |
899 | * "The IET stat aMACMergeFragCountRx is derived by adding the |
900 | * Receive Assembly Error count to this value. i.e. AM65_CPSW_STATN_IET_RX_FRAG" |
901 | */ |
902 | s->MACMergeFragCountRx = readl(addr: base + AM65_CPSW_STATN_IET_RX_FRAG) + s->MACMergeFrameAssErrorCount; |
903 | s->MACMergeFragCountTx = readl(addr: base + AM65_CPSW_STATN_IET_TX_FRAG); |
904 | s->MACMergeHoldCount = readl(addr: base + AM65_CPSW_STATN_IET_TX_HOLD); |
905 | } |
906 | |
907 | static int am65_cpsw_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal, |
908 | struct kernel_ethtool_coalesce *kernel_coal, |
909 | struct netlink_ext_ack *extack) |
910 | { |
911 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); |
912 | struct am65_cpsw_tx_chn *tx_chn; |
913 | |
914 | tx_chn = &common->tx_chns[0]; |
915 | |
916 | coal->rx_coalesce_usecs = common->rx_pace_timeout / 1000; |
917 | coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout / 1000; |
918 | |
919 | return 0; |
920 | } |
921 | |
922 | static int am65_cpsw_get_per_queue_coalesce(struct net_device *ndev, u32 queue, |
923 | struct ethtool_coalesce *coal) |
924 | { |
925 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); |
926 | struct am65_cpsw_tx_chn *tx_chn; |
927 | |
928 | if (queue >= AM65_CPSW_MAX_TX_QUEUES) |
929 | return -EINVAL; |
930 | |
931 | tx_chn = &common->tx_chns[queue]; |
932 | |
933 | coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout / 1000; |
934 | |
935 | return 0; |
936 | } |
937 | |
938 | static int am65_cpsw_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal, |
939 | struct kernel_ethtool_coalesce *kernel_coal, |
940 | struct netlink_ext_ack *extack) |
941 | { |
942 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); |
943 | struct am65_cpsw_tx_chn *tx_chn; |
944 | |
945 | tx_chn = &common->tx_chns[0]; |
946 | |
947 | if (coal->rx_coalesce_usecs && coal->rx_coalesce_usecs < 20) |
948 | return -EINVAL; |
949 | |
950 | if (coal->tx_coalesce_usecs && coal->tx_coalesce_usecs < 20) |
951 | return -EINVAL; |
952 | |
953 | common->rx_pace_timeout = coal->rx_coalesce_usecs * 1000; |
954 | tx_chn->tx_pace_timeout = coal->tx_coalesce_usecs * 1000; |
955 | |
956 | return 0; |
957 | } |
958 | |
959 | static int am65_cpsw_set_per_queue_coalesce(struct net_device *ndev, u32 queue, |
960 | struct ethtool_coalesce *coal) |
961 | { |
962 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); |
963 | struct am65_cpsw_tx_chn *tx_chn; |
964 | |
965 | if (queue >= AM65_CPSW_MAX_TX_QUEUES) |
966 | return -EINVAL; |
967 | |
968 | tx_chn = &common->tx_chns[queue]; |
969 | |
970 | if (coal->tx_coalesce_usecs && coal->tx_coalesce_usecs < 20) { |
971 | dev_info(common->dev, "defaulting to min value of 20us for tx-usecs for tx-%u\n" , |
972 | queue); |
973 | coal->tx_coalesce_usecs = 20; |
974 | } |
975 | |
976 | tx_chn->tx_pace_timeout = coal->tx_coalesce_usecs * 1000; |
977 | |
978 | return 0; |
979 | } |
980 | |
981 | const struct ethtool_ops am65_cpsw_ethtool_ops_slave = { |
982 | .begin = am65_cpsw_ethtool_op_begin, |
983 | .complete = am65_cpsw_ethtool_op_complete, |
984 | .get_drvinfo = am65_cpsw_get_drvinfo, |
985 | .get_msglevel = am65_cpsw_get_msglevel, |
986 | .set_msglevel = am65_cpsw_set_msglevel, |
987 | .get_channels = am65_cpsw_get_channels, |
988 | .set_channels = am65_cpsw_set_channels, |
989 | .get_ringparam = am65_cpsw_get_ringparam, |
990 | .get_regs_len = am65_cpsw_get_regs_len, |
991 | .get_regs = am65_cpsw_get_regs, |
992 | .get_sset_count = am65_cpsw_get_sset_count, |
993 | .get_strings = am65_cpsw_get_strings, |
994 | .get_ethtool_stats = am65_cpsw_get_ethtool_stats, |
995 | .get_eth_mac_stats = am65_cpsw_get_eth_mac_stats, |
996 | .get_ts_info = am65_cpsw_get_ethtool_ts_info, |
997 | .get_priv_flags = am65_cpsw_get_ethtool_priv_flags, |
998 | .set_priv_flags = am65_cpsw_set_ethtool_priv_flags, |
999 | .supported_coalesce_params = ETHTOOL_COALESCE_USECS, |
1000 | .get_coalesce = am65_cpsw_get_coalesce, |
1001 | .set_coalesce = am65_cpsw_set_coalesce, |
1002 | .get_per_queue_coalesce = am65_cpsw_get_per_queue_coalesce, |
1003 | .set_per_queue_coalesce = am65_cpsw_set_per_queue_coalesce, |
1004 | |
1005 | .get_link = ethtool_op_get_link, |
1006 | .get_link_ksettings = am65_cpsw_get_link_ksettings, |
1007 | .set_link_ksettings = am65_cpsw_set_link_ksettings, |
1008 | .get_pauseparam = am65_cpsw_get_pauseparam, |
1009 | .set_pauseparam = am65_cpsw_set_pauseparam, |
1010 | .get_wol = am65_cpsw_get_wol, |
1011 | .set_wol = am65_cpsw_set_wol, |
1012 | .get_eee = am65_cpsw_get_eee, |
1013 | .set_eee = am65_cpsw_set_eee, |
1014 | .nway_reset = am65_cpsw_nway_reset, |
1015 | .get_mm = am65_cpsw_get_mm, |
1016 | .set_mm = am65_cpsw_set_mm, |
1017 | .get_mm_stats = am65_cpsw_get_mm_stats, |
1018 | }; |
1019 | |