The default value of send and receive buffer area for host DMA
is much larger than it needs to be. Experimentation shows that
a much smaller buffer still keeps same performance; change
from 16M buffer to 4M receive and 1M send.

Make the size a module parameter so that it can be adjusted
as needed for testing or special needs. It would have been
better to use ethtool to control this but ethtool rx/tx parameters
are in number of descriptors not bytes.

Signed-off-by: Stephen Hemminger <sthem...@microsoft.com>
---
 drivers/net/hyperv/hyperv_net.h |  2 ++
 drivers/net/hyperv/netvsc.c     | 18 ++++++++++--------
 drivers/net/hyperv/netvsc_drv.c | 40 +++++++++++++++++++++++++++++++++++-----
 3 files changed, 47 insertions(+), 13 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 2b4a9b058f6d..21666df4cd35 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -148,6 +148,8 @@ struct netvsc_device_info {
        unsigned char mac_adr[ETH_ALEN];
        bool link_state;        /* 0 - link up, 1 - link down */
        u32  ring_size;
+       u32  recv_buf_size;
+       u32  send_buf_size;
        u32  max_num_vrss_chns;
        u32  num_chn;
 };
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 480bd7704b68..59ca5fd6797d 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -488,16 +488,16 @@ static int negotiate_nvsp_ver(struct hv_device *device,
        return ret;
 }
 
-static int netvsc_connect_vsp(struct hv_device *device)
+static int netvsc_connect_vsp(struct hv_device *device,
+                             const struct netvsc_device_info *device_info)
 {
-       int ret;
        struct netvsc_device *net_device;
        struct nvsp_message *init_packet;
-       int ndis_version;
        const u32 ver_list[] = {
                NVSP_PROTOCOL_VERSION_1, NVSP_PROTOCOL_VERSION_2,
                NVSP_PROTOCOL_VERSION_4, NVSP_PROTOCOL_VERSION_5 };
-       int i;
+       u32 max_recv_buf_size, ndis_version;
+       int i, ret;
 
        net_device = get_outbound_net_device(device);
        if (!net_device)
@@ -546,10 +546,12 @@ static int netvsc_connect_vsp(struct hv_device *device)
 
        /* Post the big receive buffer to NetVSP */
        if (net_device->nvsp_version <= NVSP_PROTOCOL_VERSION_2)
-               net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY;
+               max_recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY;
        else
-               net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE;
-       net_device->send_buf_size = NETVSC_SEND_BUFFER_SIZE;
+               max_recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE;
+
+       net_device->recv_buf_size = min(max_recv_buf_size, 
device_info->recv_buf_size);
+       net_device->send_buf_size = min_t(u32, NETVSC_SEND_BUFFER_SIZE, 
device_info->send_buf_size);
 
        ret = netvsc_init_buf(device);
 
@@ -1360,7 +1362,7 @@ int netvsc_device_add(struct hv_device *device,
        rcu_assign_pointer(net_device_ctx->nvdev, net_device);
 
        /* Connect with the NetVsp */
-       ret = netvsc_connect_vsp(device);
+       ret = netvsc_connect_vsp(device, device_info);
        if (ret != 0) {
                netdev_err(ndev,
                        "unable to connect to NetVSP - %d\n", ret);
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index fb743c78f3dc..ef3a3a46790f 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -40,13 +40,23 @@
 
 #include "hyperv_net.h"
 
-#define RING_SIZE_MIN 64
+#define RING_SIZE_MIN   64
+#define RECV_BUFFER_MIN         16
+#define SEND_BUFFER_MIN         4
 #define LINKCHANGE_INT (2 * HZ)
 
 static unsigned int ring_size = 128;
 module_param(ring_size, uint, 0444);
 MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)");
 
+static unsigned int recv_buffer_size = (4 * 1024 * 1024) / PAGE_SIZE;
+module_param(recv_buffer_size, uint, 0444);
+MODULE_PARM_DESC(recv_buffer_size, "Receive buffer size (# of pages)");
+
+static unsigned int send_buffer_size = (1024 * 1024) / PAGE_SIZE;
+module_param(send_buffer_size, uint, 0444);
+MODULE_PARM_DESC(send_buffer_size, "Send buffer size (# of pages)");
+
 static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE |
                                NETIF_MSG_LINK | NETIF_MSG_IFUP |
                                NETIF_MSG_IFDOWN | NETIF_MSG_RX_ERR |
@@ -764,8 +774,8 @@ 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)
+static int netvsc_set_queues(struct net_device *net, struct netvsc_device 
*nvdev,
+                            struct hv_device *dev, u32 num_chn)
 {
        struct netvsc_device_info device_info;
        int ret;
@@ -774,6 +784,8 @@ static int netvsc_set_queues(struct net_device *net, struct 
hv_device *dev,
        device_info.num_chn = num_chn;
        device_info.ring_size = ring_size;
        device_info.max_num_vrss_chns = num_chn;
+       device_info.send_buf_size = nvdev->send_buf_size;
+       device_info.recv_buf_size = nvdev->recv_buf_size;
 
        ret = rndis_filter_device_add(dev, &device_info);
        if (ret)
@@ -824,11 +836,11 @@ static int netvsc_set_channels(struct net_device *net,
 
        rndis_filter_device_remove(dev, nvdev);
 
-       ret = netvsc_set_queues(net, dev, count);
+       ret = netvsc_set_queues(net, nvdev, dev, count);
        if (ret == 0)
                nvdev->num_chn = count;
        else
-               netvsc_set_queues(net, dev, nvdev->num_chn);
+               netvsc_set_queues(net, nvdev, dev, nvdev->num_chn);
 
        if (was_running)
                ret = netvsc_open(net);
@@ -917,6 +929,8 @@ static int netvsc_change_mtu(struct net_device *ndev, int 
mtu)
        device_info.ring_size = ring_size;
        device_info.num_chn = nvdev->num_chn;
        device_info.max_num_vrss_chns = nvdev->num_chn;
+       device_info.send_buf_size = nvdev->send_buf_size;
+       device_info.recv_buf_size = nvdev->recv_buf_size;
 
        rndis_filter_device_remove(hdev, nvdev);
 
@@ -1568,6 +1582,9 @@ static int netvsc_probe(struct hv_device *dev,
        memset(&device_info, 0, sizeof(device_info));
        device_info.ring_size = ring_size;
        device_info.num_chn = VRSS_CHANNEL_DEFAULT;
+       device_info.send_buf_size = send_buffer_size * PAGE_SIZE;
+       device_info.recv_buf_size = recv_buffer_size * PAGE_SIZE;
+
        ret = rndis_filter_device_add(dev, &device_info);
        if (ret != 0) {
                netdev_err(net, "unable to add netvsc device (ret %d)\n", ret);
@@ -1716,6 +1733,19 @@ static int __init netvsc_drv_init(void)
                pr_notice("Increased ring_size to %u (min allowed)\n",
                          ring_size);
        }
+
+       if (recv_buffer_size < RECV_BUFFER_MIN) {
+               recv_buffer_size = RECV_BUFFER_MIN;
+               pr_notice("Increased receive buffer size to %u (min allowed)\n",
+                         recv_buffer_size);
+       }
+
+       if (send_buffer_size < SEND_BUFFER_MIN) {
+               send_buffer_size = SEND_BUFFER_MIN;
+               pr_notice("Increased receive buffer size to %u (min allowed)\n",
+                         send_buffer_size);
+       }
+
        ret = vmbus_driver_register(&netvsc_drv);
 
        if (ret)
-- 
2.11.0

Reply via email to