mdio.c (17637B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * mdio.c: Generic support for MDIO-compatible transceivers 4 * Copyright 2006-2009 Solarflare Communications Inc. 5 */ 6 7#include <linux/kernel.h> 8#include <linux/capability.h> 9#include <linux/errno.h> 10#include <linux/ethtool.h> 11#include <linux/mdio.h> 12#include <linux/module.h> 13 14MODULE_DESCRIPTION("Generic support for MDIO-compatible transceivers"); 15MODULE_AUTHOR("Copyright 2006-2009 Solarflare Communications Inc."); 16MODULE_LICENSE("GPL"); 17 18/** 19 * mdio45_probe - probe for an MDIO (clause 45) device 20 * @mdio: MDIO interface 21 * @prtad: Expected PHY address 22 * 23 * This sets @prtad and @mmds in the MDIO interface if successful. 24 * Returns 0 on success, negative on error. 25 */ 26int mdio45_probe(struct mdio_if_info *mdio, int prtad) 27{ 28 int mmd, stat2, devs1, devs2; 29 30 /* Assume PHY must have at least one of PMA/PMD, WIS, PCS, PHY 31 * XS or DTE XS; give up if none is present. */ 32 for (mmd = 1; mmd <= 5; mmd++) { 33 /* Is this MMD present? */ 34 stat2 = mdio->mdio_read(mdio->dev, prtad, mmd, MDIO_STAT2); 35 if (stat2 < 0 || 36 (stat2 & MDIO_STAT2_DEVPRST) != MDIO_STAT2_DEVPRST_VAL) 37 continue; 38 39 /* It should tell us about all the other MMDs */ 40 devs1 = mdio->mdio_read(mdio->dev, prtad, mmd, MDIO_DEVS1); 41 devs2 = mdio->mdio_read(mdio->dev, prtad, mmd, MDIO_DEVS2); 42 if (devs1 < 0 || devs2 < 0) 43 continue; 44 45 mdio->prtad = prtad; 46 mdio->mmds = devs1 | (devs2 << 16); 47 return 0; 48 } 49 50 return -ENODEV; 51} 52EXPORT_SYMBOL(mdio45_probe); 53 54/** 55 * mdio_set_flag - set or clear flag in an MDIO register 56 * @mdio: MDIO interface 57 * @prtad: PHY address 58 * @devad: MMD address 59 * @addr: Register address 60 * @mask: Mask for flag (single bit set) 61 * @sense: New value of flag 62 * 63 * This debounces changes: it does not write the register if the flag 64 * already has the proper value. Returns 0 on success, negative on error. 65 */ 66int mdio_set_flag(const struct mdio_if_info *mdio, 67 int prtad, int devad, u16 addr, int mask, 68 bool sense) 69{ 70 int old_val = mdio->mdio_read(mdio->dev, prtad, devad, addr); 71 int new_val; 72 73 if (old_val < 0) 74 return old_val; 75 if (sense) 76 new_val = old_val | mask; 77 else 78 new_val = old_val & ~mask; 79 if (old_val == new_val) 80 return 0; 81 return mdio->mdio_write(mdio->dev, prtad, devad, addr, new_val); 82} 83EXPORT_SYMBOL(mdio_set_flag); 84 85/** 86 * mdio45_links_ok - is link status up/OK 87 * @mdio: MDIO interface 88 * @mmd_mask: Mask for MMDs to check 89 * 90 * Returns 1 if the PHY reports link status up/OK, 0 otherwise. 91 * @mmd_mask is normally @mdio->mmds, but if loopback is enabled 92 * the MMDs being bypassed should be excluded from the mask. 93 */ 94int mdio45_links_ok(const struct mdio_if_info *mdio, u32 mmd_mask) 95{ 96 int devad, reg; 97 98 if (!mmd_mask) { 99 /* Use absence of XGMII faults in lieu of link state */ 100 reg = mdio->mdio_read(mdio->dev, mdio->prtad, 101 MDIO_MMD_PHYXS, MDIO_STAT2); 102 return reg >= 0 && !(reg & MDIO_STAT2_RXFAULT); 103 } 104 105 for (devad = 0; mmd_mask; devad++) { 106 if (mmd_mask & (1 << devad)) { 107 mmd_mask &= ~(1 << devad); 108 109 /* Reset the latched status and fault flags */ 110 mdio->mdio_read(mdio->dev, mdio->prtad, 111 devad, MDIO_STAT1); 112 if (devad == MDIO_MMD_PMAPMD || devad == MDIO_MMD_PCS || 113 devad == MDIO_MMD_PHYXS || devad == MDIO_MMD_DTEXS) 114 mdio->mdio_read(mdio->dev, mdio->prtad, 115 devad, MDIO_STAT2); 116 117 /* Check the current status and fault flags */ 118 reg = mdio->mdio_read(mdio->dev, mdio->prtad, 119 devad, MDIO_STAT1); 120 if (reg < 0 || 121 (reg & (MDIO_STAT1_FAULT | MDIO_STAT1_LSTATUS)) != 122 MDIO_STAT1_LSTATUS) 123 return false; 124 } 125 } 126 127 return true; 128} 129EXPORT_SYMBOL(mdio45_links_ok); 130 131/** 132 * mdio45_nway_restart - restart auto-negotiation for this interface 133 * @mdio: MDIO interface 134 * 135 * Returns 0 on success, negative on error. 136 */ 137int mdio45_nway_restart(const struct mdio_if_info *mdio) 138{ 139 if (!(mdio->mmds & MDIO_DEVS_AN)) 140 return -EOPNOTSUPP; 141 142 mdio_set_flag(mdio, mdio->prtad, MDIO_MMD_AN, MDIO_CTRL1, 143 MDIO_AN_CTRL1_RESTART, true); 144 return 0; 145} 146EXPORT_SYMBOL(mdio45_nway_restart); 147 148static u32 mdio45_get_an(const struct mdio_if_info *mdio, u16 addr) 149{ 150 u32 result = 0; 151 int reg; 152 153 reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN, addr); 154 if (reg & ADVERTISE_10HALF) 155 result |= ADVERTISED_10baseT_Half; 156 if (reg & ADVERTISE_10FULL) 157 result |= ADVERTISED_10baseT_Full; 158 if (reg & ADVERTISE_100HALF) 159 result |= ADVERTISED_100baseT_Half; 160 if (reg & ADVERTISE_100FULL) 161 result |= ADVERTISED_100baseT_Full; 162 if (reg & ADVERTISE_PAUSE_CAP) 163 result |= ADVERTISED_Pause; 164 if (reg & ADVERTISE_PAUSE_ASYM) 165 result |= ADVERTISED_Asym_Pause; 166 return result; 167} 168 169/** 170 * mdio45_ethtool_gset_npage - get settings for ETHTOOL_GSET 171 * @mdio: MDIO interface 172 * @ecmd: Ethtool request structure 173 * @npage_adv: Modes currently advertised on next pages 174 * @npage_lpa: Modes advertised by link partner on next pages 175 * 176 * The @ecmd parameter is expected to have been cleared before calling 177 * mdio45_ethtool_gset_npage(). 178 * 179 * Since the CSRs for auto-negotiation using next pages are not fully 180 * standardised, this function does not attempt to decode them. The 181 * caller must pass them in. 182 */ 183void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, 184 struct ethtool_cmd *ecmd, 185 u32 npage_adv, u32 npage_lpa) 186{ 187 int reg; 188 u32 speed; 189 190 BUILD_BUG_ON(MDIO_SUPPORTS_C22 != ETH_MDIO_SUPPORTS_C22); 191 BUILD_BUG_ON(MDIO_SUPPORTS_C45 != ETH_MDIO_SUPPORTS_C45); 192 193 ecmd->transceiver = XCVR_INTERNAL; 194 ecmd->phy_address = mdio->prtad; 195 ecmd->mdio_support = 196 mdio->mode_support & (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22); 197 198 reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, 199 MDIO_CTRL2); 200 switch (reg & MDIO_PMA_CTRL2_TYPE) { 201 case MDIO_PMA_CTRL2_10GBT: 202 case MDIO_PMA_CTRL2_1000BT: 203 case MDIO_PMA_CTRL2_100BTX: 204 case MDIO_PMA_CTRL2_10BT: 205 ecmd->port = PORT_TP; 206 ecmd->supported = SUPPORTED_TP; 207 reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, 208 MDIO_SPEED); 209 if (reg & MDIO_SPEED_10G) 210 ecmd->supported |= SUPPORTED_10000baseT_Full; 211 if (reg & MDIO_PMA_SPEED_1000) 212 ecmd->supported |= (SUPPORTED_1000baseT_Full | 213 SUPPORTED_1000baseT_Half); 214 if (reg & MDIO_PMA_SPEED_100) 215 ecmd->supported |= (SUPPORTED_100baseT_Full | 216 SUPPORTED_100baseT_Half); 217 if (reg & MDIO_PMA_SPEED_10) 218 ecmd->supported |= (SUPPORTED_10baseT_Full | 219 SUPPORTED_10baseT_Half); 220 ecmd->advertising = ADVERTISED_TP; 221 break; 222 223 case MDIO_PMA_CTRL2_10GBCX4: 224 ecmd->port = PORT_OTHER; 225 ecmd->supported = 0; 226 ecmd->advertising = 0; 227 break; 228 229 case MDIO_PMA_CTRL2_10GBKX4: 230 case MDIO_PMA_CTRL2_10GBKR: 231 case MDIO_PMA_CTRL2_1000BKX: 232 ecmd->port = PORT_OTHER; 233 ecmd->supported = SUPPORTED_Backplane; 234 reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, 235 MDIO_PMA_EXTABLE); 236 if (reg & MDIO_PMA_EXTABLE_10GBKX4) 237 ecmd->supported |= SUPPORTED_10000baseKX4_Full; 238 if (reg & MDIO_PMA_EXTABLE_10GBKR) 239 ecmd->supported |= SUPPORTED_10000baseKR_Full; 240 if (reg & MDIO_PMA_EXTABLE_1000BKX) 241 ecmd->supported |= SUPPORTED_1000baseKX_Full; 242 reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, 243 MDIO_PMA_10GBR_FECABLE); 244 if (reg & MDIO_PMA_10GBR_FECABLE_ABLE) 245 ecmd->supported |= SUPPORTED_10000baseR_FEC; 246 ecmd->advertising = ADVERTISED_Backplane; 247 break; 248 249 /* All the other defined modes are flavours of optical */ 250 default: 251 ecmd->port = PORT_FIBRE; 252 ecmd->supported = SUPPORTED_FIBRE; 253 ecmd->advertising = ADVERTISED_FIBRE; 254 break; 255 } 256 257 if (mdio->mmds & MDIO_DEVS_AN) { 258 ecmd->supported |= SUPPORTED_Autoneg; 259 reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN, 260 MDIO_CTRL1); 261 if (reg & MDIO_AN_CTRL1_ENABLE) { 262 ecmd->autoneg = AUTONEG_ENABLE; 263 ecmd->advertising |= 264 ADVERTISED_Autoneg | 265 mdio45_get_an(mdio, MDIO_AN_ADVERTISE) | 266 npage_adv; 267 } else { 268 ecmd->autoneg = AUTONEG_DISABLE; 269 } 270 } else { 271 ecmd->autoneg = AUTONEG_DISABLE; 272 } 273 274 if (ecmd->autoneg) { 275 u32 modes = 0; 276 int an_stat = mdio->mdio_read(mdio->dev, mdio->prtad, 277 MDIO_MMD_AN, MDIO_STAT1); 278 279 /* If AN is complete and successful, report best common 280 * mode, otherwise report best advertised mode. */ 281 if (an_stat & MDIO_AN_STAT1_COMPLETE) { 282 ecmd->lp_advertising = 283 mdio45_get_an(mdio, MDIO_AN_LPA) | npage_lpa; 284 if (an_stat & MDIO_AN_STAT1_LPABLE) 285 ecmd->lp_advertising |= ADVERTISED_Autoneg; 286 modes = ecmd->advertising & ecmd->lp_advertising; 287 } 288 if ((modes & ~ADVERTISED_Autoneg) == 0) 289 modes = ecmd->advertising; 290 291 if (modes & (ADVERTISED_10000baseT_Full | 292 ADVERTISED_10000baseKX4_Full | 293 ADVERTISED_10000baseKR_Full)) { 294 speed = SPEED_10000; 295 ecmd->duplex = DUPLEX_FULL; 296 } else if (modes & (ADVERTISED_1000baseT_Full | 297 ADVERTISED_1000baseT_Half | 298 ADVERTISED_1000baseKX_Full)) { 299 speed = SPEED_1000; 300 ecmd->duplex = !(modes & ADVERTISED_1000baseT_Half); 301 } else if (modes & (ADVERTISED_100baseT_Full | 302 ADVERTISED_100baseT_Half)) { 303 speed = SPEED_100; 304 ecmd->duplex = !!(modes & ADVERTISED_100baseT_Full); 305 } else { 306 speed = SPEED_10; 307 ecmd->duplex = !!(modes & ADVERTISED_10baseT_Full); 308 } 309 } else { 310 /* Report forced settings */ 311 reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, 312 MDIO_CTRL1); 313 speed = (((reg & MDIO_PMA_CTRL1_SPEED1000) ? 100 : 1) 314 * ((reg & MDIO_PMA_CTRL1_SPEED100) ? 100 : 10)); 315 ecmd->duplex = (reg & MDIO_CTRL1_FULLDPLX || 316 speed == SPEED_10000); 317 } 318 319 ethtool_cmd_speed_set(ecmd, speed); 320 321 /* 10GBASE-T MDI/MDI-X */ 322 if (ecmd->port == PORT_TP 323 && (ethtool_cmd_speed(ecmd) == SPEED_10000)) { 324 switch (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, 325 MDIO_PMA_10GBT_SWAPPOL)) { 326 case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX: 327 ecmd->eth_tp_mdix = ETH_TP_MDI; 328 break; 329 case 0: 330 ecmd->eth_tp_mdix = ETH_TP_MDI_X; 331 break; 332 default: 333 /* It's complicated... */ 334 ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID; 335 break; 336 } 337 } 338} 339EXPORT_SYMBOL(mdio45_ethtool_gset_npage); 340 341/** 342 * mdio45_ethtool_ksettings_get_npage - get settings for ETHTOOL_GLINKSETTINGS 343 * @mdio: MDIO interface 344 * @cmd: Ethtool request structure 345 * @npage_adv: Modes currently advertised on next pages 346 * @npage_lpa: Modes advertised by link partner on next pages 347 * 348 * The @cmd parameter is expected to have been cleared before calling 349 * mdio45_ethtool_ksettings_get_npage(). 350 * 351 * Since the CSRs for auto-negotiation using next pages are not fully 352 * standardised, this function does not attempt to decode them. The 353 * caller must pass them in. 354 */ 355void mdio45_ethtool_ksettings_get_npage(const struct mdio_if_info *mdio, 356 struct ethtool_link_ksettings *cmd, 357 u32 npage_adv, u32 npage_lpa) 358{ 359 int reg; 360 u32 speed, supported = 0, advertising = 0, lp_advertising = 0; 361 362 BUILD_BUG_ON(MDIO_SUPPORTS_C22 != ETH_MDIO_SUPPORTS_C22); 363 BUILD_BUG_ON(MDIO_SUPPORTS_C45 != ETH_MDIO_SUPPORTS_C45); 364 365 cmd->base.phy_address = mdio->prtad; 366 cmd->base.mdio_support = 367 mdio->mode_support & (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22); 368 369 reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, 370 MDIO_CTRL2); 371 switch (reg & MDIO_PMA_CTRL2_TYPE) { 372 case MDIO_PMA_CTRL2_10GBT: 373 case MDIO_PMA_CTRL2_1000BT: 374 case MDIO_PMA_CTRL2_100BTX: 375 case MDIO_PMA_CTRL2_10BT: 376 cmd->base.port = PORT_TP; 377 supported = SUPPORTED_TP; 378 reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, 379 MDIO_SPEED); 380 if (reg & MDIO_SPEED_10G) 381 supported |= SUPPORTED_10000baseT_Full; 382 if (reg & MDIO_PMA_SPEED_1000) 383 supported |= (SUPPORTED_1000baseT_Full | 384 SUPPORTED_1000baseT_Half); 385 if (reg & MDIO_PMA_SPEED_100) 386 supported |= (SUPPORTED_100baseT_Full | 387 SUPPORTED_100baseT_Half); 388 if (reg & MDIO_PMA_SPEED_10) 389 supported |= (SUPPORTED_10baseT_Full | 390 SUPPORTED_10baseT_Half); 391 advertising = ADVERTISED_TP; 392 break; 393 394 case MDIO_PMA_CTRL2_10GBCX4: 395 cmd->base.port = PORT_OTHER; 396 supported = 0; 397 advertising = 0; 398 break; 399 400 case MDIO_PMA_CTRL2_10GBKX4: 401 case MDIO_PMA_CTRL2_10GBKR: 402 case MDIO_PMA_CTRL2_1000BKX: 403 cmd->base.port = PORT_OTHER; 404 supported = SUPPORTED_Backplane; 405 reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, 406 MDIO_PMA_EXTABLE); 407 if (reg & MDIO_PMA_EXTABLE_10GBKX4) 408 supported |= SUPPORTED_10000baseKX4_Full; 409 if (reg & MDIO_PMA_EXTABLE_10GBKR) 410 supported |= SUPPORTED_10000baseKR_Full; 411 if (reg & MDIO_PMA_EXTABLE_1000BKX) 412 supported |= SUPPORTED_1000baseKX_Full; 413 reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, 414 MDIO_PMA_10GBR_FECABLE); 415 if (reg & MDIO_PMA_10GBR_FECABLE_ABLE) 416 supported |= SUPPORTED_10000baseR_FEC; 417 advertising = ADVERTISED_Backplane; 418 break; 419 420 /* All the other defined modes are flavours of optical */ 421 default: 422 cmd->base.port = PORT_FIBRE; 423 supported = SUPPORTED_FIBRE; 424 advertising = ADVERTISED_FIBRE; 425 break; 426 } 427 428 if (mdio->mmds & MDIO_DEVS_AN) { 429 supported |= SUPPORTED_Autoneg; 430 reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN, 431 MDIO_CTRL1); 432 if (reg & MDIO_AN_CTRL1_ENABLE) { 433 cmd->base.autoneg = AUTONEG_ENABLE; 434 advertising |= 435 ADVERTISED_Autoneg | 436 mdio45_get_an(mdio, MDIO_AN_ADVERTISE) | 437 npage_adv; 438 } else { 439 cmd->base.autoneg = AUTONEG_DISABLE; 440 } 441 } else { 442 cmd->base.autoneg = AUTONEG_DISABLE; 443 } 444 445 if (cmd->base.autoneg) { 446 u32 modes = 0; 447 int an_stat = mdio->mdio_read(mdio->dev, mdio->prtad, 448 MDIO_MMD_AN, MDIO_STAT1); 449 450 /* If AN is complete and successful, report best common 451 * mode, otherwise report best advertised mode. 452 */ 453 if (an_stat & MDIO_AN_STAT1_COMPLETE) { 454 lp_advertising = 455 mdio45_get_an(mdio, MDIO_AN_LPA) | npage_lpa; 456 if (an_stat & MDIO_AN_STAT1_LPABLE) 457 lp_advertising |= ADVERTISED_Autoneg; 458 modes = advertising & lp_advertising; 459 } 460 if ((modes & ~ADVERTISED_Autoneg) == 0) 461 modes = advertising; 462 463 if (modes & (ADVERTISED_10000baseT_Full | 464 ADVERTISED_10000baseKX4_Full | 465 ADVERTISED_10000baseKR_Full)) { 466 speed = SPEED_10000; 467 cmd->base.duplex = DUPLEX_FULL; 468 } else if (modes & (ADVERTISED_1000baseT_Full | 469 ADVERTISED_1000baseT_Half | 470 ADVERTISED_1000baseKX_Full)) { 471 speed = SPEED_1000; 472 cmd->base.duplex = !(modes & ADVERTISED_1000baseT_Half); 473 } else if (modes & (ADVERTISED_100baseT_Full | 474 ADVERTISED_100baseT_Half)) { 475 speed = SPEED_100; 476 cmd->base.duplex = !!(modes & ADVERTISED_100baseT_Full); 477 } else { 478 speed = SPEED_10; 479 cmd->base.duplex = !!(modes & ADVERTISED_10baseT_Full); 480 } 481 } else { 482 /* Report forced settings */ 483 reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, 484 MDIO_CTRL1); 485 speed = (((reg & MDIO_PMA_CTRL1_SPEED1000) ? 100 : 1) 486 * ((reg & MDIO_PMA_CTRL1_SPEED100) ? 100 : 10)); 487 cmd->base.duplex = (reg & MDIO_CTRL1_FULLDPLX || 488 speed == SPEED_10000); 489 } 490 491 cmd->base.speed = speed; 492 493 ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, 494 supported); 495 ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, 496 advertising); 497 ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising, 498 lp_advertising); 499 500 /* 10GBASE-T MDI/MDI-X */ 501 if (cmd->base.port == PORT_TP && (cmd->base.speed == SPEED_10000)) { 502 switch (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, 503 MDIO_PMA_10GBT_SWAPPOL)) { 504 case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX: 505 cmd->base.eth_tp_mdix = ETH_TP_MDI; 506 break; 507 case 0: 508 cmd->base.eth_tp_mdix = ETH_TP_MDI_X; 509 break; 510 default: 511 /* It's complicated... */ 512 cmd->base.eth_tp_mdix = ETH_TP_MDI_INVALID; 513 break; 514 } 515 } 516} 517EXPORT_SYMBOL(mdio45_ethtool_ksettings_get_npage); 518 519/** 520 * mdio_mii_ioctl - MII ioctl interface for MDIO (clause 22 or 45) PHYs 521 * @mdio: MDIO interface 522 * @mii_data: MII ioctl data structure 523 * @cmd: MII ioctl command 524 * 525 * Returns 0 on success, negative on error. 526 */ 527int mdio_mii_ioctl(const struct mdio_if_info *mdio, 528 struct mii_ioctl_data *mii_data, int cmd) 529{ 530 int prtad, devad; 531 u16 addr = mii_data->reg_num; 532 533 /* Validate/convert cmd to one of SIOC{G,S}MIIREG */ 534 switch (cmd) { 535 case SIOCGMIIPHY: 536 if (mdio->prtad == MDIO_PRTAD_NONE) 537 return -EOPNOTSUPP; 538 mii_data->phy_id = mdio->prtad; 539 cmd = SIOCGMIIREG; 540 break; 541 case SIOCGMIIREG: 542 case SIOCSMIIREG: 543 break; 544 default: 545 return -EOPNOTSUPP; 546 } 547 548 /* Validate/convert phy_id */ 549 if ((mdio->mode_support & MDIO_SUPPORTS_C45) && 550 mdio_phy_id_is_c45(mii_data->phy_id)) { 551 prtad = mdio_phy_id_prtad(mii_data->phy_id); 552 devad = mdio_phy_id_devad(mii_data->phy_id); 553 } else if ((mdio->mode_support & MDIO_SUPPORTS_C22) && 554 mii_data->phy_id < 0x20) { 555 prtad = mii_data->phy_id; 556 devad = MDIO_DEVAD_NONE; 557 addr &= 0x1f; 558 } else if ((mdio->mode_support & MDIO_EMULATE_C22) && 559 mdio->prtad != MDIO_PRTAD_NONE && 560 mii_data->phy_id == mdio->prtad) { 561 /* Remap commonly-used MII registers. */ 562 prtad = mdio->prtad; 563 switch (addr) { 564 case MII_BMCR: 565 case MII_BMSR: 566 case MII_PHYSID1: 567 case MII_PHYSID2: 568 devad = __ffs(mdio->mmds); 569 break; 570 case MII_ADVERTISE: 571 case MII_LPA: 572 if (!(mdio->mmds & MDIO_DEVS_AN)) 573 return -EINVAL; 574 devad = MDIO_MMD_AN; 575 if (addr == MII_ADVERTISE) 576 addr = MDIO_AN_ADVERTISE; 577 else 578 addr = MDIO_AN_LPA; 579 break; 580 default: 581 return -EINVAL; 582 } 583 } else { 584 return -EINVAL; 585 } 586 587 if (cmd == SIOCGMIIREG) { 588 int rc = mdio->mdio_read(mdio->dev, prtad, devad, addr); 589 if (rc < 0) 590 return rc; 591 mii_data->val_out = rc; 592 return 0; 593 } else { 594 return mdio->mdio_write(mdio->dev, prtad, devad, addr, 595 mii_data->val_in); 596 } 597} 598EXPORT_SYMBOL(mdio_mii_ioctl);