FILE
serdes.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/dsa/mv88e6xxx/serdes.c
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Marvell 88E6xxx SERDES manipulation, via SMI bus 4 * 5 * Copyright (c) 2008 Marvell Semiconductor 6 * 7 * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch> 8 */ 9 10#include <linux/interrupt.h> 11#include <linux/irqdomain.h> 12#include <linux/mii.h> 13 14#include "chip.h" 15#include "global2.h" 16#include "phy.h" 17#include "port.h" 18#include "serdes.h" 19 20static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int reg, 21 u16 *val) 22{ 23 return mv88e6xxx_phy_page_read(chip, MV88E6352_ADDR_SERDES, 24 MV88E6352_SERDES_PAGE_FIBER, 25 reg, val); 26} 27 28static int mv88e6390_serdes_read(struct mv88e6xxx_chip *chip, 29 int lane, int device, int reg, u16 *val) 30{ 31 return mv88e6xxx_phy_read_c45(chip, lane, device, reg, val); 32} 33 34int mv88e6xxx_pcs_decode_state(struct device *dev, u16 bmsr, u16 lpa, 35 u16 status, struct phylink_link_state *state) 36{ 37 state->link = false; 38 39 /* If the BMSR reports that the link had failed, report this to 40 * phylink. 41 */ 42 if (!(bmsr & BMSR_LSTATUS)) 43 return 0; 44 45 state->link = !!(status & MV88E6390_SGMII_PHY_STATUS_LINK); 46 state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE); 47 48 if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) { 49 /* The Spped and Duplex Resolved register is 1 if AN is enabled 50 * and complete, or if AN is disabled. So with disabled AN we 51 * still get here on link up. 52 */ 53 state->duplex = status & 54 MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ? 55 DUPLEX_FULL : DUPLEX_HALF; 56 57 if (status & MV88E6390_SGMII_PHY_STATUS_TX_PAUSE) 58 state->pause |= MLO_PAUSE_TX; 59 if (status & MV88E6390_SGMII_PHY_STATUS_RX_PAUSE) 60 state->pause |= MLO_PAUSE_RX; 61 62 switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) { 63 case MV88E6390_SGMII_PHY_STATUS_SPEED_1000: 64 if (state->interface == PHY_INTERFACE_MODE_2500BASEX) 65 state->speed = SPEED_2500; 66 else 67 state->speed = SPEED_1000; 68 break; 69 case MV88E6390_SGMII_PHY_STATUS_SPEED_100: 70 state->speed = SPEED_100; 71 break; 72 case MV88E6390_SGMII_PHY_STATUS_SPEED_10: 73 state->speed = SPEED_10; 74 break; 75 default: 76 dev_err(dev, "invalid PHY speed\n"); 77 return -EINVAL; 78 } 79 } else if (state->link && 80 state->interface != PHY_INTERFACE_MODE_SGMII) { 81 /* If Speed and Duplex Resolved register is 0 and link is up, it 82 * means that AN was enabled, but link partner had it disabled 83 * and the PHY invoked the Auto-Negotiation Bypass feature and 84 * linked anyway. 85 */ 86 state->duplex = DUPLEX_FULL; 87 if (state->interface == PHY_INTERFACE_MODE_2500BASEX) 88 state->speed = SPEED_2500; 89 else 90 state->speed = SPEED_1000; 91 } else { 92 state->link = false; 93 } 94 95 if (state->interface == PHY_INTERFACE_MODE_2500BASEX) 96 mii_lpa_mod_linkmode_x(state->lp_advertising, lpa, 97 ETHTOOL_LINK_MODE_2500baseX_Full_BIT); 98 else if (state->interface == PHY_INTERFACE_MODE_1000BASEX) 99 mii_lpa_mod_linkmode_x(state->lp_advertising, lpa, 100 ETHTOOL_LINK_MODE_1000baseX_Full_BIT); 101 102 return 0; 103} 104 105struct mv88e6352_serdes_hw_stat { 106 char string[ETH_GSTRING_LEN]; 107 int sizeof_stat; 108 int reg; 109}; 110 111static struct mv88e6352_serdes_hw_stat mv88e6352_serdes_hw_stats[] = { 112 { "serdes_fibre_rx_error", 16, 21 }, 113 { "serdes_PRBS_error", 32, 24 }, 114}; 115 116int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port) 117{ 118 int err; 119 120 err = mv88e6352_g2_scratch_port_has_serdes(chip, port); 121 if (err <= 0) 122 return err; 123 124 return ARRAY_SIZE(mv88e6352_serdes_hw_stats); 125} 126 127int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, int port, 128 uint8_t **data) 129{ 130 struct mv88e6352_serdes_hw_stat *stat; 131 int err, i; 132 133 err = mv88e6352_g2_scratch_port_has_serdes(chip, port); 134 if (err <= 0) 135 return err; 136 137 for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) { 138 stat = &mv88e6352_serdes_hw_stats[i]; 139 ethtool_puts(data, stat->string); 140 } 141 return ARRAY_SIZE(mv88e6352_serdes_hw_stats); 142} 143 144static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip *chip, 145 struct mv88e6352_serdes_hw_stat *stat) 146{ 147 u64 val = 0; 148 u16 reg; 149 int err; 150 151 err = mv88e6352_serdes_read(chip, stat->reg, ®); 152 if (err) { 153 dev_err(chip->dev, "failed to read statistic\n"); 154 return 0; 155 } 156 157 val = reg; 158 159 if (stat->sizeof_stat == 32) { 160 err = mv88e6352_serdes_read(chip, stat->reg + 1, ®); 161 if (err) { 162 dev_err(chip->dev, "failed to read statistic\n"); 163 return 0; 164 } 165 val = val << 16 | reg; 166 } 167 168 return val; 169} 170 171size_t mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, 172 uint64_t *data) 173{ 174 struct mv88e6xxx_port *mv88e6xxx_port = &chip->ports[port]; 175 struct mv88e6352_serdes_hw_stat *stat; 176 int i, err; 177 u64 value; 178 179 err = mv88e6352_g2_scratch_port_has_serdes(chip, port); 180 if (err <= 0) 181 return 0; 182 183 BUILD_BUG_ON(ARRAY_SIZE(mv88e6352_serdes_hw_stats) > 184 ARRAY_SIZE(mv88e6xxx_port->serdes_stats)); 185 186 for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) { 187 stat = &mv88e6352_serdes_hw_stats[i]; 188 value = mv88e6352_serdes_get_stat(chip, stat); 189 mv88e6xxx_port->serdes_stats[i] += value; 190 data[i] = mv88e6xxx_port->serdes_stats[i]; 191 } 192 193 return ARRAY_SIZE(mv88e6352_serdes_hw_stats); 194} 195 196unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port) 197{ 198 return irq_find_mapping(chip->g2_irq.domain, MV88E6352_SERDES_IRQ); 199} 200 201int mv88e6352_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port) 202{ 203 int err; 204 205 mv88e6xxx_reg_lock(chip); 206 err = mv88e6352_g2_scratch_port_has_serdes(chip, port); 207 mv88e6xxx_reg_unlock(chip); 208 if (err <= 0) 209 return err; 210 211 return 32 * sizeof(u16); 212} 213 214void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p) 215{ 216 u16 *p = _p; 217 u16 reg; 218 int err; 219 int i; 220 221 err = mv88e6352_g2_scratch_port_has_serdes(chip, port); 222 if (err <= 0) 223 return; 224 225 for (i = 0 ; i < 32; i++) { 226 err = mv88e6352_serdes_read(chip, i, ®); 227 if (!err) 228 p[i] = reg; 229 } 230} 231 232int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) 233{ 234 u8 cmode = chip->ports[port].cmode; 235 int lane = -ENODEV; 236 237 switch (port) { 238 case 5: 239 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 240 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || 241 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 242 lane = MV88E6341_PORT5_LANE; 243 break; 244 } 245 246 return lane; 247} 248 249int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) 250{ 251 u8 cmode = chip->ports[port].cmode; 252 int lane = -ENODEV; 253 254 switch (port) { 255 case 9: 256 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 257 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || 258 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 259 lane = MV88E6390_PORT9_LANE0; 260 break; 261 case 10: 262 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 263 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || 264 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 265 lane = MV88E6390_PORT10_LANE0; 266 break; 267 } 268 269 return lane; 270} 271 272int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) 273{ 274 u8 cmode_port = chip->ports[port].cmode; 275 u8 cmode_port10 = chip->ports[10].cmode; 276 u8 cmode_port9 = chip->ports[9].cmode; 277 int lane = -ENODEV; 278 279 switch (port) { 280 case 2: 281 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 282 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 283 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 284 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) 285 lane = MV88E6390_PORT9_LANE1; 286 break; 287 case 3: 288 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 289 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 290 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 291 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 292 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) 293 lane = MV88E6390_PORT9_LANE2; 294 break; 295 case 4: 296 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 297 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 298 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 299 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 300 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) 301 lane = MV88E6390_PORT9_LANE3; 302 break; 303 case 5: 304 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 305 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 306 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 307 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) 308 lane = MV88E6390_PORT10_LANE1; 309 break; 310 case 6: 311 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 312 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 313 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 314 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 315 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) 316 lane = MV88E6390_PORT10_LANE2; 317 break; 318 case 7: 319 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 320 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 321 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 322 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 323 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) 324 lane = MV88E6390_PORT10_LANE3; 325 break; 326 case 9: 327 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 328 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 329 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 330 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI || 331 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 332 lane = MV88E6390_PORT9_LANE0; 333 break; 334 case 10: 335 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 336 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 337 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 338 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI || 339 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 340 lane = MV88E6390_PORT10_LANE0; 341 break; 342 } 343 344 return lane; 345} 346 347/* Only Ports 0, 9 and 10 have SERDES lanes. Return the SERDES lane address 348 * a port is using else Returns -ENODEV. 349 */ 350int mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) 351{ 352 u8 cmode = chip->ports[port].cmode; 353 int lane = -ENODEV; 354 355 if (port != 0 && port != 9 && port != 10) 356 return -EOPNOTSUPP; 357 358 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 359 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || 360 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 361 cmode == MV88E6393X_PORT_STS_CMODE_5GBASER || 362 cmode == MV88E6393X_PORT_STS_CMODE_10GBASER || 363 cmode == MV88E6393X_PORT_STS_CMODE_USXGMII) 364 lane = port; 365 366 return lane; 367} 368 369struct mv88e6390_serdes_hw_stat { 370 char string[ETH_GSTRING_LEN]; 371 int reg; 372}; 373 374static struct mv88e6390_serdes_hw_stat mv88e6390_serdes_hw_stats[] = { 375 { "serdes_rx_pkts", 0xf021 }, 376 { "serdes_rx_bytes", 0xf024 }, 377 { "serdes_rx_pkts_error", 0xf027 }, 378}; 379 380int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port) 381{ 382 if (mv88e6xxx_serdes_get_lane(chip, port) < 0) 383 return 0; 384 385 return ARRAY_SIZE(mv88e6390_serdes_hw_stats); 386} 387 388int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip, int port, 389 uint8_t **data) 390{ 391 struct mv88e6390_serdes_hw_stat *stat; 392 int i; 393 394 if (mv88e6xxx_serdes_get_lane(chip, port) < 0) 395 return 0; 396 397 for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) { 398 stat = &mv88e6390_serdes_hw_stats[i]; 399 ethtool_puts(data, stat->string); 400 } 401 return ARRAY_SIZE(mv88e6390_serdes_hw_stats); 402} 403 404static uint64_t mv88e6390_serdes_get_stat(struct mv88e6xxx_chip *chip, int lane, 405 struct mv88e6390_serdes_hw_stat *stat) 406{ 407 u16 reg[3]; 408 int err, i; 409 410 for (i = 0; i < 3; i++) { 411 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, 412 stat->reg + i, ®[i]); 413 if (err) { 414 dev_err(chip->dev, "failed to read statistic\n"); 415 return 0; 416 } 417 } 418 419 return reg[0] | ((u64)reg[1] << 16) | ((u64)reg[2] << 32); 420} 421 422size_t mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, 423 uint64_t *data) 424{ 425 struct mv88e6390_serdes_hw_stat *stat; 426 int lane; 427 int i; 428 429 lane = mv88e6xxx_serdes_get_lane(chip, port); 430 if (lane < 0) 431 return 0; 432 433 for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) { 434 stat = &mv88e6390_serdes_hw_stats[i]; 435 data[i] = mv88e6390_serdes_get_stat(chip, lane, stat); 436 } 437 438 return ARRAY_SIZE(mv88e6390_serdes_hw_stats); 439} 440 441unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port) 442{ 443 return irq_find_mapping(chip->g2_irq.domain, port); 444} 445 446static const u16 mv88e6390_serdes_regs[] = { 447 /* SERDES common registers */ 448 0xf00a, 0xf00b, 0xf00c, 449 0xf010, 0xf011, 0xf012, 0xf013, 450 0xf016, 0xf017, 0xf018, 451 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f, 452 0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027, 453 0xf028, 0xf029, 454 0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037, 455 0xf038, 0xf039, 456 /* SGMII */ 457 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 458 0x2008, 459 0x200f, 460 0xa000, 0xa001, 0xa002, 0xa003, 461 /* 10Gbase-X */ 462 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 463 0x1008, 464 0x100e, 0x100f, 465 0x1018, 0x1019, 466 0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 467 0x9006, 468 0x9010, 0x9011, 0x9012, 0x9013, 0x9014, 0x9015, 0x9016, 469 /* 10Gbase-R */ 470 0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027, 471 0x1028, 0x1029, 0x102a, 0x102b, 472}; 473 474int mv88e6390_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port) 475{ 476 if (mv88e6xxx_serdes_get_lane(chip, port) < 0) 477 return 0; 478 479 return ARRAY_SIZE(mv88e6390_serdes_regs) * sizeof(u16); 480} 481 482void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p) 483{ 484 u16 *p = _p; 485 int lane; 486 u16 reg; 487 int err; 488 int i; 489 490 lane = mv88e6xxx_serdes_get_lane(chip, port); 491 if (lane < 0) 492 return; 493 494 for (i = 0 ; i < ARRAY_SIZE(mv88e6390_serdes_regs); i++) { 495 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, 496 mv88e6390_serdes_regs[i], ®); 497 if (!err) 498 p[i] = reg; 499 } 500}
~/
Read-only file preview.