netvsc: allow more flexible setting of number of channels
authorstephen hemminger <stephen@networkplumber.org>
Tue, 24 Jan 2017 21:06:03 +0000 (13:06 -0800)
committerDavid S. Miller <davem@davemloft.net>
Tue, 24 Jan 2017 21:28:58 +0000 (16:28 -0500)
This allows for number of channels to be managed in a manner similar
to existing hardware drivers. It also removes the restriction of
maximum 8 channels and allows as many as the host will allow.

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc_drv.c

index 5bf2141..5a652eb 100644 (file)
@@ -628,6 +628,7 @@ struct nvsp_message {
 
 #define VRSS_SEND_TAB_SIZE 16
 #define VRSS_CHANNEL_MAX 64
+#define VRSS_CHANNEL_DEFAULT 8
 
 #define RNDIS_MAX_PKT_DEFAULT 8
 #define RNDIS_PKT_ALIGN_DEFAULT 8
index 40a8838..ead4721 100644 (file)
@@ -47,8 +47,6 @@ static int ring_size = 128;
 module_param(ring_size, int, S_IRUGO);
 MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)");
 
-static int max_num_vrss_chns = 8;
-
 static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE |
                                NETIF_MSG_LINK | NETIF_MSG_IFUP |
                                NETIF_MSG_IFDOWN | NETIF_MSG_RX_ERR |
@@ -709,102 +707,76 @@ static void netvsc_get_channels(struct net_device *net,
        }
 }
 
+static int netvsc_set_queues(struct net_device *net, struct hv_device *dev,
+                            u32 num_chn)
+{
+       struct netvsc_device_info device_info;
+       int ret;
+
+       memset(&device_info, 0, sizeof(device_info));
+       device_info.num_chn = num_chn;
+       device_info.ring_size = ring_size;
+       device_info.max_num_vrss_chns = num_chn;
+
+       ret = rndis_filter_device_add(dev, &device_info);
+       if (ret)
+               return ret;
+
+       ret = netif_set_real_num_tx_queues(net, num_chn);
+       if (ret)
+               return ret;
+
+       ret = netif_set_real_num_rx_queues(net, num_chn);
+
+       return ret;
+}
+
 static int netvsc_set_channels(struct net_device *net,
                               struct ethtool_channels *channels)
 {
        struct net_device_context *net_device_ctx = netdev_priv(net);
        struct hv_device *dev = net_device_ctx->device_ctx;
        struct netvsc_device *nvdev = net_device_ctx->nvdev;
-       struct netvsc_device_info device_info;
-       u32 num_chn;
-       u32 max_chn;
-       int ret = 0;
-       bool recovering = false;
+       unsigned int count = channels->combined_count;
+       int ret;
+
+       /* We do not support separate count for rx, tx, or other */
+       if (count == 0 ||
+           channels->rx_count || channels->tx_count || channels->other_count)
+               return -EINVAL;
+
+       if (count > net->num_tx_queues || count > net->num_rx_queues)
+               return -EINVAL;
 
        if (net_device_ctx->start_remove || !nvdev || nvdev->destroy)
                return -ENODEV;
 
-       num_chn = nvdev->num_chn;
-       max_chn = min_t(u32, nvdev->max_chn, num_online_cpus());
-
-       if (nvdev->nvsp_version < NVSP_PROTOCOL_VERSION_5) {
-               pr_info("vRSS unsupported before NVSP Version 5\n");
+       if (nvdev->nvsp_version < NVSP_PROTOCOL_VERSION_5)
                return -EINVAL;
-       }
 
-       /* We do not support rx, tx, or other */
-       if (!channels ||
-           channels->rx_count ||
-           channels->tx_count ||
-           channels->other_count ||
-           (channels->combined_count < 1))
+       if (count > nvdev->max_chn)
                return -EINVAL;
 
-       if (channels->combined_count > max_chn) {
-               pr_info("combined channels too high, using %d\n", max_chn);
-               channels->combined_count = max_chn;
-       }
-
        ret = netvsc_close(net);
        if (ret)
-               goto out;
+               return ret;
 
- do_set:
        net_device_ctx->start_remove = true;
        rndis_filter_device_remove(dev);
 
-       nvdev->num_chn = channels->combined_count;
-
-       memset(&device_info, 0, sizeof(device_info));
-       device_info.num_chn = nvdev->num_chn; /* passed to RNDIS */
-       device_info.ring_size = ring_size;
-       device_info.max_num_vrss_chns = max_num_vrss_chns;
-
-       ret = rndis_filter_device_add(dev, &device_info);
-       if (ret) {
-               if (recovering) {
-                       netdev_err(net, "unable to add netvsc device (ret %d)\n", ret);
-                       return ret;
-               }
-               goto recover;
-       }
-
-       nvdev = net_device_ctx->nvdev;
-
-       ret = netif_set_real_num_tx_queues(net, nvdev->num_chn);
-       if (ret) {
-               if (recovering) {
-                       netdev_err(net, "could not set tx queue count (ret %d)\n", ret);
-                       return ret;
-               }
-               goto recover;
-       }
-
-       ret = netif_set_real_num_rx_queues(net, nvdev->num_chn);
-       if (ret) {
-               if (recovering) {
-                       netdev_err(net, "could not set rx queue count (ret %d)\n", ret);
-                       return ret;
-               }
-               goto recover;
-       }
+       ret = netvsc_set_queues(net, dev, count);
+       if (ret == 0)
+               nvdev->num_chn = count;
+       else
+               netvsc_set_queues(net, dev, nvdev->num_chn);
 
- out:
        netvsc_open(net);
        net_device_ctx->start_remove = false;
+
        /* We may have missed link change notifications */
        schedule_delayed_work(&net_device_ctx->dwork, 0);
 
        return ret;
-
- recover:
-       /* If the above failed, we attempt to recover through the same
-        * process but with the original number of channels.
-        */
-       netdev_err(net, "could not set channels, recovering\n");
-       recovering = true;
-       channels->combined_count = num_chn;
-       goto do_set;
 }
 
 static bool netvsc_validate_ethtool_ss_cmd(const struct ethtool_cmd *cmd)
@@ -865,8 +837,7 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
        struct netvsc_device *nvdev = ndevctx->nvdev;
        struct hv_device *hdev = ndevctx->device_ctx;
        struct netvsc_device_info device_info;
-       u32 num_chn;
-       int ret = 0;
+       int ret;
 
        if (ndevctx->start_remove || !nvdev || nvdev->destroy)
                return -ENODEV;
@@ -875,8 +846,6 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
        if (ret)
                goto out;
 
-       num_chn = nvdev->num_chn;
-
        ndevctx->start_remove = true;
        rndis_filter_device_remove(hdev);
 
@@ -884,8 +853,8 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
 
        memset(&device_info, 0, sizeof(device_info));
        device_info.ring_size = ring_size;
-       device_info.num_chn = num_chn;
-       device_info.max_num_vrss_chns = max_num_vrss_chns;
+       device_info.num_chn = nvdev->num_chn;
+       device_info.max_num_vrss_chns = nvdev->num_chn;
        rndis_filter_device_add(hdev, &device_info);
 
 out:
@@ -1410,7 +1379,7 @@ static int netvsc_probe(struct hv_device *dev,
        int ret;
 
        net = alloc_etherdev_mq(sizeof(struct net_device_context),
-                               num_online_cpus());
+                               VRSS_CHANNEL_MAX);
        if (!net)
                return -ENOMEM;
 
@@ -1457,7 +1426,8 @@ static int netvsc_probe(struct hv_device *dev,
        /* Notify the netvsc driver of the new device */
        memset(&device_info, 0, sizeof(device_info));
        device_info.ring_size = ring_size;
-       device_info.max_num_vrss_chns = max_num_vrss_chns;
+       device_info.max_num_vrss_chns = min_t(u32, VRSS_CHANNEL_DEFAULT,
+                                             num_online_cpus());
        ret = rndis_filter_device_add(dev, &device_info);
        if (ret != 0) {
                netdev_err(net, "unable to add netvsc device (ret %d)\n", ret);