net/ethtool: Introduce link_ksettings API for virtual network devices
With the ethtool_virtdev_set_link_ksettings function in core/ethtool.c, ibmveth, netvsc, and virtio now use the core's helper function. Funtionality changes that pertain to ibmveth driver include: 1. Changed the initial hardcoded link speed to 1GB. 2. Added support for allowing a user to change the reported link speed via ethtool. Functionality changes to the netvsc driver include: 1. When netvsc_get_link_ksettings is called, it will defer to the VF device if it exists to pull accelerated networking values, otherwise pull default or user-defined values. 2. Similarly, if netvsc_set_link_ksettings called and a VF device exists, the real values of speed and duplex are changed. Signed-off-by: Cris Forno <cforno12@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
70ae1e127b
commit
9aedc6e2f1
@ -712,29 +712,36 @@ static int ibmveth_close(struct net_device *netdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdev_get_link_ksettings(struct net_device *dev,
|
||||
struct ethtool_link_ksettings *cmd)
|
||||
static int ibmveth_set_link_ksettings(struct net_device *dev,
|
||||
const struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
u32 supported, advertising;
|
||||
struct ibmveth_adapter *adapter = netdev_priv(dev);
|
||||
|
||||
supported = (SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
|
||||
SUPPORTED_FIBRE);
|
||||
advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg |
|
||||
ADVERTISED_FIBRE);
|
||||
cmd->base.speed = SPEED_1000;
|
||||
cmd->base.duplex = DUPLEX_FULL;
|
||||
cmd->base.port = PORT_FIBRE;
|
||||
cmd->base.phy_address = 0;
|
||||
cmd->base.autoneg = AUTONEG_ENABLE;
|
||||
return ethtool_virtdev_set_link_ksettings(dev, cmd,
|
||||
&adapter->speed,
|
||||
&adapter->duplex);
|
||||
}
|
||||
|
||||
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
|
||||
supported);
|
||||
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
|
||||
advertising);
|
||||
static int ibmveth_get_link_ksettings(struct net_device *dev,
|
||||
struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct ibmveth_adapter *adapter = netdev_priv(dev);
|
||||
|
||||
cmd->base.speed = adapter->speed;
|
||||
cmd->base.duplex = adapter->duplex;
|
||||
cmd->base.port = PORT_OTHER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ibmveth_init_link_settings(struct net_device *dev)
|
||||
{
|
||||
struct ibmveth_adapter *adapter = netdev_priv(dev);
|
||||
|
||||
adapter->speed = SPEED_1000;
|
||||
adapter->duplex = DUPLEX_FULL;
|
||||
}
|
||||
|
||||
static void netdev_get_drvinfo(struct net_device *dev,
|
||||
struct ethtool_drvinfo *info)
|
||||
{
|
||||
@ -965,12 +972,13 @@ static void ibmveth_get_ethtool_stats(struct net_device *dev,
|
||||
}
|
||||
|
||||
static const struct ethtool_ops netdev_ethtool_ops = {
|
||||
.get_drvinfo = netdev_get_drvinfo,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.get_strings = ibmveth_get_strings,
|
||||
.get_sset_count = ibmveth_get_sset_count,
|
||||
.get_ethtool_stats = ibmveth_get_ethtool_stats,
|
||||
.get_link_ksettings = netdev_get_link_ksettings,
|
||||
.get_drvinfo = netdev_get_drvinfo,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.get_strings = ibmveth_get_strings,
|
||||
.get_sset_count = ibmveth_get_sset_count,
|
||||
.get_ethtool_stats = ibmveth_get_ethtool_stats,
|
||||
.get_link_ksettings = ibmveth_get_link_ksettings,
|
||||
.set_link_ksettings = ibmveth_set_link_ksettings,
|
||||
};
|
||||
|
||||
static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||
@ -1674,6 +1682,7 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
|
||||
adapter->netdev = netdev;
|
||||
adapter->mcastFilterSize = be32_to_cpu(*mcastFilterSize_p);
|
||||
adapter->pool_config = 0;
|
||||
ibmveth_init_link_settings(netdev);
|
||||
|
||||
netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16);
|
||||
|
||||
|
@ -162,6 +162,9 @@ struct ibmveth_adapter {
|
||||
u64 tx_send_failed;
|
||||
u64 tx_large_packets;
|
||||
u64 rx_large_packets;
|
||||
/* Ethtool settings */
|
||||
u8 duplex;
|
||||
u32 speed;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1140,23 +1140,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
netvsc_validate_ethtool_ss_cmd(const struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct ethtool_link_ksettings diff1 = *cmd;
|
||||
struct ethtool_link_ksettings diff2 = {};
|
||||
|
||||
diff1.base.speed = 0;
|
||||
diff1.base.duplex = 0;
|
||||
/* advertising and cmd are usually set */
|
||||
ethtool_link_ksettings_zero_link_mode(&diff1, advertising);
|
||||
diff1.base.cmd = 0;
|
||||
/* We set port to PORT_OTHER */
|
||||
diff2.base.port = PORT_OTHER;
|
||||
|
||||
return !memcmp(&diff1, &diff2, sizeof(diff1));
|
||||
}
|
||||
|
||||
static void netvsc_init_settings(struct net_device *dev)
|
||||
{
|
||||
struct net_device_context *ndc = netdev_priv(dev);
|
||||
@ -1173,6 +1156,12 @@ static int netvsc_get_link_ksettings(struct net_device *dev,
|
||||
struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct net_device_context *ndc = netdev_priv(dev);
|
||||
struct net_device *vf_netdev;
|
||||
|
||||
vf_netdev = rtnl_dereference(ndc->vf_netdev);
|
||||
|
||||
if (vf_netdev)
|
||||
return __ethtool_get_link_ksettings(vf_netdev, cmd);
|
||||
|
||||
cmd->base.speed = ndc->speed;
|
||||
cmd->base.duplex = ndc->duplex;
|
||||
@ -1185,18 +1174,18 @@ static int netvsc_set_link_ksettings(struct net_device *dev,
|
||||
const struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct net_device_context *ndc = netdev_priv(dev);
|
||||
u32 speed;
|
||||
struct net_device *vf_netdev = rtnl_dereference(ndc->vf_netdev);
|
||||
|
||||
speed = cmd->base.speed;
|
||||
if (!ethtool_validate_speed(speed) ||
|
||||
!ethtool_validate_duplex(cmd->base.duplex) ||
|
||||
!netvsc_validate_ethtool_ss_cmd(cmd))
|
||||
return -EINVAL;
|
||||
if (vf_netdev) {
|
||||
if (!vf_netdev->ethtool_ops->set_link_ksettings)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ndc->speed = speed;
|
||||
ndc->duplex = cmd->base.duplex;
|
||||
return vf_netdev->ethtool_ops->set_link_ksettings(vf_netdev,
|
||||
cmd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ethtool_virtdev_set_link_ksettings(dev, cmd,
|
||||
&ndc->speed, &ndc->duplex);
|
||||
}
|
||||
|
||||
static int netvsc_change_mtu(struct net_device *ndev, int mtu)
|
||||
|
@ -2178,48 +2178,13 @@ static void virtnet_get_channels(struct net_device *dev,
|
||||
channels->other_count = 0;
|
||||
}
|
||||
|
||||
/* Check if the user is trying to change anything besides speed/duplex */
|
||||
static bool
|
||||
virtnet_validate_ethtool_cmd(const struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct ethtool_link_ksettings diff1 = *cmd;
|
||||
struct ethtool_link_ksettings diff2 = {};
|
||||
|
||||
/* cmd is always set so we need to clear it, validate the port type
|
||||
* and also without autonegotiation we can ignore advertising
|
||||
*/
|
||||
diff1.base.speed = 0;
|
||||
diff2.base.port = PORT_OTHER;
|
||||
ethtool_link_ksettings_zero_link_mode(&diff1, advertising);
|
||||
diff1.base.duplex = 0;
|
||||
diff1.base.cmd = 0;
|
||||
diff1.base.link_mode_masks_nwords = 0;
|
||||
|
||||
return !memcmp(&diff1.base, &diff2.base, sizeof(diff1.base)) &&
|
||||
bitmap_empty(diff1.link_modes.supported,
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS) &&
|
||||
bitmap_empty(diff1.link_modes.advertising,
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS) &&
|
||||
bitmap_empty(diff1.link_modes.lp_advertising,
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS);
|
||||
}
|
||||
|
||||
static int virtnet_set_link_ksettings(struct net_device *dev,
|
||||
const struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct virtnet_info *vi = netdev_priv(dev);
|
||||
u32 speed;
|
||||
|
||||
speed = cmd->base.speed;
|
||||
/* don't allow custom speed and duplex */
|
||||
if (!ethtool_validate_speed(speed) ||
|
||||
!ethtool_validate_duplex(cmd->base.duplex) ||
|
||||
!virtnet_validate_ethtool_cmd(cmd))
|
||||
return -EINVAL;
|
||||
vi->speed = speed;
|
||||
vi->duplex = cmd->base.duplex;
|
||||
|
||||
return 0;
|
||||
return ethtool_virtdev_set_link_ksettings(dev, cmd,
|
||||
&vi->speed, &vi->duplex);
|
||||
}
|
||||
|
||||
static int virtnet_get_link_ksettings(struct net_device *dev,
|
||||
|
Loading…
Reference in New Issue
Block a user