diff options
author | sixiao@microsoft.com <sixiao@microsoft.com> | 2016-02-25 18:24:08 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-02-29 17:08:50 -0500 |
commit | 49eb93892d8dfcf5dc5088e640f486d08572d8bf (patch) | |
tree | ebf8dcecb343fcf13f1020d118c210a1fbd6ebb9 /drivers/net/hyperv/netvsc_drv.c | |
parent | c0affa19589bb198c15670af3b6a0d39b1b1755a (diff) |
hv_netvsc: add ethtool support for set and get of settings
This patch allows the user to set and retrieve speed and duplex of the
hv_netvsc device via ethtool.
Example:
$ ethtool eth0
Settings for eth0:
...
Speed: Unknown!
Duplex: Unknown! (255)
...
$ ethtool -s eth0 speed 1000 duplex full
$ ethtool eth0
Settings for eth0:
...
Speed: 1000Mb/s
Duplex: Full
...
This is based on patches by Roopa Prabhu and Nikolay Aleksandrov.
Signed-off-by: Simon Xiao <sixiao@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/hyperv/netvsc_drv.c')
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 2b6595e24f43..08608499fa17 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
@@ -799,6 +799,58 @@ static int netvsc_set_channels(struct net_device *net, | |||
799 | goto do_set; | 799 | goto do_set; |
800 | } | 800 | } |
801 | 801 | ||
802 | static bool netvsc_validate_ethtool_ss_cmd(const struct ethtool_cmd *cmd) | ||
803 | { | ||
804 | struct ethtool_cmd diff1 = *cmd; | ||
805 | struct ethtool_cmd diff2 = {}; | ||
806 | |||
807 | ethtool_cmd_speed_set(&diff1, 0); | ||
808 | diff1.duplex = 0; | ||
809 | /* advertising and cmd are usually set */ | ||
810 | diff1.advertising = 0; | ||
811 | diff1.cmd = 0; | ||
812 | /* We set port to PORT_OTHER */ | ||
813 | diff2.port = PORT_OTHER; | ||
814 | |||
815 | return !memcmp(&diff1, &diff2, sizeof(diff1)); | ||
816 | } | ||
817 | |||
818 | static void netvsc_init_settings(struct net_device *dev) | ||
819 | { | ||
820 | struct net_device_context *ndc = netdev_priv(dev); | ||
821 | |||
822 | ndc->speed = SPEED_UNKNOWN; | ||
823 | ndc->duplex = DUPLEX_UNKNOWN; | ||
824 | } | ||
825 | |||
826 | static int netvsc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
827 | { | ||
828 | struct net_device_context *ndc = netdev_priv(dev); | ||
829 | |||
830 | ethtool_cmd_speed_set(cmd, ndc->speed); | ||
831 | cmd->duplex = ndc->duplex; | ||
832 | cmd->port = PORT_OTHER; | ||
833 | |||
834 | return 0; | ||
835 | } | ||
836 | |||
837 | static int netvsc_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
838 | { | ||
839 | struct net_device_context *ndc = netdev_priv(dev); | ||
840 | u32 speed; | ||
841 | |||
842 | speed = ethtool_cmd_speed(cmd); | ||
843 | if (!ethtool_validate_speed(speed) || | ||
844 | !ethtool_validate_duplex(cmd->duplex) || | ||
845 | !netvsc_validate_ethtool_ss_cmd(cmd)) | ||
846 | return -EINVAL; | ||
847 | |||
848 | ndc->speed = speed; | ||
849 | ndc->duplex = cmd->duplex; | ||
850 | |||
851 | return 0; | ||
852 | } | ||
853 | |||
802 | static int netvsc_change_mtu(struct net_device *ndev, int mtu) | 854 | static int netvsc_change_mtu(struct net_device *ndev, int mtu) |
803 | { | 855 | { |
804 | struct net_device_context *ndevctx = netdev_priv(ndev); | 856 | struct net_device_context *ndevctx = netdev_priv(ndev); |
@@ -923,6 +975,8 @@ static const struct ethtool_ops ethtool_ops = { | |||
923 | .get_channels = netvsc_get_channels, | 975 | .get_channels = netvsc_get_channels, |
924 | .set_channels = netvsc_set_channels, | 976 | .set_channels = netvsc_set_channels, |
925 | .get_ts_info = ethtool_op_get_ts_info, | 977 | .get_ts_info = ethtool_op_get_ts_info, |
978 | .get_settings = netvsc_get_settings, | ||
979 | .set_settings = netvsc_set_settings, | ||
926 | }; | 980 | }; |
927 | 981 | ||
928 | static const struct net_device_ops device_ops = { | 982 | static const struct net_device_ops device_ops = { |
@@ -1115,6 +1169,8 @@ static int netvsc_probe(struct hv_device *dev, | |||
1115 | netif_set_real_num_tx_queues(net, nvdev->num_chn); | 1169 | netif_set_real_num_tx_queues(net, nvdev->num_chn); |
1116 | netif_set_real_num_rx_queues(net, nvdev->num_chn); | 1170 | netif_set_real_num_rx_queues(net, nvdev->num_chn); |
1117 | 1171 | ||
1172 | netvsc_init_settings(net); | ||
1173 | |||
1118 | ret = register_netdev(net); | 1174 | ret = register_netdev(net); |
1119 | if (ret != 0) { | 1175 | if (ret != 0) { |
1120 | pr_err("Unable to register netdev.\n"); | 1176 | pr_err("Unable to register netdev.\n"); |