提交 968ad9da 编写于 作者: R Raju Lakkaraju 提交者: David S. Miller

ethtool: Implements ETHTOOL_PHY_GTUNABLE/ETHTOOL_PHY_STUNABLE

Adding get_tunable/set_tunable function pointer to the phy_driver
structure, and uses these function pointers to implement the
ETHTOOL_PHY_GTUNABLE/ETHTOOL_PHY_STUNABLE ioctls.
Signed-off-by: NRaju Lakkaraju <Raju.Lakkaraju@microsemi.com>
Reviewed-by: NAndrew Lunn <andrew@lunn.ch>
Signed-off-by: NAllan W. Nielsen <allan.nielsen@microsemi.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 0d27f4e4
...@@ -611,6 +611,13 @@ struct phy_driver { ...@@ -611,6 +611,13 @@ struct phy_driver {
void (*get_strings)(struct phy_device *dev, u8 *data); void (*get_strings)(struct phy_device *dev, u8 *data);
void (*get_stats)(struct phy_device *dev, void (*get_stats)(struct phy_device *dev,
struct ethtool_stats *stats, u64 *data); struct ethtool_stats *stats, u64 *data);
/* Get and Set PHY tunables */
int (*get_tunable)(struct phy_device *dev,
struct ethtool_tunable *tuna, void *data);
int (*set_tunable)(struct phy_device *dev,
struct ethtool_tunable *tuna,
const void *data);
}; };
#define to_phy_driver(d) container_of(to_mdio_common_driver(d), \ #define to_phy_driver(d) container_of(to_mdio_common_driver(d), \
struct phy_driver, mdiodrv) struct phy_driver, mdiodrv)
......
...@@ -119,6 +119,11 @@ tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN] = { ...@@ -119,6 +119,11 @@ tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN] = {
[ETHTOOL_TX_COPYBREAK] = "tx-copybreak", [ETHTOOL_TX_COPYBREAK] = "tx-copybreak",
}; };
static const char
phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN] = {
[ETHTOOL_ID_UNSPEC] = "Unspec",
};
static int ethtool_get_features(struct net_device *dev, void __user *useraddr) static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
{ {
struct ethtool_gfeatures cmd = { struct ethtool_gfeatures cmd = {
...@@ -227,6 +232,9 @@ static int __ethtool_get_sset_count(struct net_device *dev, int sset) ...@@ -227,6 +232,9 @@ static int __ethtool_get_sset_count(struct net_device *dev, int sset)
if (sset == ETH_SS_TUNABLES) if (sset == ETH_SS_TUNABLES)
return ARRAY_SIZE(tunable_strings); return ARRAY_SIZE(tunable_strings);
if (sset == ETH_SS_PHY_TUNABLES)
return ARRAY_SIZE(phy_tunable_strings);
if (sset == ETH_SS_PHY_STATS) { if (sset == ETH_SS_PHY_STATS) {
if (dev->phydev) if (dev->phydev)
return phy_get_sset_count(dev->phydev); return phy_get_sset_count(dev->phydev);
...@@ -253,6 +261,8 @@ static void __ethtool_get_strings(struct net_device *dev, ...@@ -253,6 +261,8 @@ static void __ethtool_get_strings(struct net_device *dev,
sizeof(rss_hash_func_strings)); sizeof(rss_hash_func_strings));
else if (stringset == ETH_SS_TUNABLES) else if (stringset == ETH_SS_TUNABLES)
memcpy(data, tunable_strings, sizeof(tunable_strings)); memcpy(data, tunable_strings, sizeof(tunable_strings));
else if (stringset == ETH_SS_PHY_TUNABLES)
memcpy(data, phy_tunable_strings, sizeof(phy_tunable_strings));
else if (stringset == ETH_SS_PHY_STATS) { else if (stringset == ETH_SS_PHY_STATS) {
struct phy_device *phydev = dev->phydev; struct phy_device *phydev = dev->phydev;
...@@ -2422,6 +2432,76 @@ static int ethtool_set_per_queue(struct net_device *dev, void __user *useraddr) ...@@ -2422,6 +2432,76 @@ static int ethtool_set_per_queue(struct net_device *dev, void __user *useraddr)
}; };
} }
static int ethtool_phy_tunable_valid(const struct ethtool_tunable *tuna)
{
switch (tuna->id) {
default:
return -EINVAL;
}
return 0;
}
static int get_phy_tunable(struct net_device *dev, void __user *useraddr)
{
int ret;
struct ethtool_tunable tuna;
struct phy_device *phydev = dev->phydev;
void *data;
if (!(phydev && phydev->drv && phydev->drv->get_tunable))
return -EOPNOTSUPP;
if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
return -EFAULT;
ret = ethtool_phy_tunable_valid(&tuna);
if (ret)
return ret;
data = kmalloc(tuna.len, GFP_USER);
if (!data)
return -ENOMEM;
ret = phydev->drv->get_tunable(phydev, &tuna, data);
if (ret)
goto out;
useraddr += sizeof(tuna);
ret = -EFAULT;
if (copy_to_user(useraddr, data, tuna.len))
goto out;
ret = 0;
out:
kfree(data);
return ret;
}
static int set_phy_tunable(struct net_device *dev, void __user *useraddr)
{
int ret;
struct ethtool_tunable tuna;
struct phy_device *phydev = dev->phydev;
void *data;
if (!(phydev && phydev->drv && phydev->drv->set_tunable))
return -EOPNOTSUPP;
if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
return -EFAULT;
ret = ethtool_phy_tunable_valid(&tuna);
if (ret)
return ret;
data = kmalloc(tuna.len, GFP_USER);
if (!data)
return -ENOMEM;
useraddr += sizeof(tuna);
ret = -EFAULT;
if (copy_from_user(data, useraddr, tuna.len))
goto out;
ret = phydev->drv->set_tunable(phydev, &tuna, data);
out:
kfree(data);
return ret;
}
/* The main entry point in this file. Called from net/core/dev_ioctl.c */ /* The main entry point in this file. Called from net/core/dev_ioctl.c */
int dev_ethtool(struct net *net, struct ifreq *ifr) int dev_ethtool(struct net *net, struct ifreq *ifr)
...@@ -2479,6 +2559,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) ...@@ -2479,6 +2559,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
case ETHTOOL_GET_TS_INFO: case ETHTOOL_GET_TS_INFO:
case ETHTOOL_GEEE: case ETHTOOL_GEEE:
case ETHTOOL_GTUNABLE: case ETHTOOL_GTUNABLE:
case ETHTOOL_PHY_GTUNABLE:
break; break;
default: default:
if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
...@@ -2684,6 +2765,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) ...@@ -2684,6 +2765,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
case ETHTOOL_SLINKSETTINGS: case ETHTOOL_SLINKSETTINGS:
rc = ethtool_set_link_ksettings(dev, useraddr); rc = ethtool_set_link_ksettings(dev, useraddr);
break; break;
case ETHTOOL_PHY_GTUNABLE:
rc = get_phy_tunable(dev, useraddr);
break;
case ETHTOOL_PHY_STUNABLE:
rc = set_phy_tunable(dev, useraddr);
break;
default: default:
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册