18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci	mii.c: MII interface library
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci	Maintained by Jeff Garzik <jgarzik@pobox.com>
68c2ecf20Sopenharmony_ci	Copyright 2001,2002 Jeff Garzik
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci	Various code came from myson803.c and other files by
98c2ecf20Sopenharmony_ci	Donald Becker.  Copyright:
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci		Written 1998-2002 by Donald Becker.
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci		This software may be used and distributed according
148c2ecf20Sopenharmony_ci		to the terms of the GNU General Public License (GPL),
158c2ecf20Sopenharmony_ci		incorporated herein by reference.  Drivers based on
168c2ecf20Sopenharmony_ci		or derived from this code fall under the GPL and must
178c2ecf20Sopenharmony_ci		retain the authorship, copyright and license notice.
188c2ecf20Sopenharmony_ci		This file is not a complete program and may only be
198c2ecf20Sopenharmony_ci		used when the entire operating system is licensed
208c2ecf20Sopenharmony_ci		under the GPL.
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci		The author may be reached as becker@scyld.com, or C/O
238c2ecf20Sopenharmony_ci		Scyld Computing Corporation
248c2ecf20Sopenharmony_ci		410 Severn Ave., Suite 210
258c2ecf20Sopenharmony_ci		Annapolis MD 21403
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include <linux/kernel.h>
318c2ecf20Sopenharmony_ci#include <linux/module.h>
328c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
338c2ecf20Sopenharmony_ci#include <linux/ethtool.h>
348c2ecf20Sopenharmony_ci#include <linux/mii.h>
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic u32 mii_get_an(struct mii_if_info *mii, u16 addr)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	int advert;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	advert = mii->mdio_read(mii->dev, mii->phy_id, addr);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	return mii_lpa_to_ethtool_lpa_t(advert);
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/**
468c2ecf20Sopenharmony_ci * mii_ethtool_gset - get settings that are specified in @ecmd
478c2ecf20Sopenharmony_ci * @mii: MII interface
488c2ecf20Sopenharmony_ci * @ecmd: requested ethtool_cmd
498c2ecf20Sopenharmony_ci *
508c2ecf20Sopenharmony_ci * The @ecmd parameter is expected to have been cleared before calling
518c2ecf20Sopenharmony_ci * mii_ethtool_gset().
528c2ecf20Sopenharmony_ci *
538c2ecf20Sopenharmony_ci * Returns 0 for success, negative on error.
548c2ecf20Sopenharmony_ci */
558c2ecf20Sopenharmony_ciint mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	struct net_device *dev = mii->dev;
588c2ecf20Sopenharmony_ci	u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0;
598c2ecf20Sopenharmony_ci	u32 nego;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	ecmd->supported =
628c2ecf20Sopenharmony_ci	    (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
638c2ecf20Sopenharmony_ci	     SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
648c2ecf20Sopenharmony_ci	     SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
658c2ecf20Sopenharmony_ci	if (mii->supports_gmii)
668c2ecf20Sopenharmony_ci		ecmd->supported |= SUPPORTED_1000baseT_Half |
678c2ecf20Sopenharmony_ci			SUPPORTED_1000baseT_Full;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	/* only supports twisted-pair */
708c2ecf20Sopenharmony_ci	ecmd->port = PORT_MII;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	/* only supports internal transceiver */
738c2ecf20Sopenharmony_ci	ecmd->transceiver = XCVR_INTERNAL;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	/* this isn't fully supported at higher layers */
768c2ecf20Sopenharmony_ci	ecmd->phy_address = mii->phy_id;
778c2ecf20Sopenharmony_ci	ecmd->mdio_support = ETH_MDIO_SUPPORTS_C22;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
828c2ecf20Sopenharmony_ci	bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR);
838c2ecf20Sopenharmony_ci	if (mii->supports_gmii) {
848c2ecf20Sopenharmony_ci 		ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
858c2ecf20Sopenharmony_ci		stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci	if (bmcr & BMCR_ANENABLE) {
888c2ecf20Sopenharmony_ci		ecmd->advertising |= ADVERTISED_Autoneg;
898c2ecf20Sopenharmony_ci		ecmd->autoneg = AUTONEG_ENABLE;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci		ecmd->advertising |= mii_get_an(mii, MII_ADVERTISE);
928c2ecf20Sopenharmony_ci		if (mii->supports_gmii)
938c2ecf20Sopenharmony_ci			ecmd->advertising |=
948c2ecf20Sopenharmony_ci					mii_ctrl1000_to_ethtool_adv_t(ctrl1000);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci		if (bmsr & BMSR_ANEGCOMPLETE) {
978c2ecf20Sopenharmony_ci			ecmd->lp_advertising = mii_get_an(mii, MII_LPA);
988c2ecf20Sopenharmony_ci			ecmd->lp_advertising |=
998c2ecf20Sopenharmony_ci					mii_stat1000_to_ethtool_lpa_t(stat1000);
1008c2ecf20Sopenharmony_ci		} else {
1018c2ecf20Sopenharmony_ci			ecmd->lp_advertising = 0;
1028c2ecf20Sopenharmony_ci		}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci		nego = ecmd->advertising & ecmd->lp_advertising;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci		if (nego & (ADVERTISED_1000baseT_Full |
1078c2ecf20Sopenharmony_ci			    ADVERTISED_1000baseT_Half)) {
1088c2ecf20Sopenharmony_ci			ethtool_cmd_speed_set(ecmd, SPEED_1000);
1098c2ecf20Sopenharmony_ci			ecmd->duplex = !!(nego & ADVERTISED_1000baseT_Full);
1108c2ecf20Sopenharmony_ci		} else if (nego & (ADVERTISED_100baseT_Full |
1118c2ecf20Sopenharmony_ci				   ADVERTISED_100baseT_Half)) {
1128c2ecf20Sopenharmony_ci			ethtool_cmd_speed_set(ecmd, SPEED_100);
1138c2ecf20Sopenharmony_ci			ecmd->duplex = !!(nego & ADVERTISED_100baseT_Full);
1148c2ecf20Sopenharmony_ci		} else {
1158c2ecf20Sopenharmony_ci			ethtool_cmd_speed_set(ecmd, SPEED_10);
1168c2ecf20Sopenharmony_ci			ecmd->duplex = !!(nego & ADVERTISED_10baseT_Full);
1178c2ecf20Sopenharmony_ci		}
1188c2ecf20Sopenharmony_ci	} else {
1198c2ecf20Sopenharmony_ci		ecmd->autoneg = AUTONEG_DISABLE;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci		ethtool_cmd_speed_set(ecmd,
1228c2ecf20Sopenharmony_ci				      ((bmcr & BMCR_SPEED1000 &&
1238c2ecf20Sopenharmony_ci					(bmcr & BMCR_SPEED100) == 0) ?
1248c2ecf20Sopenharmony_ci				       SPEED_1000 :
1258c2ecf20Sopenharmony_ci				       ((bmcr & BMCR_SPEED100) ?
1268c2ecf20Sopenharmony_ci					SPEED_100 : SPEED_10)));
1278c2ecf20Sopenharmony_ci		ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	mii->full_duplex = ecmd->duplex;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	/* ignore maxtxpkt, maxrxpkt for now */
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	return 0;
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci/**
1388c2ecf20Sopenharmony_ci * mii_ethtool_get_link_ksettings - get settings that are specified in @cmd
1398c2ecf20Sopenharmony_ci * @mii: MII interface
1408c2ecf20Sopenharmony_ci * @cmd: requested ethtool_link_ksettings
1418c2ecf20Sopenharmony_ci *
1428c2ecf20Sopenharmony_ci * The @cmd parameter is expected to have been cleared before calling
1438c2ecf20Sopenharmony_ci * mii_ethtool_get_link_ksettings().
1448c2ecf20Sopenharmony_ci */
1458c2ecf20Sopenharmony_civoid mii_ethtool_get_link_ksettings(struct mii_if_info *mii,
1468c2ecf20Sopenharmony_ci				    struct ethtool_link_ksettings *cmd)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	struct net_device *dev = mii->dev;
1498c2ecf20Sopenharmony_ci	u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0;
1508c2ecf20Sopenharmony_ci	u32 nego, supported, advertising, lp_advertising;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
1538c2ecf20Sopenharmony_ci		     SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
1548c2ecf20Sopenharmony_ci		     SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
1558c2ecf20Sopenharmony_ci	if (mii->supports_gmii)
1568c2ecf20Sopenharmony_ci		supported |= SUPPORTED_1000baseT_Half |
1578c2ecf20Sopenharmony_ci			SUPPORTED_1000baseT_Full;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	/* only supports twisted-pair */
1608c2ecf20Sopenharmony_ci	cmd->base.port = PORT_MII;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	/* this isn't fully supported at higher layers */
1638c2ecf20Sopenharmony_ci	cmd->base.phy_address = mii->phy_id;
1648c2ecf20Sopenharmony_ci	cmd->base.mdio_support = ETH_MDIO_SUPPORTS_C22;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	advertising = ADVERTISED_TP | ADVERTISED_MII;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
1698c2ecf20Sopenharmony_ci	bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR);
1708c2ecf20Sopenharmony_ci	if (mii->supports_gmii) {
1718c2ecf20Sopenharmony_ci		ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
1728c2ecf20Sopenharmony_ci		stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci	if (bmcr & BMCR_ANENABLE) {
1758c2ecf20Sopenharmony_ci		advertising |= ADVERTISED_Autoneg;
1768c2ecf20Sopenharmony_ci		cmd->base.autoneg = AUTONEG_ENABLE;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci		advertising |= mii_get_an(mii, MII_ADVERTISE);
1798c2ecf20Sopenharmony_ci		if (mii->supports_gmii)
1808c2ecf20Sopenharmony_ci			advertising |= mii_ctrl1000_to_ethtool_adv_t(ctrl1000);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci		if (bmsr & BMSR_ANEGCOMPLETE) {
1838c2ecf20Sopenharmony_ci			lp_advertising = mii_get_an(mii, MII_LPA);
1848c2ecf20Sopenharmony_ci			lp_advertising |=
1858c2ecf20Sopenharmony_ci					mii_stat1000_to_ethtool_lpa_t(stat1000);
1868c2ecf20Sopenharmony_ci		} else {
1878c2ecf20Sopenharmony_ci			lp_advertising = 0;
1888c2ecf20Sopenharmony_ci		}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci		nego = advertising & lp_advertising;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci		if (nego & (ADVERTISED_1000baseT_Full |
1938c2ecf20Sopenharmony_ci			    ADVERTISED_1000baseT_Half)) {
1948c2ecf20Sopenharmony_ci			cmd->base.speed = SPEED_1000;
1958c2ecf20Sopenharmony_ci			cmd->base.duplex = !!(nego & ADVERTISED_1000baseT_Full);
1968c2ecf20Sopenharmony_ci		} else if (nego & (ADVERTISED_100baseT_Full |
1978c2ecf20Sopenharmony_ci				   ADVERTISED_100baseT_Half)) {
1988c2ecf20Sopenharmony_ci			cmd->base.speed = SPEED_100;
1998c2ecf20Sopenharmony_ci			cmd->base.duplex = !!(nego & ADVERTISED_100baseT_Full);
2008c2ecf20Sopenharmony_ci		} else {
2018c2ecf20Sopenharmony_ci			cmd->base.speed = SPEED_10;
2028c2ecf20Sopenharmony_ci			cmd->base.duplex = !!(nego & ADVERTISED_10baseT_Full);
2038c2ecf20Sopenharmony_ci		}
2048c2ecf20Sopenharmony_ci	} else {
2058c2ecf20Sopenharmony_ci		cmd->base.autoneg = AUTONEG_DISABLE;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci		cmd->base.speed = ((bmcr & BMCR_SPEED1000 &&
2088c2ecf20Sopenharmony_ci				    (bmcr & BMCR_SPEED100) == 0) ?
2098c2ecf20Sopenharmony_ci				   SPEED_1000 :
2108c2ecf20Sopenharmony_ci				   ((bmcr & BMCR_SPEED100) ?
2118c2ecf20Sopenharmony_ci				    SPEED_100 : SPEED_10));
2128c2ecf20Sopenharmony_ci		cmd->base.duplex = (bmcr & BMCR_FULLDPLX) ?
2138c2ecf20Sopenharmony_ci			DUPLEX_FULL : DUPLEX_HALF;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci		lp_advertising = 0;
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	mii->full_duplex = cmd->base.duplex;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
2218c2ecf20Sopenharmony_ci						supported);
2228c2ecf20Sopenharmony_ci	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
2238c2ecf20Sopenharmony_ci						advertising);
2248c2ecf20Sopenharmony_ci	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising,
2258c2ecf20Sopenharmony_ci						lp_advertising);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	/* ignore maxtxpkt, maxrxpkt for now */
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci/**
2318c2ecf20Sopenharmony_ci * mii_ethtool_sset - set settings that are specified in @ecmd
2328c2ecf20Sopenharmony_ci * @mii: MII interface
2338c2ecf20Sopenharmony_ci * @ecmd: requested ethtool_cmd
2348c2ecf20Sopenharmony_ci *
2358c2ecf20Sopenharmony_ci * Returns 0 for success, negative on error.
2368c2ecf20Sopenharmony_ci */
2378c2ecf20Sopenharmony_ciint mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	struct net_device *dev = mii->dev;
2408c2ecf20Sopenharmony_ci	u32 speed = ethtool_cmd_speed(ecmd);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	if (speed != SPEED_10 &&
2438c2ecf20Sopenharmony_ci	    speed != SPEED_100 &&
2448c2ecf20Sopenharmony_ci	    speed != SPEED_1000)
2458c2ecf20Sopenharmony_ci		return -EINVAL;
2468c2ecf20Sopenharmony_ci	if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
2478c2ecf20Sopenharmony_ci		return -EINVAL;
2488c2ecf20Sopenharmony_ci	if (ecmd->port != PORT_MII)
2498c2ecf20Sopenharmony_ci		return -EINVAL;
2508c2ecf20Sopenharmony_ci	if (ecmd->transceiver != XCVR_INTERNAL)
2518c2ecf20Sopenharmony_ci		return -EINVAL;
2528c2ecf20Sopenharmony_ci	if (ecmd->phy_address != mii->phy_id)
2538c2ecf20Sopenharmony_ci		return -EINVAL;
2548c2ecf20Sopenharmony_ci	if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
2558c2ecf20Sopenharmony_ci		return -EINVAL;
2568c2ecf20Sopenharmony_ci	if ((speed == SPEED_1000) && (!mii->supports_gmii))
2578c2ecf20Sopenharmony_ci		return -EINVAL;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	/* ignore supported, maxtxpkt, maxrxpkt */
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (ecmd->autoneg == AUTONEG_ENABLE) {
2628c2ecf20Sopenharmony_ci		u32 bmcr, advert, tmp;
2638c2ecf20Sopenharmony_ci		u32 advert2 = 0, tmp2 = 0;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci		if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
2668c2ecf20Sopenharmony_ci					  ADVERTISED_10baseT_Full |
2678c2ecf20Sopenharmony_ci					  ADVERTISED_100baseT_Half |
2688c2ecf20Sopenharmony_ci					  ADVERTISED_100baseT_Full |
2698c2ecf20Sopenharmony_ci					  ADVERTISED_1000baseT_Half |
2708c2ecf20Sopenharmony_ci					  ADVERTISED_1000baseT_Full)) == 0)
2718c2ecf20Sopenharmony_ci			return -EINVAL;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci		/* advertise only what has been requested */
2748c2ecf20Sopenharmony_ci		advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
2758c2ecf20Sopenharmony_ci		tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
2768c2ecf20Sopenharmony_ci		if (mii->supports_gmii) {
2778c2ecf20Sopenharmony_ci			advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
2788c2ecf20Sopenharmony_ci			tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
2798c2ecf20Sopenharmony_ci		}
2808c2ecf20Sopenharmony_ci		tmp |= ethtool_adv_to_mii_adv_t(ecmd->advertising);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci		if (mii->supports_gmii)
2838c2ecf20Sopenharmony_ci			tmp2 |=
2848c2ecf20Sopenharmony_ci			      ethtool_adv_to_mii_ctrl1000_t(ecmd->advertising);
2858c2ecf20Sopenharmony_ci		if (advert != tmp) {
2868c2ecf20Sopenharmony_ci			mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
2878c2ecf20Sopenharmony_ci			mii->advertising = tmp;
2888c2ecf20Sopenharmony_ci		}
2898c2ecf20Sopenharmony_ci		if ((mii->supports_gmii) && (advert2 != tmp2))
2908c2ecf20Sopenharmony_ci			mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci		/* turn on autonegotiation, and force a renegotiate */
2938c2ecf20Sopenharmony_ci		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
2948c2ecf20Sopenharmony_ci		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
2958c2ecf20Sopenharmony_ci		mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci		mii->force_media = 0;
2988c2ecf20Sopenharmony_ci	} else {
2998c2ecf20Sopenharmony_ci		u32 bmcr, tmp;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci		/* turn off auto negotiation, set speed and duplexity */
3028c2ecf20Sopenharmony_ci		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
3038c2ecf20Sopenharmony_ci		tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
3048c2ecf20Sopenharmony_ci			       BMCR_SPEED1000 | BMCR_FULLDPLX);
3058c2ecf20Sopenharmony_ci		if (speed == SPEED_1000)
3068c2ecf20Sopenharmony_ci			tmp |= BMCR_SPEED1000;
3078c2ecf20Sopenharmony_ci		else if (speed == SPEED_100)
3088c2ecf20Sopenharmony_ci			tmp |= BMCR_SPEED100;
3098c2ecf20Sopenharmony_ci		if (ecmd->duplex == DUPLEX_FULL) {
3108c2ecf20Sopenharmony_ci			tmp |= BMCR_FULLDPLX;
3118c2ecf20Sopenharmony_ci			mii->full_duplex = 1;
3128c2ecf20Sopenharmony_ci		} else
3138c2ecf20Sopenharmony_ci			mii->full_duplex = 0;
3148c2ecf20Sopenharmony_ci		if (bmcr != tmp)
3158c2ecf20Sopenharmony_ci			mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		mii->force_media = 1;
3188c2ecf20Sopenharmony_ci	}
3198c2ecf20Sopenharmony_ci	return 0;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci/**
3238c2ecf20Sopenharmony_ci * mii_ethtool_set_link_ksettings - set settings that are specified in @cmd
3248c2ecf20Sopenharmony_ci * @mii: MII interfaces
3258c2ecf20Sopenharmony_ci * @cmd: requested ethtool_link_ksettings
3268c2ecf20Sopenharmony_ci *
3278c2ecf20Sopenharmony_ci * Returns 0 for success, negative on error.
3288c2ecf20Sopenharmony_ci */
3298c2ecf20Sopenharmony_ciint mii_ethtool_set_link_ksettings(struct mii_if_info *mii,
3308c2ecf20Sopenharmony_ci				   const struct ethtool_link_ksettings *cmd)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	struct net_device *dev = mii->dev;
3338c2ecf20Sopenharmony_ci	u32 speed = cmd->base.speed;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	if (speed != SPEED_10 &&
3368c2ecf20Sopenharmony_ci	    speed != SPEED_100 &&
3378c2ecf20Sopenharmony_ci	    speed != SPEED_1000)
3388c2ecf20Sopenharmony_ci		return -EINVAL;
3398c2ecf20Sopenharmony_ci	if (cmd->base.duplex != DUPLEX_HALF && cmd->base.duplex != DUPLEX_FULL)
3408c2ecf20Sopenharmony_ci		return -EINVAL;
3418c2ecf20Sopenharmony_ci	if (cmd->base.port != PORT_MII)
3428c2ecf20Sopenharmony_ci		return -EINVAL;
3438c2ecf20Sopenharmony_ci	if (cmd->base.phy_address != mii->phy_id)
3448c2ecf20Sopenharmony_ci		return -EINVAL;
3458c2ecf20Sopenharmony_ci	if (cmd->base.autoneg != AUTONEG_DISABLE &&
3468c2ecf20Sopenharmony_ci	    cmd->base.autoneg != AUTONEG_ENABLE)
3478c2ecf20Sopenharmony_ci		return -EINVAL;
3488c2ecf20Sopenharmony_ci	if ((speed == SPEED_1000) && (!mii->supports_gmii))
3498c2ecf20Sopenharmony_ci		return -EINVAL;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	/* ignore supported, maxtxpkt, maxrxpkt */
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	if (cmd->base.autoneg == AUTONEG_ENABLE) {
3548c2ecf20Sopenharmony_ci		u32 bmcr, advert, tmp;
3558c2ecf20Sopenharmony_ci		u32 advert2 = 0, tmp2 = 0;
3568c2ecf20Sopenharmony_ci		u32 advertising;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci		ethtool_convert_link_mode_to_legacy_u32(
3598c2ecf20Sopenharmony_ci			&advertising, cmd->link_modes.advertising);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci		if ((advertising & (ADVERTISED_10baseT_Half |
3628c2ecf20Sopenharmony_ci				    ADVERTISED_10baseT_Full |
3638c2ecf20Sopenharmony_ci				    ADVERTISED_100baseT_Half |
3648c2ecf20Sopenharmony_ci				    ADVERTISED_100baseT_Full |
3658c2ecf20Sopenharmony_ci				    ADVERTISED_1000baseT_Half |
3668c2ecf20Sopenharmony_ci				    ADVERTISED_1000baseT_Full)) == 0)
3678c2ecf20Sopenharmony_ci			return -EINVAL;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci		/* advertise only what has been requested */
3708c2ecf20Sopenharmony_ci		advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
3718c2ecf20Sopenharmony_ci		tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
3728c2ecf20Sopenharmony_ci		if (mii->supports_gmii) {
3738c2ecf20Sopenharmony_ci			advert2 = mii->mdio_read(dev, mii->phy_id,
3748c2ecf20Sopenharmony_ci						 MII_CTRL1000);
3758c2ecf20Sopenharmony_ci			tmp2 = advert2 &
3768c2ecf20Sopenharmony_ci				~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
3778c2ecf20Sopenharmony_ci		}
3788c2ecf20Sopenharmony_ci		tmp |= ethtool_adv_to_mii_adv_t(advertising);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci		if (mii->supports_gmii)
3818c2ecf20Sopenharmony_ci			tmp2 |= ethtool_adv_to_mii_ctrl1000_t(advertising);
3828c2ecf20Sopenharmony_ci		if (advert != tmp) {
3838c2ecf20Sopenharmony_ci			mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
3848c2ecf20Sopenharmony_ci			mii->advertising = tmp;
3858c2ecf20Sopenharmony_ci		}
3868c2ecf20Sopenharmony_ci		if ((mii->supports_gmii) && (advert2 != tmp2))
3878c2ecf20Sopenharmony_ci			mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci		/* turn on autonegotiation, and force a renegotiate */
3908c2ecf20Sopenharmony_ci		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
3918c2ecf20Sopenharmony_ci		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
3928c2ecf20Sopenharmony_ci		mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci		mii->force_media = 0;
3958c2ecf20Sopenharmony_ci	} else {
3968c2ecf20Sopenharmony_ci		u32 bmcr, tmp;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci		/* turn off auto negotiation, set speed and duplexity */
3998c2ecf20Sopenharmony_ci		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
4008c2ecf20Sopenharmony_ci		tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
4018c2ecf20Sopenharmony_ci			       BMCR_SPEED1000 | BMCR_FULLDPLX);
4028c2ecf20Sopenharmony_ci		if (speed == SPEED_1000)
4038c2ecf20Sopenharmony_ci			tmp |= BMCR_SPEED1000;
4048c2ecf20Sopenharmony_ci		else if (speed == SPEED_100)
4058c2ecf20Sopenharmony_ci			tmp |= BMCR_SPEED100;
4068c2ecf20Sopenharmony_ci		if (cmd->base.duplex == DUPLEX_FULL) {
4078c2ecf20Sopenharmony_ci			tmp |= BMCR_FULLDPLX;
4088c2ecf20Sopenharmony_ci			mii->full_duplex = 1;
4098c2ecf20Sopenharmony_ci		} else {
4108c2ecf20Sopenharmony_ci			mii->full_duplex = 0;
4118c2ecf20Sopenharmony_ci		}
4128c2ecf20Sopenharmony_ci		if (bmcr != tmp)
4138c2ecf20Sopenharmony_ci			mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci		mii->force_media = 1;
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci	return 0;
4188c2ecf20Sopenharmony_ci}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci/**
4218c2ecf20Sopenharmony_ci * mii_check_gmii_support - check if the MII supports Gb interfaces
4228c2ecf20Sopenharmony_ci * @mii: the MII interface
4238c2ecf20Sopenharmony_ci */
4248c2ecf20Sopenharmony_ciint mii_check_gmii_support(struct mii_if_info *mii)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	int reg;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
4298c2ecf20Sopenharmony_ci	if (reg & BMSR_ESTATEN) {
4308c2ecf20Sopenharmony_ci		reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS);
4318c2ecf20Sopenharmony_ci		if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
4328c2ecf20Sopenharmony_ci			return 1;
4338c2ecf20Sopenharmony_ci	}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	return 0;
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci/**
4398c2ecf20Sopenharmony_ci * mii_link_ok - is link status up/ok
4408c2ecf20Sopenharmony_ci * @mii: the MII interface
4418c2ecf20Sopenharmony_ci *
4428c2ecf20Sopenharmony_ci * Returns 1 if the MII reports link status up/ok, 0 otherwise.
4438c2ecf20Sopenharmony_ci */
4448c2ecf20Sopenharmony_ciint mii_link_ok (struct mii_if_info *mii)
4458c2ecf20Sopenharmony_ci{
4468c2ecf20Sopenharmony_ci	/* first, a dummy read, needed to latch some MII phys */
4478c2ecf20Sopenharmony_ci	mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
4488c2ecf20Sopenharmony_ci	if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
4498c2ecf20Sopenharmony_ci		return 1;
4508c2ecf20Sopenharmony_ci	return 0;
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci/**
4548c2ecf20Sopenharmony_ci * mii_nway_restart - restart NWay (autonegotiation) for this interface
4558c2ecf20Sopenharmony_ci * @mii: the MII interface
4568c2ecf20Sopenharmony_ci *
4578c2ecf20Sopenharmony_ci * Returns 0 on success, negative on error.
4588c2ecf20Sopenharmony_ci */
4598c2ecf20Sopenharmony_ciint mii_nway_restart (struct mii_if_info *mii)
4608c2ecf20Sopenharmony_ci{
4618c2ecf20Sopenharmony_ci	int bmcr;
4628c2ecf20Sopenharmony_ci	int r = -EINVAL;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	/* if autoneg is off, it's an error */
4658c2ecf20Sopenharmony_ci	bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	if (bmcr & BMCR_ANENABLE) {
4688c2ecf20Sopenharmony_ci		bmcr |= BMCR_ANRESTART;
4698c2ecf20Sopenharmony_ci		mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
4708c2ecf20Sopenharmony_ci		r = 0;
4718c2ecf20Sopenharmony_ci	}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	return r;
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci/**
4778c2ecf20Sopenharmony_ci * mii_check_link - check MII link status
4788c2ecf20Sopenharmony_ci * @mii: MII interface
4798c2ecf20Sopenharmony_ci *
4808c2ecf20Sopenharmony_ci * If the link status changed (previous != current), call
4818c2ecf20Sopenharmony_ci * netif_carrier_on() if current link status is Up or call
4828c2ecf20Sopenharmony_ci * netif_carrier_off() if current link status is Down.
4838c2ecf20Sopenharmony_ci */
4848c2ecf20Sopenharmony_civoid mii_check_link (struct mii_if_info *mii)
4858c2ecf20Sopenharmony_ci{
4868c2ecf20Sopenharmony_ci	int cur_link = mii_link_ok(mii);
4878c2ecf20Sopenharmony_ci	int prev_link = netif_carrier_ok(mii->dev);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	if (cur_link && !prev_link)
4908c2ecf20Sopenharmony_ci		netif_carrier_on(mii->dev);
4918c2ecf20Sopenharmony_ci	else if (prev_link && !cur_link)
4928c2ecf20Sopenharmony_ci		netif_carrier_off(mii->dev);
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci/**
4968c2ecf20Sopenharmony_ci * mii_check_media - check the MII interface for a carrier/speed/duplex change
4978c2ecf20Sopenharmony_ci * @mii: the MII interface
4988c2ecf20Sopenharmony_ci * @ok_to_print: OK to print link up/down messages
4998c2ecf20Sopenharmony_ci * @init_media: OK to save duplex mode in @mii
5008c2ecf20Sopenharmony_ci *
5018c2ecf20Sopenharmony_ci * Returns 1 if the duplex mode changed, 0 if not.
5028c2ecf20Sopenharmony_ci * If the media type is forced, always returns 0.
5038c2ecf20Sopenharmony_ci */
5048c2ecf20Sopenharmony_ciunsigned int mii_check_media (struct mii_if_info *mii,
5058c2ecf20Sopenharmony_ci			      unsigned int ok_to_print,
5068c2ecf20Sopenharmony_ci			      unsigned int init_media)
5078c2ecf20Sopenharmony_ci{
5088c2ecf20Sopenharmony_ci	unsigned int old_carrier, new_carrier;
5098c2ecf20Sopenharmony_ci	int advertise, lpa, media, duplex;
5108c2ecf20Sopenharmony_ci	int lpa2 = 0;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	/* check current and old link status */
5138c2ecf20Sopenharmony_ci	old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
5148c2ecf20Sopenharmony_ci	new_carrier = (unsigned int) mii_link_ok(mii);
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	/* if carrier state did not change, this is a "bounce",
5178c2ecf20Sopenharmony_ci	 * just exit as everything is already set correctly
5188c2ecf20Sopenharmony_ci	 */
5198c2ecf20Sopenharmony_ci	if ((!init_media) && (old_carrier == new_carrier))
5208c2ecf20Sopenharmony_ci		return 0; /* duplex did not change */
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	/* no carrier, nothing much to do */
5238c2ecf20Sopenharmony_ci	if (!new_carrier) {
5248c2ecf20Sopenharmony_ci		netif_carrier_off(mii->dev);
5258c2ecf20Sopenharmony_ci		if (ok_to_print)
5268c2ecf20Sopenharmony_ci			netdev_info(mii->dev, "link down\n");
5278c2ecf20Sopenharmony_ci		return 0; /* duplex did not change */
5288c2ecf20Sopenharmony_ci	}
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	/*
5318c2ecf20Sopenharmony_ci	 * we have carrier, see who's on the other end
5328c2ecf20Sopenharmony_ci	 */
5338c2ecf20Sopenharmony_ci	netif_carrier_on(mii->dev);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	if (mii->force_media) {
5368c2ecf20Sopenharmony_ci		if (ok_to_print)
5378c2ecf20Sopenharmony_ci			netdev_info(mii->dev, "link up\n");
5388c2ecf20Sopenharmony_ci		return 0; /* duplex did not change */
5398c2ecf20Sopenharmony_ci	}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	/* get MII advertise and LPA values */
5428c2ecf20Sopenharmony_ci	if ((!init_media) && (mii->advertising))
5438c2ecf20Sopenharmony_ci		advertise = mii->advertising;
5448c2ecf20Sopenharmony_ci	else {
5458c2ecf20Sopenharmony_ci		advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
5468c2ecf20Sopenharmony_ci		mii->advertising = advertise;
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci	lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
5498c2ecf20Sopenharmony_ci	if (mii->supports_gmii)
5508c2ecf20Sopenharmony_ci		lpa2 = mii->mdio_read(mii->dev, mii->phy_id, MII_STAT1000);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	/* figure out media and duplex from advertise and LPA values */
5538c2ecf20Sopenharmony_ci	media = mii_nway_result(lpa & advertise);
5548c2ecf20Sopenharmony_ci	duplex = (media & ADVERTISE_FULL) ? 1 : 0;
5558c2ecf20Sopenharmony_ci	if (lpa2 & LPA_1000FULL)
5568c2ecf20Sopenharmony_ci		duplex = 1;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	if (ok_to_print)
5598c2ecf20Sopenharmony_ci		netdev_info(mii->dev, "link up, %uMbps, %s-duplex, lpa 0x%04X\n",
5608c2ecf20Sopenharmony_ci			    lpa2 & (LPA_1000FULL | LPA_1000HALF) ? 1000 :
5618c2ecf20Sopenharmony_ci			    media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ?
5628c2ecf20Sopenharmony_ci			    100 : 10,
5638c2ecf20Sopenharmony_ci			    duplex ? "full" : "half",
5648c2ecf20Sopenharmony_ci			    lpa);
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	if ((init_media) || (mii->full_duplex != duplex)) {
5678c2ecf20Sopenharmony_ci		mii->full_duplex = duplex;
5688c2ecf20Sopenharmony_ci		return 1; /* duplex changed */
5698c2ecf20Sopenharmony_ci	}
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	return 0; /* duplex did not change */
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci/**
5758c2ecf20Sopenharmony_ci * generic_mii_ioctl - main MII ioctl interface
5768c2ecf20Sopenharmony_ci * @mii_if: the MII interface
5778c2ecf20Sopenharmony_ci * @mii_data: MII ioctl data structure
5788c2ecf20Sopenharmony_ci * @cmd: MII ioctl command
5798c2ecf20Sopenharmony_ci * @duplex_chg_out: pointer to @duplex_changed status if there was no
5808c2ecf20Sopenharmony_ci *	ioctl error
5818c2ecf20Sopenharmony_ci *
5828c2ecf20Sopenharmony_ci * Returns 0 on success, negative on error.
5838c2ecf20Sopenharmony_ci */
5848c2ecf20Sopenharmony_ciint generic_mii_ioctl(struct mii_if_info *mii_if,
5858c2ecf20Sopenharmony_ci		      struct mii_ioctl_data *mii_data, int cmd,
5868c2ecf20Sopenharmony_ci		      unsigned int *duplex_chg_out)
5878c2ecf20Sopenharmony_ci{
5888c2ecf20Sopenharmony_ci	int rc = 0;
5898c2ecf20Sopenharmony_ci	unsigned int duplex_changed = 0;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	if (duplex_chg_out)
5928c2ecf20Sopenharmony_ci		*duplex_chg_out = 0;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	mii_data->phy_id &= mii_if->phy_id_mask;
5958c2ecf20Sopenharmony_ci	mii_data->reg_num &= mii_if->reg_num_mask;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	switch(cmd) {
5988c2ecf20Sopenharmony_ci	case SIOCGMIIPHY:
5998c2ecf20Sopenharmony_ci		mii_data->phy_id = mii_if->phy_id;
6008c2ecf20Sopenharmony_ci		fallthrough;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	case SIOCGMIIREG:
6038c2ecf20Sopenharmony_ci		mii_data->val_out =
6048c2ecf20Sopenharmony_ci			mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
6058c2ecf20Sopenharmony_ci					  mii_data->reg_num);
6068c2ecf20Sopenharmony_ci		break;
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	case SIOCSMIIREG: {
6098c2ecf20Sopenharmony_ci		u16 val = mii_data->val_in;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci		if (mii_data->phy_id == mii_if->phy_id) {
6128c2ecf20Sopenharmony_ci			switch(mii_data->reg_num) {
6138c2ecf20Sopenharmony_ci			case MII_BMCR: {
6148c2ecf20Sopenharmony_ci				unsigned int new_duplex = 0;
6158c2ecf20Sopenharmony_ci				if (val & (BMCR_RESET|BMCR_ANENABLE))
6168c2ecf20Sopenharmony_ci					mii_if->force_media = 0;
6178c2ecf20Sopenharmony_ci				else
6188c2ecf20Sopenharmony_ci					mii_if->force_media = 1;
6198c2ecf20Sopenharmony_ci				if (mii_if->force_media &&
6208c2ecf20Sopenharmony_ci				    (val & BMCR_FULLDPLX))
6218c2ecf20Sopenharmony_ci					new_duplex = 1;
6228c2ecf20Sopenharmony_ci				if (mii_if->full_duplex != new_duplex) {
6238c2ecf20Sopenharmony_ci					duplex_changed = 1;
6248c2ecf20Sopenharmony_ci					mii_if->full_duplex = new_duplex;
6258c2ecf20Sopenharmony_ci				}
6268c2ecf20Sopenharmony_ci				break;
6278c2ecf20Sopenharmony_ci			}
6288c2ecf20Sopenharmony_ci			case MII_ADVERTISE:
6298c2ecf20Sopenharmony_ci				mii_if->advertising = val;
6308c2ecf20Sopenharmony_ci				break;
6318c2ecf20Sopenharmony_ci			default:
6328c2ecf20Sopenharmony_ci				/* do nothing */
6338c2ecf20Sopenharmony_ci				break;
6348c2ecf20Sopenharmony_ci			}
6358c2ecf20Sopenharmony_ci		}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci		mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
6388c2ecf20Sopenharmony_ci				   mii_data->reg_num, val);
6398c2ecf20Sopenharmony_ci		break;
6408c2ecf20Sopenharmony_ci	}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	default:
6438c2ecf20Sopenharmony_ci		rc = -EOPNOTSUPP;
6448c2ecf20Sopenharmony_ci		break;
6458c2ecf20Sopenharmony_ci	}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
6488c2ecf20Sopenharmony_ci		*duplex_chg_out = 1;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	return rc;
6518c2ecf20Sopenharmony_ci}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ciMODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
6548c2ecf20Sopenharmony_ciMODULE_DESCRIPTION ("MII hardware support library");
6558c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mii_link_ok);
6588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mii_nway_restart);
6598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mii_ethtool_gset);
6608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mii_ethtool_get_link_ksettings);
6618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mii_ethtool_sset);
6628c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mii_ethtool_set_link_ksettings);
6638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mii_check_link);
6648c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mii_check_media);
6658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mii_check_gmii_support);
6668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(generic_mii_ioctl);
6678c2ecf20Sopenharmony_ci
668