mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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: Raju Lakkaraju <Raju.Lakkaraju@microsemi.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: Allan W. Nielsen <allan.nielsen@microsemi.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									0d27f4e437
								
							
						
					
					
						commit
						968ad9da7e
					
				
					 2 changed files with 94 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -611,6 +611,13 @@ struct phy_driver {
 | 
			
		|||
	void (*get_strings)(struct phy_device *dev, u8 *data);
 | 
			
		||||
	void (*get_stats)(struct phy_device *dev,
 | 
			
		||||
			  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),		\
 | 
			
		||||
				      struct phy_driver, mdiodrv)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -119,6 +119,11 @@ tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN] = {
 | 
			
		|||
	[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)
 | 
			
		||||
{
 | 
			
		||||
	struct ethtool_gfeatures cmd = {
 | 
			
		||||
| 
						 | 
				
			
			@ -227,6 +232,9 @@ static int __ethtool_get_sset_count(struct net_device *dev, int sset)
 | 
			
		|||
	if (sset == ETH_SS_TUNABLES)
 | 
			
		||||
		return ARRAY_SIZE(tunable_strings);
 | 
			
		||||
 | 
			
		||||
	if (sset == ETH_SS_PHY_TUNABLES)
 | 
			
		||||
		return ARRAY_SIZE(phy_tunable_strings);
 | 
			
		||||
 | 
			
		||||
	if (sset == ETH_SS_PHY_STATS) {
 | 
			
		||||
		if (dev->phydev)
 | 
			
		||||
			return phy_get_sset_count(dev->phydev);
 | 
			
		||||
| 
						 | 
				
			
			@ -253,6 +261,8 @@ static void __ethtool_get_strings(struct net_device *dev,
 | 
			
		|||
		       sizeof(rss_hash_func_strings));
 | 
			
		||||
	else if (stringset == ETH_SS_TUNABLES)
 | 
			
		||||
		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) {
 | 
			
		||||
		struct phy_device *phydev = dev->phydev;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
 | 
			
		||||
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_GEEE:
 | 
			
		||||
	case ETHTOOL_GTUNABLE:
 | 
			
		||||
	case ETHTOOL_PHY_GTUNABLE:
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
 | 
			
		||||
| 
						 | 
				
			
			@ -2684,6 +2765,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
 | 
			
		|||
	case ETHTOOL_SLINKSETTINGS:
 | 
			
		||||
		rc = ethtool_set_link_ksettings(dev, useraddr);
 | 
			
		||||
		break;
 | 
			
		||||
	case ETHTOOL_PHY_GTUNABLE:
 | 
			
		||||
		rc = get_phy_tunable(dev, useraddr);
 | 
			
		||||
		break;
 | 
			
		||||
	case ETHTOOL_PHY_STUNABLE:
 | 
			
		||||
		rc = set_phy_tunable(dev, useraddr);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		rc = -EOPNOTSUPP;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue