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, &state->mdix, NULL, NULL, NULL)) { 503 netdev_warn(port->dev, "MDIX params get failed"); 504 state->mdix = ETH_TP_MDI_INVALID; 505 } 506 507 ecmd->base.eth_tp_mdix = port->state_phy.mdix; 508 ecmd->base.eth_tp_mdix_ctrl = port->cfg_phy.mdix; 509 } 510 511 static int 512 prestera_ethtool_get_link_ksettings(struct net_device *dev, 513 struct ethtool_link_ksettings *ecmd) 514 { 515 struct prestera_port *port = netdev_priv(dev); 516 517 ethtool_link_ksettings_zero_link_mode(ecmd, supported); 518 ethtool_link_ksettings_zero_link_mode(ecmd, advertising); 519 ethtool_link_ksettings_zero_link_mode(ecmd, lp_advertising); 520 ecmd->base.speed = SPEED_UNKNOWN; 521 ecmd->base.duplex = DUPLEX_UNKNOWN; 522 523 ecmd->base.autoneg = port->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE; 524 525 if (port->caps.type == PRESTERA_PORT_TYPE_TP) { 526 ethtool_link_ksettings_add_link_mode(ecmd, supported, Autoneg); 527 528 if (netif_running(dev) && 529 (port->autoneg || 530 port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER)) 531 ethtool_link_ksettings_add_link_mode(ecmd, advertising, 532 Autoneg); 533 } 534 535 prestera_modes_to_eth(ecmd->link_modes.supported, 536 port->caps.supp_link_modes, 537 port->caps.supp_fec, 538 port->caps.type); 539 540 prestera_port_supp_types_get(ecmd, port); 541 542 if (netif_carrier_ok(dev)) 543 prestera_port_link_mode_get(ecmd, port); 544 545 ecmd->base.port = prestera_port_type_get(port); 546 547 if (port->autoneg) { 548 if (netif_running(dev)) 549 prestera_modes_to_eth(ecmd->link_modes.advertising, 550 port->adver_link_modes, 551 port->adver_fec, 552 port->caps.type); 553 554 if (netif_carrier_ok(dev) && 555 port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER) 556 prestera_port_remote_cap_get(ecmd, port); 557 } 558 559 if (port->caps.type == PRESTERA_PORT_TYPE_TP && 560 port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER) 561 prestera_port_mdix_get(ecmd, port); 562 563 return 0; 564 } 565 566 static int prestera_port_mdix_set(const struct ethtool_link_ksettings *ecmd, 567 struct prestera_port *port) 568 { 569 if (ecmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_INVALID && 570 port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER && 571 port->caps.type == PRESTERA_PORT_TYPE_TP) { 572 port->cfg_phy.mdix = ecmd->base.eth_tp_mdix_ctrl; 573 return prestera_hw_port_phy_mode_set(port, port->cfg_phy.admin, 574 port->autoneg, 575 port->cfg_phy.mode, 576 port->adver_link_modes, 577 port->cfg_phy.mdix); 578 } 579 return 0; 580 581 } 582 583 static int prestera_port_link_mode_set(struct prestera_port *port, 584 u32 speed, u8 duplex, u8 type) 585 { 586 u32 new_mode = PRESTERA_LINK_MODE_MAX; 587 u32 mode; 588 int err; 589 590 for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) { 591 if (speed != SPEED_UNKNOWN && 592 speed != port_link_modes[mode].speed) 593 continue; 594 595 if (duplex != DUPLEX_UNKNOWN && 596 duplex != port_link_modes[mode].duplex) 597 continue; 598 599 if (!(port_link_modes[mode].pr_mask & 600 port->caps.supp_link_modes)) 601 continue; 602 603 if (type != port_link_modes[mode].port_type) 604 continue; 605 606 new_mode = mode; 607 break; 608 } 609 610 if (new_mode == PRESTERA_LINK_MODE_MAX) 611 return -EOPNOTSUPP; 612 613 err = prestera_hw_port_phy_mode_set(port, port->cfg_phy.admin, 614 false, new_mode, 0, 615 port->cfg_phy.mdix); 616 if (err) 617 return err; 618 619 port->adver_fec = BIT(PRESTERA_PORT_FEC_OFF); 620 port->adver_link_modes = 0; 621 port->cfg_phy.mode = new_mode; 622 port->autoneg = false; 623 624 return 0; 625 } 626 627 static int 628 prestera_port_speed_duplex_set(const struct ethtool_link_ksettings *ecmd, 629 struct prestera_port *port) 630 { 631 u8 duplex = DUPLEX_UNKNOWN; 632 633 if (ecmd->base.duplex != DUPLEX_UNKNOWN) 634 duplex = ecmd->base.duplex == DUPLEX_FULL ? 635 PRESTERA_PORT_DUPLEX_FULL : PRESTERA_PORT_DUPLEX_HALF; 636 637 return prestera_port_link_mode_set(port, ecmd->base.speed, duplex, 638 port->caps.type); 639 } 640 641 static int 642 prestera_ethtool_set_link_ksettings(struct net_device *dev, 643 const struct ethtool_link_ksettings *ecmd) 644 { 645 struct prestera_port *port = netdev_priv(dev); 646 u64 adver_modes; 647 u8 adver_fec; 648 int err; 649 650 err = prestera_port_type_set(ecmd, port); 651 if (err) 652 return err; 653 654 if (port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER) { 655 err = prestera_port_mdix_set(ecmd, port); 656 if (err) 657 return err; 658 } 659 660 prestera_modes_from_eth(ecmd->link_modes.advertising, &adver_modes, 661 &adver_fec, port->caps.type); 662 663 if (ecmd->base.autoneg == AUTONEG_ENABLE) 664 err = prestera_port_autoneg_set(port, adver_modes); 665 else 666 err = prestera_port_speed_duplex_set(ecmd, port); 667 668 return err; 669 } 670 671 static int prestera_ethtool_get_fecparam(struct net_device *dev, 672 struct ethtool_fecparam *fecparam) 673 { 674 struct prestera_port *port = netdev_priv(dev); 675 u8 active; 676 u32 mode; 677 int err; 678 679 err = prestera_hw_port_mac_mode_get(port, NULL, NULL, NULL, &active); 680 if (err) 681 return err; 682 683 fecparam->fec = 0; 684 685 for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) { 686 if ((port_fec_caps[mode].pr_fec & port->caps.supp_fec) == 0) 687 continue; 688 689 fecparam->fec |= port_fec_caps[mode].eth_fec; 690 } 691 692 if (active < PRESTERA_PORT_FEC_MAX) 693 fecparam->active_fec = port_fec_caps[active].eth_fec; 694 else 695 fecparam->active_fec = ETHTOOL_FEC_AUTO; 696 697 return 0; 698 } 699 700 static int prestera_ethtool_set_fecparam(struct net_device *dev, 701 struct ethtool_fecparam *fecparam) 702 { 703 struct prestera_port *port = netdev_priv(dev); 704 struct prestera_port_mac_config cfg_mac; 705 u32 mode; 706 u8 fec; 707 708 if (port->autoneg) { 709 netdev_err(dev, "FEC set is not allowed while autoneg is on\n"); 710 return -EINVAL; 711 } 712 713 if (port->caps.transceiver == PRESTERA_PORT_TCVR_SFP) { 714 netdev_err(dev, "FEC set is not allowed on non-SFP ports\n"); 715 return -EINVAL; 716 } 717 718 fec = PRESTERA_PORT_FEC_MAX; 719 for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) { 720 if ((port_fec_caps[mode].eth_fec & fecparam->fec) && 721 (port_fec_caps[mode].pr_fec & port->caps.supp_fec)) { 722 fec = mode; 723 break; 724 } 725 } 726 727 prestera_port_cfg_mac_read(port, &cfg_mac); 728 729 if (fec == cfg_mac.fec) 730 return 0; 731 732 if (fec == PRESTERA_PORT_FEC_MAX) { 733 netdev_err(dev, "Unsupported FEC requested"); 734 return -EINVAL; 735 } 736 737 cfg_mac.fec = fec; 738 739 return prestera_port_cfg_mac_write(port, &cfg_mac); 740 } 741 742 static int prestera_ethtool_get_sset_count(struct net_device *dev, int sset) 743 { 744 switch (sset) { 745 case ETH_SS_STATS: 746 return PRESTERA_STATS_CNT; 747 default: 748 return -EOPNOTSUPP; 749 } 750 } 751 752 static void prestera_ethtool_get_strings(struct net_device *dev, 753 u32 stringset, u8 *data) 754 { 755 if (stringset != ETH_SS_STATS) 756 return; 757 758 memcpy(data, prestera_cnt_name, sizeof(prestera_cnt_name)); 759 } 760 761 static void prestera_ethtool_get_stats(struct net_device *dev, 762 struct ethtool_stats *stats, u64 *data) 763 { 764 struct prestera_port *port = netdev_priv(dev); 765 struct prestera_port_stats *port_stats; 766 767 port_stats = &port->cached_hw_stats.stats; 768 769 memcpy(data, port_stats, sizeof(*port_stats)); 770 } 771 772 static int prestera_ethtool_nway_reset(struct net_device *dev) 773 { 774 struct prestera_port *port = netdev_priv(dev); 775 776 if (netif_running(dev) && 777 port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER && 778 port->caps.type == PRESTERA_PORT_TYPE_TP) 779 return prestera_hw_port_autoneg_restart(port); 780 781 return -EINVAL; 782 } 783 784 void prestera_ethtool_port_state_changed(struct prestera_port *port, 785 struct prestera_port_event *evt) 786 { 787 struct prestera_port_mac_state *smac = &port->state_mac; 788 789 smac->oper = evt->data.mac.oper; 790 791 if (smac->oper) { 792 smac->mode = evt->data.mac.mode; 793 smac->speed = evt->data.mac.speed; 794 smac->duplex = evt->data.mac.duplex; 795 smac->fc = evt->data.mac.fc; 796 smac->fec = evt->data.mac.fec; 797 } else { 798 smac->mode = PRESTERA_MAC_MODE_MAX; 799 smac->speed = SPEED_UNKNOWN; 800 smac->duplex = DUPLEX_UNKNOWN; 801 smac->fc = 0; 802 smac->fec = 0; 803 } 804 } 805 806 const struct ethtool_ops prestera_ethtool_ops = { 807 .get_drvinfo = prestera_ethtool_get_drvinfo, 808 .get_link_ksettings = prestera_ethtool_get_link_ksettings, 809 .set_link_ksettings = prestera_ethtool_set_link_ksettings, 810 .get_fecparam = prestera_ethtool_get_fecparam, 811 .set_fecparam = prestera_ethtool_set_fecparam, 812 .get_sset_count = prestera_ethtool_get_sset_count, 813 .get_strings = prestera_ethtool_get_strings, 814 .get_ethtool_stats = prestera_ethtool_get_stats, 815 .get_link = ethtool_op_get_link, 816 .nway_reset = prestera_ethtool_nway_reset 817 }; 818