brintos

brintos / linux-shallow public Read only

0
0
Text · 17.2 KiB · e08c90a Raw
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