int alx_setup_speed_duplex(struct alx_hw *hw, u32 ethadv, u8 flowctrl) { u16 adv, giga, cr; u32 val; int err = 0; alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, 0); val = alx_read_mem32(hw, ALX_DRV); ALX_SET_FIELD(val, ALX_DRV_PHY, 0); if (ethadv & ADVERTISED_Autoneg) { adv = ADVERTISE_CSMA; adv |= ethtool_adv_to_mii_adv_t(ethadv); if (flowctrl & ALX_FC_ANEG) { if (flowctrl & ALX_FC_RX) { adv |= ADVERTISED_Pause; if (!(flowctrl & ALX_FC_TX)) adv |= ADVERTISED_Asym_Pause; } else if (flowctrl & ALX_FC_TX) { adv |= ADVERTISED_Asym_Pause; } } giga = 0; if (alx_hw_giga(hw)) giga = ethtool_adv_to_mii_ctrl1000_t(ethadv); cr = BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART; if (alx_write_phy_reg(hw, MII_ADVERTISE, adv) || alx_write_phy_reg(hw, MII_CTRL1000, giga) || alx_write_phy_reg(hw, MII_BMCR, cr)) err = -EBUSY; } else { cr = BMCR_RESET; if (ethadv == ADVERTISED_100baseT_Half || ethadv == ADVERTISED_100baseT_Full) cr |= BMCR_SPEED100; if (ethadv == ADVERTISED_10baseT_Full || ethadv == ADVERTISED_100baseT_Full) cr |= BMCR_FULLDPLX; err = alx_write_phy_reg(hw, MII_BMCR, cr); } if (!err) { alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, ALX_PHY_INITED); val |= ethadv_to_hw_cfg(hw, ethadv); } alx_write_mem32(hw, ALX_DRV, val); return err; }
static int mv3310_config_aneg(struct phy_device *phydev) { bool changed = false; u32 advertising; int ret; /* We don't support manual MDI control */ phydev->mdix_ctrl = ETH_TP_MDI_AUTO; if (phydev->autoneg == AUTONEG_DISABLE) { ret = genphy_c45_pma_setup_forced(phydev); if (ret < 0) return ret; return genphy_c45_an_disable_aneg(phydev); } phydev->advertising &= phydev->supported; advertising = phydev->advertising; ret = mv3310_modify(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM, ethtool_adv_to_mii_adv_t(advertising)); if (ret < 0) return ret; if (ret > 0) changed = true; ret = mv3310_modify(phydev, MDIO_MMD_AN, MV_AN_CTRL1000, ADVERTISE_1000FULL | ADVERTISE_1000HALF, ethtool_adv_to_mii_ctrl1000_t(advertising)); if (ret < 0) return ret; if (ret > 0) changed = true; /* 10G control register */ ret = mv3310_modify(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, MDIO_AN_10GBT_CTRL_ADV10G, advertising & ADVERTISED_10000baseT_Full ? MDIO_AN_10GBT_CTRL_ADV10G : 0); if (ret < 0) return ret; if (ret > 0) changed = true; if (changed) ret = genphy_c45_restart_aneg(phydev); return ret; }
/** * mii_ethtool_set_link_ksettings - set settings that are specified in @cmd * @mii: MII interfaces * @cmd: requested ethtool_link_ksettings * * Returns 0 for success, negative on error. */ int mii_ethtool_set_link_ksettings(struct mii_if_info *mii, const struct ethtool_link_ksettings *cmd) { struct net_device *dev = mii->dev; u32 speed = cmd->base.speed; if (speed != SPEED_10 && speed != SPEED_100 && speed != SPEED_1000) return -EINVAL; if (cmd->base.duplex != DUPLEX_HALF && cmd->base.duplex != DUPLEX_FULL) return -EINVAL; if (cmd->base.port != PORT_MII) return -EINVAL; if (cmd->base.phy_address != mii->phy_id) return -EINVAL; if (cmd->base.autoneg != AUTONEG_DISABLE && cmd->base.autoneg != AUTONEG_ENABLE) return -EINVAL; if ((speed == SPEED_1000) && (!mii->supports_gmii)) return -EINVAL; /* ignore supported, maxtxpkt, maxrxpkt */ if (cmd->base.autoneg == AUTONEG_ENABLE) { u32 bmcr, advert, tmp; u32 advert2 = 0, tmp2 = 0; u32 advertising; ethtool_convert_link_mode_to_legacy_u32( &advertising, cmd->link_modes.advertising); if ((advertising & (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) == 0) return -EINVAL; /* advertise only what has been requested */ advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE); tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4); if (mii->supports_gmii) { advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); } tmp |= ethtool_adv_to_mii_adv_t(advertising); if (mii->supports_gmii) tmp2 |= ethtool_adv_to_mii_ctrl1000_t(advertising); if (advert != tmp) { mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp); mii->advertising = tmp; } if ((mii->supports_gmii) && (advert2 != tmp2)) mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2); /* turn on autonegotiation, and force a renegotiate */ bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr); mii->force_media = 0; } else { u32 bmcr, tmp; /* turn off auto negotiation, set speed and duplexity */ bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_FULLDPLX); if (speed == SPEED_1000) tmp |= BMCR_SPEED1000; else if (speed == SPEED_100) tmp |= BMCR_SPEED100; if (cmd->base.duplex == DUPLEX_FULL) { tmp |= BMCR_FULLDPLX; mii->full_duplex = 1; } else { mii->full_duplex = 0; } if (bmcr != tmp) mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp); mii->force_media = 1; } return 0; }