Commit c6db31ff authored by Igor Russkikh's avatar Igor Russkikh Committed by David S. Miller

ethtool: allow netdev driver to define phy tunables

Define get/set phy tunable callbacks in ethtool ops.
This will allow MAC drivers with integrated PHY still to implement
these tunables.
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarIgor Russkikh <irusskikh@marvell.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 302af7c6
...@@ -505,6 +505,10 @@ struct ethtool_ops { ...@@ -505,6 +505,10 @@ struct ethtool_ops {
struct ethtool_fecparam *); struct ethtool_fecparam *);
void (*get_ethtool_phy_stats)(struct net_device *, void (*get_ethtool_phy_stats)(struct net_device *,
struct ethtool_stats *, u64 *); struct ethtool_stats *, u64 *);
int (*get_phy_tunable)(struct net_device *,
const struct ethtool_tunable *, void *);
int (*set_phy_tunable)(struct net_device *,
const struct ethtool_tunable *, const void *);
}; };
int ethtool_check_ops(const struct ethtool_ops *ops); int ethtool_check_ops(const struct ethtool_ops *ops);
......
...@@ -2459,14 +2459,15 @@ static int ethtool_phy_tunable_valid(const struct ethtool_tunable *tuna) ...@@ -2459,14 +2459,15 @@ static int ethtool_phy_tunable_valid(const struct ethtool_tunable *tuna)
static int get_phy_tunable(struct net_device *dev, void __user *useraddr) static int get_phy_tunable(struct net_device *dev, void __user *useraddr)
{ {
int ret;
struct ethtool_tunable tuna;
struct phy_device *phydev = dev->phydev; struct phy_device *phydev = dev->phydev;
struct ethtool_tunable tuna;
bool phy_drv_tunable;
void *data; void *data;
int ret;
if (!(phydev && phydev->drv && phydev->drv->get_tunable)) phy_drv_tunable = phydev && phydev->drv && phydev->drv->get_tunable;
if (!phy_drv_tunable && !dev->ethtool_ops->get_phy_tunable)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (copy_from_user(&tuna, useraddr, sizeof(tuna))) if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
return -EFAULT; return -EFAULT;
ret = ethtool_phy_tunable_valid(&tuna); ret = ethtool_phy_tunable_valid(&tuna);
...@@ -2475,9 +2476,13 @@ static int get_phy_tunable(struct net_device *dev, void __user *useraddr) ...@@ -2475,9 +2476,13 @@ static int get_phy_tunable(struct net_device *dev, void __user *useraddr)
data = kmalloc(tuna.len, GFP_USER); data = kmalloc(tuna.len, GFP_USER);
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
mutex_lock(&phydev->lock); if (phy_drv_tunable) {
ret = phydev->drv->get_tunable(phydev, &tuna, data); mutex_lock(&phydev->lock);
mutex_unlock(&phydev->lock); ret = phydev->drv->get_tunable(phydev, &tuna, data);
mutex_unlock(&phydev->lock);
} else {
ret = dev->ethtool_ops->get_phy_tunable(dev, &tuna, data);
}
if (ret) if (ret)
goto out; goto out;
useraddr += sizeof(tuna); useraddr += sizeof(tuna);
...@@ -2493,12 +2498,14 @@ static int get_phy_tunable(struct net_device *dev, void __user *useraddr) ...@@ -2493,12 +2498,14 @@ static int get_phy_tunable(struct net_device *dev, void __user *useraddr)
static int set_phy_tunable(struct net_device *dev, void __user *useraddr) static int set_phy_tunable(struct net_device *dev, void __user *useraddr)
{ {
int ret;
struct ethtool_tunable tuna;
struct phy_device *phydev = dev->phydev; struct phy_device *phydev = dev->phydev;
struct ethtool_tunable tuna;
bool phy_drv_tunable;
void *data; void *data;
int ret;
if (!(phydev && phydev->drv && phydev->drv->set_tunable)) phy_drv_tunable = phydev && phydev->drv && phydev->drv->get_tunable;
if (!phy_drv_tunable && !dev->ethtool_ops->set_phy_tunable)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (copy_from_user(&tuna, useraddr, sizeof(tuna))) if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
return -EFAULT; return -EFAULT;
...@@ -2509,9 +2516,13 @@ static int set_phy_tunable(struct net_device *dev, void __user *useraddr) ...@@ -2509,9 +2516,13 @@ static int set_phy_tunable(struct net_device *dev, void __user *useraddr)
data = memdup_user(useraddr, tuna.len); data = memdup_user(useraddr, tuna.len);
if (IS_ERR(data)) if (IS_ERR(data))
return PTR_ERR(data); return PTR_ERR(data);
mutex_lock(&phydev->lock); if (phy_drv_tunable) {
ret = phydev->drv->set_tunable(phydev, &tuna, data); mutex_lock(&phydev->lock);
mutex_unlock(&phydev->lock); ret = phydev->drv->set_tunable(phydev, &tuna, data);
mutex_unlock(&phydev->lock);
} else {
ret = dev->ethtool_ops->set_phy_tunable(dev, &tuna, data);
}
kfree(data); kfree(data);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment