0001
0002
0003
0004 #include <linux/ethtool.h>
0005 #include <linux/kernel.h>
0006 #include <linux/netdevice.h>
0007
0008 #include "prestera_ethtool.h"
0009 #include "prestera.h"
0010 #include "prestera_hw.h"
0011
0012 #define PRESTERA_STATS_CNT \
0013 (sizeof(struct prestera_port_stats) / sizeof(u64))
0014 #define PRESTERA_STATS_IDX(name) \
0015 (offsetof(struct prestera_port_stats, name) / sizeof(u64))
0016 #define PRESTERA_STATS_FIELD(name) \
0017 [PRESTERA_STATS_IDX(name)] = __stringify(name)
0018
0019 static const char driver_kind[] = "prestera";
0020
0021 static const struct prestera_link_mode {
0022 enum ethtool_link_mode_bit_indices eth_mode;
0023 u32 speed;
0024 u64 pr_mask;
0025 u8 duplex;
0026 u8 port_type;
0027 } port_link_modes[PRESTERA_LINK_MODE_MAX] = {
0028 [PRESTERA_LINK_MODE_10baseT_Half] = {
0029 .eth_mode = ETHTOOL_LINK_MODE_10baseT_Half_BIT,
0030 .speed = 10,
0031 .pr_mask = 1 << PRESTERA_LINK_MODE_10baseT_Half,
0032 .duplex = PRESTERA_PORT_DUPLEX_HALF,
0033 .port_type = PRESTERA_PORT_TYPE_TP,
0034 },
0035 [PRESTERA_LINK_MODE_10baseT_Full] = {
0036 .eth_mode = ETHTOOL_LINK_MODE_10baseT_Full_BIT,
0037 .speed = 10,
0038 .pr_mask = 1 << PRESTERA_LINK_MODE_10baseT_Full,
0039 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0040 .port_type = PRESTERA_PORT_TYPE_TP,
0041 },
0042 [PRESTERA_LINK_MODE_100baseT_Half] = {
0043 .eth_mode = ETHTOOL_LINK_MODE_100baseT_Half_BIT,
0044 .speed = 100,
0045 .pr_mask = 1 << PRESTERA_LINK_MODE_100baseT_Half,
0046 .duplex = PRESTERA_PORT_DUPLEX_HALF,
0047 .port_type = PRESTERA_PORT_TYPE_TP,
0048 },
0049 [PRESTERA_LINK_MODE_100baseT_Full] = {
0050 .eth_mode = ETHTOOL_LINK_MODE_100baseT_Full_BIT,
0051 .speed = 100,
0052 .pr_mask = 1 << PRESTERA_LINK_MODE_100baseT_Full,
0053 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0054 .port_type = PRESTERA_PORT_TYPE_TP,
0055 },
0056 [PRESTERA_LINK_MODE_1000baseT_Half] = {
0057 .eth_mode = ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
0058 .speed = 1000,
0059 .pr_mask = 1 << PRESTERA_LINK_MODE_1000baseT_Half,
0060 .duplex = PRESTERA_PORT_DUPLEX_HALF,
0061 .port_type = PRESTERA_PORT_TYPE_TP,
0062 },
0063 [PRESTERA_LINK_MODE_1000baseT_Full] = {
0064 .eth_mode = ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
0065 .speed = 1000,
0066 .pr_mask = 1 << PRESTERA_LINK_MODE_1000baseT_Full,
0067 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0068 .port_type = PRESTERA_PORT_TYPE_TP,
0069 },
0070 [PRESTERA_LINK_MODE_1000baseX_Full] = {
0071 .eth_mode = ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
0072 .speed = 1000,
0073 .pr_mask = 1 << PRESTERA_LINK_MODE_1000baseX_Full,
0074 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0075 .port_type = PRESTERA_PORT_TYPE_FIBRE,
0076 },
0077 [PRESTERA_LINK_MODE_1000baseKX_Full] = {
0078 .eth_mode = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
0079 .speed = 1000,
0080 .pr_mask = 1 << PRESTERA_LINK_MODE_1000baseKX_Full,
0081 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0082 .port_type = PRESTERA_PORT_TYPE_TP,
0083 },
0084 [PRESTERA_LINK_MODE_2500baseX_Full] = {
0085 .eth_mode = ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
0086 .speed = 2500,
0087 .pr_mask = 1 << PRESTERA_LINK_MODE_2500baseX_Full,
0088 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0089 },
0090 [PRESTERA_LINK_MODE_10GbaseKR_Full] = {
0091 .eth_mode = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
0092 .speed = 10000,
0093 .pr_mask = 1 << PRESTERA_LINK_MODE_10GbaseKR_Full,
0094 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0095 .port_type = PRESTERA_PORT_TYPE_TP,
0096 },
0097 [PRESTERA_LINK_MODE_10GbaseSR_Full] = {
0098 .eth_mode = ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
0099 .speed = 10000,
0100 .pr_mask = 1 << PRESTERA_LINK_MODE_10GbaseSR_Full,
0101 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0102 .port_type = PRESTERA_PORT_TYPE_FIBRE,
0103 },
0104 [PRESTERA_LINK_MODE_10GbaseLR_Full] = {
0105 .eth_mode = ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
0106 .speed = 10000,
0107 .pr_mask = 1 << PRESTERA_LINK_MODE_10GbaseLR_Full,
0108 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0109 .port_type = PRESTERA_PORT_TYPE_FIBRE,
0110 },
0111 [PRESTERA_LINK_MODE_20GbaseKR2_Full] = {
0112 .eth_mode = ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
0113 .speed = 20000,
0114 .pr_mask = 1 << PRESTERA_LINK_MODE_20GbaseKR2_Full,
0115 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0116 .port_type = PRESTERA_PORT_TYPE_TP,
0117 },
0118 [PRESTERA_LINK_MODE_25GbaseCR_Full] = {
0119 .eth_mode = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
0120 .speed = 25000,
0121 .pr_mask = 1 << PRESTERA_LINK_MODE_25GbaseCR_Full,
0122 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0123 .port_type = PRESTERA_PORT_TYPE_DA,
0124 },
0125 [PRESTERA_LINK_MODE_25GbaseKR_Full] = {
0126 .eth_mode = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
0127 .speed = 25000,
0128 .pr_mask = 1 << PRESTERA_LINK_MODE_25GbaseKR_Full,
0129 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0130 .port_type = PRESTERA_PORT_TYPE_TP,
0131 },
0132 [PRESTERA_LINK_MODE_25GbaseSR_Full] = {
0133 .eth_mode = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
0134 .speed = 25000,
0135 .pr_mask = 1 << PRESTERA_LINK_MODE_25GbaseSR_Full,
0136 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0137 .port_type = PRESTERA_PORT_TYPE_FIBRE,
0138 },
0139 [PRESTERA_LINK_MODE_40GbaseKR4_Full] = {
0140 .eth_mode = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
0141 .speed = 40000,
0142 .pr_mask = 1 << PRESTERA_LINK_MODE_40GbaseKR4_Full,
0143 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0144 .port_type = PRESTERA_PORT_TYPE_TP,
0145 },
0146 [PRESTERA_LINK_MODE_40GbaseCR4_Full] = {
0147 .eth_mode = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
0148 .speed = 40000,
0149 .pr_mask = 1 << PRESTERA_LINK_MODE_40GbaseCR4_Full,
0150 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0151 .port_type = PRESTERA_PORT_TYPE_DA,
0152 },
0153 [PRESTERA_LINK_MODE_40GbaseSR4_Full] = {
0154 .eth_mode = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
0155 .speed = 40000,
0156 .pr_mask = 1 << PRESTERA_LINK_MODE_40GbaseSR4_Full,
0157 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0158 .port_type = PRESTERA_PORT_TYPE_FIBRE,
0159 },
0160 [PRESTERA_LINK_MODE_50GbaseCR2_Full] = {
0161 .eth_mode = ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
0162 .speed = 50000,
0163 .pr_mask = 1 << PRESTERA_LINK_MODE_50GbaseCR2_Full,
0164 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0165 .port_type = PRESTERA_PORT_TYPE_DA,
0166 },
0167 [PRESTERA_LINK_MODE_50GbaseKR2_Full] = {
0168 .eth_mode = ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
0169 .speed = 50000,
0170 .pr_mask = 1 << PRESTERA_LINK_MODE_50GbaseKR2_Full,
0171 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0172 .port_type = PRESTERA_PORT_TYPE_TP,
0173 },
0174 [PRESTERA_LINK_MODE_50GbaseSR2_Full] = {
0175 .eth_mode = ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
0176 .speed = 50000,
0177 .pr_mask = 1 << PRESTERA_LINK_MODE_50GbaseSR2_Full,
0178 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0179 .port_type = PRESTERA_PORT_TYPE_FIBRE,
0180 },
0181 [PRESTERA_LINK_MODE_100GbaseKR4_Full] = {
0182 .eth_mode = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
0183 .speed = 100000,
0184 .pr_mask = 1 << PRESTERA_LINK_MODE_100GbaseKR4_Full,
0185 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0186 .port_type = PRESTERA_PORT_TYPE_TP,
0187 },
0188 [PRESTERA_LINK_MODE_100GbaseSR4_Full] = {
0189 .eth_mode = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
0190 .speed = 100000,
0191 .pr_mask = 1 << PRESTERA_LINK_MODE_100GbaseSR4_Full,
0192 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0193 .port_type = PRESTERA_PORT_TYPE_FIBRE,
0194 },
0195 [PRESTERA_LINK_MODE_100GbaseCR4_Full] = {
0196 .eth_mode = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
0197 .speed = 100000,
0198 .pr_mask = 1 << PRESTERA_LINK_MODE_100GbaseCR4_Full,
0199 .duplex = PRESTERA_PORT_DUPLEX_FULL,
0200 .port_type = PRESTERA_PORT_TYPE_DA,
0201 }
0202 };
0203
0204 static const struct prestera_fec {
0205 u32 eth_fec;
0206 enum ethtool_link_mode_bit_indices eth_mode;
0207 u8 pr_fec;
0208 } port_fec_caps[PRESTERA_PORT_FEC_MAX] = {
0209 [PRESTERA_PORT_FEC_OFF] = {
0210 .eth_fec = ETHTOOL_FEC_OFF,
0211 .eth_mode = ETHTOOL_LINK_MODE_FEC_NONE_BIT,
0212 .pr_fec = 1 << PRESTERA_PORT_FEC_OFF,
0213 },
0214 [PRESTERA_PORT_FEC_BASER] = {
0215 .eth_fec = ETHTOOL_FEC_BASER,
0216 .eth_mode = ETHTOOL_LINK_MODE_FEC_BASER_BIT,
0217 .pr_fec = 1 << PRESTERA_PORT_FEC_BASER,
0218 },
0219 [PRESTERA_PORT_FEC_RS] = {
0220 .eth_fec = ETHTOOL_FEC_RS,
0221 .eth_mode = ETHTOOL_LINK_MODE_FEC_RS_BIT,
0222 .pr_fec = 1 << PRESTERA_PORT_FEC_RS,
0223 }
0224 };
0225
0226 static const struct prestera_port_type {
0227 enum ethtool_link_mode_bit_indices eth_mode;
0228 u8 eth_type;
0229 } port_types[PRESTERA_PORT_TYPE_MAX] = {
0230 [PRESTERA_PORT_TYPE_NONE] = {
0231 .eth_mode = __ETHTOOL_LINK_MODE_MASK_NBITS,
0232 .eth_type = PORT_NONE,
0233 },
0234 [PRESTERA_PORT_TYPE_TP] = {
0235 .eth_mode = ETHTOOL_LINK_MODE_TP_BIT,
0236 .eth_type = PORT_TP,
0237 },
0238 [PRESTERA_PORT_TYPE_AUI] = {
0239 .eth_mode = ETHTOOL_LINK_MODE_AUI_BIT,
0240 .eth_type = PORT_AUI,
0241 },
0242 [PRESTERA_PORT_TYPE_MII] = {
0243 .eth_mode = ETHTOOL_LINK_MODE_MII_BIT,
0244 .eth_type = PORT_MII,
0245 },
0246 [PRESTERA_PORT_TYPE_FIBRE] = {
0247 .eth_mode = ETHTOOL_LINK_MODE_FIBRE_BIT,
0248 .eth_type = PORT_FIBRE,
0249 },
0250 [PRESTERA_PORT_TYPE_BNC] = {
0251 .eth_mode = ETHTOOL_LINK_MODE_BNC_BIT,
0252 .eth_type = PORT_BNC,
0253 },
0254 [PRESTERA_PORT_TYPE_DA] = {
0255 .eth_mode = ETHTOOL_LINK_MODE_TP_BIT,
0256 .eth_type = PORT_TP,
0257 },
0258 [PRESTERA_PORT_TYPE_OTHER] = {
0259 .eth_mode = __ETHTOOL_LINK_MODE_MASK_NBITS,
0260 .eth_type = PORT_OTHER,
0261 }
0262 };
0263
0264 static const char prestera_cnt_name[PRESTERA_STATS_CNT][ETH_GSTRING_LEN] = {
0265 PRESTERA_STATS_FIELD(good_octets_received),
0266 PRESTERA_STATS_FIELD(bad_octets_received),
0267 PRESTERA_STATS_FIELD(mac_trans_error),
0268 PRESTERA_STATS_FIELD(broadcast_frames_received),
0269 PRESTERA_STATS_FIELD(multicast_frames_received),
0270 PRESTERA_STATS_FIELD(frames_64_octets),
0271 PRESTERA_STATS_FIELD(frames_65_to_127_octets),
0272 PRESTERA_STATS_FIELD(frames_128_to_255_octets),
0273 PRESTERA_STATS_FIELD(frames_256_to_511_octets),
0274 PRESTERA_STATS_FIELD(frames_512_to_1023_octets),
0275 PRESTERA_STATS_FIELD(frames_1024_to_max_octets),
0276 PRESTERA_STATS_FIELD(excessive_collision),
0277 PRESTERA_STATS_FIELD(multicast_frames_sent),
0278 PRESTERA_STATS_FIELD(broadcast_frames_sent),
0279 PRESTERA_STATS_FIELD(fc_sent),
0280 PRESTERA_STATS_FIELD(fc_received),
0281 PRESTERA_STATS_FIELD(buffer_overrun),
0282 PRESTERA_STATS_FIELD(undersize),
0283 PRESTERA_STATS_FIELD(fragments),
0284 PRESTERA_STATS_FIELD(oversize),
0285 PRESTERA_STATS_FIELD(jabber),
0286 PRESTERA_STATS_FIELD(rx_error_frame_received),
0287 PRESTERA_STATS_FIELD(bad_crc),
0288 PRESTERA_STATS_FIELD(collisions),
0289 PRESTERA_STATS_FIELD(late_collision),
0290 PRESTERA_STATS_FIELD(unicast_frames_received),
0291 PRESTERA_STATS_FIELD(unicast_frames_sent),
0292 PRESTERA_STATS_FIELD(sent_multiple),
0293 PRESTERA_STATS_FIELD(sent_deferred),
0294 PRESTERA_STATS_FIELD(good_octets_sent),
0295 };
0296
0297 static void prestera_ethtool_get_drvinfo(struct net_device *dev,
0298 struct ethtool_drvinfo *drvinfo)
0299 {
0300 struct prestera_port *port = netdev_priv(dev);
0301 struct prestera_switch *sw = port->sw;
0302
0303 strlcpy(drvinfo->driver, driver_kind, sizeof(drvinfo->driver));
0304 strlcpy(drvinfo->bus_info, dev_name(prestera_dev(sw)),
0305 sizeof(drvinfo->bus_info));
0306 snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
0307 "%d.%d.%d",
0308 sw->dev->fw_rev.maj,
0309 sw->dev->fw_rev.min,
0310 sw->dev->fw_rev.sub);
0311 }
0312
0313 static u8 prestera_port_type_get(struct prestera_port *port)
0314 {
0315 if (port->caps.type < PRESTERA_PORT_TYPE_MAX)
0316 return port_types[port->caps.type].eth_type;
0317
0318 return PORT_OTHER;
0319 }
0320
0321 static int prestera_port_type_set(const struct ethtool_link_ksettings *ecmd,
0322 struct prestera_port *port)
0323 {
0324 u32 new_mode = PRESTERA_LINK_MODE_MAX;
0325 u32 type, mode;
0326
0327 for (type = 0; type < PRESTERA_PORT_TYPE_MAX; type++) {
0328 if (port_types[type].eth_type == ecmd->base.port &&
0329 test_bit(port_types[type].eth_mode,
0330 ecmd->link_modes.supported)) {
0331 break;
0332 }
0333 }
0334
0335 if (type == port->caps.type)
0336 return 0;
0337 if (type != port->caps.type && ecmd->base.autoneg == AUTONEG_ENABLE)
0338 return -EINVAL;
0339 if (type == PRESTERA_PORT_TYPE_MAX)
0340 return -EOPNOTSUPP;
0341
0342 for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
0343 if ((port_link_modes[mode].pr_mask &
0344 port->caps.supp_link_modes) &&
0345 type == port_link_modes[mode].port_type) {
0346 new_mode = mode;
0347 }
0348 }
0349
0350 if (new_mode >= PRESTERA_LINK_MODE_MAX)
0351 return -EINVAL;
0352
0353 port->caps.type = type;
0354 port->autoneg = false;
0355
0356 return 0;
0357 }
0358
0359 static void prestera_modes_to_eth(unsigned long *eth_modes, u64 link_modes,
0360 u8 fec, u8 type)
0361 {
0362 u32 mode;
0363
0364 for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
0365 if ((port_link_modes[mode].pr_mask & link_modes) == 0)
0366 continue;
0367
0368 if (type != PRESTERA_PORT_TYPE_NONE &&
0369 port_link_modes[mode].port_type != type)
0370 continue;
0371
0372 __set_bit(port_link_modes[mode].eth_mode, eth_modes);
0373 }
0374
0375 for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) {
0376 if ((port_fec_caps[mode].pr_fec & fec) == 0)
0377 continue;
0378
0379 __set_bit(port_fec_caps[mode].eth_mode, eth_modes);
0380 }
0381 }
0382
0383 static void prestera_modes_from_eth(const unsigned long *eth_modes,
0384 u64 *link_modes, u8 *fec, u8 type)
0385 {
0386 u64 adver_modes = 0;
0387 u32 fec_modes = 0;
0388 u32 mode;
0389
0390 for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
0391 if (!test_bit(port_link_modes[mode].eth_mode, eth_modes))
0392 continue;
0393
0394 if (port_link_modes[mode].port_type != type)
0395 continue;
0396
0397 adver_modes |= port_link_modes[mode].pr_mask;
0398 }
0399
0400 for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) {
0401 if (!test_bit(port_fec_caps[mode].eth_mode, eth_modes))
0402 continue;
0403
0404 fec_modes |= port_fec_caps[mode].pr_fec;
0405 }
0406
0407 *link_modes = adver_modes;
0408 *fec = fec_modes;
0409 }
0410
0411 static void prestera_port_supp_types_get(struct ethtool_link_ksettings *ecmd,
0412 struct prestera_port *port)
0413 {
0414 u32 mode;
0415 u8 ptype;
0416
0417 for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
0418 if ((port_link_modes[mode].pr_mask &
0419 port->caps.supp_link_modes) == 0)
0420 continue;
0421
0422 ptype = port_link_modes[mode].port_type;
0423 __set_bit(port_types[ptype].eth_mode,
0424 ecmd->link_modes.supported);
0425 }
0426 }
0427
0428 static void prestera_port_remote_cap_get(struct ethtool_link_ksettings *ecmd,
0429 struct prestera_port *port)
0430 {
0431 struct prestera_port_phy_state *state = &port->state_phy;
0432 bool asym_pause;
0433 bool pause;
0434 u64 bitmap;
0435 int err;
0436
0437 err = prestera_hw_port_phy_mode_get(port, NULL, &state->lmode_bmap,
0438 &state->remote_fc.pause,
0439 &state->remote_fc.asym_pause);
0440 if (err)
0441 netdev_warn(port->dev, "Remote link caps get failed %d",
0442 port->caps.transceiver);
0443
0444 bitmap = state->lmode_bmap;
0445
0446 prestera_modes_to_eth(ecmd->link_modes.lp_advertising,
0447 bitmap, 0, PRESTERA_PORT_TYPE_NONE);
0448
0449 if (!bitmap_empty(ecmd->link_modes.lp_advertising,
0450 __ETHTOOL_LINK_MODE_MASK_NBITS)) {
0451 ethtool_link_ksettings_add_link_mode(ecmd,
0452 lp_advertising,
0453 Autoneg);
0454 }
0455
0456 pause = state->remote_fc.pause;
0457 asym_pause = state->remote_fc.asym_pause;
0458
0459 if (pause)
0460 ethtool_link_ksettings_add_link_mode(ecmd,
0461 lp_advertising,
0462 Pause);
0463 if (asym_pause)
0464 ethtool_link_ksettings_add_link_mode(ecmd,
0465 lp_advertising,
0466 Asym_Pause);
0467 }
0468
0469 static void prestera_port_link_mode_get(struct ethtool_link_ksettings *ecmd,
0470 struct prestera_port *port)
0471 {
0472 struct prestera_port_mac_state *state = &port->state_mac;
0473 u32 speed;
0474 u8 duplex;
0475 int err;
0476
0477 if (!port->state_mac.oper)
0478 return;
0479
0480 if (state->speed == SPEED_UNKNOWN || state->duplex == DUPLEX_UNKNOWN) {
0481 err = prestera_hw_port_mac_mode_get(port, NULL, &speed,
0482 &duplex, NULL);
0483 if (err) {
0484 state->speed = SPEED_UNKNOWN;
0485 state->duplex = DUPLEX_UNKNOWN;
0486 } else {
0487 state->speed = speed;
0488 state->duplex = duplex == PRESTERA_PORT_DUPLEX_FULL ?
0489 DUPLEX_FULL : DUPLEX_HALF;
0490 }
0491 }
0492
0493 ecmd->base.speed = port->state_mac.speed;
0494 ecmd->base.duplex = port->state_mac.duplex;
0495 }
0496
0497 static void prestera_port_mdix_get(struct ethtool_link_ksettings *ecmd,
0498 struct prestera_port *port)
0499 {
0500 struct prestera_port_phy_state *state = &port->state_phy;
0501
0502 if (prestera_hw_port_phy_mode_get(port,
0503 &state->mdix, NULL, NULL, NULL)) {
0504 netdev_warn(port->dev, "MDIX params get failed");
0505 state->mdix = ETH_TP_MDI_INVALID;
0506 }
0507
0508 ecmd->base.eth_tp_mdix = port->state_phy.mdix;
0509 ecmd->base.eth_tp_mdix_ctrl = port->cfg_phy.mdix;
0510 }
0511
0512 static int
0513 prestera_ethtool_get_link_ksettings(struct net_device *dev,
0514 struct ethtool_link_ksettings *ecmd)
0515 {
0516 struct prestera_port *port = netdev_priv(dev);
0517
0518 ethtool_link_ksettings_zero_link_mode(ecmd, supported);
0519 ethtool_link_ksettings_zero_link_mode(ecmd, advertising);
0520 ethtool_link_ksettings_zero_link_mode(ecmd, lp_advertising);
0521 ecmd->base.speed = SPEED_UNKNOWN;
0522 ecmd->base.duplex = DUPLEX_UNKNOWN;
0523
0524 if (port->phy_link)
0525 return phylink_ethtool_ksettings_get(port->phy_link, ecmd);
0526
0527 ecmd->base.autoneg = port->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
0528
0529 if (port->caps.type == PRESTERA_PORT_TYPE_TP) {
0530 ethtool_link_ksettings_add_link_mode(ecmd, supported, Autoneg);
0531
0532 if (netif_running(dev) &&
0533 (port->autoneg ||
0534 port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER))
0535 ethtool_link_ksettings_add_link_mode(ecmd, advertising,
0536 Autoneg);
0537 }
0538
0539 prestera_modes_to_eth(ecmd->link_modes.supported,
0540 port->caps.supp_link_modes,
0541 port->caps.supp_fec,
0542 port->caps.type);
0543
0544 prestera_port_supp_types_get(ecmd, port);
0545
0546 if (netif_carrier_ok(dev))
0547 prestera_port_link_mode_get(ecmd, port);
0548
0549 ecmd->base.port = prestera_port_type_get(port);
0550
0551 if (port->autoneg) {
0552 if (netif_running(dev))
0553 prestera_modes_to_eth(ecmd->link_modes.advertising,
0554 port->adver_link_modes,
0555 port->adver_fec,
0556 port->caps.type);
0557
0558 if (netif_carrier_ok(dev) &&
0559 port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER)
0560 prestera_port_remote_cap_get(ecmd, port);
0561 }
0562
0563 if (port->caps.type == PRESTERA_PORT_TYPE_TP &&
0564 port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER)
0565 prestera_port_mdix_get(ecmd, port);
0566
0567 return 0;
0568 }
0569
0570 static int prestera_port_mdix_set(const struct ethtool_link_ksettings *ecmd,
0571 struct prestera_port *port)
0572 {
0573 if (ecmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_INVALID &&
0574 port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER &&
0575 port->caps.type == PRESTERA_PORT_TYPE_TP) {
0576 port->cfg_phy.mdix = ecmd->base.eth_tp_mdix_ctrl;
0577 return prestera_hw_port_phy_mode_set(port, port->cfg_phy.admin,
0578 port->autoneg,
0579 port->cfg_phy.mode,
0580 port->adver_link_modes,
0581 port->cfg_phy.mdix);
0582 }
0583 return 0;
0584
0585 }
0586
0587 static int prestera_port_link_mode_set(struct prestera_port *port,
0588 u32 speed, u8 duplex, u8 type)
0589 {
0590 u32 new_mode = PRESTERA_LINK_MODE_MAX;
0591 u32 mode;
0592 int err;
0593
0594 for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
0595 if (speed != SPEED_UNKNOWN &&
0596 speed != port_link_modes[mode].speed)
0597 continue;
0598
0599 if (duplex != DUPLEX_UNKNOWN &&
0600 duplex != port_link_modes[mode].duplex)
0601 continue;
0602
0603 if (!(port_link_modes[mode].pr_mask &
0604 port->caps.supp_link_modes))
0605 continue;
0606
0607 if (type != port_link_modes[mode].port_type)
0608 continue;
0609
0610 new_mode = mode;
0611 break;
0612 }
0613
0614 if (new_mode == PRESTERA_LINK_MODE_MAX)
0615 return -EOPNOTSUPP;
0616
0617 err = prestera_hw_port_phy_mode_set(port, port->cfg_phy.admin,
0618 false, new_mode, 0,
0619 port->cfg_phy.mdix);
0620 if (err)
0621 return err;
0622
0623 port->adver_fec = BIT(PRESTERA_PORT_FEC_OFF);
0624 port->adver_link_modes = 0;
0625 port->cfg_phy.mode = new_mode;
0626 port->autoneg = false;
0627
0628 return 0;
0629 }
0630
0631 static int
0632 prestera_port_speed_duplex_set(const struct ethtool_link_ksettings *ecmd,
0633 struct prestera_port *port)
0634 {
0635 u8 duplex = DUPLEX_UNKNOWN;
0636
0637 if (ecmd->base.duplex != DUPLEX_UNKNOWN)
0638 duplex = ecmd->base.duplex == DUPLEX_FULL ?
0639 PRESTERA_PORT_DUPLEX_FULL : PRESTERA_PORT_DUPLEX_HALF;
0640
0641 return prestera_port_link_mode_set(port, ecmd->base.speed, duplex,
0642 port->caps.type);
0643 }
0644
0645 static int
0646 prestera_ethtool_set_link_ksettings(struct net_device *dev,
0647 const struct ethtool_link_ksettings *ecmd)
0648 {
0649 struct prestera_port *port = netdev_priv(dev);
0650 u64 adver_modes;
0651 u8 adver_fec;
0652 int err;
0653
0654 if (port->phy_link)
0655 return phylink_ethtool_ksettings_set(port->phy_link, ecmd);
0656
0657 err = prestera_port_type_set(ecmd, port);
0658 if (err)
0659 return err;
0660
0661 if (port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER) {
0662 err = prestera_port_mdix_set(ecmd, port);
0663 if (err)
0664 return err;
0665 }
0666
0667 prestera_modes_from_eth(ecmd->link_modes.advertising, &adver_modes,
0668 &adver_fec, port->caps.type);
0669
0670 if (ecmd->base.autoneg == AUTONEG_ENABLE)
0671 err = prestera_port_autoneg_set(port, adver_modes);
0672 else
0673 err = prestera_port_speed_duplex_set(ecmd, port);
0674
0675 return err;
0676 }
0677
0678 static int prestera_ethtool_get_fecparam(struct net_device *dev,
0679 struct ethtool_fecparam *fecparam)
0680 {
0681 struct prestera_port *port = netdev_priv(dev);
0682 u8 active;
0683 u32 mode;
0684 int err;
0685
0686 err = prestera_hw_port_mac_mode_get(port, NULL, NULL, NULL, &active);
0687 if (err)
0688 return err;
0689
0690 fecparam->fec = 0;
0691
0692 for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) {
0693 if ((port_fec_caps[mode].pr_fec & port->caps.supp_fec) == 0)
0694 continue;
0695
0696 fecparam->fec |= port_fec_caps[mode].eth_fec;
0697 }
0698
0699 if (active < PRESTERA_PORT_FEC_MAX)
0700 fecparam->active_fec = port_fec_caps[active].eth_fec;
0701 else
0702 fecparam->active_fec = ETHTOOL_FEC_AUTO;
0703
0704 return 0;
0705 }
0706
0707 static int prestera_ethtool_set_fecparam(struct net_device *dev,
0708 struct ethtool_fecparam *fecparam)
0709 {
0710 struct prestera_port *port = netdev_priv(dev);
0711 struct prestera_port_mac_config cfg_mac;
0712 u32 mode;
0713 u8 fec;
0714
0715 if (port->autoneg) {
0716 netdev_err(dev, "FEC set is not allowed while autoneg is on\n");
0717 return -EINVAL;
0718 }
0719
0720 if (port->caps.transceiver == PRESTERA_PORT_TCVR_SFP) {
0721 netdev_err(dev, "FEC set is not allowed on non-SFP ports\n");
0722 return -EINVAL;
0723 }
0724
0725 fec = PRESTERA_PORT_FEC_MAX;
0726 for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) {
0727 if ((port_fec_caps[mode].eth_fec & fecparam->fec) &&
0728 (port_fec_caps[mode].pr_fec & port->caps.supp_fec)) {
0729 fec = mode;
0730 break;
0731 }
0732 }
0733
0734 prestera_port_cfg_mac_read(port, &cfg_mac);
0735
0736 if (fec == cfg_mac.fec)
0737 return 0;
0738
0739 if (fec == PRESTERA_PORT_FEC_MAX) {
0740 netdev_err(dev, "Unsupported FEC requested");
0741 return -EINVAL;
0742 }
0743
0744 cfg_mac.fec = fec;
0745
0746 return prestera_port_cfg_mac_write(port, &cfg_mac);
0747 }
0748
0749 static int prestera_ethtool_get_sset_count(struct net_device *dev, int sset)
0750 {
0751 switch (sset) {
0752 case ETH_SS_STATS:
0753 return PRESTERA_STATS_CNT;
0754 default:
0755 return -EOPNOTSUPP;
0756 }
0757 }
0758
0759 static void prestera_ethtool_get_strings(struct net_device *dev,
0760 u32 stringset, u8 *data)
0761 {
0762 if (stringset != ETH_SS_STATS)
0763 return;
0764
0765 memcpy(data, prestera_cnt_name, sizeof(prestera_cnt_name));
0766 }
0767
0768 static void prestera_ethtool_get_stats(struct net_device *dev,
0769 struct ethtool_stats *stats, u64 *data)
0770 {
0771 struct prestera_port *port = netdev_priv(dev);
0772 struct prestera_port_stats *port_stats;
0773
0774 port_stats = &port->cached_hw_stats.stats;
0775
0776 memcpy(data, port_stats, sizeof(*port_stats));
0777 }
0778
0779 static int prestera_ethtool_nway_reset(struct net_device *dev)
0780 {
0781 struct prestera_port *port = netdev_priv(dev);
0782
0783 if (netif_running(dev) &&
0784 port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER &&
0785 port->caps.type == PRESTERA_PORT_TYPE_TP)
0786 return prestera_hw_port_autoneg_restart(port);
0787
0788 return -EINVAL;
0789 }
0790
0791 const struct ethtool_ops prestera_ethtool_ops = {
0792 .get_drvinfo = prestera_ethtool_get_drvinfo,
0793 .get_link_ksettings = prestera_ethtool_get_link_ksettings,
0794 .set_link_ksettings = prestera_ethtool_set_link_ksettings,
0795 .get_fecparam = prestera_ethtool_get_fecparam,
0796 .set_fecparam = prestera_ethtool_set_fecparam,
0797 .get_sset_count = prestera_ethtool_get_sset_count,
0798 .get_strings = prestera_ethtool_get_strings,
0799 .get_ethtool_stats = prestera_ethtool_get_stats,
0800 .get_link = ethtool_op_get_link,
0801 .nway_reset = prestera_ethtool_nway_reset
0802 };