Commit | Line | Data |
---|---|---|
93a76530 GS |
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> | |
e8609e69 | 9 | #include <linux/phylink.h> |
93a76530 GS |
10 | #include <linux/platform_device.h> |
11 | #include <linux/pm_runtime.h> | |
12 | ||
13 | #include "am65-cpsw-nuss.h" | |
14 | #include "cpsw_ale.h" | |
b1f66a5b | 15 | #include "am65-cpts.h" |
93a76530 GS |
16 | |
17 | #define AM65_CPSW_REGDUMP_VER 0x1 | |
18 | ||
19 | enum { | |
20 | AM65_CPSW_REGDUMP_MOD_NUSS = 1, | |
21 | AM65_CPSW_REGDUMP_MOD_RGMII_STATUS = 2, | |
22 | AM65_CPSW_REGDUMP_MOD_MDIO = 3, | |
23 | AM65_CPSW_REGDUMP_MOD_CPSW = 4, | |
24 | AM65_CPSW_REGDUMP_MOD_CPSW_P0 = 5, | |
25 | AM65_CPSW_REGDUMP_MOD_CPSW_P1 = 6, | |
26 | AM65_CPSW_REGDUMP_MOD_CPSW_CPTS = 7, | |
27 | AM65_CPSW_REGDUMP_MOD_CPSW_ALE = 8, | |
28 | AM65_CPSW_REGDUMP_MOD_CPSW_ALE_TBL = 9, | |
29 | AM65_CPSW_REGDUMP_MOD_LAST, | |
30 | }; | |
31 | ||
32 | /** | |
33 | * struct am65_cpsw_regdump_hdr - regdump record header | |
34 | * | |
35 | * @module_id: CPSW module ID | |
36 | * @len: CPSW module registers space length in u32 | |
37 | */ | |
38 | ||
39 | struct am65_cpsw_regdump_hdr { | |
40 | u32 module_id; | |
41 | u32 len; | |
42 | }; | |
43 | ||
44 | /** | |
45 | * struct am65_cpsw_regdump_item - regdump module description | |
46 | * | |
47 | * @hdr: CPSW module header | |
48 | * @start_ofs: CPSW module registers start addr | |
49 | * @end_ofs: CPSW module registers end addr | |
50 | * | |
51 | * Registers dump provided in the format: | |
52 | * u32 : module ID | |
53 | * u32 : dump length | |
54 | * u32[..len]: registers values | |
55 | */ | |
56 | struct am65_cpsw_regdump_item { | |
57 | struct am65_cpsw_regdump_hdr hdr; | |
58 | u32 start_ofs; | |
59 | u32 end_ofs; | |
60 | }; | |
61 | ||
62 | #define AM65_CPSW_REGDUMP_REC(mod, start, end) { \ | |
63 | .hdr.module_id = (mod), \ | |
861f40fa | 64 | .hdr.len = (end + 4 - start) * 2 + \ |
93a76530 GS |
65 | sizeof(struct am65_cpsw_regdump_hdr), \ |
66 | .start_ofs = (start), \ | |
67 | .end_ofs = end, \ | |
68 | } | |
69 | ||
70 | static const struct am65_cpsw_regdump_item am65_cpsw_regdump[] = { | |
71 | AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_NUSS, 0x0, 0x1c), | |
72 | AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_RGMII_STATUS, 0x30, 0x4c), | |
73 | AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_MDIO, 0xf00, 0xffc), | |
74 | AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW, 0x20000, 0x2011c), | |
75 | AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_P0, 0x21000, 0x21320), | |
76 | AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_P1, 0x22000, 0x223a4), | |
77 | AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_CPTS, | |
78 | 0x3d000, 0x3d048), | |
79 | AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_ALE, 0x3e000, 0x3e13c), | |
80 | AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_ALE_TBL, 0, 0), | |
81 | }; | |
82 | ||
83 | struct am65_cpsw_stats_regs { | |
84 | u32 rx_good_frames; | |
85 | u32 rx_broadcast_frames; | |
86 | u32 rx_multicast_frames; | |
87 | u32 rx_pause_frames; /* slave */ | |
88 | u32 rx_crc_errors; | |
89 | u32 rx_align_code_errors; /* slave */ | |
90 | u32 rx_oversized_frames; | |
91 | u32 rx_jabber_frames; /* slave */ | |
92 | u32 rx_undersized_frames; | |
93 | u32 rx_fragments; /* slave */ | |
94 | u32 ale_drop; | |
95 | u32 ale_overrun_drop; | |
96 | u32 rx_octets; | |
97 | u32 tx_good_frames; | |
98 | u32 tx_broadcast_frames; | |
99 | u32 tx_multicast_frames; | |
100 | u32 tx_pause_frames; /* slave */ | |
101 | u32 tx_deferred_frames; /* slave */ | |
102 | u32 tx_collision_frames; /* slave */ | |
103 | u32 tx_single_coll_frames; /* slave */ | |
104 | u32 tx_mult_coll_frames; /* slave */ | |
105 | u32 tx_excessive_collisions; /* slave */ | |
106 | u32 tx_late_collisions; /* slave */ | |
107 | u32 rx_ipg_error; /* slave 10G only */ | |
108 | u32 tx_carrier_sense_errors; /* slave */ | |
109 | u32 tx_octets; | |
110 | u32 tx_64B_frames; | |
111 | u32 tx_65_to_127B_frames; | |
112 | u32 tx_128_to_255B_frames; | |
113 | u32 tx_256_to_511B_frames; | |
114 | u32 tx_512_to_1023B_frames; | |
115 | u32 tx_1024B_frames; | |
116 | u32 net_octets; | |
117 | u32 rx_bottom_fifo_drop; | |
118 | u32 rx_port_mask_drop; | |
119 | u32 rx_top_fifo_drop; | |
120 | u32 ale_rate_limit_drop; | |
121 | u32 ale_vid_ingress_drop; | |
122 | u32 ale_da_eq_sa_drop; | |
123 | u32 ale_block_drop; /* K3 */ | |
124 | u32 ale_secure_drop; /* K3 */ | |
125 | u32 ale_auth_drop; /* K3 */ | |
126 | u32 ale_unknown_ucast; | |
127 | u32 ale_unknown_ucast_bytes; | |
128 | u32 ale_unknown_mcast; | |
129 | u32 ale_unknown_mcast_bytes; | |
130 | u32 ale_unknown_bcast; | |
131 | u32 ale_unknown_bcast_bytes; | |
132 | u32 ale_pol_match; | |
133 | u32 ale_pol_match_red; | |
134 | u32 ale_pol_match_yellow; | |
135 | u32 ale_mcast_sa_drop; /* K3 */ | |
136 | u32 ale_dual_vlan_drop; /* K3 */ | |
137 | u32 ale_len_err_drop; /* K3 */ | |
138 | u32 ale_ip_next_hdr_drop; /* K3 */ | |
139 | u32 ale_ipv4_frag_drop; /* K3 */ | |
140 | u32 __rsvd_1[24]; | |
141 | u32 iet_rx_assembly_err; /* K3 slave */ | |
142 | u32 iet_rx_assembly_ok; /* K3 slave */ | |
143 | u32 iet_rx_smd_err; /* K3 slave */ | |
144 | u32 iet_rx_frag; /* K3 slave */ | |
145 | u32 iet_tx_hold; /* K3 slave */ | |
146 | u32 iet_tx_frag; /* K3 slave */ | |
147 | u32 __rsvd_2[9]; | |
148 | u32 tx_mem_protect_err; | |
149 | /* following NU only */ | |
150 | u32 tx_pri0; | |
151 | u32 tx_pri1; | |
152 | u32 tx_pri2; | |
153 | u32 tx_pri3; | |
154 | u32 tx_pri4; | |
155 | u32 tx_pri5; | |
156 | u32 tx_pri6; | |
157 | u32 tx_pri7; | |
158 | u32 tx_pri0_bcnt; | |
159 | u32 tx_pri1_bcnt; | |
160 | u32 tx_pri2_bcnt; | |
161 | u32 tx_pri3_bcnt; | |
162 | u32 tx_pri4_bcnt; | |
163 | u32 tx_pri5_bcnt; | |
164 | u32 tx_pri6_bcnt; | |
165 | u32 tx_pri7_bcnt; | |
166 | u32 tx_pri0_drop; | |
167 | u32 tx_pri1_drop; | |
168 | u32 tx_pri2_drop; | |
169 | u32 tx_pri3_drop; | |
170 | u32 tx_pri4_drop; | |
171 | u32 tx_pri5_drop; | |
172 | u32 tx_pri6_drop; | |
173 | u32 tx_pri7_drop; | |
174 | u32 tx_pri0_drop_bcnt; | |
175 | u32 tx_pri1_drop_bcnt; | |
176 | u32 tx_pri2_drop_bcnt; | |
177 | u32 tx_pri3_drop_bcnt; | |
178 | u32 tx_pri4_drop_bcnt; | |
179 | u32 tx_pri5_drop_bcnt; | |
180 | u32 tx_pri6_drop_bcnt; | |
181 | u32 tx_pri7_drop_bcnt; | |
182 | }; | |
183 | ||
184 | struct am65_cpsw_ethtool_stat { | |
185 | char desc[ETH_GSTRING_LEN]; | |
186 | int offset; | |
187 | }; | |
188 | ||
189 | #define AM65_CPSW_STATS(prefix, field) \ | |
190 | { \ | |
191 | #prefix#field, \ | |
192 | offsetof(struct am65_cpsw_stats_regs, field) \ | |
193 | } | |
194 | ||
195 | static const struct am65_cpsw_ethtool_stat am65_host_stats[] = { | |
196 | AM65_CPSW_STATS(p0_, rx_good_frames), | |
197 | AM65_CPSW_STATS(p0_, rx_broadcast_frames), | |
198 | AM65_CPSW_STATS(p0_, rx_multicast_frames), | |
199 | AM65_CPSW_STATS(p0_, rx_crc_errors), | |
200 | AM65_CPSW_STATS(p0_, rx_oversized_frames), | |
201 | AM65_CPSW_STATS(p0_, rx_undersized_frames), | |
202 | AM65_CPSW_STATS(p0_, ale_drop), | |
203 | AM65_CPSW_STATS(p0_, ale_overrun_drop), | |
204 | AM65_CPSW_STATS(p0_, rx_octets), | |
205 | AM65_CPSW_STATS(p0_, tx_good_frames), | |
206 | AM65_CPSW_STATS(p0_, tx_broadcast_frames), | |
207 | AM65_CPSW_STATS(p0_, tx_multicast_frames), | |
208 | AM65_CPSW_STATS(p0_, tx_octets), | |
209 | AM65_CPSW_STATS(p0_, tx_64B_frames), | |
210 | AM65_CPSW_STATS(p0_, tx_65_to_127B_frames), | |
211 | AM65_CPSW_STATS(p0_, tx_128_to_255B_frames), | |
212 | AM65_CPSW_STATS(p0_, tx_256_to_511B_frames), | |
213 | AM65_CPSW_STATS(p0_, tx_512_to_1023B_frames), | |
214 | AM65_CPSW_STATS(p0_, tx_1024B_frames), | |
215 | AM65_CPSW_STATS(p0_, net_octets), | |
216 | AM65_CPSW_STATS(p0_, rx_bottom_fifo_drop), | |
217 | AM65_CPSW_STATS(p0_, rx_port_mask_drop), | |
218 | AM65_CPSW_STATS(p0_, rx_top_fifo_drop), | |
219 | AM65_CPSW_STATS(p0_, ale_rate_limit_drop), | |
220 | AM65_CPSW_STATS(p0_, ale_vid_ingress_drop), | |
221 | AM65_CPSW_STATS(p0_, ale_da_eq_sa_drop), | |
222 | AM65_CPSW_STATS(p0_, ale_block_drop), | |
223 | AM65_CPSW_STATS(p0_, ale_secure_drop), | |
224 | AM65_CPSW_STATS(p0_, ale_auth_drop), | |
225 | AM65_CPSW_STATS(p0_, ale_unknown_ucast), | |
226 | AM65_CPSW_STATS(p0_, ale_unknown_ucast_bytes), | |
227 | AM65_CPSW_STATS(p0_, ale_unknown_mcast), | |
228 | AM65_CPSW_STATS(p0_, ale_unknown_mcast_bytes), | |
229 | AM65_CPSW_STATS(p0_, ale_unknown_bcast), | |
230 | AM65_CPSW_STATS(p0_, ale_unknown_bcast_bytes), | |
231 | AM65_CPSW_STATS(p0_, ale_pol_match), | |
232 | AM65_CPSW_STATS(p0_, ale_pol_match_red), | |
233 | AM65_CPSW_STATS(p0_, ale_pol_match_yellow), | |
234 | AM65_CPSW_STATS(p0_, ale_mcast_sa_drop), | |
235 | AM65_CPSW_STATS(p0_, ale_dual_vlan_drop), | |
236 | AM65_CPSW_STATS(p0_, ale_len_err_drop), | |
237 | AM65_CPSW_STATS(p0_, ale_ip_next_hdr_drop), | |
238 | AM65_CPSW_STATS(p0_, ale_ipv4_frag_drop), | |
239 | AM65_CPSW_STATS(p0_, tx_mem_protect_err), | |
240 | AM65_CPSW_STATS(p0_, tx_pri0), | |
241 | AM65_CPSW_STATS(p0_, tx_pri1), | |
242 | AM65_CPSW_STATS(p0_, tx_pri2), | |
243 | AM65_CPSW_STATS(p0_, tx_pri3), | |
244 | AM65_CPSW_STATS(p0_, tx_pri4), | |
245 | AM65_CPSW_STATS(p0_, tx_pri5), | |
246 | AM65_CPSW_STATS(p0_, tx_pri6), | |
247 | AM65_CPSW_STATS(p0_, tx_pri7), | |
248 | AM65_CPSW_STATS(p0_, tx_pri0_bcnt), | |
249 | AM65_CPSW_STATS(p0_, tx_pri1_bcnt), | |
250 | AM65_CPSW_STATS(p0_, tx_pri2_bcnt), | |
251 | AM65_CPSW_STATS(p0_, tx_pri3_bcnt), | |
252 | AM65_CPSW_STATS(p0_, tx_pri4_bcnt), | |
253 | AM65_CPSW_STATS(p0_, tx_pri5_bcnt), | |
254 | AM65_CPSW_STATS(p0_, tx_pri6_bcnt), | |
255 | AM65_CPSW_STATS(p0_, tx_pri7_bcnt), | |
256 | AM65_CPSW_STATS(p0_, tx_pri0_drop), | |
257 | AM65_CPSW_STATS(p0_, tx_pri1_drop), | |
258 | AM65_CPSW_STATS(p0_, tx_pri2_drop), | |
259 | AM65_CPSW_STATS(p0_, tx_pri3_drop), | |
260 | AM65_CPSW_STATS(p0_, tx_pri4_drop), | |
261 | AM65_CPSW_STATS(p0_, tx_pri5_drop), | |
262 | AM65_CPSW_STATS(p0_, tx_pri6_drop), | |
263 | AM65_CPSW_STATS(p0_, tx_pri7_drop), | |
264 | AM65_CPSW_STATS(p0_, tx_pri0_drop_bcnt), | |
265 | AM65_CPSW_STATS(p0_, tx_pri1_drop_bcnt), | |
266 | AM65_CPSW_STATS(p0_, tx_pri2_drop_bcnt), | |
267 | AM65_CPSW_STATS(p0_, tx_pri3_drop_bcnt), | |
268 | AM65_CPSW_STATS(p0_, tx_pri4_drop_bcnt), | |
269 | AM65_CPSW_STATS(p0_, tx_pri5_drop_bcnt), | |
270 | AM65_CPSW_STATS(p0_, tx_pri6_drop_bcnt), | |
271 | AM65_CPSW_STATS(p0_, tx_pri7_drop_bcnt), | |
272 | }; | |
273 | ||
274 | static const struct am65_cpsw_ethtool_stat am65_slave_stats[] = { | |
275 | AM65_CPSW_STATS(, rx_good_frames), | |
276 | AM65_CPSW_STATS(, rx_broadcast_frames), | |
277 | AM65_CPSW_STATS(, rx_multicast_frames), | |
278 | AM65_CPSW_STATS(, rx_pause_frames), | |
279 | AM65_CPSW_STATS(, rx_crc_errors), | |
280 | AM65_CPSW_STATS(, rx_align_code_errors), | |
281 | AM65_CPSW_STATS(, rx_oversized_frames), | |
282 | AM65_CPSW_STATS(, rx_jabber_frames), | |
283 | AM65_CPSW_STATS(, rx_undersized_frames), | |
284 | AM65_CPSW_STATS(, rx_fragments), | |
285 | AM65_CPSW_STATS(, ale_drop), | |
286 | AM65_CPSW_STATS(, ale_overrun_drop), | |
287 | AM65_CPSW_STATS(, rx_octets), | |
288 | AM65_CPSW_STATS(, tx_good_frames), | |
289 | AM65_CPSW_STATS(, tx_broadcast_frames), | |
290 | AM65_CPSW_STATS(, tx_multicast_frames), | |
291 | AM65_CPSW_STATS(, tx_pause_frames), | |
292 | AM65_CPSW_STATS(, tx_deferred_frames), | |
293 | AM65_CPSW_STATS(, tx_collision_frames), | |
294 | AM65_CPSW_STATS(, tx_single_coll_frames), | |
295 | AM65_CPSW_STATS(, tx_mult_coll_frames), | |
296 | AM65_CPSW_STATS(, tx_excessive_collisions), | |
297 | AM65_CPSW_STATS(, tx_late_collisions), | |
298 | AM65_CPSW_STATS(, rx_ipg_error), | |
299 | AM65_CPSW_STATS(, tx_carrier_sense_errors), | |
300 | AM65_CPSW_STATS(, tx_octets), | |
301 | AM65_CPSW_STATS(, tx_64B_frames), | |
302 | AM65_CPSW_STATS(, tx_65_to_127B_frames), | |
303 | AM65_CPSW_STATS(, tx_128_to_255B_frames), | |
304 | AM65_CPSW_STATS(, tx_256_to_511B_frames), | |
305 | AM65_CPSW_STATS(, tx_512_to_1023B_frames), | |
306 | AM65_CPSW_STATS(, tx_1024B_frames), | |
307 | AM65_CPSW_STATS(, net_octets), | |
308 | AM65_CPSW_STATS(, rx_bottom_fifo_drop), | |
309 | AM65_CPSW_STATS(, rx_port_mask_drop), | |
310 | AM65_CPSW_STATS(, rx_top_fifo_drop), | |
311 | AM65_CPSW_STATS(, ale_rate_limit_drop), | |
312 | AM65_CPSW_STATS(, ale_vid_ingress_drop), | |
313 | AM65_CPSW_STATS(, ale_da_eq_sa_drop), | |
314 | AM65_CPSW_STATS(, ale_block_drop), | |
315 | AM65_CPSW_STATS(, ale_secure_drop), | |
316 | AM65_CPSW_STATS(, ale_auth_drop), | |
317 | AM65_CPSW_STATS(, ale_unknown_ucast), | |
318 | AM65_CPSW_STATS(, ale_unknown_ucast_bytes), | |
319 | AM65_CPSW_STATS(, ale_unknown_mcast), | |
320 | AM65_CPSW_STATS(, ale_unknown_mcast_bytes), | |
321 | AM65_CPSW_STATS(, ale_unknown_bcast), | |
322 | AM65_CPSW_STATS(, ale_unknown_bcast_bytes), | |
323 | AM65_CPSW_STATS(, ale_pol_match), | |
324 | AM65_CPSW_STATS(, ale_pol_match_red), | |
325 | AM65_CPSW_STATS(, ale_pol_match_yellow), | |
326 | AM65_CPSW_STATS(, ale_mcast_sa_drop), | |
327 | AM65_CPSW_STATS(, ale_dual_vlan_drop), | |
328 | AM65_CPSW_STATS(, ale_len_err_drop), | |
329 | AM65_CPSW_STATS(, ale_ip_next_hdr_drop), | |
330 | AM65_CPSW_STATS(, ale_ipv4_frag_drop), | |
331 | AM65_CPSW_STATS(, iet_rx_assembly_err), | |
332 | AM65_CPSW_STATS(, iet_rx_assembly_ok), | |
333 | AM65_CPSW_STATS(, iet_rx_smd_err), | |
334 | AM65_CPSW_STATS(, iet_rx_frag), | |
335 | AM65_CPSW_STATS(, iet_tx_hold), | |
336 | AM65_CPSW_STATS(, iet_tx_frag), | |
337 | AM65_CPSW_STATS(, tx_mem_protect_err), | |
338 | AM65_CPSW_STATS(, tx_pri0), | |
339 | AM65_CPSW_STATS(, tx_pri1), | |
340 | AM65_CPSW_STATS(, tx_pri2), | |
341 | AM65_CPSW_STATS(, tx_pri3), | |
342 | AM65_CPSW_STATS(, tx_pri4), | |
343 | AM65_CPSW_STATS(, tx_pri5), | |
344 | AM65_CPSW_STATS(, tx_pri6), | |
345 | AM65_CPSW_STATS(, tx_pri7), | |
346 | AM65_CPSW_STATS(, tx_pri0_bcnt), | |
347 | AM65_CPSW_STATS(, tx_pri1_bcnt), | |
348 | AM65_CPSW_STATS(, tx_pri2_bcnt), | |
349 | AM65_CPSW_STATS(, tx_pri3_bcnt), | |
350 | AM65_CPSW_STATS(, tx_pri4_bcnt), | |
351 | AM65_CPSW_STATS(, tx_pri5_bcnt), | |
352 | AM65_CPSW_STATS(, tx_pri6_bcnt), | |
353 | AM65_CPSW_STATS(, tx_pri7_bcnt), | |
354 | AM65_CPSW_STATS(, tx_pri0_drop), | |
355 | AM65_CPSW_STATS(, tx_pri1_drop), | |
356 | AM65_CPSW_STATS(, tx_pri2_drop), | |
357 | AM65_CPSW_STATS(, tx_pri3_drop), | |
358 | AM65_CPSW_STATS(, tx_pri4_drop), | |
359 | AM65_CPSW_STATS(, tx_pri5_drop), | |
360 | AM65_CPSW_STATS(, tx_pri6_drop), | |
361 | AM65_CPSW_STATS(, tx_pri7_drop), | |
362 | AM65_CPSW_STATS(, tx_pri0_drop_bcnt), | |
363 | AM65_CPSW_STATS(, tx_pri1_drop_bcnt), | |
364 | AM65_CPSW_STATS(, tx_pri2_drop_bcnt), | |
365 | AM65_CPSW_STATS(, tx_pri3_drop_bcnt), | |
366 | AM65_CPSW_STATS(, tx_pri4_drop_bcnt), | |
367 | AM65_CPSW_STATS(, tx_pri5_drop_bcnt), | |
368 | AM65_CPSW_STATS(, tx_pri6_drop_bcnt), | |
369 | AM65_CPSW_STATS(, tx_pri7_drop_bcnt), | |
370 | }; | |
371 | ||
372 | /* Ethtool priv_flags */ | |
373 | static const char am65_cpsw_ethtool_priv_flags[][ETH_GSTRING_LEN] = { | |
374 | #define AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN BIT(0) | |
375 | "p0-rx-ptype-rrobin", | |
376 | }; | |
377 | ||
378 | static int am65_cpsw_ethtool_op_begin(struct net_device *ndev) | |
379 | { | |
380 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); | |
381 | int ret; | |
382 | ||
e350dbac MC |
383 | ret = pm_runtime_resume_and_get(common->dev); |
384 | if (ret < 0) | |
93a76530 | 385 | dev_err(common->dev, "ethtool begin failed %d\n", ret); |
93a76530 GS |
386 | |
387 | return ret; | |
388 | } | |
389 | ||
390 | static void am65_cpsw_ethtool_op_complete(struct net_device *ndev) | |
391 | { | |
392 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); | |
393 | int ret; | |
394 | ||
395 | ret = pm_runtime_put(common->dev); | |
396 | if (ret < 0 && ret != -EBUSY) | |
397 | dev_err(common->dev, "ethtool complete failed %d\n", ret); | |
398 | } | |
399 | ||
400 | static void am65_cpsw_get_drvinfo(struct net_device *ndev, | |
401 | struct ethtool_drvinfo *info) | |
402 | { | |
403 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); | |
404 | ||
405 | strlcpy(info->driver, dev_driver_string(common->dev), | |
406 | sizeof(info->driver)); | |
407 | strlcpy(info->bus_info, dev_name(common->dev), sizeof(info->bus_info)); | |
408 | } | |
409 | ||
410 | static u32 am65_cpsw_get_msglevel(struct net_device *ndev) | |
411 | { | |
412 | struct am65_cpsw_ndev_priv *priv = am65_ndev_to_priv(ndev); | |
413 | ||
414 | return priv->msg_enable; | |
415 | } | |
416 | ||
417 | static void am65_cpsw_set_msglevel(struct net_device *ndev, u32 value) | |
418 | { | |
419 | struct am65_cpsw_ndev_priv *priv = am65_ndev_to_priv(ndev); | |
420 | ||
421 | priv->msg_enable = value; | |
422 | } | |
423 | ||
424 | static void am65_cpsw_get_channels(struct net_device *ndev, | |
425 | struct ethtool_channels *ch) | |
426 | { | |
427 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); | |
428 | ||
429 | ch->max_rx = AM65_CPSW_MAX_RX_QUEUES; | |
430 | ch->max_tx = AM65_CPSW_MAX_TX_QUEUES; | |
431 | ch->rx_count = AM65_CPSW_MAX_RX_QUEUES; | |
432 | ch->tx_count = common->tx_ch_num; | |
433 | } | |
434 | ||
435 | static int am65_cpsw_set_channels(struct net_device *ndev, | |
436 | struct ethtool_channels *chs) | |
437 | { | |
438 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); | |
439 | ||
440 | if (!chs->rx_count || !chs->tx_count) | |
441 | return -EINVAL; | |
442 | ||
443 | /* Check if interface is up. Can change the num queues when | |
444 | * the interface is down. | |
445 | */ | |
3d0fda90 | 446 | if (common->usage_count) |
93a76530 GS |
447 | return -EBUSY; |
448 | ||
449 | am65_cpsw_nuss_remove_tx_chns(common); | |
450 | ||
451 | return am65_cpsw_nuss_update_tx_chns(common, chs->tx_count); | |
452 | } | |
453 | ||
74624944 HC |
454 | static void |
455 | am65_cpsw_get_ringparam(struct net_device *ndev, | |
456 | struct ethtool_ringparam *ering, | |
457 | struct kernel_ethtool_ringparam *kernel_ering, | |
458 | struct netlink_ext_ack *extack) | |
93a76530 GS |
459 | { |
460 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); | |
461 | ||
462 | /* not supported */ | |
463 | ering->tx_pending = common->tx_chns[0].descs_num; | |
464 | ering->rx_pending = common->rx_chns.descs_num; | |
465 | } | |
466 | ||
467 | static void am65_cpsw_get_pauseparam(struct net_device *ndev, | |
468 | struct ethtool_pauseparam *pause) | |
469 | { | |
470 | struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); | |
471 | ||
e8609e69 | 472 | phylink_ethtool_get_pauseparam(salve->phylink, pause); |
93a76530 GS |
473 | } |
474 | ||
475 | static int am65_cpsw_set_pauseparam(struct net_device *ndev, | |
476 | struct ethtool_pauseparam *pause) | |
477 | { | |
478 | struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); | |
479 | ||
e8609e69 | 480 | return phylink_ethtool_set_pauseparam(salve->phylink, pause); |
93a76530 GS |
481 | } |
482 | ||
483 | static void am65_cpsw_get_wol(struct net_device *ndev, | |
484 | struct ethtool_wolinfo *wol) | |
485 | { | |
486 | struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); | |
487 | ||
e8609e69 | 488 | phylink_ethtool_get_wol(salve->phylink, wol); |
93a76530 GS |
489 | } |
490 | ||
491 | static int am65_cpsw_set_wol(struct net_device *ndev, | |
492 | struct ethtool_wolinfo *wol) | |
493 | { | |
494 | struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); | |
495 | ||
e8609e69 | 496 | return phylink_ethtool_set_wol(salve->phylink, wol); |
93a76530 GS |
497 | } |
498 | ||
499 | static int am65_cpsw_get_link_ksettings(struct net_device *ndev, | |
500 | struct ethtool_link_ksettings *ecmd) | |
501 | { | |
502 | struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); | |
503 | ||
e8609e69 | 504 | return phylink_ethtool_ksettings_get(salve->phylink, ecmd); |
93a76530 GS |
505 | } |
506 | ||
507 | static int | |
508 | am65_cpsw_set_link_ksettings(struct net_device *ndev, | |
509 | const struct ethtool_link_ksettings *ecmd) | |
510 | { | |
511 | struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); | |
512 | ||
e8609e69 | 513 | return phylink_ethtool_ksettings_set(salve->phylink, ecmd); |
93a76530 GS |
514 | } |
515 | ||
516 | static int am65_cpsw_get_eee(struct net_device *ndev, struct ethtool_eee *edata) | |
517 | { | |
518 | struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); | |
519 | ||
e8609e69 | 520 | return phylink_ethtool_get_eee(salve->phylink, edata); |
93a76530 GS |
521 | } |
522 | ||
523 | static int am65_cpsw_set_eee(struct net_device *ndev, struct ethtool_eee *edata) | |
524 | { | |
525 | struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); | |
526 | ||
e8609e69 | 527 | return phylink_ethtool_set_eee(salve->phylink, edata); |
93a76530 GS |
528 | } |
529 | ||
530 | static int am65_cpsw_nway_reset(struct net_device *ndev) | |
531 | { | |
532 | struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); | |
533 | ||
e8609e69 | 534 | return phylink_ethtool_nway_reset(salve->phylink); |
93a76530 GS |
535 | } |
536 | ||
537 | static int am65_cpsw_get_regs_len(struct net_device *ndev) | |
538 | { | |
539 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); | |
b574bf0c | 540 | u32 ale_entries, i, regdump_len = 0; |
93a76530 | 541 | |
b574bf0c | 542 | ale_entries = cpsw_ale_get_num_entries(common->ale); |
93a76530 GS |
543 | for (i = 0; i < ARRAY_SIZE(am65_cpsw_regdump); i++) { |
544 | if (am65_cpsw_regdump[i].hdr.module_id == | |
545 | AM65_CPSW_REGDUMP_MOD_CPSW_ALE_TBL) { | |
546 | regdump_len += sizeof(struct am65_cpsw_regdump_hdr); | |
b574bf0c | 547 | regdump_len += ale_entries * |
93a76530 GS |
548 | ALE_ENTRY_WORDS * sizeof(u32); |
549 | continue; | |
550 | } | |
551 | regdump_len += am65_cpsw_regdump[i].hdr.len; | |
552 | } | |
553 | ||
554 | return regdump_len; | |
555 | } | |
556 | ||
557 | static void am65_cpsw_get_regs(struct net_device *ndev, | |
558 | struct ethtool_regs *regs, void *p) | |
559 | { | |
560 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); | |
b574bf0c | 561 | u32 ale_entries, i, j, pos, *reg = p; |
93a76530 GS |
562 | |
563 | /* update CPSW IP version */ | |
564 | regs->version = AM65_CPSW_REGDUMP_VER; | |
b574bf0c | 565 | ale_entries = cpsw_ale_get_num_entries(common->ale); |
93a76530 GS |
566 | |
567 | pos = 0; | |
568 | for (i = 0; i < ARRAY_SIZE(am65_cpsw_regdump); i++) { | |
569 | reg[pos++] = am65_cpsw_regdump[i].hdr.module_id; | |
570 | ||
571 | if (am65_cpsw_regdump[i].hdr.module_id == | |
572 | AM65_CPSW_REGDUMP_MOD_CPSW_ALE_TBL) { | |
b574bf0c | 573 | u32 ale_tbl_len = ale_entries * |
93a76530 GS |
574 | ALE_ENTRY_WORDS * sizeof(u32) + |
575 | sizeof(struct am65_cpsw_regdump_hdr); | |
576 | reg[pos++] = ale_tbl_len; | |
577 | cpsw_ale_dump(common->ale, ®[pos]); | |
578 | pos += ale_tbl_len; | |
579 | continue; | |
580 | } | |
581 | ||
582 | reg[pos++] = am65_cpsw_regdump[i].hdr.len; | |
583 | ||
584 | j = am65_cpsw_regdump[i].start_ofs; | |
585 | do { | |
586 | reg[pos++] = j; | |
587 | reg[pos++] = readl_relaxed(common->ss_base + j); | |
588 | j += sizeof(u32); | |
589 | } while (j <= am65_cpsw_regdump[i].end_ofs); | |
590 | } | |
591 | } | |
592 | ||
593 | static int am65_cpsw_get_sset_count(struct net_device *ndev, int sset) | |
594 | { | |
595 | switch (sset) { | |
596 | case ETH_SS_STATS: | |
597 | return ARRAY_SIZE(am65_host_stats) + | |
598 | ARRAY_SIZE(am65_slave_stats); | |
599 | case ETH_SS_PRIV_FLAGS: | |
600 | return ARRAY_SIZE(am65_cpsw_ethtool_priv_flags); | |
601 | default: | |
602 | return -EOPNOTSUPP; | |
603 | } | |
604 | } | |
605 | ||
606 | static void am65_cpsw_get_strings(struct net_device *ndev, | |
607 | u32 stringset, u8 *data) | |
608 | { | |
609 | const struct am65_cpsw_ethtool_stat *hw_stats; | |
610 | u32 i, num_stats; | |
611 | u8 *p = data; | |
612 | ||
613 | switch (stringset) { | |
614 | case ETH_SS_STATS: | |
615 | num_stats = ARRAY_SIZE(am65_host_stats); | |
616 | hw_stats = am65_host_stats; | |
617 | for (i = 0; i < num_stats; i++) { | |
618 | memcpy(p, hw_stats[i].desc, ETH_GSTRING_LEN); | |
619 | p += ETH_GSTRING_LEN; | |
620 | } | |
621 | ||
622 | num_stats = ARRAY_SIZE(am65_slave_stats); | |
623 | hw_stats = am65_slave_stats; | |
624 | for (i = 0; i < num_stats; i++) { | |
625 | memcpy(p, hw_stats[i].desc, ETH_GSTRING_LEN); | |
626 | p += ETH_GSTRING_LEN; | |
627 | } | |
628 | break; | |
629 | case ETH_SS_PRIV_FLAGS: | |
630 | num_stats = ARRAY_SIZE(am65_cpsw_ethtool_priv_flags); | |
631 | ||
632 | for (i = 0; i < num_stats; i++) { | |
633 | memcpy(p, am65_cpsw_ethtool_priv_flags[i], | |
634 | ETH_GSTRING_LEN); | |
635 | p += ETH_GSTRING_LEN; | |
636 | } | |
637 | break; | |
638 | } | |
639 | } | |
640 | ||
641 | static void am65_cpsw_get_ethtool_stats(struct net_device *ndev, | |
642 | struct ethtool_stats *stats, u64 *data) | |
643 | { | |
644 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); | |
645 | const struct am65_cpsw_ethtool_stat *hw_stats; | |
646 | struct am65_cpsw_host *host_p; | |
647 | struct am65_cpsw_port *port; | |
648 | u32 i, num_stats; | |
649 | ||
650 | host_p = am65_common_get_host(common); | |
651 | port = am65_ndev_to_port(ndev); | |
652 | num_stats = ARRAY_SIZE(am65_host_stats); | |
653 | hw_stats = am65_host_stats; | |
654 | for (i = 0; i < num_stats; i++) | |
655 | *data++ = readl_relaxed(host_p->stat_base + | |
656 | hw_stats[i].offset); | |
657 | ||
658 | num_stats = ARRAY_SIZE(am65_slave_stats); | |
659 | hw_stats = am65_slave_stats; | |
660 | for (i = 0; i < num_stats; i++) | |
661 | *data++ = readl_relaxed(port->stat_base + | |
662 | hw_stats[i].offset); | |
663 | } | |
664 | ||
b1f66a5b GS |
665 | static int am65_cpsw_get_ethtool_ts_info(struct net_device *ndev, |
666 | struct ethtool_ts_info *info) | |
667 | { | |
668 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); | |
669 | ||
670 | if (!IS_ENABLED(CONFIG_TI_K3_AM65_CPTS)) | |
671 | return ethtool_op_get_ts_info(ndev, info); | |
672 | ||
673 | info->so_timestamping = | |
674 | SOF_TIMESTAMPING_TX_HARDWARE | | |
675 | SOF_TIMESTAMPING_TX_SOFTWARE | | |
676 | SOF_TIMESTAMPING_RX_HARDWARE | | |
677 | SOF_TIMESTAMPING_RX_SOFTWARE | | |
678 | SOF_TIMESTAMPING_SOFTWARE | | |
679 | SOF_TIMESTAMPING_RAW_HARDWARE; | |
680 | info->phc_index = am65_cpts_phc_index(common->cpts); | |
681 | info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON); | |
682 | info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL); | |
683 | return 0; | |
684 | } | |
685 | ||
93a76530 GS |
686 | static u32 am65_cpsw_get_ethtool_priv_flags(struct net_device *ndev) |
687 | { | |
688 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); | |
689 | u32 priv_flags = 0; | |
690 | ||
691 | if (common->pf_p0_rx_ptype_rrobin) | |
692 | priv_flags |= AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN; | |
693 | ||
694 | return priv_flags; | |
695 | } | |
696 | ||
697 | static int am65_cpsw_set_ethtool_priv_flags(struct net_device *ndev, u32 flags) | |
698 | { | |
699 | struct am65_cpsw_common *common = am65_ndev_to_common(ndev); | |
8127224c | 700 | int rrobin; |
93a76530 | 701 | |
8127224c IK |
702 | rrobin = !!(flags & AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN); |
703 | ||
3d0fda90 GS |
704 | if (common->usage_count) |
705 | return -EBUSY; | |
706 | ||
8127224c IK |
707 | if (common->est_enabled && rrobin) { |
708 | netdev_err(ndev, | |
709 | "p0-rx-ptype-rrobin flag conflicts with QOS\n"); | |
710 | return -EINVAL; | |
711 | } | |
712 | ||
713 | common->pf_p0_rx_ptype_rrobin = rrobin; | |
93a76530 GS |
714 | |
715 | return 0; | |
716 | } | |
717 | ||
718 | const struct ethtool_ops am65_cpsw_ethtool_ops_slave = { | |
719 | .begin = am65_cpsw_ethtool_op_begin, | |
720 | .complete = am65_cpsw_ethtool_op_complete, | |
721 | .get_drvinfo = am65_cpsw_get_drvinfo, | |
722 | .get_msglevel = am65_cpsw_get_msglevel, | |
723 | .set_msglevel = am65_cpsw_set_msglevel, | |
724 | .get_channels = am65_cpsw_get_channels, | |
725 | .set_channels = am65_cpsw_set_channels, | |
726 | .get_ringparam = am65_cpsw_get_ringparam, | |
727 | .get_regs_len = am65_cpsw_get_regs_len, | |
728 | .get_regs = am65_cpsw_get_regs, | |
729 | .get_sset_count = am65_cpsw_get_sset_count, | |
730 | .get_strings = am65_cpsw_get_strings, | |
731 | .get_ethtool_stats = am65_cpsw_get_ethtool_stats, | |
b1f66a5b | 732 | .get_ts_info = am65_cpsw_get_ethtool_ts_info, |
93a76530 GS |
733 | .get_priv_flags = am65_cpsw_get_ethtool_priv_flags, |
734 | .set_priv_flags = am65_cpsw_set_ethtool_priv_flags, | |
735 | ||
736 | .get_link = ethtool_op_get_link, | |
737 | .get_link_ksettings = am65_cpsw_get_link_ksettings, | |
738 | .set_link_ksettings = am65_cpsw_set_link_ksettings, | |
739 | .get_pauseparam = am65_cpsw_get_pauseparam, | |
740 | .set_pauseparam = am65_cpsw_set_pauseparam, | |
741 | .get_wol = am65_cpsw_get_wol, | |
742 | .set_wol = am65_cpsw_set_wol, | |
743 | .get_eee = am65_cpsw_get_eee, | |
744 | .set_eee = am65_cpsw_set_eee, | |
745 | .nway_reset = am65_cpsw_nway_reset, | |
746 | }; |