599 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * mdio.c: Generic support for MDIO-compatible transceivers4 * 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) device20 * @mdio: MDIO interface21 * @prtad: Expected PHY address22 *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, PHY31 * 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 register56 * @mdio: MDIO interface57 * @prtad: PHY address58 * @devad: MMD address59 * @addr: Register address60 * @mask: Mask for flag (single bit set)61 * @sense: New value of flag62 *63 * This debounces changes: it does not write the register if the flag64 * 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 else78 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/OK87 * @mdio: MDIO interface88 * @mmd_mask: Mask for MMDs to check89 *90 * Returns 1 if the PHY reports link status up/OK, 0 otherwise.91 * @mmd_mask is normally @mdio->mmds, but if loopback is enabled92 * 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 interface133 * @mdio: MDIO interface134 *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_GSET171 * @mdio: MDIO interface172 * @ecmd: Ethtool request structure173 * @npage_adv: Modes currently advertised on next pages174 * @npage_lpa: Modes advertised by link partner on next pages175 *176 * The @ecmd parameter is expected to have been cleared before calling177 * mdio45_ethtool_gset_npage().178 *179 * Since the CSRs for auto-negotiation using next pages are not fully180 * standardised, this function does not attempt to decode them. The181 * 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 common280 * 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_TP323 && (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_GLINKSETTINGS343 * @mdio: MDIO interface344 * @cmd: Ethtool request structure345 * @npage_adv: Modes currently advertised on next pages346 * @npage_lpa: Modes advertised by link partner on next pages347 *348 * The @cmd parameter is expected to have been cleared before calling349 * mdio45_ethtool_ksettings_get_npage().350 *351 * Since the CSRs for auto-negotiation using next pages are not fully352 * standardised, this function does not attempt to decode them. The353 * 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 common451 * 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) PHYs521 * @mdio: MDIO interface522 * @mii_data: MII ioctl data structure523 * @cmd: MII ioctl command524 *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 else578 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);599