GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / net / ethernet / marvell / prestera / prestera_ethtool.c
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved */
3
4 #include <linux/ethtool.h>
5 #include <linux/kernel.h>
6 #include <linux/netdevice.h>
7
8 #include "prestera_ethtool.h"
9 #include "prestera.h"
10 #include "prestera_hw.h"
11
12 #define PRESTERA_STATS_CNT \
13         (sizeof(struct prestera_port_stats) / sizeof(u64))
14 #define PRESTERA_STATS_IDX(name) \
15         (offsetof(struct prestera_port_stats, name) / sizeof(u64))
16 #define PRESTERA_STATS_FIELD(name)      \
17         [PRESTERA_STATS_IDX(name)] = __stringify(name)
18
19 static const char driver_kind[] = "prestera";
20
21 static const struct prestera_link_mode {
22         enum ethtool_link_mode_bit_indices eth_mode;
23         u32 speed;
24         u64 pr_mask;
25         u8 duplex;
26         u8 port_type;
27 } port_link_modes[PRESTERA_LINK_MODE_MAX] = {
28         [PRESTERA_LINK_MODE_10baseT_Half] = {
29                 .eth_mode =  ETHTOOL_LINK_MODE_10baseT_Half_BIT,
30                 .speed = 10,
31                 .pr_mask = 1 << PRESTERA_LINK_MODE_10baseT_Half,
32                 .duplex = PRESTERA_PORT_DUPLEX_HALF,
33                 .port_type = PRESTERA_PORT_TYPE_TP,
34         },
35         [PRESTERA_LINK_MODE_10baseT_Full] = {
36                 .eth_mode =  ETHTOOL_LINK_MODE_10baseT_Full_BIT,
37                 .speed = 10,
38                 .pr_mask = 1 << PRESTERA_LINK_MODE_10baseT_Full,
39                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
40                 .port_type = PRESTERA_PORT_TYPE_TP,
41         },
42         [PRESTERA_LINK_MODE_100baseT_Half] = {
43                 .eth_mode =  ETHTOOL_LINK_MODE_100baseT_Half_BIT,
44                 .speed = 100,
45                 .pr_mask = 1 << PRESTERA_LINK_MODE_100baseT_Half,
46                 .duplex = PRESTERA_PORT_DUPLEX_HALF,
47                 .port_type = PRESTERA_PORT_TYPE_TP,
48         },
49         [PRESTERA_LINK_MODE_100baseT_Full] = {
50                 .eth_mode =  ETHTOOL_LINK_MODE_100baseT_Full_BIT,
51                 .speed = 100,
52                 .pr_mask = 1 << PRESTERA_LINK_MODE_100baseT_Full,
53                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
54                 .port_type = PRESTERA_PORT_TYPE_TP,
55         },
56         [PRESTERA_LINK_MODE_1000baseT_Half] = {
57                 .eth_mode =  ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
58                 .speed = 1000,
59                 .pr_mask = 1 << PRESTERA_LINK_MODE_1000baseT_Half,
60                 .duplex = PRESTERA_PORT_DUPLEX_HALF,
61                 .port_type = PRESTERA_PORT_TYPE_TP,
62         },
63         [PRESTERA_LINK_MODE_1000baseT_Full] = {
64                 .eth_mode =  ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
65                 .speed = 1000,
66                 .pr_mask = 1 << PRESTERA_LINK_MODE_1000baseT_Full,
67                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
68                 .port_type = PRESTERA_PORT_TYPE_TP,
69         },
70         [PRESTERA_LINK_MODE_1000baseX_Full] = {
71                 .eth_mode = ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
72                 .speed = 1000,
73                 .pr_mask = 1 << PRESTERA_LINK_MODE_1000baseX_Full,
74                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
75                 .port_type = PRESTERA_PORT_TYPE_FIBRE,
76         },
77         [PRESTERA_LINK_MODE_1000baseKX_Full] = {
78                 .eth_mode = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
79                 .speed = 1000,
80                 .pr_mask = 1 << PRESTERA_LINK_MODE_1000baseKX_Full,
81                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
82                 .port_type = PRESTERA_PORT_TYPE_TP,
83         },
84         [PRESTERA_LINK_MODE_2500baseX_Full] = {
85                 .eth_mode =  ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
86                 .speed = 2500,
87                 .pr_mask = 1 << PRESTERA_LINK_MODE_2500baseX_Full,
88                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
89         },
90         [PRESTERA_LINK_MODE_10GbaseKR_Full] = {
91                 .eth_mode = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
92                 .speed = 10000,
93                 .pr_mask = 1 << PRESTERA_LINK_MODE_10GbaseKR_Full,
94                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
95                 .port_type = PRESTERA_PORT_TYPE_TP,
96         },
97         [PRESTERA_LINK_MODE_10GbaseSR_Full] = {
98                 .eth_mode = ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
99                 .speed = 10000,
100                 .pr_mask = 1 << PRESTERA_LINK_MODE_10GbaseSR_Full,
101                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
102                 .port_type = PRESTERA_PORT_TYPE_FIBRE,
103         },
104         [PRESTERA_LINK_MODE_10GbaseLR_Full] = {
105                 .eth_mode = ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
106                 .speed = 10000,
107                 .pr_mask = 1 << PRESTERA_LINK_MODE_10GbaseLR_Full,
108                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
109                 .port_type = PRESTERA_PORT_TYPE_FIBRE,
110         },
111         [PRESTERA_LINK_MODE_20GbaseKR2_Full] = {
112                 .eth_mode = ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
113                 .speed = 20000,
114                 .pr_mask = 1 << PRESTERA_LINK_MODE_20GbaseKR2_Full,
115                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
116                 .port_type = PRESTERA_PORT_TYPE_TP,
117         },
118         [PRESTERA_LINK_MODE_25GbaseCR_Full] = {
119                 .eth_mode = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
120                 .speed = 25000,
121                 .pr_mask = 1 << PRESTERA_LINK_MODE_25GbaseCR_Full,
122                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
123                 .port_type = PRESTERA_PORT_TYPE_DA,
124         },
125         [PRESTERA_LINK_MODE_25GbaseKR_Full] = {
126                 .eth_mode = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
127                 .speed = 25000,
128                 .pr_mask = 1 << PRESTERA_LINK_MODE_25GbaseKR_Full,
129                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
130                 .port_type = PRESTERA_PORT_TYPE_TP,
131         },
132         [PRESTERA_LINK_MODE_25GbaseSR_Full] = {
133                 .eth_mode = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
134                 .speed = 25000,
135                 .pr_mask = 1 << PRESTERA_LINK_MODE_25GbaseSR_Full,
136                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
137                 .port_type = PRESTERA_PORT_TYPE_FIBRE,
138         },
139         [PRESTERA_LINK_MODE_40GbaseKR4_Full] = {
140                 .eth_mode = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
141                 .speed = 40000,
142                 .pr_mask = 1 << PRESTERA_LINK_MODE_40GbaseKR4_Full,
143                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
144                 .port_type = PRESTERA_PORT_TYPE_TP,
145         },
146         [PRESTERA_LINK_MODE_40GbaseCR4_Full] = {
147                 .eth_mode = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
148                 .speed = 40000,
149                 .pr_mask = 1 << PRESTERA_LINK_MODE_40GbaseCR4_Full,
150                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
151                 .port_type = PRESTERA_PORT_TYPE_DA,
152         },
153         [PRESTERA_LINK_MODE_40GbaseSR4_Full] = {
154                 .eth_mode = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
155                 .speed = 40000,
156                 .pr_mask = 1 << PRESTERA_LINK_MODE_40GbaseSR4_Full,
157                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
158                 .port_type = PRESTERA_PORT_TYPE_FIBRE,
159         },
160         [PRESTERA_LINK_MODE_50GbaseCR2_Full] = {
161                 .eth_mode = ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
162                 .speed = 50000,
163                 .pr_mask = 1 << PRESTERA_LINK_MODE_50GbaseCR2_Full,
164                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
165                 .port_type = PRESTERA_PORT_TYPE_DA,
166         },
167         [PRESTERA_LINK_MODE_50GbaseKR2_Full] = {
168                 .eth_mode = ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
169                 .speed = 50000,
170                 .pr_mask = 1 << PRESTERA_LINK_MODE_50GbaseKR2_Full,
171                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
172                 .port_type = PRESTERA_PORT_TYPE_TP,
173         },
174         [PRESTERA_LINK_MODE_50GbaseSR2_Full] = {
175                 .eth_mode = ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
176                 .speed = 50000,
177                 .pr_mask = 1 << PRESTERA_LINK_MODE_50GbaseSR2_Full,
178                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
179                 .port_type = PRESTERA_PORT_TYPE_FIBRE,
180         },
181         [PRESTERA_LINK_MODE_100GbaseKR4_Full] = {
182                 .eth_mode = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
183                 .speed = 100000,
184                 .pr_mask = 1 << PRESTERA_LINK_MODE_100GbaseKR4_Full,
185                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
186                 .port_type = PRESTERA_PORT_TYPE_TP,
187         },
188         [PRESTERA_LINK_MODE_100GbaseSR4_Full] = {
189                 .eth_mode = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
190                 .speed = 100000,
191                 .pr_mask = 1 << PRESTERA_LINK_MODE_100GbaseSR4_Full,
192                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
193                 .port_type = PRESTERA_PORT_TYPE_FIBRE,
194         },
195         [PRESTERA_LINK_MODE_100GbaseCR4_Full] = {
196                 .eth_mode = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
197                 .speed = 100000,
198                 .pr_mask = 1 << PRESTERA_LINK_MODE_100GbaseCR4_Full,
199                 .duplex = PRESTERA_PORT_DUPLEX_FULL,
200                 .port_type = PRESTERA_PORT_TYPE_DA,
201         }
202 };
203
204 static const struct prestera_fec {
205         u32 eth_fec;
206         enum ethtool_link_mode_bit_indices eth_mode;
207         u8 pr_fec;
208 } port_fec_caps[PRESTERA_PORT_FEC_MAX] = {
209         [PRESTERA_PORT_FEC_OFF] = {
210                 .eth_fec = ETHTOOL_FEC_OFF,
211                 .eth_mode = ETHTOOL_LINK_MODE_FEC_NONE_BIT,
212                 .pr_fec = 1 << PRESTERA_PORT_FEC_OFF,
213         },
214         [PRESTERA_PORT_FEC_BASER] = {
215                 .eth_fec = ETHTOOL_FEC_BASER,
216                 .eth_mode = ETHTOOL_LINK_MODE_FEC_BASER_BIT,
217                 .pr_fec = 1 << PRESTERA_PORT_FEC_BASER,
218         },
219         [PRESTERA_PORT_FEC_RS] = {
220                 .eth_fec = ETHTOOL_FEC_RS,
221                 .eth_mode = ETHTOOL_LINK_MODE_FEC_RS_BIT,
222                 .pr_fec = 1 << PRESTERA_PORT_FEC_RS,
223         }
224 };
225
226 static const struct prestera_port_type {
227         enum ethtool_link_mode_bit_indices eth_mode;
228         u8 eth_type;
229 } port_types[PRESTERA_PORT_TYPE_MAX] = {
230         [PRESTERA_PORT_TYPE_NONE] = {
231                 .eth_mode = __ETHTOOL_LINK_MODE_MASK_NBITS,
232                 .eth_type = PORT_NONE,
233         },
234         [PRESTERA_PORT_TYPE_TP] = {
235                 .eth_mode = ETHTOOL_LINK_MODE_TP_BIT,
236                 .eth_type = PORT_TP,
237         },
238         [PRESTERA_PORT_TYPE_AUI] = {
239                 .eth_mode = ETHTOOL_LINK_MODE_AUI_BIT,
240                 .eth_type = PORT_AUI,
241         },
242         [PRESTERA_PORT_TYPE_MII] = {
243                 .eth_mode = ETHTOOL_LINK_MODE_MII_BIT,
244                 .eth_type = PORT_MII,
245         },
246         [PRESTERA_PORT_TYPE_FIBRE] = {
247                 .eth_mode = ETHTOOL_LINK_MODE_FIBRE_BIT,
248                 .eth_type = PORT_FIBRE,
249         },
250         [PRESTERA_PORT_TYPE_BNC] = {
251                 .eth_mode = ETHTOOL_LINK_MODE_BNC_BIT,
252                 .eth_type = PORT_BNC,
253         },
254         [PRESTERA_PORT_TYPE_DA] = {
255                 .eth_mode = ETHTOOL_LINK_MODE_TP_BIT,
256                 .eth_type = PORT_TP,
257         },
258         [PRESTERA_PORT_TYPE_OTHER] = {
259                 .eth_mode = __ETHTOOL_LINK_MODE_MASK_NBITS,
260                 .eth_type = PORT_OTHER,
261         }
262 };
263
264 static const char prestera_cnt_name[PRESTERA_STATS_CNT][ETH_GSTRING_LEN] = {
265         PRESTERA_STATS_FIELD(good_octets_received),
266         PRESTERA_STATS_FIELD(bad_octets_received),
267         PRESTERA_STATS_FIELD(mac_trans_error),
268         PRESTERA_STATS_FIELD(broadcast_frames_received),
269         PRESTERA_STATS_FIELD(multicast_frames_received),
270         PRESTERA_STATS_FIELD(frames_64_octets),
271         PRESTERA_STATS_FIELD(frames_65_to_127_octets),
272         PRESTERA_STATS_FIELD(frames_128_to_255_octets),
273         PRESTERA_STATS_FIELD(frames_256_to_511_octets),
274         PRESTERA_STATS_FIELD(frames_512_to_1023_octets),
275         PRESTERA_STATS_FIELD(frames_1024_to_max_octets),
276         PRESTERA_STATS_FIELD(excessive_collision),
277         PRESTERA_STATS_FIELD(multicast_frames_sent),
278         PRESTERA_STATS_FIELD(broadcast_frames_sent),
279         PRESTERA_STATS_FIELD(fc_sent),
280         PRESTERA_STATS_FIELD(fc_received),
281         PRESTERA_STATS_FIELD(buffer_overrun),
282         PRESTERA_STATS_FIELD(undersize),
283         PRESTERA_STATS_FIELD(fragments),
284         PRESTERA_STATS_FIELD(oversize),
285         PRESTERA_STATS_FIELD(jabber),
286         PRESTERA_STATS_FIELD(rx_error_frame_received),
287         PRESTERA_STATS_FIELD(bad_crc),
288         PRESTERA_STATS_FIELD(collisions),
289         PRESTERA_STATS_FIELD(late_collision),
290         PRESTERA_STATS_FIELD(unicast_frames_received),
291         PRESTERA_STATS_FIELD(unicast_frames_sent),
292         PRESTERA_STATS_FIELD(sent_multiple),
293         PRESTERA_STATS_FIELD(sent_deferred),
294         PRESTERA_STATS_FIELD(good_octets_sent),
295 };
296
297 static void prestera_ethtool_get_drvinfo(struct net_device *dev,
298                                          struct ethtool_drvinfo *drvinfo)
299 {
300         struct prestera_port *port = netdev_priv(dev);
301         struct prestera_switch *sw = port->sw;
302
303         strlcpy(drvinfo->driver, driver_kind, sizeof(drvinfo->driver));
304         strlcpy(drvinfo->bus_info, dev_name(prestera_dev(sw)),
305                 sizeof(drvinfo->bus_info));
306         snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
307                  "%d.%d.%d",
308                  sw->dev->fw_rev.maj,
309                  sw->dev->fw_rev.min,
310                  sw->dev->fw_rev.sub);
311 }
312
313 static u8 prestera_port_type_get(struct prestera_port *port)
314 {
315         if (port->caps.type < PRESTERA_PORT_TYPE_MAX)
316                 return port_types[port->caps.type].eth_type;
317
318         return PORT_OTHER;
319 }
320
321 static int prestera_port_type_set(const struct ethtool_link_ksettings *ecmd,
322                                   struct prestera_port *port)
323 {
324         u32 new_mode = PRESTERA_LINK_MODE_MAX;
325         u32 type, mode;
326
327         for (type = 0; type < PRESTERA_PORT_TYPE_MAX; type++) {
328                 if (port_types[type].eth_type == ecmd->base.port &&
329                     test_bit(port_types[type].eth_mode,
330                              ecmd->link_modes.supported)) {
331                         break;
332                 }
333         }
334
335         if (type == port->caps.type)
336                 return 0;
337         if (type != port->caps.type && ecmd->base.autoneg == AUTONEG_ENABLE)
338                 return -EINVAL;
339         if (type == PRESTERA_PORT_TYPE_MAX)
340                 return -EOPNOTSUPP;
341
342         for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
343                 if ((port_link_modes[mode].pr_mask &
344                     port->caps.supp_link_modes) &&
345                     type == port_link_modes[mode].port_type) {
346                         new_mode = mode;
347                 }
348         }
349
350         if (new_mode >= PRESTERA_LINK_MODE_MAX)
351                 return -EINVAL;
352
353         port->caps.type = type;
354         port->autoneg = false;
355
356         return 0;
357 }
358
359 static void prestera_modes_to_eth(unsigned long *eth_modes, u64 link_modes,
360                                   u8 fec, u8 type)
361 {
362         u32 mode;
363
364         for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
365                 if ((port_link_modes[mode].pr_mask & link_modes) == 0)
366                         continue;
367
368                 if (type != PRESTERA_PORT_TYPE_NONE &&
369                     port_link_modes[mode].port_type != type)
370                         continue;
371
372                 __set_bit(port_link_modes[mode].eth_mode, eth_modes);
373         }
374
375         for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) {
376                 if ((port_fec_caps[mode].pr_fec & fec) == 0)
377                         continue;
378
379                 __set_bit(port_fec_caps[mode].eth_mode, eth_modes);
380         }
381 }
382
383 static void prestera_modes_from_eth(const unsigned long *eth_modes,
384                                     u64 *link_modes, u8 *fec, u8 type)
385 {
386         u64 adver_modes = 0;
387         u32 fec_modes = 0;
388         u32 mode;
389
390         for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
391                 if (!test_bit(port_link_modes[mode].eth_mode, eth_modes))
392                         continue;
393
394                 if (port_link_modes[mode].port_type != type)
395                         continue;
396
397                 adver_modes |= port_link_modes[mode].pr_mask;
398         }
399
400         for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) {
401                 if (!test_bit(port_fec_caps[mode].eth_mode, eth_modes))
402                         continue;
403
404                 fec_modes |= port_fec_caps[mode].pr_fec;
405         }
406
407         *link_modes = adver_modes;
408         *fec = fec_modes;
409 }
410
411 static void prestera_port_supp_types_get(struct ethtool_link_ksettings *ecmd,
412                                          struct prestera_port *port)
413 {
414         u32 mode;
415         u8 ptype;
416
417         for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
418                 if ((port_link_modes[mode].pr_mask &
419                     port->caps.supp_link_modes) == 0)
420                         continue;
421
422                 ptype = port_link_modes[mode].port_type;
423                 __set_bit(port_types[ptype].eth_mode,
424                           ecmd->link_modes.supported);
425         }
426 }
427
428 static void prestera_port_remote_cap_get(struct ethtool_link_ksettings *ecmd,
429                                          struct prestera_port *port)
430 {
431         struct prestera_port_phy_state *state = &port->state_phy;
432         bool asym_pause;
433         bool pause;
434         u64 bitmap;
435         int err;
436
437         err = prestera_hw_port_phy_mode_get(port, NULL, &state->lmode_bmap,
438                                             &state->remote_fc.pause,
439                                             &state->remote_fc.asym_pause);
440         if (err)
441                 netdev_warn(port->dev, "Remote link caps get failed %d",
442                             port->caps.transceiver);
443
444         bitmap = state->lmode_bmap;
445
446         prestera_modes_to_eth(ecmd->link_modes.lp_advertising,
447                               bitmap, 0, PRESTERA_PORT_TYPE_NONE);
448
449         if (!bitmap_empty(ecmd->link_modes.lp_advertising,
450                           __ETHTOOL_LINK_MODE_MASK_NBITS)) {
451                 ethtool_link_ksettings_add_link_mode(ecmd,
452                                                      lp_advertising,
453                                                      Autoneg);
454         }
455
456         pause = state->remote_fc.pause;
457         asym_pause = state->remote_fc.asym_pause;
458
459         if (pause)
460                 ethtool_link_ksettings_add_link_mode(ecmd,
461                                                      lp_advertising,
462                                                      Pause);
463         if (asym_pause)
464                 ethtool_link_ksettings_add_link_mode(ecmd,
465                                                      lp_advertising,
466                                                      Asym_Pause);
467 }
468
469 static void prestera_port_link_mode_get(struct ethtool_link_ksettings *ecmd,
470                                         struct prestera_port *port)
471 {
472         struct prestera_port_mac_state *state = &port->state_mac;
473         u32 speed;
474         u8 duplex;
475         int err;
476
477         if (!port->state_mac.oper)
478                 return;
479
480         if (state->speed == SPEED_UNKNOWN || state->duplex == DUPLEX_UNKNOWN) {
481                 err = prestera_hw_port_mac_mode_get(port, NULL, &speed,
482                                                     &duplex, NULL);
483                 if (err) {
484                         state->speed = SPEED_UNKNOWN;
485                         state->duplex = DUPLEX_UNKNOWN;
486                 } else {
487                         state->speed = speed;
488                         state->duplex = duplex == PRESTERA_PORT_DUPLEX_FULL ?
489                                           DUPLEX_FULL : DUPLEX_HALF;
490                 }
491         }
492
493         ecmd->base.speed = port->state_mac.speed;
494         ecmd->base.duplex = port->state_mac.duplex;
495 }
496
497 static void prestera_port_mdix_get(struct ethtool_link_ksettings *ecmd,
498                                    struct prestera_port *port)
499 {
500         struct prestera_port_phy_state *state = &port->state_phy;
501
502         if (prestera_hw_port_phy_mode_get(port,
503                                           &state->mdix, NULL, NULL, NULL)) {
504                 netdev_warn(port->dev, "MDIX params get failed");
505                 state->mdix = ETH_TP_MDI_INVALID;
506         }
507
508         ecmd->base.eth_tp_mdix = port->state_phy.mdix;
509         ecmd->base.eth_tp_mdix_ctrl = port->cfg_phy.mdix;
510 }
511
512 static int
513 prestera_ethtool_get_link_ksettings(struct net_device *dev,
514                                     struct ethtool_link_ksettings *ecmd)
515 {
516         struct prestera_port *port = netdev_priv(dev);
517
518         ethtool_link_ksettings_zero_link_mode(ecmd, supported);
519         ethtool_link_ksettings_zero_link_mode(ecmd, advertising);
520         ethtool_link_ksettings_zero_link_mode(ecmd, lp_advertising);
521         ecmd->base.speed = SPEED_UNKNOWN;
522         ecmd->base.duplex = DUPLEX_UNKNOWN;
523
524         ecmd->base.autoneg = port->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
525
526         if (port->caps.type == PRESTERA_PORT_TYPE_TP) {
527                 ethtool_link_ksettings_add_link_mode(ecmd, supported, Autoneg);
528
529                 if (netif_running(dev) &&
530                     (port->autoneg ||
531                      port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER))
532                         ethtool_link_ksettings_add_link_mode(ecmd, advertising,
533                                                              Autoneg);
534         }
535
536         prestera_modes_to_eth(ecmd->link_modes.supported,
537                               port->caps.supp_link_modes,
538                               port->caps.supp_fec,
539                               port->caps.type);
540
541         prestera_port_supp_types_get(ecmd, port);
542
543         if (netif_carrier_ok(dev))
544                 prestera_port_link_mode_get(ecmd, port);
545
546         ecmd->base.port = prestera_port_type_get(port);
547
548         if (port->autoneg) {
549                 if (netif_running(dev))
550                         prestera_modes_to_eth(ecmd->link_modes.advertising,
551                                               port->adver_link_modes,
552                                               port->adver_fec,
553                                               port->caps.type);
554
555                 if (netif_carrier_ok(dev) &&
556                     port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER)
557                         prestera_port_remote_cap_get(ecmd, port);
558         }
559
560         if (port->caps.type == PRESTERA_PORT_TYPE_TP &&
561             port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER)
562                 prestera_port_mdix_get(ecmd, port);
563
564         return 0;
565 }
566
567 static int prestera_port_mdix_set(const struct ethtool_link_ksettings *ecmd,
568                                   struct prestera_port *port)
569 {
570         if (ecmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_INVALID &&
571             port->caps.transceiver ==  PRESTERA_PORT_TCVR_COPPER &&
572             port->caps.type == PRESTERA_PORT_TYPE_TP) {
573                 port->cfg_phy.mdix = ecmd->base.eth_tp_mdix_ctrl;
574                 return prestera_hw_port_phy_mode_set(port, port->cfg_phy.admin,
575                                                      port->autoneg,
576                                                      port->cfg_phy.mode,
577                                                      port->adver_link_modes,
578                                                      port->cfg_phy.mdix);
579         }
580         return 0;
581
582 }
583
584 static int prestera_port_link_mode_set(struct prestera_port *port,
585                                        u32 speed, u8 duplex, u8 type)
586 {
587         u32 new_mode = PRESTERA_LINK_MODE_MAX;
588         u32 mode;
589         int err;
590
591         for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
592                 if (speed != SPEED_UNKNOWN &&
593                     speed != port_link_modes[mode].speed)
594                         continue;
595
596                 if (duplex != DUPLEX_UNKNOWN &&
597                     duplex != port_link_modes[mode].duplex)
598                         continue;
599
600                 if (!(port_link_modes[mode].pr_mask &
601                     port->caps.supp_link_modes))
602                         continue;
603
604                 if (type != port_link_modes[mode].port_type)
605                         continue;
606
607                 new_mode = mode;
608                 break;
609         }
610
611         if (new_mode == PRESTERA_LINK_MODE_MAX)
612                 return -EOPNOTSUPP;
613
614         err = prestera_hw_port_phy_mode_set(port, port->cfg_phy.admin,
615                                             false, new_mode, 0,
616                                             port->cfg_phy.mdix);
617         if (err)
618                 return err;
619
620         port->adver_fec = BIT(PRESTERA_PORT_FEC_OFF);
621         port->adver_link_modes = 0;
622         port->cfg_phy.mode = new_mode;
623         port->autoneg = false;
624
625         return 0;
626 }
627
628 static int
629 prestera_port_speed_duplex_set(const struct ethtool_link_ksettings *ecmd,
630                                struct prestera_port *port)
631 {
632         u8 duplex = DUPLEX_UNKNOWN;
633
634         if (ecmd->base.duplex != DUPLEX_UNKNOWN)
635                 duplex = ecmd->base.duplex == DUPLEX_FULL ?
636                          PRESTERA_PORT_DUPLEX_FULL : PRESTERA_PORT_DUPLEX_HALF;
637
638         return prestera_port_link_mode_set(port, ecmd->base.speed, duplex,
639                                            port->caps.type);
640 }
641
642 static int
643 prestera_ethtool_set_link_ksettings(struct net_device *dev,
644                                     const struct ethtool_link_ksettings *ecmd)
645 {
646         struct prestera_port *port = netdev_priv(dev);
647         u64 adver_modes;
648         u8 adver_fec;
649         int err;
650
651         err = prestera_port_type_set(ecmd, port);
652         if (err)
653                 return err;
654
655         if (port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER) {
656                 err = prestera_port_mdix_set(ecmd, port);
657                 if (err)
658                         return err;
659         }
660
661         prestera_modes_from_eth(ecmd->link_modes.advertising, &adver_modes,
662                                 &adver_fec, port->caps.type);
663
664         if (ecmd->base.autoneg == AUTONEG_ENABLE)
665                 err = prestera_port_autoneg_set(port, adver_modes);
666         else
667                 err = prestera_port_speed_duplex_set(ecmd, port);
668
669         return err;
670 }
671
672 static int prestera_ethtool_get_fecparam(struct net_device *dev,
673                                          struct ethtool_fecparam *fecparam)
674 {
675         struct prestera_port *port = netdev_priv(dev);
676         u8 active;
677         u32 mode;
678         int err;
679
680         err = prestera_hw_port_mac_mode_get(port, NULL, NULL, NULL, &active);
681         if (err)
682                 return err;
683
684         fecparam->fec = 0;
685
686         for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) {
687                 if ((port_fec_caps[mode].pr_fec & port->caps.supp_fec) == 0)
688                         continue;
689
690                 fecparam->fec |= port_fec_caps[mode].eth_fec;
691         }
692
693         if (active < PRESTERA_PORT_FEC_MAX)
694                 fecparam->active_fec = port_fec_caps[active].eth_fec;
695         else
696                 fecparam->active_fec = ETHTOOL_FEC_AUTO;
697
698         return 0;
699 }
700
701 static int prestera_ethtool_set_fecparam(struct net_device *dev,
702                                          struct ethtool_fecparam *fecparam)
703 {
704         struct prestera_port *port = netdev_priv(dev);
705         struct prestera_port_mac_config cfg_mac;
706         u32 mode;
707         u8 fec;
708
709         if (port->autoneg) {
710                 netdev_err(dev, "FEC set is not allowed while autoneg is on\n");
711                 return -EINVAL;
712         }
713
714         if (port->caps.transceiver == PRESTERA_PORT_TCVR_SFP) {
715                 netdev_err(dev, "FEC set is not allowed on non-SFP ports\n");
716                 return -EINVAL;
717         }
718
719         fec = PRESTERA_PORT_FEC_MAX;
720         for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) {
721                 if ((port_fec_caps[mode].eth_fec & fecparam->fec) &&
722                     (port_fec_caps[mode].pr_fec & port->caps.supp_fec)) {
723                         fec = mode;
724                         break;
725                 }
726         }
727
728         prestera_port_cfg_mac_read(port, &cfg_mac);
729
730         if (fec == cfg_mac.fec)
731                 return 0;
732
733         if (fec == PRESTERA_PORT_FEC_MAX) {
734                 netdev_err(dev, "Unsupported FEC requested");
735                 return -EINVAL;
736         }
737
738         cfg_mac.fec = fec;
739
740         return prestera_port_cfg_mac_write(port, &cfg_mac);
741 }
742
743 static int prestera_ethtool_get_sset_count(struct net_device *dev, int sset)
744 {
745         switch (sset) {
746         case ETH_SS_STATS:
747                 return PRESTERA_STATS_CNT;
748         default:
749                 return -EOPNOTSUPP;
750         }
751 }
752
753 static void prestera_ethtool_get_strings(struct net_device *dev,
754                                          u32 stringset, u8 *data)
755 {
756         if (stringset != ETH_SS_STATS)
757                 return;
758
759         memcpy(data, prestera_cnt_name, sizeof(prestera_cnt_name));
760 }
761
762 static void prestera_ethtool_get_stats(struct net_device *dev,
763                                        struct ethtool_stats *stats, u64 *data)
764 {
765         struct prestera_port *port = netdev_priv(dev);
766         struct prestera_port_stats *port_stats;
767
768         port_stats = &port->cached_hw_stats.stats;
769
770         memcpy(data, port_stats, sizeof(*port_stats));
771 }
772
773 static int prestera_ethtool_nway_reset(struct net_device *dev)
774 {
775         struct prestera_port *port = netdev_priv(dev);
776
777         if (netif_running(dev) &&
778             port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER &&
779             port->caps.type == PRESTERA_PORT_TYPE_TP)
780                 return prestera_hw_port_autoneg_restart(port);
781
782         return -EINVAL;
783 }
784
785 void prestera_ethtool_port_state_changed(struct prestera_port *port,
786                                          struct prestera_port_event *evt)
787 {
788         struct prestera_port_mac_state *smac = &port->state_mac;
789
790         smac->oper = evt->data.mac.oper;
791
792         if (smac->oper) {
793                 smac->mode = evt->data.mac.mode;
794                 smac->speed = evt->data.mac.speed;
795                 smac->duplex = evt->data.mac.duplex;
796                 smac->fc = evt->data.mac.fc;
797                 smac->fec = evt->data.mac.fec;
798         } else {
799                 smac->mode = PRESTERA_MAC_MODE_MAX;
800                 smac->speed = SPEED_UNKNOWN;
801                 smac->duplex = DUPLEX_UNKNOWN;
802                 smac->fc = 0;
803                 smac->fec = 0;
804         }
805 }
806
807 const struct ethtool_ops prestera_ethtool_ops = {
808         .get_drvinfo = prestera_ethtool_get_drvinfo,
809         .get_link_ksettings = prestera_ethtool_get_link_ksettings,
810         .set_link_ksettings = prestera_ethtool_set_link_ksettings,
811         .get_fecparam = prestera_ethtool_get_fecparam,
812         .set_fecparam = prestera_ethtool_set_fecparam,
813         .get_sset_count = prestera_ethtool_get_sset_count,
814         .get_strings = prestera_ethtool_get_strings,
815         .get_ethtool_stats = prestera_ethtool_get_stats,
816         .get_link = ethtool_op_get_link,
817         .nway_reset = prestera_ethtool_nway_reset
818 };