Merge tag 'amlogic-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/khilman...
[linux-2.6-microblaze.git] / drivers / net / ethernet / ti / am65-cpsw-ethtool.c
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/phy.h>
10 #include <linux/platform_device.h>
11 #include <linux/pm_runtime.h>
12
13 #include "am65-cpsw-nuss.h"
14 #include "cpsw_ale.h"
15 #include "am65-cpts.h"
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), \
64         .hdr.len = (((u32 *)(end)) - ((u32 *)(start)) + 1) * sizeof(u32) * 2 + \
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
383         ret = pm_runtime_get_sync(common->dev);
384         if (ret < 0) {
385                 dev_err(common->dev, "ethtool begin failed %d\n", ret);
386                 pm_runtime_put_noidle(common->dev);
387         }
388
389         return ret;
390 }
391
392 static void am65_cpsw_ethtool_op_complete(struct net_device *ndev)
393 {
394         struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
395         int ret;
396
397         ret = pm_runtime_put(common->dev);
398         if (ret < 0 && ret != -EBUSY)
399                 dev_err(common->dev, "ethtool complete failed %d\n", ret);
400 }
401
402 static void am65_cpsw_get_drvinfo(struct net_device *ndev,
403                                   struct ethtool_drvinfo *info)
404 {
405         struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
406
407         strlcpy(info->driver, dev_driver_string(common->dev),
408                 sizeof(info->driver));
409         strlcpy(info->bus_info, dev_name(common->dev), sizeof(info->bus_info));
410 }
411
412 static u32 am65_cpsw_get_msglevel(struct net_device *ndev)
413 {
414         struct am65_cpsw_ndev_priv *priv = am65_ndev_to_priv(ndev);
415
416         return priv->msg_enable;
417 }
418
419 static void am65_cpsw_set_msglevel(struct net_device *ndev, u32 value)
420 {
421         struct am65_cpsw_ndev_priv *priv = am65_ndev_to_priv(ndev);
422
423         priv->msg_enable = value;
424 }
425
426 static void am65_cpsw_get_channels(struct net_device *ndev,
427                                    struct ethtool_channels *ch)
428 {
429         struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
430
431         ch->max_rx = AM65_CPSW_MAX_RX_QUEUES;
432         ch->max_tx = AM65_CPSW_MAX_TX_QUEUES;
433         ch->rx_count = AM65_CPSW_MAX_RX_QUEUES;
434         ch->tx_count = common->tx_ch_num;
435 }
436
437 static int am65_cpsw_set_channels(struct net_device *ndev,
438                                   struct ethtool_channels *chs)
439 {
440         struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
441
442         if (!chs->rx_count || !chs->tx_count)
443                 return -EINVAL;
444
445         /* Check if interface is up. Can change the num queues when
446          * the interface is down.
447          */
448         if (common->usage_count)
449                 return -EBUSY;
450
451         am65_cpsw_nuss_remove_tx_chns(common);
452
453         return am65_cpsw_nuss_update_tx_chns(common, chs->tx_count);
454 }
455
456 static void am65_cpsw_get_ringparam(struct net_device *ndev,
457                                     struct ethtool_ringparam *ering)
458 {
459         struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
460
461         /* not supported */
462         ering->tx_pending = common->tx_chns[0].descs_num;
463         ering->rx_pending = common->rx_chns.descs_num;
464 }
465
466 static void am65_cpsw_get_pauseparam(struct net_device *ndev,
467                                      struct ethtool_pauseparam *pause)
468 {
469         struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
470
471         pause->autoneg = AUTONEG_DISABLE;
472         pause->rx_pause = salve->rx_pause ? true : false;
473         pause->tx_pause = salve->tx_pause ? true : false;
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         if (!salve->phy)
482                 return -EINVAL;
483
484         if (!phy_validate_pause(salve->phy, pause))
485                 return -EINVAL;
486
487         salve->rx_pause = pause->rx_pause ? true : false;
488         salve->tx_pause = pause->tx_pause ? true : false;
489
490         phy_set_asym_pause(salve->phy, salve->rx_pause, salve->tx_pause);
491
492         return 0;
493 }
494
495 static void am65_cpsw_get_wol(struct net_device *ndev,
496                               struct ethtool_wolinfo *wol)
497 {
498         struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
499
500         wol->supported = 0;
501         wol->wolopts = 0;
502
503         if (salve->phy)
504                 phy_ethtool_get_wol(salve->phy, wol);
505 }
506
507 static int am65_cpsw_set_wol(struct net_device *ndev,
508                              struct ethtool_wolinfo *wol)
509 {
510         struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
511
512         if (!salve->phy)
513                 return -EOPNOTSUPP;
514
515         return phy_ethtool_set_wol(salve->phy, wol);
516 }
517
518 static int am65_cpsw_get_link_ksettings(struct net_device *ndev,
519                                         struct ethtool_link_ksettings *ecmd)
520 {
521         struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
522
523         if (!salve->phy)
524                 return -EOPNOTSUPP;
525
526         phy_ethtool_ksettings_get(salve->phy, ecmd);
527         return 0;
528 }
529
530 static int
531 am65_cpsw_set_link_ksettings(struct net_device *ndev,
532                              const struct ethtool_link_ksettings *ecmd)
533 {
534         struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
535
536         if (!salve->phy || phy_is_pseudo_fixed_link(salve->phy))
537                 return -EOPNOTSUPP;
538
539         return phy_ethtool_ksettings_set(salve->phy, ecmd);
540 }
541
542 static int am65_cpsw_get_eee(struct net_device *ndev, struct ethtool_eee *edata)
543 {
544         struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
545
546         if (!salve->phy || phy_is_pseudo_fixed_link(salve->phy))
547                 return -EOPNOTSUPP;
548
549         return phy_ethtool_get_eee(salve->phy, edata);
550 }
551
552 static int am65_cpsw_set_eee(struct net_device *ndev, struct ethtool_eee *edata)
553 {
554         struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
555
556         if (!salve->phy || phy_is_pseudo_fixed_link(salve->phy))
557                 return -EOPNOTSUPP;
558
559         return phy_ethtool_set_eee(salve->phy, edata);
560 }
561
562 static int am65_cpsw_nway_reset(struct net_device *ndev)
563 {
564         struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
565
566         if (!salve->phy || phy_is_pseudo_fixed_link(salve->phy))
567                 return -EOPNOTSUPP;
568
569         return phy_restart_aneg(salve->phy);
570 }
571
572 static int am65_cpsw_get_regs_len(struct net_device *ndev)
573 {
574         struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
575         u32 ale_entries, i, regdump_len = 0;
576
577         ale_entries = cpsw_ale_get_num_entries(common->ale);
578         for (i = 0; i < ARRAY_SIZE(am65_cpsw_regdump); i++) {
579                 if (am65_cpsw_regdump[i].hdr.module_id ==
580                     AM65_CPSW_REGDUMP_MOD_CPSW_ALE_TBL) {
581                         regdump_len += sizeof(struct am65_cpsw_regdump_hdr);
582                         regdump_len += ale_entries *
583                                        ALE_ENTRY_WORDS * sizeof(u32);
584                         continue;
585                 }
586                 regdump_len += am65_cpsw_regdump[i].hdr.len;
587         }
588
589         return regdump_len;
590 }
591
592 static void am65_cpsw_get_regs(struct net_device *ndev,
593                                struct ethtool_regs *regs, void *p)
594 {
595         struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
596         u32 ale_entries, i, j, pos, *reg = p;
597
598         /* update CPSW IP version */
599         regs->version = AM65_CPSW_REGDUMP_VER;
600         ale_entries = cpsw_ale_get_num_entries(common->ale);
601
602         pos = 0;
603         for (i = 0; i < ARRAY_SIZE(am65_cpsw_regdump); i++) {
604                 reg[pos++] = am65_cpsw_regdump[i].hdr.module_id;
605
606                 if (am65_cpsw_regdump[i].hdr.module_id ==
607                     AM65_CPSW_REGDUMP_MOD_CPSW_ALE_TBL) {
608                         u32 ale_tbl_len = ale_entries *
609                                           ALE_ENTRY_WORDS * sizeof(u32) +
610                                           sizeof(struct am65_cpsw_regdump_hdr);
611                         reg[pos++] = ale_tbl_len;
612                         cpsw_ale_dump(common->ale, &reg[pos]);
613                         pos += ale_tbl_len;
614                         continue;
615                 }
616
617                 reg[pos++] = am65_cpsw_regdump[i].hdr.len;
618
619                 j = am65_cpsw_regdump[i].start_ofs;
620                 do {
621                         reg[pos++] = j;
622                         reg[pos++] = readl_relaxed(common->ss_base + j);
623                         j += sizeof(u32);
624                 } while (j <= am65_cpsw_regdump[i].end_ofs);
625         }
626 }
627
628 static int am65_cpsw_get_sset_count(struct net_device *ndev, int sset)
629 {
630         switch (sset) {
631         case ETH_SS_STATS:
632                 return ARRAY_SIZE(am65_host_stats) +
633                        ARRAY_SIZE(am65_slave_stats);
634         case ETH_SS_PRIV_FLAGS:
635                 return ARRAY_SIZE(am65_cpsw_ethtool_priv_flags);
636         default:
637                 return -EOPNOTSUPP;
638         }
639 }
640
641 static void am65_cpsw_get_strings(struct net_device *ndev,
642                                   u32 stringset, u8 *data)
643 {
644         const struct am65_cpsw_ethtool_stat *hw_stats;
645         u32 i, num_stats;
646         u8 *p = data;
647
648         switch (stringset) {
649         case ETH_SS_STATS:
650                 num_stats = ARRAY_SIZE(am65_host_stats);
651                 hw_stats = am65_host_stats;
652                 for (i = 0; i < num_stats; i++) {
653                         memcpy(p, hw_stats[i].desc, ETH_GSTRING_LEN);
654                         p += ETH_GSTRING_LEN;
655                 }
656
657                 num_stats = ARRAY_SIZE(am65_slave_stats);
658                 hw_stats = am65_slave_stats;
659                 for (i = 0; i < num_stats; i++) {
660                         memcpy(p, hw_stats[i].desc, ETH_GSTRING_LEN);
661                         p += ETH_GSTRING_LEN;
662                 }
663                 break;
664         case ETH_SS_PRIV_FLAGS:
665                 num_stats = ARRAY_SIZE(am65_cpsw_ethtool_priv_flags);
666
667                 for (i = 0; i < num_stats; i++) {
668                         memcpy(p, am65_cpsw_ethtool_priv_flags[i],
669                                ETH_GSTRING_LEN);
670                         p += ETH_GSTRING_LEN;
671                 }
672                 break;
673         }
674 }
675
676 static void am65_cpsw_get_ethtool_stats(struct net_device *ndev,
677                                         struct ethtool_stats *stats, u64 *data)
678 {
679         struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
680         const struct am65_cpsw_ethtool_stat *hw_stats;
681         struct am65_cpsw_host *host_p;
682         struct am65_cpsw_port *port;
683         u32 i, num_stats;
684
685         host_p = am65_common_get_host(common);
686         port = am65_ndev_to_port(ndev);
687         num_stats = ARRAY_SIZE(am65_host_stats);
688         hw_stats = am65_host_stats;
689         for (i = 0; i < num_stats; i++)
690                 *data++ = readl_relaxed(host_p->stat_base +
691                                         hw_stats[i].offset);
692
693         num_stats = ARRAY_SIZE(am65_slave_stats);
694         hw_stats = am65_slave_stats;
695         for (i = 0; i < num_stats; i++)
696                 *data++ = readl_relaxed(port->stat_base +
697                                         hw_stats[i].offset);
698 }
699
700 static int am65_cpsw_get_ethtool_ts_info(struct net_device *ndev,
701                                          struct ethtool_ts_info *info)
702 {
703         struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
704
705         if (!IS_ENABLED(CONFIG_TI_K3_AM65_CPTS))
706                 return ethtool_op_get_ts_info(ndev, info);
707
708         info->so_timestamping =
709                 SOF_TIMESTAMPING_TX_HARDWARE |
710                 SOF_TIMESTAMPING_TX_SOFTWARE |
711                 SOF_TIMESTAMPING_RX_HARDWARE |
712                 SOF_TIMESTAMPING_RX_SOFTWARE |
713                 SOF_TIMESTAMPING_SOFTWARE |
714                 SOF_TIMESTAMPING_RAW_HARDWARE;
715         info->phc_index = am65_cpts_phc_index(common->cpts);
716         info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
717         info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);
718         return 0;
719 }
720
721 static u32 am65_cpsw_get_ethtool_priv_flags(struct net_device *ndev)
722 {
723         struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
724         u32 priv_flags = 0;
725
726         if (common->pf_p0_rx_ptype_rrobin)
727                 priv_flags |= AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN;
728
729         return priv_flags;
730 }
731
732 static int am65_cpsw_set_ethtool_priv_flags(struct net_device *ndev, u32 flags)
733 {
734         struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
735         int rrobin;
736
737         rrobin = !!(flags & AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN);
738
739         if (common->usage_count)
740                 return -EBUSY;
741
742         if (common->est_enabled && rrobin) {
743                 netdev_err(ndev,
744                            "p0-rx-ptype-rrobin flag conflicts with QOS\n");
745                 return -EINVAL;
746         }
747
748         common->pf_p0_rx_ptype_rrobin = rrobin;
749
750         return 0;
751 }
752
753 const struct ethtool_ops am65_cpsw_ethtool_ops_slave = {
754         .begin                  = am65_cpsw_ethtool_op_begin,
755         .complete               = am65_cpsw_ethtool_op_complete,
756         .get_drvinfo            = am65_cpsw_get_drvinfo,
757         .get_msglevel           = am65_cpsw_get_msglevel,
758         .set_msglevel           = am65_cpsw_set_msglevel,
759         .get_channels           = am65_cpsw_get_channels,
760         .set_channels           = am65_cpsw_set_channels,
761         .get_ringparam          = am65_cpsw_get_ringparam,
762         .get_regs_len           = am65_cpsw_get_regs_len,
763         .get_regs               = am65_cpsw_get_regs,
764         .get_sset_count         = am65_cpsw_get_sset_count,
765         .get_strings            = am65_cpsw_get_strings,
766         .get_ethtool_stats      = am65_cpsw_get_ethtool_stats,
767         .get_ts_info            = am65_cpsw_get_ethtool_ts_info,
768         .get_priv_flags         = am65_cpsw_get_ethtool_priv_flags,
769         .set_priv_flags         = am65_cpsw_set_ethtool_priv_flags,
770
771         .get_link               = ethtool_op_get_link,
772         .get_link_ksettings     = am65_cpsw_get_link_ksettings,
773         .set_link_ksettings     = am65_cpsw_set_link_ksettings,
774         .get_pauseparam         = am65_cpsw_get_pauseparam,
775         .set_pauseparam         = am65_cpsw_set_pauseparam,
776         .get_wol                = am65_cpsw_get_wol,
777         .set_wol                = am65_cpsw_set_wol,
778         .get_eee                = am65_cpsw_get_eee,
779         .set_eee                = am65_cpsw_set_eee,
780         .nway_reset             = am65_cpsw_nway_reset,
781 };