From: John Crispin Subject: net: phy: add phy_ethtool_ioctl() Signed-off-by: John Crispin --- drivers/net/phy/phy.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/phy.h | 1 + 2 files changed, 45 insertions(+) --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -382,6 +382,73 @@ void phy_ethtool_ksettings_get(struct ph } EXPORT_SYMBOL(phy_ethtool_ksettings_get); +static int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) +{ + cmd->supported = phydev->supported; + + cmd->advertising = phydev->advertising; + cmd->lp_advertising = phydev->lp_advertising; + + ethtool_cmd_speed_set(cmd, phydev->speed); + cmd->duplex = phydev->duplex; + if (phydev->interface == PHY_INTERFACE_MODE_MOCA) + cmd->port = PORT_BNC; + else + cmd->port = PORT_MII; + cmd->phy_address = phydev->mdio.addr; + cmd->transceiver = phy_is_internal(phydev) ? + XCVR_INTERNAL : XCVR_EXTERNAL; + cmd->autoneg = phydev->autoneg; + cmd->eth_tp_mdix_ctrl = phydev->mdix_ctrl; + cmd->eth_tp_mdix = phydev->mdix; + + return 0; +} + +int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr) +{ + u32 cmd; + int tmp; + struct ethtool_cmd ecmd = { ETHTOOL_GSET }; + struct ethtool_value edata = { ETHTOOL_GLINK }; + + if (get_user(cmd, (u32 *) useraddr)) + return -EFAULT; + + switch (cmd) { + case ETHTOOL_GSET: + phy_ethtool_gset(phydev, &ecmd); + if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) + return -EFAULT; + return 0; + + case ETHTOOL_SSET: + if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) + return -EFAULT; + return phy_ethtool_sset(phydev, &ecmd); + + case ETHTOOL_NWAY_RST: + /* if autoneg is off, it's an error */ + tmp = phy_read(phydev, MII_BMCR); + if (tmp & BMCR_ANENABLE) { + tmp |= (BMCR_ANRESTART); + phy_write(phydev, MII_BMCR, tmp); + return 0; + } + return -EINVAL; + + case ETHTOOL_GLINK: + edata.data = (phy_read(phydev, + MII_BMSR) & BMSR_LSTATUS) ? 1 : 0; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(phy_ethtool_ioctl); + /** * phy_mii_ioctl - generic PHY MII ioctl interface * @phydev: the phy_device struct --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -909,6 +909,7 @@ void phy_ethtool_ksettings_get(struct ph struct ethtool_link_ksettings *cmd); int phy_ethtool_ksettings_set(struct phy_device *phydev, const struct ethtool_link_ksettings *cmd); +int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr); int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd); int phy_start_interrupts(struct phy_device *phydev); void phy_print_status(struct phy_device *phydev);