OSDN Git Service

ethtool: allow netdev driver to define phy tunables
authorIgor Russkikh <irusskikh@marvell.com>
Mon, 5 Oct 2020 15:39:37 +0000 (18:39 +0300)
committerDavid S. Miller <davem@davemloft.net>
Tue, 6 Oct 2020 13:16:01 +0000 (06:16 -0700)
Define get/set phy tunable callbacks in ethtool ops.
This will allow MAC drivers with integrated PHY still to implement
these tunables.

Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/ethtool.h
net/ethtool/ioctl.c

index 060b20f..6408b44 100644 (file)
@@ -505,6 +505,10 @@ struct ethtool_ops {
                                      struct ethtool_fecparam *);
        void    (*get_ethtool_phy_stats)(struct net_device *,
                                         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);
index 328d15c..ec2cd7a 100644 (file)
@@ -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)
 {
-       int ret;
-       struct ethtool_tunable tuna;
        struct phy_device *phydev = dev->phydev;
+       struct ethtool_tunable tuna;
+       bool phy_drv_tunable;
        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;
-
        if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
                return -EFAULT;
        ret = ethtool_phy_tunable_valid(&tuna);
@@ -2475,9 +2476,13 @@ static int get_phy_tunable(struct net_device *dev, void __user *useraddr)
        data = kmalloc(tuna.len, GFP_USER);
        if (!data)
                return -ENOMEM;
-       mutex_lock(&phydev->lock);
-       ret = phydev->drv->get_tunable(phydev, &tuna, data);
-       mutex_unlock(&phydev->lock);
+       if (phy_drv_tunable) {
+               mutex_lock(&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)
                goto out;
        useraddr += sizeof(tuna);
@@ -2493,12 +2498,14 @@ out:
 
 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 ethtool_tunable tuna;
+       bool phy_drv_tunable;
        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;
        if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
                return -EFAULT;
@@ -2509,9 +2516,13 @@ static int set_phy_tunable(struct net_device *dev, void __user *useraddr)
        data = memdup_user(useraddr, tuna.len);
        if (IS_ERR(data))
                return PTR_ERR(data);
-       mutex_lock(&phydev->lock);
-       ret = phydev->drv->set_tunable(phydev, &tuna, data);
-       mutex_unlock(&phydev->lock);
+       if (phy_drv_tunable) {
+               mutex_lock(&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);
        return ret;