[2/5] net/netvsc: allow tuning latency with devargs

Message ID 20180830223512.21297-3-stephen@networkplumber.org
State Accepted, archived
Delegated to: Ferruh Yigit
Headers show
Series
  • netvsc changes for 18.11
Related show

Checks

Context Check Description
ci/Intel-compilation success Compilation OK
ci/checkpatch success coding style OK

Commit Message

Stephen Hemminger Aug. 30, 2018, 10:35 p.m.
From: Stephen Hemminger <sthemmin@microsoft.com>

Allow overriding default guest to host latency on per device basis
with devargs.

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
---
 doc/guides/nics/netvsc.rst     | 16 +++++++++
 drivers/net/netvsc/hn_ethdev.c | 62 +++++++++++++++++++++++++++++++---
 drivers/net/netvsc/hn_var.h    |  1 +
 3 files changed, 75 insertions(+), 4 deletions(-)

Comments

Ferruh Yigit Sept. 14, 2018, 12:47 p.m. | #1
On 8/30/2018 11:35 PM, Stephen Hemminger wrote:
> From: Stephen Hemminger <sthemmin@microsoft.com>
> 
> Allow overriding default guest to host latency on per device basis
> with devargs.
> 
> Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>

Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>

Patch

diff --git a/doc/guides/nics/netvsc.rst b/doc/guides/nics/netvsc.rst
index 345f393c24ba..cc07ce46f885 100644
--- a/doc/guides/nics/netvsc.rst
+++ b/doc/guides/nics/netvsc.rst
@@ -103,3 +103,19 @@  The following prerequisites apply:
 *   Linux kernel support for UIO on vmbus is done with the uio_hv_generic driver.
     Full support of multiple queues requires the 4.17 kernel. It is possible
     to use the netvsc PMD with 4.16 kernel but it is limited to a single queue.
+
+
+Netvsc PMD arguments
+--------------------
+
+The user can specify below argument in devargs.
+
+#.  ``latency``:
+
+    A netvsc device uses a mailbox page to indicate to the host that there
+    is something in the transmit queue. The host scans this page at a
+    periodic interval. This parameter allows adjusting the value that
+    is used by the host. Smaller values improve transmit latency, and larger
+    values save CPU cycles. This parameter is in microseconds.
+    If the value is too large or too small it will be
+    ignored by the host. (Default: 50)
diff --git a/drivers/net/netvsc/hn_ethdev.c b/drivers/net/netvsc/hn_ethdev.c
index 2200ee319f98..97e4b0da4410 100644
--- a/drivers/net/netvsc/hn_ethdev.c
+++ b/drivers/net/netvsc/hn_ethdev.c
@@ -14,7 +14,9 @@ 
 #include <rte_memcpy.h>
 #include <rte_string_fns.h>
 #include <rte_memzone.h>
+#include <rte_devargs.h>
 #include <rte_malloc.h>
+#include <rte_kvargs.h>
 #include <rte_atomic.h>
 #include <rte_branch_prediction.h>
 #include <rte_ether.h>
@@ -131,6 +133,55 @@  eth_dev_vmbus_release(struct rte_eth_dev *eth_dev)
 	eth_dev->intr_handle = NULL;
 }
 
+/* handle "latency=X" from devargs */
+static int hn_set_latency(const char *key, const char *value, void *opaque)
+{
+	struct hn_data *hv = opaque;
+	char *endp = NULL;
+	unsigned long lat;
+
+	errno = 0;
+	lat = strtoul(value, &endp, 0);
+
+	if (*value == '\0' || *endp != '\0') {
+		PMD_DRV_LOG(ERR, "invalid parameter %s=%s", key, value);
+		return -EINVAL;
+	}
+
+	PMD_DRV_LOG(DEBUG, "set latency %lu usec", lat);
+
+	hv->latency = lat * 1000;	/* usec to nsec */
+	return 0;
+}
+
+/* Parse device arguments */
+static int hn_parse_args(const struct rte_eth_dev *dev)
+{
+	struct hn_data *hv = dev->data->dev_private;
+	struct rte_devargs *devargs = dev->device->devargs;
+	static const char * const valid_keys[] = {
+		"latency",
+		NULL
+	};
+	struct rte_kvargs *kvlist;
+
+	if (!devargs)
+		return 0;
+
+	PMD_INIT_LOG(DEBUG, "device args %s %s",
+		     devargs->name, devargs->args);
+
+	kvlist = rte_kvargs_parse(devargs->args, valid_keys);
+	if (!kvlist) {
+		PMD_DRV_LOG(NOTICE, "invalid parameters");
+		return -EINVAL;
+	}
+
+	rte_kvargs_process(kvlist, "latency", hn_set_latency, hv);
+	rte_kvargs_free(kvlist);
+	return 0;
+}
+
 /* Update link status.
  * Note: the DPDK definition of "wait_to_complete"
  *   means block this call until link is up.
@@ -264,8 +315,7 @@  static int hn_subchan_configure(struct hn_data *hv,
 			return err;
 		}
 
-		rte_vmbus_set_latency(hv->vmbus, new_sc,
-				      HN_CHAN_LATENCY_NS);
+		rte_vmbus_set_latency(hv->vmbus, new_sc, hv->latency);
 
 		retry = 0;
 		chn_index = rte_vmbus_sub_channel_index(new_sc);
@@ -627,14 +677,18 @@  eth_hn_dev_init(struct rte_eth_dev *eth_dev)
 	hv->rxbuf_res = &vmbus->resource[HV_RECV_BUF_MAP];
 	hv->chim_res  = &vmbus->resource[HV_SEND_BUF_MAP];
 	hv->port_id = eth_dev->data->port_id;
+	hv->latency = HN_CHAN_LATENCY_NS;
+
+	err = hn_parse_args(eth_dev);
+	if (err)
+		return err;
 
 	/* Initialize primary channel input for control operations */
 	err = rte_vmbus_chan_open(vmbus, &hv->channels[0]);
 	if (err)
 		return err;
 
-	rte_vmbus_set_latency(hv->vmbus, hv->channels[0],
-			      HN_CHAN_LATENCY_NS);
+	rte_vmbus_set_latency(hv->vmbus, hv->channels[0], hv->latency);
 
 	hv->primary = hn_rx_queue_alloc(hv, 0,
 					eth_dev->device->numa_node);
diff --git a/drivers/net/netvsc/hn_var.h b/drivers/net/netvsc/hn_var.h
index b42bd97b9a45..f188f6360f79 100644
--- a/drivers/net/netvsc/hn_var.h
+++ b/drivers/net/netvsc/hn_var.h
@@ -113,6 +113,7 @@  struct hn_data {
 	uint32_t	chim_szmax;		/* Max size per buffer */
 	uint32_t	chim_cnt;		/* Max packets per buffer */
 
+	uint32_t	latency;
 	uint32_t	nvs_ver;
 	uint32_t	ndis_ver;
 	uint32_t	rndis_agg_size;