xref: /linux/drivers/net/ethernet/ti/am65-cpsw-ethtool.c (revision a3a02a52bcfcbcc4a637d4b68bf1bc391c9fad02)
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(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(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, 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(salve->phylink, 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(salve->phylink, 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(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(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(common->ale, &reg[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 kernel_ethtool_ts_info *info)
696 {
697 	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
698 	unsigned int ptp_v2_filter;
699 
700 	ptp_v2_filter = BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT)	 |
701 			BIT(HWTSTAMP_FILTER_PTP_V2_L4_SYNC)	 |
702 			BIT(HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
703 			BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT)	 |
704 			BIT(HWTSTAMP_FILTER_PTP_V2_L2_SYNC)	 |
705 			BIT(HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
706 			BIT(HWTSTAMP_FILTER_PTP_V2_EVENT)	 |
707 			BIT(HWTSTAMP_FILTER_PTP_V2_SYNC)	 |
708 			BIT(HWTSTAMP_FILTER_PTP_V2_DELAY_REQ);
709 
710 	if (!IS_ENABLED(CONFIG_TI_K3_AM65_CPTS))
711 		return ethtool_op_get_ts_info(ndev, info);
712 
713 	info->so_timestamping =
714 		SOF_TIMESTAMPING_TX_HARDWARE |
715 		SOF_TIMESTAMPING_TX_SOFTWARE |
716 		SOF_TIMESTAMPING_RX_HARDWARE |
717 		SOF_TIMESTAMPING_RX_SOFTWARE |
718 		SOF_TIMESTAMPING_SOFTWARE |
719 		SOF_TIMESTAMPING_RAW_HARDWARE;
720 	info->phc_index = am65_cpts_phc_index(common->cpts);
721 	info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
722 	info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | ptp_v2_filter;
723 	return 0;
724 }
725 
726 static u32 am65_cpsw_get_ethtool_priv_flags(struct net_device *ndev)
727 {
728 	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
729 	u32 priv_flags = 0;
730 
731 	if (common->pf_p0_rx_ptype_rrobin)
732 		priv_flags |= AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN;
733 
734 	return priv_flags;
735 }
736 
737 static int am65_cpsw_set_ethtool_priv_flags(struct net_device *ndev, u32 flags)
738 {
739 	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
740 	int rrobin;
741 
742 	rrobin = !!(flags & AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN);
743 
744 	if (common->usage_count)
745 		return -EBUSY;
746 
747 	if (common->est_enabled && rrobin) {
748 		netdev_err(ndev,
749 			   "p0-rx-ptype-rrobin flag conflicts with QOS\n");
750 		return -EINVAL;
751 	}
752 
753 	common->pf_p0_rx_ptype_rrobin = rrobin;
754 
755 	return 0;
756 }
757 
758 static void am65_cpsw_port_iet_rx_enable(struct am65_cpsw_port *port, bool enable)
759 {
760 	u32 val;
761 
762 	val = readl(port->port_base + AM65_CPSW_PN_REG_CTL);
763 	if (enable)
764 		val |= AM65_CPSW_PN_CTL_IET_PORT_EN;
765 	else
766 		val &= ~AM65_CPSW_PN_CTL_IET_PORT_EN;
767 
768 	writel(val, port->port_base + AM65_CPSW_PN_REG_CTL);
769 	am65_cpsw_iet_common_enable(port->common);
770 }
771 
772 static void am65_cpsw_port_iet_tx_enable(struct am65_cpsw_port *port, bool enable)
773 {
774 	u32 val;
775 
776 	val = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
777 	if (enable)
778 		val |= AM65_CPSW_PN_IET_MAC_PENABLE;
779 	else
780 		val &= ~AM65_CPSW_PN_IET_MAC_PENABLE;
781 
782 	writel(val, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
783 }
784 
785 static int am65_cpsw_get_mm(struct net_device *ndev, struct ethtool_mm_state *state)
786 {
787 	struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
788 	struct am65_cpsw_ndev_priv *priv = netdev_priv(ndev);
789 	u32 port_ctrl, iet_ctrl, iet_status;
790 	u32 add_frag_size;
791 
792 	if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_QOS))
793 		return -EOPNOTSUPP;
794 
795 	mutex_lock(&priv->mm_lock);
796 
797 	iet_ctrl = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
798 	port_ctrl = readl(port->port_base + AM65_CPSW_PN_REG_CTL);
799 
800 	state->tx_enabled = !!(iet_ctrl & AM65_CPSW_PN_IET_MAC_PENABLE);
801 	state->pmac_enabled = !!(port_ctrl & AM65_CPSW_PN_CTL_IET_PORT_EN);
802 
803 	iet_status = readl(port->port_base + AM65_CPSW_PN_REG_IET_STATUS);
804 
805 	if (iet_ctrl & AM65_CPSW_PN_IET_MAC_DISABLEVERIFY)
806 		state->verify_status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
807 	else if (iet_status & AM65_CPSW_PN_MAC_VERIFIED)
808 		state->verify_status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;
809 	else if (iet_status & AM65_CPSW_PN_MAC_VERIFY_FAIL)
810 		state->verify_status = ETHTOOL_MM_VERIFY_STATUS_FAILED;
811 	else
812 		state->verify_status = ETHTOOL_MM_VERIFY_STATUS_UNKNOWN;
813 
814 	add_frag_size = AM65_CPSW_PN_IET_MAC_GET_ADDFRAGSIZE(iet_ctrl);
815 	state->tx_min_frag_size = ethtool_mm_frag_size_add_to_min(add_frag_size);
816 
817 	/* Errata i2208: RX min fragment size cannot be less than 124 */
818 	state->rx_min_frag_size = 124;
819 
820 	/* FPE active if common tx_enabled and verification success or disabled (forced) */
821 	state->tx_active = state->tx_enabled &&
822 			   (state->verify_status == ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED ||
823 			    state->verify_status == ETHTOOL_MM_VERIFY_STATUS_DISABLED);
824 	state->verify_enabled = !(iet_ctrl & AM65_CPSW_PN_IET_MAC_DISABLEVERIFY);
825 
826 	state->verify_time = port->qos.iet.verify_time_ms;
827 
828 	/* 802.3-2018 clause 30.14.1.6, says that the aMACMergeVerifyTime
829 	 * variable has a range between 1 and 128 ms inclusive. Limit to that.
830 	 */
831 	state->max_verify_time = 128;
832 
833 	mutex_unlock(&priv->mm_lock);
834 
835 	return 0;
836 }
837 
838 static int am65_cpsw_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg,
839 			    struct netlink_ext_ack *extack)
840 {
841 	struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
842 	struct am65_cpsw_ndev_priv *priv = netdev_priv(ndev);
843 	struct am65_cpsw_iet *iet = &port->qos.iet;
844 	u32 val, add_frag_size;
845 	int err;
846 
847 	if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_QOS))
848 		return -EOPNOTSUPP;
849 
850 	err = ethtool_mm_frag_size_min_to_add(cfg->tx_min_frag_size, &add_frag_size, extack);
851 	if (err)
852 		return err;
853 
854 	mutex_lock(&priv->mm_lock);
855 
856 	if (cfg->pmac_enabled) {
857 		/* change TX & RX FIFO MAX_BLKS as per TRM recommendation */
858 		if (!iet->original_max_blks)
859 			iet->original_max_blks = readl(port->port_base + AM65_CPSW_PN_REG_MAX_BLKS);
860 
861 		writel(AM65_CPSW_PN_TX_RX_MAX_BLKS_IET,
862 		       port->port_base + AM65_CPSW_PN_REG_MAX_BLKS);
863 	} else if (iet->original_max_blks) {
864 		/* restore RX & TX FIFO MAX_BLKS */
865 		writel(iet->original_max_blks,
866 		       port->port_base + AM65_CPSW_PN_REG_MAX_BLKS);
867 	}
868 
869 	am65_cpsw_port_iet_rx_enable(port, cfg->pmac_enabled);
870 	am65_cpsw_port_iet_tx_enable(port, cfg->tx_enabled);
871 
872 	val = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
873 	if (cfg->verify_enabled) {
874 		val &= ~AM65_CPSW_PN_IET_MAC_DISABLEVERIFY;
875 		/* Reset Verify state machine. Verification won't start here.
876 		 * Verification will be done once link-up.
877 		 */
878 		val |= AM65_CPSW_PN_IET_MAC_LINKFAIL;
879 	} else {
880 		val |= AM65_CPSW_PN_IET_MAC_DISABLEVERIFY;
881 		/* Clear LINKFAIL to allow verify/response packets */
882 		val &= ~AM65_CPSW_PN_IET_MAC_LINKFAIL;
883 	}
884 
885 	val &= ~AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_MASK;
886 	val |= AM65_CPSW_PN_IET_MAC_SET_ADDFRAGSIZE(add_frag_size);
887 	writel(val, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
888 
889 	/* verify_timeout_count can only be set at valid link */
890 	port->qos.iet.verify_time_ms = cfg->verify_time;
891 
892 	/* enable/disable preemption based on link status */
893 	am65_cpsw_iet_commit_preemptible_tcs(port);
894 
895 	mutex_unlock(&priv->mm_lock);
896 
897 	return 0;
898 }
899 
900 static void am65_cpsw_get_mm_stats(struct net_device *ndev,
901 				   struct ethtool_mm_stats *s)
902 {
903 	struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
904 	void __iomem *base = port->stat_base;
905 
906 	s->MACMergeFrameAssOkCount = readl(base + AM65_CPSW_STATN_IET_RX_ASSEMBLY_OK);
907 	s->MACMergeFrameAssErrorCount = readl(base + AM65_CPSW_STATN_IET_RX_ASSEMBLY_ERROR);
908 	s->MACMergeFrameSmdErrorCount = readl(base + AM65_CPSW_STATN_IET_RX_SMD_ERROR);
909 	/* CPSW Functional Spec states:
910 	 * "The IET stat aMACMergeFragCountRx is derived by adding the
911 	 *  Receive Assembly Error count to this value. i.e. AM65_CPSW_STATN_IET_RX_FRAG"
912 	 */
913 	s->MACMergeFragCountRx = readl(base + AM65_CPSW_STATN_IET_RX_FRAG) + s->MACMergeFrameAssErrorCount;
914 	s->MACMergeFragCountTx = readl(base + AM65_CPSW_STATN_IET_TX_FRAG);
915 	s->MACMergeHoldCount = readl(base + AM65_CPSW_STATN_IET_TX_HOLD);
916 }
917 
918 static int am65_cpsw_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal,
919 				  struct kernel_ethtool_coalesce *kernel_coal,
920 				  struct netlink_ext_ack *extack)
921 {
922 	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
923 	struct am65_cpsw_tx_chn *tx_chn;
924 
925 	tx_chn = &common->tx_chns[0];
926 
927 	coal->rx_coalesce_usecs = common->rx_pace_timeout / 1000;
928 	coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout / 1000;
929 
930 	return 0;
931 }
932 
933 static int am65_cpsw_get_per_queue_coalesce(struct net_device *ndev, u32 queue,
934 					    struct ethtool_coalesce *coal)
935 {
936 	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
937 	struct am65_cpsw_tx_chn *tx_chn;
938 
939 	if (queue >= AM65_CPSW_MAX_TX_QUEUES)
940 		return -EINVAL;
941 
942 	tx_chn = &common->tx_chns[queue];
943 
944 	coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout / 1000;
945 
946 	return 0;
947 }
948 
949 static int am65_cpsw_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal,
950 				  struct kernel_ethtool_coalesce *kernel_coal,
951 				  struct netlink_ext_ack *extack)
952 {
953 	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
954 	struct am65_cpsw_tx_chn *tx_chn;
955 
956 	tx_chn = &common->tx_chns[0];
957 
958 	if (coal->rx_coalesce_usecs && coal->rx_coalesce_usecs < 20)
959 		return -EINVAL;
960 
961 	if (coal->tx_coalesce_usecs && coal->tx_coalesce_usecs < 20)
962 		return -EINVAL;
963 
964 	common->rx_pace_timeout = coal->rx_coalesce_usecs * 1000;
965 	tx_chn->tx_pace_timeout = coal->tx_coalesce_usecs * 1000;
966 
967 	return 0;
968 }
969 
970 static int am65_cpsw_set_per_queue_coalesce(struct net_device *ndev, u32 queue,
971 					    struct ethtool_coalesce *coal)
972 {
973 	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
974 	struct am65_cpsw_tx_chn *tx_chn;
975 
976 	if (queue >= AM65_CPSW_MAX_TX_QUEUES)
977 		return -EINVAL;
978 
979 	tx_chn = &common->tx_chns[queue];
980 
981 	if (coal->tx_coalesce_usecs && coal->tx_coalesce_usecs < 20) {
982 		dev_info(common->dev, "defaulting to min value of 20us for tx-usecs for tx-%u\n",
983 			 queue);
984 		coal->tx_coalesce_usecs = 20;
985 	}
986 
987 	tx_chn->tx_pace_timeout = coal->tx_coalesce_usecs * 1000;
988 
989 	return 0;
990 }
991 
992 const struct ethtool_ops am65_cpsw_ethtool_ops_slave = {
993 	.begin			= am65_cpsw_ethtool_op_begin,
994 	.complete		= am65_cpsw_ethtool_op_complete,
995 	.get_drvinfo		= am65_cpsw_get_drvinfo,
996 	.get_msglevel		= am65_cpsw_get_msglevel,
997 	.set_msglevel		= am65_cpsw_set_msglevel,
998 	.get_channels		= am65_cpsw_get_channels,
999 	.set_channels		= am65_cpsw_set_channels,
1000 	.get_ringparam		= am65_cpsw_get_ringparam,
1001 	.get_regs_len		= am65_cpsw_get_regs_len,
1002 	.get_regs		= am65_cpsw_get_regs,
1003 	.get_sset_count		= am65_cpsw_get_sset_count,
1004 	.get_strings		= am65_cpsw_get_strings,
1005 	.get_ethtool_stats	= am65_cpsw_get_ethtool_stats,
1006 	.get_eth_mac_stats	= am65_cpsw_get_eth_mac_stats,
1007 	.get_ts_info		= am65_cpsw_get_ethtool_ts_info,
1008 	.get_priv_flags		= am65_cpsw_get_ethtool_priv_flags,
1009 	.set_priv_flags		= am65_cpsw_set_ethtool_priv_flags,
1010 	.supported_coalesce_params = ETHTOOL_COALESCE_USECS,
1011 	.get_coalesce           = am65_cpsw_get_coalesce,
1012 	.set_coalesce           = am65_cpsw_set_coalesce,
1013 	.get_per_queue_coalesce = am65_cpsw_get_per_queue_coalesce,
1014 	.set_per_queue_coalesce = am65_cpsw_set_per_queue_coalesce,
1015 
1016 	.get_link		= ethtool_op_get_link,
1017 	.get_link_ksettings	= am65_cpsw_get_link_ksettings,
1018 	.set_link_ksettings	= am65_cpsw_set_link_ksettings,
1019 	.get_pauseparam		= am65_cpsw_get_pauseparam,
1020 	.set_pauseparam		= am65_cpsw_set_pauseparam,
1021 	.get_wol		= am65_cpsw_get_wol,
1022 	.set_wol		= am65_cpsw_set_wol,
1023 	.get_eee		= am65_cpsw_get_eee,
1024 	.set_eee		= am65_cpsw_set_eee,
1025 	.nway_reset		= am65_cpsw_nway_reset,
1026 	.get_mm			= am65_cpsw_get_mm,
1027 	.set_mm			= am65_cpsw_set_mm,
1028 	.get_mm_stats		= am65_cpsw_get_mm_stats,
1029 };
1030