1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved */
4 #include <linux/ethtool.h>
5 #include <linux/kernel.h>
6 #include <linux/netdevice.h>
8 #include "prestera_ethtool.h"
10 #include "prestera_hw.h"
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)
19 static const char driver_kind[] = "prestera";
21 static const struct prestera_link_mode {
22 enum ethtool_link_mode_bit_indices eth_mode;
27 } port_link_modes[PRESTERA_LINK_MODE_MAX] = {
28 [PRESTERA_LINK_MODE_10baseT_Half] = {
29 .eth_mode = ETHTOOL_LINK_MODE_10baseT_Half_BIT,
31 .pr_mask = 1 << PRESTERA_LINK_MODE_10baseT_Half,
32 .duplex = PRESTERA_PORT_DUPLEX_HALF,
33 .port_type = PRESTERA_PORT_TYPE_TP,
35 [PRESTERA_LINK_MODE_10baseT_Full] = {
36 .eth_mode = ETHTOOL_LINK_MODE_10baseT_Full_BIT,
38 .pr_mask = 1 << PRESTERA_LINK_MODE_10baseT_Full,
39 .duplex = PRESTERA_PORT_DUPLEX_FULL,
40 .port_type = PRESTERA_PORT_TYPE_TP,
42 [PRESTERA_LINK_MODE_100baseT_Half] = {
43 .eth_mode = ETHTOOL_LINK_MODE_100baseT_Half_BIT,
45 .pr_mask = 1 << PRESTERA_LINK_MODE_100baseT_Half,
46 .duplex = PRESTERA_PORT_DUPLEX_HALF,
47 .port_type = PRESTERA_PORT_TYPE_TP,
49 [PRESTERA_LINK_MODE_100baseT_Full] = {
50 .eth_mode = ETHTOOL_LINK_MODE_100baseT_Full_BIT,
52 .pr_mask = 1 << PRESTERA_LINK_MODE_100baseT_Full,
53 .duplex = PRESTERA_PORT_DUPLEX_FULL,
54 .port_type = PRESTERA_PORT_TYPE_TP,
56 [PRESTERA_LINK_MODE_1000baseT_Half] = {
57 .eth_mode = ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
59 .pr_mask = 1 << PRESTERA_LINK_MODE_1000baseT_Half,
60 .duplex = PRESTERA_PORT_DUPLEX_HALF,
61 .port_type = PRESTERA_PORT_TYPE_TP,
63 [PRESTERA_LINK_MODE_1000baseT_Full] = {
64 .eth_mode = ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
66 .pr_mask = 1 << PRESTERA_LINK_MODE_1000baseT_Full,
67 .duplex = PRESTERA_PORT_DUPLEX_FULL,
68 .port_type = PRESTERA_PORT_TYPE_TP,
70 [PRESTERA_LINK_MODE_1000baseX_Full] = {
71 .eth_mode = ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
73 .pr_mask = 1 << PRESTERA_LINK_MODE_1000baseX_Full,
74 .duplex = PRESTERA_PORT_DUPLEX_FULL,
75 .port_type = PRESTERA_PORT_TYPE_FIBRE,
77 [PRESTERA_LINK_MODE_1000baseKX_Full] = {
78 .eth_mode = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
80 .pr_mask = 1 << PRESTERA_LINK_MODE_1000baseKX_Full,
81 .duplex = PRESTERA_PORT_DUPLEX_FULL,
82 .port_type = PRESTERA_PORT_TYPE_TP,
84 [PRESTERA_LINK_MODE_2500baseX_Full] = {
85 .eth_mode = ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
87 .pr_mask = 1 << PRESTERA_LINK_MODE_2500baseX_Full,
88 .duplex = PRESTERA_PORT_DUPLEX_FULL,
90 [PRESTERA_LINK_MODE_10GbaseKR_Full] = {
91 .eth_mode = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
93 .pr_mask = 1 << PRESTERA_LINK_MODE_10GbaseKR_Full,
94 .duplex = PRESTERA_PORT_DUPLEX_FULL,
95 .port_type = PRESTERA_PORT_TYPE_TP,
97 [PRESTERA_LINK_MODE_10GbaseSR_Full] = {
98 .eth_mode = ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
100 .pr_mask = 1 << PRESTERA_LINK_MODE_10GbaseSR_Full,
101 .duplex = PRESTERA_PORT_DUPLEX_FULL,
102 .port_type = PRESTERA_PORT_TYPE_FIBRE,
104 [PRESTERA_LINK_MODE_10GbaseLR_Full] = {
105 .eth_mode = ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
107 .pr_mask = 1 << PRESTERA_LINK_MODE_10GbaseLR_Full,
108 .duplex = PRESTERA_PORT_DUPLEX_FULL,
109 .port_type = PRESTERA_PORT_TYPE_FIBRE,
111 [PRESTERA_LINK_MODE_20GbaseKR2_Full] = {
112 .eth_mode = ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
114 .pr_mask = 1 << PRESTERA_LINK_MODE_20GbaseKR2_Full,
115 .duplex = PRESTERA_PORT_DUPLEX_FULL,
116 .port_type = PRESTERA_PORT_TYPE_TP,
118 [PRESTERA_LINK_MODE_25GbaseCR_Full] = {
119 .eth_mode = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
121 .pr_mask = 1 << PRESTERA_LINK_MODE_25GbaseCR_Full,
122 .duplex = PRESTERA_PORT_DUPLEX_FULL,
123 .port_type = PRESTERA_PORT_TYPE_DA,
125 [PRESTERA_LINK_MODE_25GbaseKR_Full] = {
126 .eth_mode = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
128 .pr_mask = 1 << PRESTERA_LINK_MODE_25GbaseKR_Full,
129 .duplex = PRESTERA_PORT_DUPLEX_FULL,
130 .port_type = PRESTERA_PORT_TYPE_TP,
132 [PRESTERA_LINK_MODE_25GbaseSR_Full] = {
133 .eth_mode = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
135 .pr_mask = 1 << PRESTERA_LINK_MODE_25GbaseSR_Full,
136 .duplex = PRESTERA_PORT_DUPLEX_FULL,
137 .port_type = PRESTERA_PORT_TYPE_FIBRE,
139 [PRESTERA_LINK_MODE_40GbaseKR4_Full] = {
140 .eth_mode = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
142 .pr_mask = 1 << PRESTERA_LINK_MODE_40GbaseKR4_Full,
143 .duplex = PRESTERA_PORT_DUPLEX_FULL,
144 .port_type = PRESTERA_PORT_TYPE_TP,
146 [PRESTERA_LINK_MODE_40GbaseCR4_Full] = {
147 .eth_mode = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
149 .pr_mask = 1 << PRESTERA_LINK_MODE_40GbaseCR4_Full,
150 .duplex = PRESTERA_PORT_DUPLEX_FULL,
151 .port_type = PRESTERA_PORT_TYPE_DA,
153 [PRESTERA_LINK_MODE_40GbaseSR4_Full] = {
154 .eth_mode = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
156 .pr_mask = 1 << PRESTERA_LINK_MODE_40GbaseSR4_Full,
157 .duplex = PRESTERA_PORT_DUPLEX_FULL,
158 .port_type = PRESTERA_PORT_TYPE_FIBRE,
160 [PRESTERA_LINK_MODE_50GbaseCR2_Full] = {
161 .eth_mode = ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
163 .pr_mask = 1 << PRESTERA_LINK_MODE_50GbaseCR2_Full,
164 .duplex = PRESTERA_PORT_DUPLEX_FULL,
165 .port_type = PRESTERA_PORT_TYPE_DA,
167 [PRESTERA_LINK_MODE_50GbaseKR2_Full] = {
168 .eth_mode = ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
170 .pr_mask = 1 << PRESTERA_LINK_MODE_50GbaseKR2_Full,
171 .duplex = PRESTERA_PORT_DUPLEX_FULL,
172 .port_type = PRESTERA_PORT_TYPE_TP,
174 [PRESTERA_LINK_MODE_50GbaseSR2_Full] = {
175 .eth_mode = ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
177 .pr_mask = 1 << PRESTERA_LINK_MODE_50GbaseSR2_Full,
178 .duplex = PRESTERA_PORT_DUPLEX_FULL,
179 .port_type = PRESTERA_PORT_TYPE_FIBRE,
181 [PRESTERA_LINK_MODE_100GbaseKR4_Full] = {
182 .eth_mode = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
184 .pr_mask = 1 << PRESTERA_LINK_MODE_100GbaseKR4_Full,
185 .duplex = PRESTERA_PORT_DUPLEX_FULL,
186 .port_type = PRESTERA_PORT_TYPE_TP,
188 [PRESTERA_LINK_MODE_100GbaseSR4_Full] = {
189 .eth_mode = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
191 .pr_mask = 1 << PRESTERA_LINK_MODE_100GbaseSR4_Full,
192 .duplex = PRESTERA_PORT_DUPLEX_FULL,
193 .port_type = PRESTERA_PORT_TYPE_FIBRE,
195 [PRESTERA_LINK_MODE_100GbaseCR4_Full] = {
196 .eth_mode = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
198 .pr_mask = 1 << PRESTERA_LINK_MODE_100GbaseCR4_Full,
199 .duplex = PRESTERA_PORT_DUPLEX_FULL,
200 .port_type = PRESTERA_PORT_TYPE_DA,
204 static const struct prestera_fec {
206 enum ethtool_link_mode_bit_indices eth_mode;
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,
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,
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,
226 static const struct prestera_port_type {
227 enum ethtool_link_mode_bit_indices eth_mode;
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,
234 [PRESTERA_PORT_TYPE_TP] = {
235 .eth_mode = ETHTOOL_LINK_MODE_TP_BIT,
238 [PRESTERA_PORT_TYPE_AUI] = {
239 .eth_mode = ETHTOOL_LINK_MODE_AUI_BIT,
240 .eth_type = PORT_AUI,
242 [PRESTERA_PORT_TYPE_MII] = {
243 .eth_mode = ETHTOOL_LINK_MODE_MII_BIT,
244 .eth_type = PORT_MII,
246 [PRESTERA_PORT_TYPE_FIBRE] = {
247 .eth_mode = ETHTOOL_LINK_MODE_FIBRE_BIT,
248 .eth_type = PORT_FIBRE,
250 [PRESTERA_PORT_TYPE_BNC] = {
251 .eth_mode = ETHTOOL_LINK_MODE_BNC_BIT,
252 .eth_type = PORT_BNC,
254 [PRESTERA_PORT_TYPE_DA] = {
255 .eth_mode = ETHTOOL_LINK_MODE_TP_BIT,
258 [PRESTERA_PORT_TYPE_OTHER] = {
259 .eth_mode = __ETHTOOL_LINK_MODE_MASK_NBITS,
260 .eth_type = PORT_OTHER,
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),
297 static void prestera_ethtool_get_drvinfo(struct net_device *dev,
298 struct ethtool_drvinfo *drvinfo)
300 struct prestera_port *port = netdev_priv(dev);
301 struct prestera_switch *sw = port->sw;
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),
310 sw->dev->fw_rev.sub);
313 static u8 prestera_port_type_get(struct prestera_port *port)
315 if (port->caps.type < PRESTERA_PORT_TYPE_MAX)
316 return port_types[port->caps.type].eth_type;
321 static int prestera_port_type_set(const struct ethtool_link_ksettings *ecmd,
322 struct prestera_port *port)
324 u32 new_mode = PRESTERA_LINK_MODE_MAX;
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)) {
335 if (type == port->caps.type)
337 if (type != port->caps.type && ecmd->base.autoneg == AUTONEG_ENABLE)
339 if (type == PRESTERA_PORT_TYPE_MAX)
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) {
350 if (new_mode >= PRESTERA_LINK_MODE_MAX)
353 port->caps.type = type;
354 port->autoneg = false;
359 static void prestera_modes_to_eth(unsigned long *eth_modes, u64 link_modes,
364 for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
365 if ((port_link_modes[mode].pr_mask & link_modes) == 0)
368 if (type != PRESTERA_PORT_TYPE_NONE &&
369 port_link_modes[mode].port_type != type)
372 __set_bit(port_link_modes[mode].eth_mode, eth_modes);
375 for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) {
376 if ((port_fec_caps[mode].pr_fec & fec) == 0)
379 __set_bit(port_fec_caps[mode].eth_mode, eth_modes);
383 static void prestera_modes_from_eth(const unsigned long *eth_modes,
384 u64 *link_modes, u8 *fec, u8 type)
390 for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
391 if (!test_bit(port_link_modes[mode].eth_mode, eth_modes))
394 if (port_link_modes[mode].port_type != type)
397 adver_modes |= port_link_modes[mode].pr_mask;
400 for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) {
401 if (!test_bit(port_fec_caps[mode].eth_mode, eth_modes))
404 fec_modes |= port_fec_caps[mode].pr_fec;
407 *link_modes = adver_modes;
411 static void prestera_port_supp_types_get(struct ethtool_link_ksettings *ecmd,
412 struct prestera_port *port)
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)
422 ptype = port_link_modes[mode].port_type;
423 __set_bit(port_types[ptype].eth_mode,
424 ecmd->link_modes.supported);
428 static void prestera_port_remote_cap_get(struct ethtool_link_ksettings *ecmd,
429 struct prestera_port *port)
431 struct prestera_port_phy_state *state = &port->state_phy;
437 err = prestera_hw_port_phy_mode_get(port, NULL, &state->lmode_bmap,
438 &state->remote_fc.pause,
439 &state->remote_fc.asym_pause);
441 netdev_warn(port->dev, "Remote link caps get failed %d",
442 port->caps.transceiver);
444 bitmap = state->lmode_bmap;
446 prestera_modes_to_eth(ecmd->link_modes.lp_advertising,
447 bitmap, 0, PRESTERA_PORT_TYPE_NONE);
449 if (!bitmap_empty(ecmd->link_modes.lp_advertising,
450 __ETHTOOL_LINK_MODE_MASK_NBITS)) {
451 ethtool_link_ksettings_add_link_mode(ecmd,
456 pause = state->remote_fc.pause;
457 asym_pause = state->remote_fc.asym_pause;
460 ethtool_link_ksettings_add_link_mode(ecmd,
464 ethtool_link_ksettings_add_link_mode(ecmd,
469 static void prestera_port_link_mode_get(struct ethtool_link_ksettings *ecmd,
470 struct prestera_port *port)
472 struct prestera_port_mac_state *state = &port->state_mac;
477 if (!port->state_mac.oper)
480 if (state->speed == SPEED_UNKNOWN || state->duplex == DUPLEX_UNKNOWN) {
481 err = prestera_hw_port_mac_mode_get(port, NULL, &speed,
484 state->speed = SPEED_UNKNOWN;
485 state->duplex = DUPLEX_UNKNOWN;
487 state->speed = speed;
488 state->duplex = duplex == PRESTERA_PORT_DUPLEX_FULL ?
489 DUPLEX_FULL : DUPLEX_HALF;
493 ecmd->base.speed = port->state_mac.speed;
494 ecmd->base.duplex = port->state_mac.duplex;
497 static void prestera_port_mdix_get(struct ethtool_link_ksettings *ecmd,
498 struct prestera_port *port)
500 struct prestera_port_phy_state *state = &port->state_phy;
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;
508 ecmd->base.eth_tp_mdix = port->state_phy.mdix;
509 ecmd->base.eth_tp_mdix_ctrl = port->cfg_phy.mdix;
513 prestera_ethtool_get_link_ksettings(struct net_device *dev,
514 struct ethtool_link_ksettings *ecmd)
516 struct prestera_port *port = netdev_priv(dev);
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;
524 ecmd->base.autoneg = port->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
526 if (port->caps.type == PRESTERA_PORT_TYPE_TP) {
527 ethtool_link_ksettings_add_link_mode(ecmd, supported, Autoneg);
529 if (netif_running(dev) &&
531 port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER))
532 ethtool_link_ksettings_add_link_mode(ecmd, advertising,
536 prestera_modes_to_eth(ecmd->link_modes.supported,
537 port->caps.supp_link_modes,
541 prestera_port_supp_types_get(ecmd, port);
543 if (netif_carrier_ok(dev))
544 prestera_port_link_mode_get(ecmd, port);
546 ecmd->base.port = prestera_port_type_get(port);
549 if (netif_running(dev))
550 prestera_modes_to_eth(ecmd->link_modes.advertising,
551 port->adver_link_modes,
555 if (netif_carrier_ok(dev) &&
556 port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER)
557 prestera_port_remote_cap_get(ecmd, port);
560 if (port->caps.type == PRESTERA_PORT_TYPE_TP &&
561 port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER)
562 prestera_port_mdix_get(ecmd, port);
567 static int prestera_port_mdix_set(const struct ethtool_link_ksettings *ecmd,
568 struct prestera_port *port)
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,
577 port->adver_link_modes,
584 static int prestera_port_link_mode_set(struct prestera_port *port,
585 u32 speed, u8 duplex, u8 type)
587 u32 new_mode = PRESTERA_LINK_MODE_MAX;
591 for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
592 if (speed != SPEED_UNKNOWN &&
593 speed != port_link_modes[mode].speed)
596 if (duplex != DUPLEX_UNKNOWN &&
597 duplex != port_link_modes[mode].duplex)
600 if (!(port_link_modes[mode].pr_mask &
601 port->caps.supp_link_modes))
604 if (type != port_link_modes[mode].port_type)
611 if (new_mode == PRESTERA_LINK_MODE_MAX)
614 err = prestera_hw_port_phy_mode_set(port, port->cfg_phy.admin,
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;
629 prestera_port_speed_duplex_set(const struct ethtool_link_ksettings *ecmd,
630 struct prestera_port *port)
632 u8 duplex = DUPLEX_UNKNOWN;
634 if (ecmd->base.duplex != DUPLEX_UNKNOWN)
635 duplex = ecmd->base.duplex == DUPLEX_FULL ?
636 PRESTERA_PORT_DUPLEX_FULL : PRESTERA_PORT_DUPLEX_HALF;
638 return prestera_port_link_mode_set(port, ecmd->base.speed, duplex,
643 prestera_ethtool_set_link_ksettings(struct net_device *dev,
644 const struct ethtool_link_ksettings *ecmd)
646 struct prestera_port *port = netdev_priv(dev);
651 err = prestera_port_type_set(ecmd, port);
655 if (port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER) {
656 err = prestera_port_mdix_set(ecmd, port);
661 prestera_modes_from_eth(ecmd->link_modes.advertising, &adver_modes,
662 &adver_fec, port->caps.type);
664 if (ecmd->base.autoneg == AUTONEG_ENABLE)
665 err = prestera_port_autoneg_set(port, adver_modes);
667 err = prestera_port_speed_duplex_set(ecmd, port);
672 static int prestera_ethtool_get_fecparam(struct net_device *dev,
673 struct ethtool_fecparam *fecparam)
675 struct prestera_port *port = netdev_priv(dev);
680 err = prestera_hw_port_mac_mode_get(port, NULL, NULL, NULL, &active);
686 for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) {
687 if ((port_fec_caps[mode].pr_fec & port->caps.supp_fec) == 0)
690 fecparam->fec |= port_fec_caps[mode].eth_fec;
693 if (active < PRESTERA_PORT_FEC_MAX)
694 fecparam->active_fec = port_fec_caps[active].eth_fec;
696 fecparam->active_fec = ETHTOOL_FEC_AUTO;
701 static int prestera_ethtool_set_fecparam(struct net_device *dev,
702 struct ethtool_fecparam *fecparam)
704 struct prestera_port *port = netdev_priv(dev);
705 struct prestera_port_mac_config cfg_mac;
710 netdev_err(dev, "FEC set is not allowed while autoneg is on\n");
714 if (port->caps.transceiver == PRESTERA_PORT_TCVR_SFP) {
715 netdev_err(dev, "FEC set is not allowed on non-SFP ports\n");
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)) {
728 prestera_port_cfg_mac_read(port, &cfg_mac);
730 if (fec == cfg_mac.fec)
733 if (fec == PRESTERA_PORT_FEC_MAX) {
734 netdev_err(dev, "Unsupported FEC requested");
740 return prestera_port_cfg_mac_write(port, &cfg_mac);
743 static int prestera_ethtool_get_sset_count(struct net_device *dev, int sset)
747 return PRESTERA_STATS_CNT;
753 static void prestera_ethtool_get_strings(struct net_device *dev,
754 u32 stringset, u8 *data)
756 if (stringset != ETH_SS_STATS)
759 memcpy(data, prestera_cnt_name, sizeof(prestera_cnt_name));
762 static void prestera_ethtool_get_stats(struct net_device *dev,
763 struct ethtool_stats *stats, u64 *data)
765 struct prestera_port *port = netdev_priv(dev);
766 struct prestera_port_stats *port_stats;
768 port_stats = &port->cached_hw_stats.stats;
770 memcpy(data, port_stats, sizeof(*port_stats));
773 static int prestera_ethtool_nway_reset(struct net_device *dev)
775 struct prestera_port *port = netdev_priv(dev);
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);
785 void prestera_ethtool_port_state_changed(struct prestera_port *port,
786 struct prestera_port_event *evt)
788 struct prestera_port_mac_state *smac = &port->state_mac;
790 smac->oper = evt->data.mac.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;
799 smac->mode = PRESTERA_MAC_MODE_MAX;
800 smac->speed = SPEED_UNKNOWN;
801 smac->duplex = DUPLEX_UNKNOWN;
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