From 7b864612a6e3b139a5a607abd0048a19078fe42f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 14 May 2014 02:55:06 +0200 Subject: [PATCH] phy: add ethtool ioctl support, used by ag71xx driver --- drivers/net/phy/phy.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/phy.h | 1 + 2 files changed, 45 insertions(+) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 76d96b9..9439ef3 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -293,6 +293,50 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) } EXPORT_SYMBOL(phy_ethtool_gset); +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 diff --git a/include/linux/phy.h b/include/linux/phy.h index 565188c..9ab0d79 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -628,6 +628,7 @@ void phy_stop_machine(struct phy_device *phydev); int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd); int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd); int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd); +int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr); int phy_start_interrupts(struct phy_device *phydev); void phy_print_status(struct phy_device *phydev); void phy_device_free(struct phy_device *phydev); -- 1.8.5.3