DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 00/56] Solarflare libefx-based PMD
From: Stephen Hemminger @ 2016-11-23 19:21 UTC (permalink / raw)
  To: Andrew Rybchenko; +Cc: Ferruh Yigit, dev
In-Reply-To: <5d041f12-ec8d-77da-47ac-671eb3a39a5b@solarflare.com>

On Wed, 23 Nov 2016 10:49:33 +0300
Andrew Rybchenko <arybchenko@solarflare.com> wrote:

> I've tried to explain it above in item (2):
> 
>  >>>  
> 
>   2. Another Solarflare PMD with in-kernel part (for control operations)
>      is considered and could be added in the future. Code for data path
>      should be shared by these two drivers. libefx-based PMD is put into
>      'efx' subdirectory to have a space for another PMD and shared code.
> 
> <<<
> 
> So, main reason is to have location for the code shared by two Solarflare
> network PMDs. May be it better to relocate when we really have it.
> I'm open for other ideas/suggestions.

So is this driver dependent on another non-upstream kernel driver to work?
Is this documented in docs directory.  If it does depend on other non-upstream
components, then the default config should disable the driver.

^ permalink raw reply

* Improved PCI hotplug support
From: Ben Walker @ 2016-11-23 19:36 UTC (permalink / raw)
  To: dev

This series of patches adds support for PCI hot insert and remove.
Detection of new devices or removed devices is accomplished by
polling rte_eal_pci_probe, with the registered PCI drivers being
loaded or unloaded when a new device is found or previously known
device is removed.

There are some additional considerations for hotplug that this
patch does not address. Full hotplug support actually consists of
three operations:

1) Hot insert. This patch series does correctly handle this case.
2) Planned hot remove. This patch series can also handle this case
        because the user can explicitly unload the driver prior to
        removal.
3) Surprise hot remove. If a driver is loaded and active, a SIGBUS
        may occur on the next access to a memory mapped region.
        This is currently NOT handled by this patch series.

^ permalink raw reply

* [PATCH 1/7] pci: If a driver's probe function fails, unmap resources.
From: Ben Walker @ 2016-11-23 19:36 UTC (permalink / raw)
  To: dev; +Cc: Ben Walker
In-Reply-To: <1479929804-19614-1-git-send-email-benjamin.walker@intel.com>

If resources were mapped prior to probe, unmap them
if probe fails.

This does not handle the case where the kernel driver was
forcibly unbound prior to probe.

Signed-off-by: Ben Walker <benjamin.walker@intel.com>
---
 lib/librte_eal/common/eal_common_pci.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index 6bff675..4f8c3a0 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -215,8 +215,11 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d
 
 		/* call the driver probe() function */
 		ret = dr->probe(dr, dev);
-		if (ret)
+		if (ret) {
 			dev->driver = NULL;
+			if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
+				rte_eal_pci_unmap_device(dev);
+		}
 
 		return ret;
 	}
-- 
2.7.4

^ permalink raw reply related

* [PATCH 3/7] pci: Pass rte_pci_addr to functions instead of separate args
From: Ben Walker @ 2016-11-23 19:36 UTC (permalink / raw)
  To: dev; +Cc: Ben Walker
In-Reply-To: <1479929804-19614-1-git-send-email-benjamin.walker@intel.com>

Instead of passing domain, bus, devid, func, just pass
an rte_pci_addr.

Signed-off-by: Ben Walker <benjamin.walker@intel.com>
---
 lib/librte_eal/linuxapp/eal/eal_pci.c | 32 +++++++++++++-------------------
 1 file changed, 13 insertions(+), 19 deletions(-)

diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 876ba38..073af5f 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -267,8 +267,7 @@ pci_parse_sysfs_resource(const char *filename, struct rte_pci_device *dev)
 
 /* Scan one pci sysfs entry, and fill the devices list from it. */
 static int
-pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
-	     uint8_t devid, uint8_t function)
+pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
 {
 	char filename[PATH_MAX];
 	unsigned long tmp;
@@ -281,10 +280,7 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
 		return -1;
 
 	memset(dev, 0, sizeof(*dev));
-	dev->addr.domain = domain;
-	dev->addr.bus = bus;
-	dev->addr.devid = devid;
-	dev->addr.function = function;
+	dev->addr = *addr;
 
 	/* get vendor id */
 	snprintf(filename, sizeof(filename), "%s/vendor", dirname);
@@ -429,16 +425,14 @@ pci_update_device(const struct rte_pci_addr *addr)
 		 pci_get_sysfs_path(), addr->domain, addr->bus, addr->devid,
 		 addr->function);
 
-	return pci_scan_one(filename, addr->domain, addr->bus, addr->devid,
-				addr->function);
+	return pci_scan_one(filename, addr);
 }
 
 /*
  * split up a pci address into its constituent parts.
  */
 static int
-parse_pci_addr_format(const char *buf, int bufsize, uint16_t *domain,
-		uint8_t *bus, uint8_t *devid, uint8_t *function)
+parse_pci_addr_format(const char *buf, int bufsize, struct rte_pci_addr *addr)
 {
 	/* first split on ':' */
 	union splitaddr {
@@ -466,10 +460,10 @@ parse_pci_addr_format(const char *buf, int bufsize, uint16_t *domain,
 
 	/* now convert to int values */
 	errno = 0;
-	*domain = (uint16_t)strtoul(splitaddr.domain, NULL, 16);
-	*bus = (uint8_t)strtoul(splitaddr.bus, NULL, 16);
-	*devid = (uint8_t)strtoul(splitaddr.devid, NULL, 16);
-	*function = (uint8_t)strtoul(splitaddr.function, NULL, 10);
+	addr->domain = (uint16_t)strtoul(splitaddr.domain, NULL, 16);
+	addr->bus = (uint8_t)strtoul(splitaddr.bus, NULL, 16);
+	addr->devid = (uint8_t)strtoul(splitaddr.devid, NULL, 16);
+	addr->function = (uint8_t)strtoul(splitaddr.function, NULL, 10);
 	if (errno != 0)
 		goto error;
 
@@ -490,8 +484,7 @@ rte_eal_pci_scan(void)
 	struct dirent *e;
 	DIR *dir;
 	char dirname[PATH_MAX];
-	uint16_t domain;
-	uint8_t bus, devid, function;
+	struct rte_pci_addr addr;
 
 	dir = opendir(pci_get_sysfs_path());
 	if (dir == NULL) {
@@ -500,20 +493,21 @@ rte_eal_pci_scan(void)
 		return -1;
 	}
 
+
 	while ((e = readdir(dir)) != NULL) {
 		if (e->d_name[0] == '.')
 			continue;
 
-		if (parse_pci_addr_format(e->d_name, sizeof(e->d_name), &domain,
-				&bus, &devid, &function) != 0)
+		if (parse_pci_addr_format(e->d_name, sizeof(e->d_name), &addr) != 0)
 			continue;
 
 		snprintf(dirname, sizeof(dirname), "%s/%s",
 				pci_get_sysfs_path(), e->d_name);
-		if (pci_scan_one(dirname, domain, bus, devid, function) < 0)
+		if (pci_scan_one(dirname, &addr) < 0)
 			goto error;
 	}
 	closedir(dir);
+
 	return 0;
 
 error:
-- 
2.7.4

^ permalink raw reply related

* [PATCH 2/7] pci: Separate detaching ethernet ports from PCI devices
From: Ben Walker @ 2016-11-23 19:36 UTC (permalink / raw)
  To: dev; +Cc: Ben Walker
In-Reply-To: <1479929804-19614-1-git-send-email-benjamin.walker@intel.com>

Attaching and detaching ethernet ports from an application
is not the same thing as physically removing a PCI device,
so clarify the flags indicating support. All PCI devices
are assumed to be physically removable, so no flag is
necessary in the PCI layer.

Signed-off-by: Ben Walker <benjamin.walker@intel.com>
---
 doc/guides/prog_guide/port_hotplug_framework.rst | 2 +-
 drivers/net/bnxt/bnxt_ethdev.c                   | 3 ++-
 drivers/net/e1000/em_ethdev.c                    | 4 ++--
 drivers/net/e1000/igb_ethdev.c                   | 7 ++++---
 drivers/net/fm10k/fm10k_ethdev.c                 | 4 ++--
 drivers/net/i40e/i40e_ethdev.c                   | 4 ++--
 drivers/net/i40e/i40e_ethdev_vf.c                | 3 ++-
 drivers/net/ixgbe/ixgbe_ethdev.c                 | 7 ++++---
 drivers/net/nfp/nfp_net.c                        | 4 ++--
 drivers/net/virtio/virtio_ethdev.c               | 3 ++-
 drivers/net/vmxnet3/vmxnet3_ethdev.c             | 3 ++-
 drivers/net/xenvirt/rte_eth_xenvirt.c            | 2 +-
 lib/librte_eal/common/include/rte_pci.h          | 2 --
 lib/librte_ether/rte_ethdev.c                    | 2 --
 14 files changed, 26 insertions(+), 24 deletions(-)

diff --git a/doc/guides/prog_guide/port_hotplug_framework.rst b/doc/guides/prog_guide/port_hotplug_framework.rst
index 6e4436e..d68d08e 100644
--- a/doc/guides/prog_guide/port_hotplug_framework.rst
+++ b/doc/guides/prog_guide/port_hotplug_framework.rst
@@ -106,5 +106,5 @@ Limitations
 
 *       Not all PMDs support detaching feature.
         To know whether a PMD can support detaching, search for the
-        "RTE_PCI_DRV_DETACHABLE" flag in PMD implementation. If the flag is
+        "RTE_ETH_DEV_DETAHABLE" flag in rte_eth_dev::data::dev_flags. If the flag is
         defined in the PMD, detaching is supported.
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 035fe07..a2100f6 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -1051,6 +1051,7 @@ bnxt_dev_init(struct rte_eth_dev *eth_dev)
 		RTE_LOG(INFO, PMD, "%s", bnxt_version);
 
 	rte_eth_copy_pci_info(eth_dev, eth_dev->pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 	bp = eth_dev->data->dev_private;
 
 	if (bnxt_vf_pciid(eth_dev->pci_dev->id.device_id))
@@ -1162,7 +1163,7 @@ static struct eth_driver bnxt_rte_pmd = {
 	.pci_drv = {
 		    .id_table = bnxt_pci_id_map,
 		    .drv_flags = RTE_PCI_DRV_NEED_MAPPING |
-			    RTE_PCI_DRV_DETACHABLE | RTE_PCI_DRV_INTR_LSC,
+			    RTE_PCI_DRV_INTR_LSC,
 		    .probe = rte_eth_dev_pci_probe,
 		    .remove = rte_eth_dev_pci_remove
 		    },
diff --git a/drivers/net/e1000/em_ethdev.c b/drivers/net/e1000/em_ethdev.c
index aee3d34..9af429b 100644
--- a/drivers/net/e1000/em_ethdev.c
+++ b/drivers/net/e1000/em_ethdev.c
@@ -312,6 +312,7 @@ eth_em_dev_init(struct rte_eth_dev *eth_dev)
 	}
 
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	hw->hw_addr = (void *)pci_dev->mem_resource[0].addr;
 	hw->device_id = pci_dev->id.device_id;
@@ -392,8 +393,7 @@ eth_em_dev_uninit(struct rte_eth_dev *eth_dev)
 static struct eth_driver rte_em_pmd = {
 	.pci_drv = {
 		.id_table = pci_id_em_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-			RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 2fddf0c..b014b8b 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -771,6 +771,7 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev)
 	}
 
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	hw->hw_addr= (void *)pci_dev->mem_resource[0].addr;
 
@@ -976,6 +977,7 @@ eth_igbvf_dev_init(struct rte_eth_dev *eth_dev)
 	pci_dev = eth_dev->pci_dev;
 
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	hw->device_id = pci_dev->id.device_id;
 	hw->vendor_id = pci_dev->id.vendor_id;
@@ -1079,8 +1081,7 @@ eth_igbvf_dev_uninit(struct rte_eth_dev *eth_dev)
 static struct eth_driver rte_igb_pmd = {
 	.pci_drv = {
 		.id_table = pci_id_igb_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-			RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
@@ -1095,7 +1096,7 @@ static struct eth_driver rte_igb_pmd = {
 static struct eth_driver rte_igbvf_pmd = {
 	.pci_drv = {
 		.id_table = pci_id_igbvf_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
diff --git a/drivers/net/fm10k/fm10k_ethdev.c b/drivers/net/fm10k/fm10k_ethdev.c
index 923690c..578de1f 100644
--- a/drivers/net/fm10k/fm10k_ethdev.c
+++ b/drivers/net/fm10k/fm10k_ethdev.c
@@ -2841,6 +2841,7 @@ eth_fm10k_dev_init(struct rte_eth_dev *dev)
 		return 0;
 
 	rte_eth_copy_pci_info(dev, dev->pci_dev);
+	dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	macvlan = FM10K_DEV_PRIVATE_TO_MACVLAN(dev->data->dev_private);
 	memset(macvlan, 0, sizeof(*macvlan));
@@ -3062,8 +3063,7 @@ static const struct rte_pci_id pci_id_fm10k_map[] = {
 static struct eth_driver rte_pmd_fm10k = {
 	.pci_drv = {
 		.id_table = pci_id_fm10k_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-			RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 67778ba..7877cc5 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -671,8 +671,7 @@ static const struct rte_i40e_xstats_name_off rte_i40e_txq_prio_strings[] = {
 static struct eth_driver rte_i40e_pmd = {
 	.pci_drv = {
 		.id_table = pci_id_i40e_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-			RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
@@ -955,6 +954,7 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
 	pci_dev = dev->pci_dev;
 
 	rte_eth_copy_pci_info(dev, pci_dev);
+	dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	pf->adapter = I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
 	pf->adapter->eth_dev = dev;
diff --git a/drivers/net/i40e/i40e_ethdev_vf.c b/drivers/net/i40e/i40e_ethdev_vf.c
index aa306d6..6aaee37 100644
--- a/drivers/net/i40e/i40e_ethdev_vf.c
+++ b/drivers/net/i40e/i40e_ethdev_vf.c
@@ -1459,6 +1459,7 @@ i40evf_dev_init(struct rte_eth_dev *eth_dev)
 	}
 
 	rte_eth_copy_pci_info(eth_dev, eth_dev->pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	hw->vendor_id = eth_dev->pci_dev->id.vendor_id;
 	hw->device_id = eth_dev->pci_dev->id.device_id;
@@ -1528,7 +1529,7 @@ i40evf_dev_uninit(struct rte_eth_dev *eth_dev)
 static struct eth_driver rte_i40evf_pmd = {
 	.pci_drv = {
 		.id_table = pci_id_i40evf_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index edc9b22..66dd0c9 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -1130,6 +1130,7 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev)
 	pci_dev = eth_dev->pci_dev;
 
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	/* Vendor and Device ID need to be set before init of shared code */
 	hw->device_id = pci_dev->id.device_id;
@@ -1422,6 +1423,7 @@ eth_ixgbevf_dev_init(struct rte_eth_dev *eth_dev)
 	pci_dev = eth_dev->pci_dev;
 
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	hw->device_id = pci_dev->id.device_id;
 	hw->vendor_id = pci_dev->id.vendor_id;
@@ -1565,8 +1567,7 @@ eth_ixgbevf_dev_uninit(struct rte_eth_dev *eth_dev)
 static struct eth_driver rte_ixgbe_pmd = {
 	.pci_drv = {
 		.id_table = pci_id_ixgbe_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-			RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
@@ -1581,7 +1582,7 @@ static struct eth_driver rte_ixgbe_pmd = {
 static struct eth_driver rte_ixgbevf_pmd = {
 	.pci_drv = {
 		.id_table = pci_id_ixgbevf_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
diff --git a/drivers/net/nfp/nfp_net.c b/drivers/net/nfp/nfp_net.c
index c6b1587..00d2ba2 100644
--- a/drivers/net/nfp/nfp_net.c
+++ b/drivers/net/nfp/nfp_net.c
@@ -2332,6 +2332,7 @@ nfp_net_init(struct rte_eth_dev *eth_dev)
 
 	pci_dev = eth_dev->pci_dev;
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	hw->device_id = pci_dev->id.device_id;
 	hw->vendor_id = pci_dev->id.vendor_id;
@@ -2470,8 +2471,7 @@ static struct rte_pci_id pci_id_nfp_net_map[] = {
 static struct eth_driver rte_nfp_net_pmd = {
 	.pci_drv = {
 		.id_table = pci_id_nfp_net_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-			     RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 079fd6c..74255c5 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -1211,6 +1211,7 @@ virtio_init_device(struct rte_eth_dev *eth_dev, uint64_t req_features)
 		eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
 
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	rx_func_get(eth_dev);
 
@@ -1379,7 +1380,7 @@ static struct eth_driver rte_virtio_pmd = {
 			.name = "net_virtio",
 		},
 		.id_table = pci_id_virtio_map,
-		.drv_flags = RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = 0,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
diff --git a/drivers/net/vmxnet3/vmxnet3_ethdev.c b/drivers/net/vmxnet3/vmxnet3_ethdev.c
index 8bb13e5..dd8dca5 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethdev.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethdev.c
@@ -247,6 +247,7 @@ eth_vmxnet3_dev_init(struct rte_eth_dev *eth_dev)
 		return 0;
 
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	/* Vendor and Device ID need to be set before init of shared code */
 	hw->device_id = pci_dev->id.device_id;
@@ -336,7 +337,7 @@ eth_vmxnet3_dev_uninit(struct rte_eth_dev *eth_dev)
 static struct eth_driver rte_vmxnet3_pmd = {
 	.pci_drv = {
 		.id_table = pci_id_vmxnet3_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
diff --git a/drivers/net/xenvirt/rte_eth_xenvirt.c b/drivers/net/xenvirt/rte_eth_xenvirt.c
index c08a056..ec5d00b 100644
--- a/drivers/net/xenvirt/rte_eth_xenvirt.c
+++ b/drivers/net/xenvirt/rte_eth_xenvirt.c
@@ -673,7 +673,7 @@ eth_dev_xenvirt_create(const char *name, const char *params,
 	eth_dev->data = data;
 	eth_dev->dev_ops = &ops;
 
-	eth_dev->data->dev_flags = RTE_PCI_DRV_DETACHABLE;
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 	eth_dev->data->kdrv = RTE_KDRV_NONE;
 	eth_dev->data->drv_name = drivername;
 	eth_dev->driver = NULL;
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 9ce8847..74be1f5 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -212,8 +212,6 @@ struct rte_pci_driver {
 #define RTE_PCI_DRV_FORCE_UNBIND 0x0004
 /** Device driver supports link state interrupt */
 #define RTE_PCI_DRV_INTR_LSC	0x0008
-/** Device driver supports detaching capability */
-#define RTE_PCI_DRV_DETACHABLE	0x0010
 
 /**
  * A structure describing a PCI mapping.
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index fde8112..3771ffc 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -3209,8 +3209,6 @@ rte_eth_copy_pci_info(struct rte_eth_dev *eth_dev, struct rte_pci_device *pci_de
 	eth_dev->data->dev_flags = 0;
 	if (pci_dev->driver->drv_flags & RTE_PCI_DRV_INTR_LSC)
 		eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
-	if (pci_dev->driver->drv_flags & RTE_PCI_DRV_DETACHABLE)
-		eth_dev->data->dev_flags |= RTE_ETH_DEV_DETACHABLE;
 
 	eth_dev->data->kdrv = pci_dev->kdrv;
 	eth_dev->data->numa_node = pci_dev->device.numa_node;
-- 
2.7.4

^ permalink raw reply related

* [PATCH 4/7] pci: rte_eal_pci_scan now handles removal of PCI devices
From: Ben Walker @ 2016-11-23 19:36 UTC (permalink / raw)
  To: dev; +Cc: Ben Walker
In-Reply-To: <1479929804-19614-1-git-send-email-benjamin.walker@intel.com>

rte_eal_pci_scan can be called repeatedly to re-scan the PCI
bus. If a device was removed from the system, the associated
driver will automatically be unloaded.

Signed-off-by: Ben Walker <benjamin.walker@intel.com>
---
 lib/librte_eal/linuxapp/eal/eal_pci.c | 58 +++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 073af5f..f237864 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -485,7 +485,65 @@ rte_eal_pci_scan(void)
 	DIR *dir;
 	char dirname[PATH_MAX];
 	struct rte_pci_addr addr;
+	struct rte_pci_device *dev, *tmp;
+
+	/* Search the device list for devices that are no longer present on the system
+	 * and remove them.
+	 */
+	TAILQ_FOREACH_SAFE(dev, &pci_device_list, next, tmp) {
+		int found = 0;
+
+		dir = opendir(pci_get_sysfs_path());
+		if (dir == NULL) {
+			RTE_LOG(ERR, EAL, "%s(): opendir failed: %s\n",
+				__func__, strerror(errno));
+			return -1;
+		}
+
+		while ((e = readdir(dir)) != NULL) {
+			if (e->d_name[0] == '.')
+				continue;
+
+			if (parse_pci_addr_format(e->d_name, sizeof(e->d_name), &addr) != 0)
+				continue;
+
+			if (rte_eal_compare_pci_addr(&addr, &dev->addr) == 0) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (!found) {
+
+			RTE_LOG(DEBUG, EAL, "PCI device "PCI_PRI_FMT" was removed from the system.\n",
+					addr.domain, addr.bus, addr.devid,
+					addr.function);
+
+			if (dev->driver) {
+				/* A driver was loaded against this device. Unload it. */
+				RTE_LOG(DEBUG, EAL, "  Unload driver: %x:%x %s\n", dev->id.vendor_id,
+						dev->id.device_id, dev->driver->driver.name);
+
+				if (dev->driver->remove) {
+					/* It doesn't matter what remove returns - we're removing the device either way. */
+					dev->driver->remove(dev);
+				}
+
+				/* clear driver structure */
+				dev->driver = NULL;
+
+				if (dev->driver->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
+					rte_eal_pci_unmap_device(dev);
+			}
+
+			TAILQ_REMOVE(&pci_device_list, dev, next);
+			free(dev);
+		}
+
+		closedir(dir);
+	}
 
+	/* Search sysfs for all PCI devices and add them to the device list */
 	dir = opendir(pci_get_sysfs_path());
 	if (dir == NULL) {
 		RTE_LOG(ERR, EAL, "%s(): opendir failed: %s\n",
-- 
2.7.4

^ permalink raw reply related

* [PATCH 5/7] pci: Move driver registration above pci scan
From: Ben Walker @ 2016-11-23 19:36 UTC (permalink / raw)
  To: dev; +Cc: Ben Walker
In-Reply-To: <1479929804-19614-1-git-send-email-benjamin.walker@intel.com>

The user needs to register drivers before scanning, so
it makes the most sense to put the registration
functions above the scan function in the header file.

Signed-off-by: Ben Walker <benjamin.walker@intel.com>
---
 lib/librte_eal/common/include/rte_pci.h | 56 ++++++++++++++++-----------------
 1 file changed, 28 insertions(+), 28 deletions(-)

diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 74be1f5..5d0feac 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -358,6 +358,34 @@ rte_eal_compare_pci_addr(const struct rte_pci_addr *addr,
 }
 
 /**
+ * Register a PCI driver.
+ *
+ * @param driver
+ *   A pointer to a rte_pci_driver structure describing the driver
+ *   to be registered.
+ */
+void rte_eal_pci_register(struct rte_pci_driver *driver);
+
+/** Statically register a PCI driver at start up */
+#define RTE_PMD_REGISTER_PCI(nm, pci_drv) \
+RTE_INIT(pciinitfn_ ##nm); \
+static void pciinitfn_ ##nm(void) \
+{\
+	(pci_drv).driver.name = RTE_STR(nm);\
+	rte_eal_pci_register(&pci_drv); \
+} \
+RTE_PMD_EXPORT_NAME(nm, __COUNTER__)
+
+/**
+ * Unregister a PCI driver.
+ *
+ * @param driver
+ *   A pointer to a rte_pci_driver structure describing the driver
+ *   to be unregistered.
+ */
+void rte_eal_pci_unregister(struct rte_pci_driver *driver);
+
+/**
  * Scan the content of the PCI bus, and the devices in the devices
  * list
  *
@@ -476,34 +504,6 @@ int rte_eal_pci_detach(const struct rte_pci_addr *addr);
 void rte_eal_pci_dump(FILE *f);
 
 /**
- * Register a PCI driver.
- *
- * @param driver
- *   A pointer to a rte_pci_driver structure describing the driver
- *   to be registered.
- */
-void rte_eal_pci_register(struct rte_pci_driver *driver);
-
-/** Helper for PCI device registration from driver (eth, crypto) instance */
-#define RTE_PMD_REGISTER_PCI(nm, pci_drv) \
-RTE_INIT(pciinitfn_ ##nm); \
-static void pciinitfn_ ##nm(void) \
-{\
-	(pci_drv).driver.name = RTE_STR(nm);\
-	rte_eal_pci_register(&pci_drv); \
-} \
-RTE_PMD_EXPORT_NAME(nm, __COUNTER__)
-
-/**
- * Unregister a PCI driver.
- *
- * @param driver
- *   A pointer to a rte_pci_driver structure describing the driver
- *   to be unregistered.
- */
-void rte_eal_pci_unregister(struct rte_pci_driver *driver);
-
-/**
  * Read PCI config space.
  *
  * @param device
-- 
2.7.4

^ permalink raw reply related

* [PATCH 6/7] pci: Combine rte_eal_pci_scan and rte_eal_pci_probe
From: Ben Walker @ 2016-11-23 19:36 UTC (permalink / raw)
  To: dev; +Cc: Ben Walker
In-Reply-To: <1479929804-19614-1-git-send-email-benjamin.walker@intel.com>

Two functions is both confusing and unnecessary. Previously,
rte_eal_pci_scan populated an internal list of devices by
scanning sysfs. Then, rte_eal_pci_probe would match registered
drivers to that internal list. These are not really useful
operations to perform separately independently, though, so
simplify the api down to just rte_eal_pci_probe which can
be called repeatedly through the lifetime of the application
to scan for new or removed PCI devices and load or unload
drivers as required.

Signed-off-by: Ben Walker <benjamin.walker@intel.com>
---
 app/test/test_pci.c                             |  2 +-
 lib/librte_eal/bsdapp/eal/eal.c                 |  3 ---
 lib/librte_eal/bsdapp/eal/eal_pci.c             | 17 +----------------
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |  1 -
 lib/librte_eal/common/eal_common_pci.c          |  7 +++++++
 lib/librte_eal/common/eal_private.h             | 14 +++++---------
 lib/librte_eal/common/include/rte_pci.h         | 17 +++++------------
 lib/librte_eal/linuxapp/eal/eal.c               |  3 ---
 lib/librte_eal/linuxapp/eal/eal_pci.c           | 18 +-----------------
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |  1 -
 10 files changed, 20 insertions(+), 63 deletions(-)

diff --git a/app/test/test_pci.c b/app/test/test_pci.c
index cda186d..fdd84f7 100644
--- a/app/test/test_pci.c
+++ b/app/test/test_pci.c
@@ -180,7 +180,7 @@ test_pci_setup(void)
 		TAILQ_INSERT_TAIL(&real_pci_device_list, dev, next);
 	}
 
-	ret = rte_eal_pci_scan();
+	ret = rte_eal_pci_probe();
 	TEST_ASSERT_SUCCESS(ret, "failed to scan PCI bus");
 	rte_eal_pci_dump(stdout);
 
diff --git a/lib/librte_eal/bsdapp/eal/eal.c b/lib/librte_eal/bsdapp/eal/eal.c
index 35e3117..fd44528 100644
--- a/lib/librte_eal/bsdapp/eal/eal.c
+++ b/lib/librte_eal/bsdapp/eal/eal.c
@@ -561,9 +561,6 @@ rte_eal_init(int argc, char **argv)
 	if (rte_eal_timer_init() < 0)
 		rte_panic("Cannot init HPET or TSC timers\n");
 
-	if (rte_eal_pci_init() < 0)
-		rte_panic("Cannot init PCI\n");
-
 	eal_check_mem_on_local_socket();
 
 	if (eal_plugins_init() < 0)
diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 8b3ed88..6c3a169 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -361,7 +361,7 @@ pci_scan_one(int dev_pci_fd, struct pci_conf *conf)
  * list. Call pci_scan_one() for each pci entry found.
  */
 int
-rte_eal_pci_scan(void)
+pci_scan(void)
 {
 	int fd;
 	unsigned dev_count = 0;
@@ -667,18 +667,3 @@ rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p)
 
 	return ret;
 }
-
-/* Init the PCI EAL subsystem */
-int
-rte_eal_pci_init(void)
-{
-	/* for debug purposes, PCI can be disabled */
-	if (internal_config.no_pci)
-		return 0;
-
-	if (rte_eal_pci_scan() < 0) {
-		RTE_LOG(ERR, EAL, "%s(): Cannot scan PCI bus\n", __func__);
-		return -1;
-	}
-	return 0;
-}
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 2f81f7c..67c469c 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -44,7 +44,6 @@ DPDK_2.0 {
 	rte_eal_pci_probe;
 	rte_eal_pci_probe_one;
 	rte_eal_pci_register;
-	rte_eal_pci_scan;
 	rte_eal_pci_unregister;
 	rte_eal_process_type;
 	rte_eal_remote_launch;
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index 4f8c3a0..62b996d 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -81,6 +81,7 @@
 #include <rte_devargs.h>
 
 #include "eal_private.h"
+#include "eal_internal_cfg.h"
 
 struct pci_driver_list pci_driver_list =
 	TAILQ_HEAD_INITIALIZER(pci_driver_list);
@@ -423,6 +424,12 @@ rte_eal_pci_probe(void)
 	int probe_all = 0;
 	int ret = 0;
 
+	if (internal_config.no_pci) {
+		return 0;
+	}
+
+	pci_scan();
+
 	if (rte_eal_devargs_type_count(RTE_DEVTYPE_WHITELISTED_PCI) == 0)
 		probe_all = 1;
 
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index 9e7d8f6..54f18ea 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -108,18 +108,14 @@ int rte_eal_timer_init(void);
  */
 int rte_eal_log_init(const char *id, int facility);
 
-/**
- * Init the PCI infrastructure
+struct rte_pci_driver;
+struct rte_pci_device;
+
+/* Scan the PCI bus for devices
  *
  * This function is private to EAL.
- *
- * @return
- *   0 on success, negative on error
  */
-int rte_eal_pci_init(void);
-
-struct rte_pci_driver;
-struct rte_pci_device;
+int pci_scan(void);
 
 /**
  * Update a pci device object by asking the kernel for the latest information.
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 5d0feac..2154a54 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -386,20 +386,13 @@ RTE_PMD_EXPORT_NAME(nm, __COUNTER__)
 void rte_eal_pci_unregister(struct rte_pci_driver *driver);
 
 /**
- * Scan the content of the PCI bus, and the devices in the devices
- * list
- *
- * @return
- *  0 on success, negative on error
- */
-int rte_eal_pci_scan(void);
-
-/**
- * Probe the PCI bus for registered drivers.
+ * Scan the PCI bus for devices and match them to their driver.
  *
  * Scan the content of the PCI bus, and call the probe() function for
- * all registered drivers that have a matching entry in its id_table
- * for discovered devices.
+ * all registered drivers that have a matching entry in their id_table.
+ * If a device already has a driver loaded, probe will not be called.
+ * If a previously discovered device is no longer present on the system,
+ * the associated driver's remove() callback will be called.
  *
  * @return
  *   - 0 on success.
diff --git a/lib/librte_eal/linuxapp/eal/eal.c b/lib/librte_eal/linuxapp/eal/eal.c
index 2075282..f47f361 100644
--- a/lib/librte_eal/linuxapp/eal/eal.c
+++ b/lib/librte_eal/linuxapp/eal/eal.c
@@ -802,9 +802,6 @@ rte_eal_init(int argc, char **argv)
 	if (rte_eal_log_init(logid, internal_config.syslog_facility) < 0)
 		rte_panic("Cannot init logs\n");
 
-	if (rte_eal_pci_init() < 0)
-		rte_panic("Cannot init PCI\n");
-
 #ifdef VFIO_PRESENT
 	if (rte_eal_vfio_setup() < 0)
 		rte_panic("Cannot init VFIO\n");
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index f237864..663e106 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -479,7 +479,7 @@ parse_pci_addr_format(const char *buf, int bufsize, struct rte_pci_addr *addr)
  * list
  */
 int
-rte_eal_pci_scan(void)
+pci_scan(void)
 {
 	struct dirent *e;
 	DIR *dir;
@@ -806,19 +806,3 @@ rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p)
 
 	return ret;
 }
-
-/* Init the PCI EAL subsystem */
-int
-rte_eal_pci_init(void)
-{
-	/* for debug purposes, PCI can be disabled */
-	if (internal_config.no_pci)
-		return 0;
-
-	if (rte_eal_pci_scan() < 0) {
-		RTE_LOG(ERR, EAL, "%s(): Cannot scan PCI bus\n", __func__);
-		return -1;
-	}
-
-	return 0;
-}
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index 83721ba..856728e 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -44,7 +44,6 @@ DPDK_2.0 {
 	rte_eal_pci_probe;
 	rte_eal_pci_probe_one;
 	rte_eal_pci_register;
-	rte_eal_pci_scan;
 	rte_eal_pci_unregister;
 	rte_eal_process_type;
 	rte_eal_remote_launch;
-- 
2.7.4

^ permalink raw reply related

* [PATCH 7/7] pci: Clarify interfaces for dynamic attach/detach of drivers
From: Ben Walker @ 2016-11-23 19:36 UTC (permalink / raw)
  To: dev; +Cc: Ben Walker
In-Reply-To: <1479929804-19614-1-git-send-email-benjamin.walker@intel.com>

There are now two functions - rte_eal_pci_attach_driver and
rte_eal_pci_detach_driver - that dynamically attempt to attach
and detach drivers from PCI devices. These only control
whether a registered PCI driver is loaded or not - they are
independent of whether the PCI device exists on the system.

Signed-off-by: Ben Walker <benjamin.walker@intel.com>
---
 lib/librte_eal/common/eal_common_dev.c  |   4 +-
 lib/librte_eal/common/eal_common_pci.c  | 111 +++++++++-----------------------
 lib/librte_eal/common/include/rte_pci.h |  22 ++++---
 3 files changed, 45 insertions(+), 92 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 4f3b493..1c6834e 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -114,7 +114,7 @@ int rte_eal_dev_attach(const char *name, const char *devargs)
 	}
 
 	if (eal_parse_pci_DomBDF(name, &addr) == 0) {
-		if (rte_eal_pci_probe_one(&addr) < 0)
+		if (rte_eal_pci_attach_driver(&addr) < 0)
 			goto err;
 
 	} else {
@@ -139,7 +139,7 @@ int rte_eal_dev_detach(const char *name)
 	}
 
 	if (eal_parse_pci_DomBDF(name, &addr) == 0) {
-		if (rte_eal_pci_detach(&addr) < 0)
+		if (rte_eal_pci_detach_driver(&addr) < 0)
 			goto err;
 	} else {
 		if (rte_eal_vdev_uninit(name))
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index 62b996d..f2879af 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -228,59 +228,37 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d
 	return 1;
 }
 
-/*
- * If vendor/device ID match, call the remove() function of the
- * driver.
- */
 static int
-rte_eal_pci_detach_dev(struct rte_pci_driver *dr,
-		struct rte_pci_device *dev)
+rte_eal_pci_remove_driver(struct rte_pci_device *dev)
 {
-	const struct rte_pci_id *id_table;
-
-	if ((dr == NULL) || (dev == NULL))
-		return -EINVAL;
-
-	for (id_table = dr->id_table; id_table->vendor_id != 0; id_table++) {
-
-		/* check if device's identifiers match the driver's ones */
-		if (id_table->vendor_id != dev->id.vendor_id &&
-				id_table->vendor_id != PCI_ANY_ID)
-			continue;
-		if (id_table->device_id != dev->id.device_id &&
-				id_table->device_id != PCI_ANY_ID)
-			continue;
-		if (id_table->subsystem_vendor_id != dev->id.subsystem_vendor_id &&
-				id_table->subsystem_vendor_id != PCI_ANY_ID)
-			continue;
-		if (id_table->subsystem_device_id != dev->id.subsystem_device_id &&
-				id_table->subsystem_device_id != PCI_ANY_ID)
-			continue;
+	struct rte_pci_driver *driver;
+	struct rte_pci_addr *loc;
 
-		struct rte_pci_addr *loc = &dev->addr;
+	loc = &dev->addr;
+	driver = dev->driver;
 
-		RTE_LOG(DEBUG, EAL, "PCI device "PCI_PRI_FMT" on NUMA socket %i\n",
-				loc->domain, loc->bus, loc->devid,
-				loc->function, dev->device.numa_node);
+	if (driver == NULL) {
+		return 0;
+	}
 
-		RTE_LOG(DEBUG, EAL, "  remove driver: %x:%x %s\n", dev->id.vendor_id,
-				dev->id.device_id, dr->driver.name);
+	RTE_LOG(DEBUG, EAL, "PCI device "PCI_PRI_FMT" on NUMA socket %i\n",
+			loc->domain, loc->bus, loc->devid,
+			loc->function, dev->device.numa_node);
 
-		if (dr->remove && (dr->remove(dev) < 0))
-			return -1;	/* negative value is an error */
+	RTE_LOG(DEBUG, EAL, "  remove driver: %x:%x %s\n", dev->id.vendor_id,
+			dev->id.device_id, driver->driver.name);
 
-		/* clear driver structure */
-		dev->driver = NULL;
+	if (driver->remove && (driver->remove(dev) < 0))
+		return -1;	/* negative value is an error */
 
-		if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
-			/* unmap resources for devices that use igb_uio */
-			rte_eal_pci_unmap_device(dev);
+	/* clear driver structure */
+	dev->driver = NULL;
 
-		return 0;
-	}
+	if (driver->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
+		/* unmap resources for devices that use igb_uio */
+		rte_eal_pci_unmap_device(dev);
 
-	/* return positive value if driver doesn't support this device */
-	return 1;
+	return 0;
 }
 
 /*
@@ -315,38 +293,11 @@ pci_probe_all_drivers(struct rte_pci_device *dev)
 }
 
 /*
- * If vendor/device ID match, call the remove() function of all
- * registered driver for the given device. Return -1 if initialization
- * failed, return 1 if no driver is found for this device.
- */
-static int
-pci_detach_all_drivers(struct rte_pci_device *dev)
-{
-	struct rte_pci_driver *dr = NULL;
-	int rc = 0;
-
-	if (dev == NULL)
-		return -1;
-
-	TAILQ_FOREACH(dr, &pci_driver_list, next) {
-		rc = rte_eal_pci_detach_dev(dr, dev);
-		if (rc < 0)
-			/* negative value is an error */
-			return -1;
-		if (rc > 0)
-			/* positive value means driver doesn't support it */
-			continue;
-		return 0;
-	}
-	return 1;
-}
-
-/*
  * Find the pci device specified by pci address, then invoke probe function of
  * the driver of the devive.
  */
 int
-rte_eal_pci_probe_one(const struct rte_pci_addr *addr)
+rte_eal_pci_attach_driver(const struct rte_pci_addr *addr)
 {
 	struct rte_pci_device *dev = NULL;
 	int ret = 0;
@@ -382,10 +333,9 @@ rte_eal_pci_probe_one(const struct rte_pci_addr *addr)
  * Detach device specified by its pci address.
  */
 int
-rte_eal_pci_detach(const struct rte_pci_addr *addr)
+rte_eal_pci_detach_driver(const struct rte_pci_addr *addr)
 {
 	struct rte_pci_device *dev = NULL;
-	int ret = 0;
 
 	if (addr == NULL)
 		return -1;
@@ -394,17 +344,18 @@ rte_eal_pci_detach(const struct rte_pci_addr *addr)
 		if (rte_eal_compare_pci_addr(&dev->addr, addr))
 			continue;
 
-		ret = pci_detach_all_drivers(dev);
-		if (ret < 0)
-			goto err_return;
+		if (dev->driver == NULL) {
+			/* The device at that address does not have a driver loaded */
+			return 0;
+		}
+
+		if (rte_eal_pci_remove_driver(dev) < 0) {
+			return -1;
+		}
 
-		TAILQ_REMOVE(&pci_device_list, dev, next);
-		free(dev);
 		return 0;
 	}
-	return -1;
 
-err_return:
 	RTE_LOG(WARNING, EAL, "Requested device " PCI_PRI_FMT
 			" cannot be used\n", dev->addr.domain, dev->addr.bus,
 			dev->addr.devid, dev->addr.function);
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 2154a54..e304853 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -459,11 +459,14 @@ void *pci_map_resource(void *requested_addr, int fd, off_t offset,
 void pci_unmap_resource(void *requested_addr, size_t size);
 
 /**
- * Probe the single PCI device.
+ * Attempt to load the registered driver for the PCI device at addr.
  *
- * Scan the content of the PCI bus, and find the pci device specified by pci
- * address, then call the probe() function for registered driver that has a
- * matching entry in its id_table for discovered device.
+ * Find the pci device specified by addr, then call the probe() function
+ * for each registered driver that has a matching entry in its id_table until
+ * the correct driver is found.
+ *
+ * If the PCI address is known, this is considerably more efficient than
+ * calling rte_eal_pci_probe.
  *
  * @param addr
  *	The PCI Bus-Device-Function address to probe.
@@ -471,14 +474,13 @@ void pci_unmap_resource(void *requested_addr, size_t size);
  *   - 0 on success.
  *   - Negative on error.
  */
-int rte_eal_pci_probe_one(const struct rte_pci_addr *addr);
+int rte_eal_pci_attach_driver(const struct rte_pci_addr *addr);
 
 /**
- * Close the single PCI device.
+ * Unload the driver for the PCI device at addr.
  *
- * Scan the content of the PCI bus, and find the pci device specified by pci
- * address, then call the remove() function for registered driver that has a
- * matching entry in its id_table for discovered device.
+ * Find the pci device specified by addr, then call the remove() function
+ * for the currently loaded driver.
  *
  * @param addr
  *	The PCI Bus-Device-Function address to close.
@@ -486,7 +488,7 @@ int rte_eal_pci_probe_one(const struct rte_pci_addr *addr);
  *   - 0 on success.
  *   - Negative on error.
  */
-int rte_eal_pci_detach(const struct rte_pci_addr *addr);
+int rte_eal_pci_detach_driver(const struct rte_pci_addr *addr);
 
 /**
  * Dump the content of the PCI bus.
-- 
2.7.4

^ permalink raw reply related

* [PATCH 1/4] ethdev: Call rx/tx_queue_release before rx/tx_queue_setup
From: Jan Blunck @ 2016-11-23 19:38 UTC (permalink / raw)
  To: dev; +Cc: ferruh.yigit, i.maximets, bruce.richardson, declan.doherty
In-Reply-To: <CALe+Z02_342X4H9aFsvpaOJVw9Yb8F_qjmRH8XKUseP=QfjdWw@mail.gmail.com>

If a queue has been setup before lets release it before we setup.
Otherwise we might leak resources.

Signed-off-by: Jan Blunck <jblunck@infradead.org>
---
 lib/librte_ether/rte_ethdev.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index fde8112..8c4b6cd 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -1010,6 +1010,7 @@ rte_eth_rx_queue_setup(uint8_t port_id, uint16_t rx_queue_id,
 	uint32_t mbp_buf_size;
 	struct rte_eth_dev *dev;
 	struct rte_eth_dev_info dev_info;
+	void **rxq;
 
 	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
 
@@ -1068,6 +1069,14 @@ rte_eth_rx_queue_setup(uint8_t port_id, uint16_t rx_queue_id,
 		return -EINVAL;
 	}
 
+	rxq = dev->data->rx_queues;
+	if (rxq[rx_queue_id]) {
+		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->rx_queue_release,
+					-ENOTSUP);
+		(*dev->dev_ops->rx_queue_release)(rxq[rx_queue_id]);
+		rxq[rx_queue_id] = NULL;
+	}
+
 	if (rx_conf == NULL)
 		rx_conf = &dev_info.default_rxconf;
 
@@ -1089,6 +1098,7 @@ rte_eth_tx_queue_setup(uint8_t port_id, uint16_t tx_queue_id,
 {
 	struct rte_eth_dev *dev;
 	struct rte_eth_dev_info dev_info;
+	void **txq;
 
 	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
 
@@ -1121,6 +1131,14 @@ rte_eth_tx_queue_setup(uint8_t port_id, uint16_t tx_queue_id,
 		return -EINVAL;
 	}
 
+	txq = dev->data->tx_queues;
+	if (txq[tx_queue_id]) {
+		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->tx_queue_release,
+					-ENOTSUP);
+		(*dev->dev_ops->tx_queue_release)(txq[tx_queue_id]);
+		txq[tx_queue_id] = NULL;
+	}
+
 	if (tx_conf == NULL)
 		tx_conf = &dev_info.default_txconf;
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH 2/4] ethdev: Free rx/tx_queues after releasing all queues
From: Jan Blunck @ 2016-11-23 19:38 UTC (permalink / raw)
  To: dev; +Cc: ferruh.yigit, i.maximets, bruce.richardson, declan.doherty
In-Reply-To: <1479929912-32079-1-git-send-email-jblunck@infradead.org>

If all queues are released lets also free up the dev->data->rx/tx_queues
to be able to properly reinitialize.

Signed-off-by: Jan Blunck <jblunck@infradead.org>
---
 lib/librte_ether/rte_ethdev.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 8c4b6cd..a3986ad 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -531,6 +531,9 @@ rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 
 		for (i = nb_queues; i < old_nb_queues; i++)
 			(*dev->dev_ops->rx_queue_release)(rxq[i]);
+
+		rte_free(dev->data->rx_queues);
+		dev->data->rx_queues = NULL;
 	}
 	dev->data->nb_rx_queues = nb_queues;
 	return 0;
@@ -682,6 +685,9 @@ rte_eth_dev_tx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 
 		for (i = nb_queues; i < old_nb_queues; i++)
 			(*dev->dev_ops->tx_queue_release)(txq[i]);
+
+		rte_free(dev->data->tx_queues);
+		dev->data->tx_queues = NULL;
 	}
 	dev->data->nb_tx_queues = nb_queues;
 	return 0;
-- 
2.7.4

^ permalink raw reply related

* [PATCH 3/4] ethdev: Add DPDK internal _rte_eth_dev_reset()
From: Jan Blunck @ 2016-11-23 19:38 UTC (permalink / raw)
  To: dev; +Cc: ferruh.yigit, i.maximets, bruce.richardson, declan.doherty
In-Reply-To: <1479929912-32079-1-git-send-email-jblunck@infradead.org>

This is a helper for DPDK internal users to force a reconfiguration of a
device.

Signed-off-by: Jan Blunck <jblunck@infradead.org>
---
 lib/librte_ether/rte_ethdev.c          | 15 +++++++++++++++
 lib/librte_ether/rte_ethdev.h          | 13 +++++++++++++
 lib/librte_ether/rte_ether_version.map |  6 ++++++
 3 files changed, 34 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index a3986ad..bd5787b 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -858,6 +858,21 @@ rte_eth_dev_configure(uint8_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
 	return 0;
 }
 
+void
+_rte_eth_dev_reset(struct rte_eth_dev *dev)
+{
+	if (dev->data->dev_started) {
+		RTE_PMD_DEBUG_TRACE(
+			"port %d must be stopped to allow reset\n", port_id);
+		return;
+	}
+
+	rte_eth_dev_rx_queue_config(dev, 0);
+	rte_eth_dev_tx_queue_config(dev, 0);
+
+	memset(&dev->data->dev_conf, 0, sizeof(dev->data->dev_conf));
+}
+
 static void
 rte_eth_dev_config_restore(uint8_t port_id)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 9678179..e0740db 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1914,6 +1914,19 @@ int rte_eth_dev_configure(uint8_t port_id, uint16_t nb_rx_queue,
 		uint16_t nb_tx_queue, const struct rte_eth_conf *eth_conf);
 
 /**
+ * @internal Release a devices rx/tx queues and clear its configuration to
+ * force the user application to reconfigure it. It is for DPDK internal user
+ * only.
+ *
+ * @param dev
+ *  Pointer to struct rte_eth_dev.
+ *
+ * @return
+ *  void
+ */
+void _rte_eth_dev_reset(struct rte_eth_dev *dev);
+
+/**
  * Allocate and set up a receive queue for an Ethernet device.
  *
  * The function allocates a contiguous block of memory for *nb_rx_desc*
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 72be66d..0c31c5d 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -147,3 +147,9 @@ DPDK_16.11 {
 	rte_eth_dev_pci_remove;
 
 } DPDK_16.07;
+
+DPDK_17.02 {
+	global:
+
+	_rte_eth_dev_reset;
+} DPDK_16.11;
-- 
2.7.4

^ permalink raw reply related

* [PATCH 4/4] bond: Force reconfiguration of removed slave interfaces
From: Jan Blunck @ 2016-11-23 19:38 UTC (permalink / raw)
  To: dev; +Cc: ferruh.yigit, i.maximets, bruce.richardson, declan.doherty
In-Reply-To: <1479929912-32079-1-git-send-email-jblunck@infradead.org>

After a slave interface is removed from a bond group it still has the
configuration of the bond interface. Lets enforce that the slave interface
is reconfigured after removal by resetting it.

Signed-off-by: Jan Blunck <jblunck@infradead.org>
---
 drivers/net/bonding/rte_eth_bond_pmd.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/bonding/rte_eth_bond_pmd.c b/drivers/net/bonding/rte_eth_bond_pmd.c
index a80b6fa..e61afc9 100644
--- a/drivers/net/bonding/rte_eth_bond_pmd.c
+++ b/drivers/net/bonding/rte_eth_bond_pmd.c
@@ -1454,6 +1454,9 @@ slave_remove(struct bond_dev_private *internals,
 				(internals->slave_count - i - 1));
 
 	internals->slave_count--;
+
+	/* force reconfiguration of slave interfaces */
+	_rte_eth_dev_reset(slave_eth_dev);
 }
 
 static void
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 1/7] pci: If a driver's probe function fails, unmap resources.
From: Ben Walker @ 2016-11-23 20:07 UTC (permalink / raw)
  To: dev; +Cc: Ben Walker
In-Reply-To: <1479929804-19614-1-git-send-email-benjamin.walker@intel.com>

If resources were mapped prior to probe, unmap them
if probe fails.

This does not handle the case where the kernel driver was
forcibly unbound prior to probe.

Signed-off-by: Ben Walker <benjamin.walker@intel.com>
---
 lib/librte_eal/common/eal_common_pci.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index 6bff675..4f8c3a0 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -215,8 +215,11 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d
 
 		/* call the driver probe() function */
 		ret = dr->probe(dr, dev);
-		if (ret)
+		if (ret) {
 			dev->driver = NULL;
+			if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
+				rte_eal_pci_unmap_device(dev);
+		}
 
 		return ret;
 	}
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 3/7] pci: Pass rte_pci_addr to functions instead of separate args
From: Ben Walker @ 2016-11-23 20:07 UTC (permalink / raw)
  To: dev; +Cc: Ben Walker
In-Reply-To: <1479931644-78960-1-git-send-email-benjamin.walker@intel.com>

Instead of passing domain, bus, devid, func, just pass
an rte_pci_addr.

Signed-off-by: Ben Walker <benjamin.walker@intel.com>
---
 lib/librte_eal/linuxapp/eal/eal_pci.c | 32 +++++++++++++-------------------
 1 file changed, 13 insertions(+), 19 deletions(-)

diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 876ba38..073af5f 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -267,8 +267,7 @@ pci_parse_sysfs_resource(const char *filename, struct rte_pci_device *dev)
 
 /* Scan one pci sysfs entry, and fill the devices list from it. */
 static int
-pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
-	     uint8_t devid, uint8_t function)
+pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
 {
 	char filename[PATH_MAX];
 	unsigned long tmp;
@@ -281,10 +280,7 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
 		return -1;
 
 	memset(dev, 0, sizeof(*dev));
-	dev->addr.domain = domain;
-	dev->addr.bus = bus;
-	dev->addr.devid = devid;
-	dev->addr.function = function;
+	dev->addr = *addr;
 
 	/* get vendor id */
 	snprintf(filename, sizeof(filename), "%s/vendor", dirname);
@@ -429,16 +425,14 @@ pci_update_device(const struct rte_pci_addr *addr)
 		 pci_get_sysfs_path(), addr->domain, addr->bus, addr->devid,
 		 addr->function);
 
-	return pci_scan_one(filename, addr->domain, addr->bus, addr->devid,
-				addr->function);
+	return pci_scan_one(filename, addr);
 }
 
 /*
  * split up a pci address into its constituent parts.
  */
 static int
-parse_pci_addr_format(const char *buf, int bufsize, uint16_t *domain,
-		uint8_t *bus, uint8_t *devid, uint8_t *function)
+parse_pci_addr_format(const char *buf, int bufsize, struct rte_pci_addr *addr)
 {
 	/* first split on ':' */
 	union splitaddr {
@@ -466,10 +460,10 @@ parse_pci_addr_format(const char *buf, int bufsize, uint16_t *domain,
 
 	/* now convert to int values */
 	errno = 0;
-	*domain = (uint16_t)strtoul(splitaddr.domain, NULL, 16);
-	*bus = (uint8_t)strtoul(splitaddr.bus, NULL, 16);
-	*devid = (uint8_t)strtoul(splitaddr.devid, NULL, 16);
-	*function = (uint8_t)strtoul(splitaddr.function, NULL, 10);
+	addr->domain = (uint16_t)strtoul(splitaddr.domain, NULL, 16);
+	addr->bus = (uint8_t)strtoul(splitaddr.bus, NULL, 16);
+	addr->devid = (uint8_t)strtoul(splitaddr.devid, NULL, 16);
+	addr->function = (uint8_t)strtoul(splitaddr.function, NULL, 10);
 	if (errno != 0)
 		goto error;
 
@@ -490,8 +484,7 @@ rte_eal_pci_scan(void)
 	struct dirent *e;
 	DIR *dir;
 	char dirname[PATH_MAX];
-	uint16_t domain;
-	uint8_t bus, devid, function;
+	struct rte_pci_addr addr;
 
 	dir = opendir(pci_get_sysfs_path());
 	if (dir == NULL) {
@@ -500,20 +493,21 @@ rte_eal_pci_scan(void)
 		return -1;
 	}
 
+
 	while ((e = readdir(dir)) != NULL) {
 		if (e->d_name[0] == '.')
 			continue;
 
-		if (parse_pci_addr_format(e->d_name, sizeof(e->d_name), &domain,
-				&bus, &devid, &function) != 0)
+		if (parse_pci_addr_format(e->d_name, sizeof(e->d_name), &addr) != 0)
 			continue;
 
 		snprintf(dirname, sizeof(dirname), "%s/%s",
 				pci_get_sysfs_path(), e->d_name);
-		if (pci_scan_one(dirname, domain, bus, devid, function) < 0)
+		if (pci_scan_one(dirname, &addr) < 0)
 			goto error;
 	}
 	closedir(dir);
+
 	return 0;
 
 error:
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 2/7] pci: Separate detaching ethernet ports from PCI devices
From: Ben Walker @ 2016-11-23 20:07 UTC (permalink / raw)
  To: dev; +Cc: Ben Walker
In-Reply-To: <1479931644-78960-1-git-send-email-benjamin.walker@intel.com>

Attaching and detaching ethernet ports from an application
is not the same thing as physically removing a PCI device,
so clarify the flags indicating support. All PCI devices
are assumed to be physically removable, so no flag is
necessary in the PCI layer.

Signed-off-by: Ben Walker <benjamin.walker@intel.com>
---
 doc/guides/prog_guide/port_hotplug_framework.rst | 2 +-
 drivers/net/bnxt/bnxt_ethdev.c                   | 3 ++-
 drivers/net/e1000/em_ethdev.c                    | 4 ++--
 drivers/net/e1000/igb_ethdev.c                   | 7 ++++---
 drivers/net/fm10k/fm10k_ethdev.c                 | 4 ++--
 drivers/net/i40e/i40e_ethdev.c                   | 4 ++--
 drivers/net/i40e/i40e_ethdev_vf.c                | 3 ++-
 drivers/net/ixgbe/ixgbe_ethdev.c                 | 7 ++++---
 drivers/net/nfp/nfp_net.c                        | 4 ++--
 drivers/net/virtio/virtio_ethdev.c               | 3 ++-
 drivers/net/vmxnet3/vmxnet3_ethdev.c             | 3 ++-
 drivers/net/xenvirt/rte_eth_xenvirt.c            | 2 +-
 lib/librte_eal/common/include/rte_pci.h          | 2 --
 lib/librte_ether/rte_ethdev.c                    | 2 --
 14 files changed, 26 insertions(+), 24 deletions(-)

diff --git a/doc/guides/prog_guide/port_hotplug_framework.rst b/doc/guides/prog_guide/port_hotplug_framework.rst
index 6e4436e..d68d08e 100644
--- a/doc/guides/prog_guide/port_hotplug_framework.rst
+++ b/doc/guides/prog_guide/port_hotplug_framework.rst
@@ -106,5 +106,5 @@ Limitations
 
 *       Not all PMDs support detaching feature.
         To know whether a PMD can support detaching, search for the
-        "RTE_PCI_DRV_DETACHABLE" flag in PMD implementation. If the flag is
+        "RTE_ETH_DEV_DETAHABLE" flag in rte_eth_dev::data::dev_flags. If the flag is
         defined in the PMD, detaching is supported.
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 035fe07..a2100f6 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -1051,6 +1051,7 @@ bnxt_dev_init(struct rte_eth_dev *eth_dev)
 		RTE_LOG(INFO, PMD, "%s", bnxt_version);
 
 	rte_eth_copy_pci_info(eth_dev, eth_dev->pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 	bp = eth_dev->data->dev_private;
 
 	if (bnxt_vf_pciid(eth_dev->pci_dev->id.device_id))
@@ -1162,7 +1163,7 @@ static struct eth_driver bnxt_rte_pmd = {
 	.pci_drv = {
 		    .id_table = bnxt_pci_id_map,
 		    .drv_flags = RTE_PCI_DRV_NEED_MAPPING |
-			    RTE_PCI_DRV_DETACHABLE | RTE_PCI_DRV_INTR_LSC,
+			    RTE_PCI_DRV_INTR_LSC,
 		    .probe = rte_eth_dev_pci_probe,
 		    .remove = rte_eth_dev_pci_remove
 		    },
diff --git a/drivers/net/e1000/em_ethdev.c b/drivers/net/e1000/em_ethdev.c
index aee3d34..9af429b 100644
--- a/drivers/net/e1000/em_ethdev.c
+++ b/drivers/net/e1000/em_ethdev.c
@@ -312,6 +312,7 @@ eth_em_dev_init(struct rte_eth_dev *eth_dev)
 	}
 
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	hw->hw_addr = (void *)pci_dev->mem_resource[0].addr;
 	hw->device_id = pci_dev->id.device_id;
@@ -392,8 +393,7 @@ eth_em_dev_uninit(struct rte_eth_dev *eth_dev)
 static struct eth_driver rte_em_pmd = {
 	.pci_drv = {
 		.id_table = pci_id_em_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-			RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 2fddf0c..b014b8b 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -771,6 +771,7 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev)
 	}
 
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	hw->hw_addr= (void *)pci_dev->mem_resource[0].addr;
 
@@ -976,6 +977,7 @@ eth_igbvf_dev_init(struct rte_eth_dev *eth_dev)
 	pci_dev = eth_dev->pci_dev;
 
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	hw->device_id = pci_dev->id.device_id;
 	hw->vendor_id = pci_dev->id.vendor_id;
@@ -1079,8 +1081,7 @@ eth_igbvf_dev_uninit(struct rte_eth_dev *eth_dev)
 static struct eth_driver rte_igb_pmd = {
 	.pci_drv = {
 		.id_table = pci_id_igb_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-			RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
@@ -1095,7 +1096,7 @@ static struct eth_driver rte_igb_pmd = {
 static struct eth_driver rte_igbvf_pmd = {
 	.pci_drv = {
 		.id_table = pci_id_igbvf_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
diff --git a/drivers/net/fm10k/fm10k_ethdev.c b/drivers/net/fm10k/fm10k_ethdev.c
index 923690c..578de1f 100644
--- a/drivers/net/fm10k/fm10k_ethdev.c
+++ b/drivers/net/fm10k/fm10k_ethdev.c
@@ -2841,6 +2841,7 @@ eth_fm10k_dev_init(struct rte_eth_dev *dev)
 		return 0;
 
 	rte_eth_copy_pci_info(dev, dev->pci_dev);
+	dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	macvlan = FM10K_DEV_PRIVATE_TO_MACVLAN(dev->data->dev_private);
 	memset(macvlan, 0, sizeof(*macvlan));
@@ -3062,8 +3063,7 @@ static const struct rte_pci_id pci_id_fm10k_map[] = {
 static struct eth_driver rte_pmd_fm10k = {
 	.pci_drv = {
 		.id_table = pci_id_fm10k_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-			RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 67778ba..7877cc5 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -671,8 +671,7 @@ static const struct rte_i40e_xstats_name_off rte_i40e_txq_prio_strings[] = {
 static struct eth_driver rte_i40e_pmd = {
 	.pci_drv = {
 		.id_table = pci_id_i40e_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-			RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
@@ -955,6 +954,7 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
 	pci_dev = dev->pci_dev;
 
 	rte_eth_copy_pci_info(dev, pci_dev);
+	dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	pf->adapter = I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
 	pf->adapter->eth_dev = dev;
diff --git a/drivers/net/i40e/i40e_ethdev_vf.c b/drivers/net/i40e/i40e_ethdev_vf.c
index aa306d6..6aaee37 100644
--- a/drivers/net/i40e/i40e_ethdev_vf.c
+++ b/drivers/net/i40e/i40e_ethdev_vf.c
@@ -1459,6 +1459,7 @@ i40evf_dev_init(struct rte_eth_dev *eth_dev)
 	}
 
 	rte_eth_copy_pci_info(eth_dev, eth_dev->pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	hw->vendor_id = eth_dev->pci_dev->id.vendor_id;
 	hw->device_id = eth_dev->pci_dev->id.device_id;
@@ -1528,7 +1529,7 @@ i40evf_dev_uninit(struct rte_eth_dev *eth_dev)
 static struct eth_driver rte_i40evf_pmd = {
 	.pci_drv = {
 		.id_table = pci_id_i40evf_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index edc9b22..66dd0c9 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -1130,6 +1130,7 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev)
 	pci_dev = eth_dev->pci_dev;
 
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	/* Vendor and Device ID need to be set before init of shared code */
 	hw->device_id = pci_dev->id.device_id;
@@ -1422,6 +1423,7 @@ eth_ixgbevf_dev_init(struct rte_eth_dev *eth_dev)
 	pci_dev = eth_dev->pci_dev;
 
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	hw->device_id = pci_dev->id.device_id;
 	hw->vendor_id = pci_dev->id.vendor_id;
@@ -1565,8 +1567,7 @@ eth_ixgbevf_dev_uninit(struct rte_eth_dev *eth_dev)
 static struct eth_driver rte_ixgbe_pmd = {
 	.pci_drv = {
 		.id_table = pci_id_ixgbe_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-			RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
@@ -1581,7 +1582,7 @@ static struct eth_driver rte_ixgbe_pmd = {
 static struct eth_driver rte_ixgbevf_pmd = {
 	.pci_drv = {
 		.id_table = pci_id_ixgbevf_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
diff --git a/drivers/net/nfp/nfp_net.c b/drivers/net/nfp/nfp_net.c
index c6b1587..00d2ba2 100644
--- a/drivers/net/nfp/nfp_net.c
+++ b/drivers/net/nfp/nfp_net.c
@@ -2332,6 +2332,7 @@ nfp_net_init(struct rte_eth_dev *eth_dev)
 
 	pci_dev = eth_dev->pci_dev;
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	hw->device_id = pci_dev->id.device_id;
 	hw->vendor_id = pci_dev->id.vendor_id;
@@ -2470,8 +2471,7 @@ static struct rte_pci_id pci_id_nfp_net_map[] = {
 static struct eth_driver rte_nfp_net_pmd = {
 	.pci_drv = {
 		.id_table = pci_id_nfp_net_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-			     RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 079fd6c..74255c5 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -1211,6 +1211,7 @@ virtio_init_device(struct rte_eth_dev *eth_dev, uint64_t req_features)
 		eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
 
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	rx_func_get(eth_dev);
 
@@ -1379,7 +1380,7 @@ static struct eth_driver rte_virtio_pmd = {
 			.name = "net_virtio",
 		},
 		.id_table = pci_id_virtio_map,
-		.drv_flags = RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = 0,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
diff --git a/drivers/net/vmxnet3/vmxnet3_ethdev.c b/drivers/net/vmxnet3/vmxnet3_ethdev.c
index 8bb13e5..dd8dca5 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethdev.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethdev.c
@@ -247,6 +247,7 @@ eth_vmxnet3_dev_init(struct rte_eth_dev *eth_dev)
 		return 0;
 
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 
 	/* Vendor and Device ID need to be set before init of shared code */
 	hw->device_id = pci_dev->id.device_id;
@@ -336,7 +337,7 @@ eth_vmxnet3_dev_uninit(struct rte_eth_dev *eth_dev)
 static struct eth_driver rte_vmxnet3_pmd = {
 	.pci_drv = {
 		.id_table = pci_id_vmxnet3_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
 		.probe = rte_eth_dev_pci_probe,
 		.remove = rte_eth_dev_pci_remove,
 	},
diff --git a/drivers/net/xenvirt/rte_eth_xenvirt.c b/drivers/net/xenvirt/rte_eth_xenvirt.c
index c08a056..ec5d00b 100644
--- a/drivers/net/xenvirt/rte_eth_xenvirt.c
+++ b/drivers/net/xenvirt/rte_eth_xenvirt.c
@@ -673,7 +673,7 @@ eth_dev_xenvirt_create(const char *name, const char *params,
 	eth_dev->data = data;
 	eth_dev->dev_ops = &ops;
 
-	eth_dev->data->dev_flags = RTE_PCI_DRV_DETACHABLE;
+	eth_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 	eth_dev->data->kdrv = RTE_KDRV_NONE;
 	eth_dev->data->drv_name = drivername;
 	eth_dev->driver = NULL;
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 9ce8847..74be1f5 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -212,8 +212,6 @@ struct rte_pci_driver {
 #define RTE_PCI_DRV_FORCE_UNBIND 0x0004
 /** Device driver supports link state interrupt */
 #define RTE_PCI_DRV_INTR_LSC	0x0008
-/** Device driver supports detaching capability */
-#define RTE_PCI_DRV_DETACHABLE	0x0010
 
 /**
  * A structure describing a PCI mapping.
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index fde8112..3771ffc 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -3209,8 +3209,6 @@ rte_eth_copy_pci_info(struct rte_eth_dev *eth_dev, struct rte_pci_device *pci_de
 	eth_dev->data->dev_flags = 0;
 	if (pci_dev->driver->drv_flags & RTE_PCI_DRV_INTR_LSC)
 		eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
-	if (pci_dev->driver->drv_flags & RTE_PCI_DRV_DETACHABLE)
-		eth_dev->data->dev_flags |= RTE_ETH_DEV_DETACHABLE;
 
 	eth_dev->data->kdrv = pci_dev->kdrv;
 	eth_dev->data->numa_node = pci_dev->device.numa_node;
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 4/7] pci: rte_eal_pci_scan now handles removal of PCI devices
From: Ben Walker @ 2016-11-23 20:07 UTC (permalink / raw)
  To: dev; +Cc: Ben Walker
In-Reply-To: <1479931644-78960-1-git-send-email-benjamin.walker@intel.com>

rte_eal_pci_scan can be called repeatedly to re-scan the PCI
bus. If a device was removed from the system, the associated
driver will automatically be unloaded.

Signed-off-by: Ben Walker <benjamin.walker@intel.com>
---
 lib/librte_eal/linuxapp/eal/eal_pci.c | 62 +++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 073af5f..936f076 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -485,7 +485,69 @@ rte_eal_pci_scan(void)
 	DIR *dir;
 	char dirname[PATH_MAX];
 	struct rte_pci_addr addr;
+	struct rte_pci_device *dev, *tmp;
+
+	/* Search the device list for devices that are no longer present on the system
+	 * and remove them.
+	 */
+	TAILQ_FOREACH_SAFE(dev, &pci_device_list, next, tmp) {
+		int found = 0;
+
+		dir = opendir(pci_get_sysfs_path());
+		if (dir == NULL) {
+			RTE_LOG(ERR, EAL, "%s(): opendir failed: %s\n",
+				__func__, strerror(errno));
+			return -1;
+		}
+
+		while ((e = readdir(dir)) != NULL) {
+			if (e->d_name[0] == '.')
+				continue;
+
+			if (parse_pci_addr_format(e->d_name, sizeof(e->d_name),
+						  &addr) != 0)
+				continue;
+
+			if (rte_eal_compare_pci_addr(&addr, &dev->addr) == 0) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (!found) {
+
+			RTE_LOG(DEBUG, EAL, "PCI device "PCI_PRI_FMT" was removed.\n",
+					addr.domain, addr.bus, addr.devid,
+					addr.function);
+
+			if (dev->driver) {
+				/* A driver was loaded against this device.
+				 * Unload it. */
+				RTE_LOG(DEBUG, EAL, "  Unload driver: %x:%x %s\n",
+						dev->id.vendor_id, dev->id.device_id,
+						dev->driver->driver.name);
+
+				if (dev->driver->remove) {
+					/* It doesn't matter what remove returns -
+					 * we're removing the device either way. */
+					dev->driver->remove(dev);
+				}
+
+				/* clear driver structure */
+				dev->driver = NULL;
+
+				if (dev->driver->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
+					rte_eal_pci_unmap_device(dev);
+			}
+
+			TAILQ_REMOVE(&pci_device_list, dev, next);
+			free(dev);
+		}
+
+		closedir(dir);
+	}
 
+	/* Search sysfs for all PCI devices and add them to the device list */
 	dir = opendir(pci_get_sysfs_path());
 	if (dir == NULL) {
 		RTE_LOG(ERR, EAL, "%s(): opendir failed: %s\n",
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 5/7] pci: Move driver registration above pci scan
From: Ben Walker @ 2016-11-23 20:07 UTC (permalink / raw)
  To: dev; +Cc: Ben Walker
In-Reply-To: <1479931644-78960-1-git-send-email-benjamin.walker@intel.com>

The user needs to register drivers before scanning, so
it makes the most sense to put the registration
functions above the scan function in the header file.

Signed-off-by: Ben Walker <benjamin.walker@intel.com>
---
 lib/librte_eal/common/include/rte_pci.h | 56 ++++++++++++++++-----------------
 1 file changed, 28 insertions(+), 28 deletions(-)

diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 74be1f5..5d0feac 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -358,6 +358,34 @@ rte_eal_compare_pci_addr(const struct rte_pci_addr *addr,
 }
 
 /**
+ * Register a PCI driver.
+ *
+ * @param driver
+ *   A pointer to a rte_pci_driver structure describing the driver
+ *   to be registered.
+ */
+void rte_eal_pci_register(struct rte_pci_driver *driver);
+
+/** Statically register a PCI driver at start up */
+#define RTE_PMD_REGISTER_PCI(nm, pci_drv) \
+RTE_INIT(pciinitfn_ ##nm); \
+static void pciinitfn_ ##nm(void) \
+{\
+	(pci_drv).driver.name = RTE_STR(nm);\
+	rte_eal_pci_register(&pci_drv); \
+} \
+RTE_PMD_EXPORT_NAME(nm, __COUNTER__)
+
+/**
+ * Unregister a PCI driver.
+ *
+ * @param driver
+ *   A pointer to a rte_pci_driver structure describing the driver
+ *   to be unregistered.
+ */
+void rte_eal_pci_unregister(struct rte_pci_driver *driver);
+
+/**
  * Scan the content of the PCI bus, and the devices in the devices
  * list
  *
@@ -476,34 +504,6 @@ int rte_eal_pci_detach(const struct rte_pci_addr *addr);
 void rte_eal_pci_dump(FILE *f);
 
 /**
- * Register a PCI driver.
- *
- * @param driver
- *   A pointer to a rte_pci_driver structure describing the driver
- *   to be registered.
- */
-void rte_eal_pci_register(struct rte_pci_driver *driver);
-
-/** Helper for PCI device registration from driver (eth, crypto) instance */
-#define RTE_PMD_REGISTER_PCI(nm, pci_drv) \
-RTE_INIT(pciinitfn_ ##nm); \
-static void pciinitfn_ ##nm(void) \
-{\
-	(pci_drv).driver.name = RTE_STR(nm);\
-	rte_eal_pci_register(&pci_drv); \
-} \
-RTE_PMD_EXPORT_NAME(nm, __COUNTER__)
-
-/**
- * Unregister a PCI driver.
- *
- * @param driver
- *   A pointer to a rte_pci_driver structure describing the driver
- *   to be unregistered.
- */
-void rte_eal_pci_unregister(struct rte_pci_driver *driver);
-
-/**
  * Read PCI config space.
  *
  * @param device
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 6/7] pci: Combine rte_eal_pci_scan and rte_eal_pci_probe
From: Ben Walker @ 2016-11-23 20:07 UTC (permalink / raw)
  To: dev; +Cc: Ben Walker
In-Reply-To: <1479931644-78960-1-git-send-email-benjamin.walker@intel.com>

Two functions is both confusing and unnecessary. Previously,
rte_eal_pci_scan populated an internal list of devices by
scanning sysfs. Then, rte_eal_pci_probe would match registered
drivers to that internal list. These are not really useful
operations to perform separately, though, so
simplify the api down to just rte_eal_pci_probe which can
be called repeatedly through the lifetime of the application
to scan for new or removed PCI devices and load or unload
drivers as required.

Signed-off-by: Ben Walker <benjamin.walker@intel.com>
---
 app/test/test_pci.c                             |  2 +-
 lib/librte_eal/bsdapp/eal/eal.c                 |  3 ---
 lib/librte_eal/bsdapp/eal/eal_pci.c             | 17 +----------------
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |  1 -
 lib/librte_eal/common/eal_common_pci.c          |  6 ++++++
 lib/librte_eal/common/eal_private.h             | 14 +++++---------
 lib/librte_eal/common/include/rte_pci.h         | 17 +++++------------
 lib/librte_eal/linuxapp/eal/eal.c               |  3 ---
 lib/librte_eal/linuxapp/eal/eal_pci.c           | 18 +-----------------
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |  1 -
 10 files changed, 19 insertions(+), 63 deletions(-)

diff --git a/app/test/test_pci.c b/app/test/test_pci.c
index cda186d..fdd84f7 100644
--- a/app/test/test_pci.c
+++ b/app/test/test_pci.c
@@ -180,7 +180,7 @@ test_pci_setup(void)
 		TAILQ_INSERT_TAIL(&real_pci_device_list, dev, next);
 	}
 
-	ret = rte_eal_pci_scan();
+	ret = rte_eal_pci_probe();
 	TEST_ASSERT_SUCCESS(ret, "failed to scan PCI bus");
 	rte_eal_pci_dump(stdout);
 
diff --git a/lib/librte_eal/bsdapp/eal/eal.c b/lib/librte_eal/bsdapp/eal/eal.c
index 35e3117..fd44528 100644
--- a/lib/librte_eal/bsdapp/eal/eal.c
+++ b/lib/librte_eal/bsdapp/eal/eal.c
@@ -561,9 +561,6 @@ rte_eal_init(int argc, char **argv)
 	if (rte_eal_timer_init() < 0)
 		rte_panic("Cannot init HPET or TSC timers\n");
 
-	if (rte_eal_pci_init() < 0)
-		rte_panic("Cannot init PCI\n");
-
 	eal_check_mem_on_local_socket();
 
 	if (eal_plugins_init() < 0)
diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 8b3ed88..6c3a169 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -361,7 +361,7 @@ pci_scan_one(int dev_pci_fd, struct pci_conf *conf)
  * list. Call pci_scan_one() for each pci entry found.
  */
 int
-rte_eal_pci_scan(void)
+pci_scan(void)
 {
 	int fd;
 	unsigned dev_count = 0;
@@ -667,18 +667,3 @@ rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p)
 
 	return ret;
 }
-
-/* Init the PCI EAL subsystem */
-int
-rte_eal_pci_init(void)
-{
-	/* for debug purposes, PCI can be disabled */
-	if (internal_config.no_pci)
-		return 0;
-
-	if (rte_eal_pci_scan() < 0) {
-		RTE_LOG(ERR, EAL, "%s(): Cannot scan PCI bus\n", __func__);
-		return -1;
-	}
-	return 0;
-}
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 2f81f7c..67c469c 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -44,7 +44,6 @@ DPDK_2.0 {
 	rte_eal_pci_probe;
 	rte_eal_pci_probe_one;
 	rte_eal_pci_register;
-	rte_eal_pci_scan;
 	rte_eal_pci_unregister;
 	rte_eal_process_type;
 	rte_eal_remote_launch;
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index 4f8c3a0..d50a534 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -81,6 +81,7 @@
 #include <rte_devargs.h>
 
 #include "eal_private.h"
+#include "eal_internal_cfg.h"
 
 struct pci_driver_list pci_driver_list =
 	TAILQ_HEAD_INITIALIZER(pci_driver_list);
@@ -423,6 +424,11 @@ rte_eal_pci_probe(void)
 	int probe_all = 0;
 	int ret = 0;
 
+	if (internal_config.no_pci)
+		return 0;
+
+	pci_scan();
+
 	if (rte_eal_devargs_type_count(RTE_DEVTYPE_WHITELISTED_PCI) == 0)
 		probe_all = 1;
 
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index 9e7d8f6..54f18ea 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -108,18 +108,14 @@ int rte_eal_timer_init(void);
  */
 int rte_eal_log_init(const char *id, int facility);
 
-/**
- * Init the PCI infrastructure
+struct rte_pci_driver;
+struct rte_pci_device;
+
+/* Scan the PCI bus for devices
  *
  * This function is private to EAL.
- *
- * @return
- *   0 on success, negative on error
  */
-int rte_eal_pci_init(void);
-
-struct rte_pci_driver;
-struct rte_pci_device;
+int pci_scan(void);
 
 /**
  * Update a pci device object by asking the kernel for the latest information.
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 5d0feac..2154a54 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -386,20 +386,13 @@ RTE_PMD_EXPORT_NAME(nm, __COUNTER__)
 void rte_eal_pci_unregister(struct rte_pci_driver *driver);
 
 /**
- * Scan the content of the PCI bus, and the devices in the devices
- * list
- *
- * @return
- *  0 on success, negative on error
- */
-int rte_eal_pci_scan(void);
-
-/**
- * Probe the PCI bus for registered drivers.
+ * Scan the PCI bus for devices and match them to their driver.
  *
  * Scan the content of the PCI bus, and call the probe() function for
- * all registered drivers that have a matching entry in its id_table
- * for discovered devices.
+ * all registered drivers that have a matching entry in their id_table.
+ * If a device already has a driver loaded, probe will not be called.
+ * If a previously discovered device is no longer present on the system,
+ * the associated driver's remove() callback will be called.
  *
  * @return
  *   - 0 on success.
diff --git a/lib/librte_eal/linuxapp/eal/eal.c b/lib/librte_eal/linuxapp/eal/eal.c
index 2075282..f47f361 100644
--- a/lib/librte_eal/linuxapp/eal/eal.c
+++ b/lib/librte_eal/linuxapp/eal/eal.c
@@ -802,9 +802,6 @@ rte_eal_init(int argc, char **argv)
 	if (rte_eal_log_init(logid, internal_config.syslog_facility) < 0)
 		rte_panic("Cannot init logs\n");
 
-	if (rte_eal_pci_init() < 0)
-		rte_panic("Cannot init PCI\n");
-
 #ifdef VFIO_PRESENT
 	if (rte_eal_vfio_setup() < 0)
 		rte_panic("Cannot init VFIO\n");
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 936f076..5146385 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -479,7 +479,7 @@ parse_pci_addr_format(const char *buf, int bufsize, struct rte_pci_addr *addr)
  * list
  */
 int
-rte_eal_pci_scan(void)
+pci_scan(void)
 {
 	struct dirent *e;
 	DIR *dir;
@@ -810,19 +810,3 @@ rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p)
 
 	return ret;
 }
-
-/* Init the PCI EAL subsystem */
-int
-rte_eal_pci_init(void)
-{
-	/* for debug purposes, PCI can be disabled */
-	if (internal_config.no_pci)
-		return 0;
-
-	if (rte_eal_pci_scan() < 0) {
-		RTE_LOG(ERR, EAL, "%s(): Cannot scan PCI bus\n", __func__);
-		return -1;
-	}
-
-	return 0;
-}
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index 83721ba..856728e 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -44,7 +44,6 @@ DPDK_2.0 {
 	rte_eal_pci_probe;
 	rte_eal_pci_probe_one;
 	rte_eal_pci_register;
-	rte_eal_pci_scan;
 	rte_eal_pci_unregister;
 	rte_eal_process_type;
 	rte_eal_remote_launch;
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 7/7] pci: Clarify interfaces for dynamic attach/detach of drivers
From: Ben Walker @ 2016-11-23 20:07 UTC (permalink / raw)
  To: dev; +Cc: Ben Walker
In-Reply-To: <1479931644-78960-1-git-send-email-benjamin.walker@intel.com>

There are now two functions - rte_eal_pci_attach_driver and
rte_eal_pci_detach_driver - that dynamically attempt to attach
and detach drivers from PCI devices. These only control
whether a registered PCI driver is loaded or not - they are
independent of whether the PCI device exists on the system.

Signed-off-by: Ben Walker <benjamin.walker@intel.com>
---
 lib/librte_eal/common/eal_common_dev.c  |   4 +-
 lib/librte_eal/common/eal_common_pci.c  | 109 +++++++++-----------------------
 lib/librte_eal/common/include/rte_pci.h |  22 ++++---
 3 files changed, 43 insertions(+), 92 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 4f3b493..1c6834e 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -114,7 +114,7 @@ int rte_eal_dev_attach(const char *name, const char *devargs)
 	}
 
 	if (eal_parse_pci_DomBDF(name, &addr) == 0) {
-		if (rte_eal_pci_probe_one(&addr) < 0)
+		if (rte_eal_pci_attach_driver(&addr) < 0)
 			goto err;
 
 	} else {
@@ -139,7 +139,7 @@ int rte_eal_dev_detach(const char *name)
 	}
 
 	if (eal_parse_pci_DomBDF(name, &addr) == 0) {
-		if (rte_eal_pci_detach(&addr) < 0)
+		if (rte_eal_pci_detach_driver(&addr) < 0)
 			goto err;
 	} else {
 		if (rte_eal_vdev_uninit(name))
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index d50a534..67c6ce6 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -228,59 +228,36 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d
 	return 1;
 }
 
-/*
- * If vendor/device ID match, call the remove() function of the
- * driver.
- */
 static int
-rte_eal_pci_detach_dev(struct rte_pci_driver *dr,
-		struct rte_pci_device *dev)
+rte_eal_pci_remove_driver(struct rte_pci_device *dev)
 {
-	const struct rte_pci_id *id_table;
+	struct rte_pci_driver *driver;
+	struct rte_pci_addr *loc;
 
-	if ((dr == NULL) || (dev == NULL))
-		return -EINVAL;
+	loc = &dev->addr;
+	driver = dev->driver;
 
-	for (id_table = dr->id_table; id_table->vendor_id != 0; id_table++) {
-
-		/* check if device's identifiers match the driver's ones */
-		if (id_table->vendor_id != dev->id.vendor_id &&
-				id_table->vendor_id != PCI_ANY_ID)
-			continue;
-		if (id_table->device_id != dev->id.device_id &&
-				id_table->device_id != PCI_ANY_ID)
-			continue;
-		if (id_table->subsystem_vendor_id != dev->id.subsystem_vendor_id &&
-				id_table->subsystem_vendor_id != PCI_ANY_ID)
-			continue;
-		if (id_table->subsystem_device_id != dev->id.subsystem_device_id &&
-				id_table->subsystem_device_id != PCI_ANY_ID)
-			continue;
-
-		struct rte_pci_addr *loc = &dev->addr;
+	if (driver == NULL)
+		return 0;
 
-		RTE_LOG(DEBUG, EAL, "PCI device "PCI_PRI_FMT" on NUMA socket %i\n",
-				loc->domain, loc->bus, loc->devid,
-				loc->function, dev->device.numa_node);
+	RTE_LOG(DEBUG, EAL, "PCI device "PCI_PRI_FMT" on NUMA socket %i\n",
+			loc->domain, loc->bus, loc->devid,
+			loc->function, dev->device.numa_node);
 
-		RTE_LOG(DEBUG, EAL, "  remove driver: %x:%x %s\n", dev->id.vendor_id,
-				dev->id.device_id, dr->driver.name);
+	RTE_LOG(DEBUG, EAL, "  remove driver: %x:%x %s\n", dev->id.vendor_id,
+			dev->id.device_id, driver->driver.name);
 
-		if (dr->remove && (dr->remove(dev) < 0))
-			return -1;	/* negative value is an error */
+	if (driver->remove && (driver->remove(dev) < 0))
+		return -1;	/* negative value is an error */
 
-		/* clear driver structure */
-		dev->driver = NULL;
+	/* clear driver structure */
+	dev->driver = NULL;
 
-		if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
-			/* unmap resources for devices that use igb_uio */
-			rte_eal_pci_unmap_device(dev);
+	if (driver->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
+		/* unmap resources for devices that use igb_uio */
+		rte_eal_pci_unmap_device(dev);
 
-		return 0;
-	}
-
-	/* return positive value if driver doesn't support this device */
-	return 1;
+	return 0;
 }
 
 /*
@@ -315,38 +292,11 @@ pci_probe_all_drivers(struct rte_pci_device *dev)
 }
 
 /*
- * If vendor/device ID match, call the remove() function of all
- * registered driver for the given device. Return -1 if initialization
- * failed, return 1 if no driver is found for this device.
- */
-static int
-pci_detach_all_drivers(struct rte_pci_device *dev)
-{
-	struct rte_pci_driver *dr = NULL;
-	int rc = 0;
-
-	if (dev == NULL)
-		return -1;
-
-	TAILQ_FOREACH(dr, &pci_driver_list, next) {
-		rc = rte_eal_pci_detach_dev(dr, dev);
-		if (rc < 0)
-			/* negative value is an error */
-			return -1;
-		if (rc > 0)
-			/* positive value means driver doesn't support it */
-			continue;
-		return 0;
-	}
-	return 1;
-}
-
-/*
  * Find the pci device specified by pci address, then invoke probe function of
  * the driver of the devive.
  */
 int
-rte_eal_pci_probe_one(const struct rte_pci_addr *addr)
+rte_eal_pci_attach_driver(const struct rte_pci_addr *addr)
 {
 	struct rte_pci_device *dev = NULL;
 	int ret = 0;
@@ -382,10 +332,9 @@ rte_eal_pci_probe_one(const struct rte_pci_addr *addr)
  * Detach device specified by its pci address.
  */
 int
-rte_eal_pci_detach(const struct rte_pci_addr *addr)
+rte_eal_pci_detach_driver(const struct rte_pci_addr *addr)
 {
 	struct rte_pci_device *dev = NULL;
-	int ret = 0;
 
 	if (addr == NULL)
 		return -1;
@@ -394,17 +343,17 @@ rte_eal_pci_detach(const struct rte_pci_addr *addr)
 		if (rte_eal_compare_pci_addr(&dev->addr, addr))
 			continue;
 
-		ret = pci_detach_all_drivers(dev);
-		if (ret < 0)
-			goto err_return;
+		if (dev->driver == NULL) {
+			/* The device at that address does not have a driver loaded */
+			return 0;
+		}
+
+		if (rte_eal_pci_remove_driver(dev) < 0)
+			return -1;
 
-		TAILQ_REMOVE(&pci_device_list, dev, next);
-		free(dev);
 		return 0;
 	}
-	return -1;
 
-err_return:
 	RTE_LOG(WARNING, EAL, "Requested device " PCI_PRI_FMT
 			" cannot be used\n", dev->addr.domain, dev->addr.bus,
 			dev->addr.devid, dev->addr.function);
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 2154a54..e304853 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -459,11 +459,14 @@ void *pci_map_resource(void *requested_addr, int fd, off_t offset,
 void pci_unmap_resource(void *requested_addr, size_t size);
 
 /**
- * Probe the single PCI device.
+ * Attempt to load the registered driver for the PCI device at addr.
  *
- * Scan the content of the PCI bus, and find the pci device specified by pci
- * address, then call the probe() function for registered driver that has a
- * matching entry in its id_table for discovered device.
+ * Find the pci device specified by addr, then call the probe() function
+ * for each registered driver that has a matching entry in its id_table until
+ * the correct driver is found.
+ *
+ * If the PCI address is known, this is considerably more efficient than
+ * calling rte_eal_pci_probe.
  *
  * @param addr
  *	The PCI Bus-Device-Function address to probe.
@@ -471,14 +474,13 @@ void pci_unmap_resource(void *requested_addr, size_t size);
  *   - 0 on success.
  *   - Negative on error.
  */
-int rte_eal_pci_probe_one(const struct rte_pci_addr *addr);
+int rte_eal_pci_attach_driver(const struct rte_pci_addr *addr);
 
 /**
- * Close the single PCI device.
+ * Unload the driver for the PCI device at addr.
  *
- * Scan the content of the PCI bus, and find the pci device specified by pci
- * address, then call the remove() function for registered driver that has a
- * matching entry in its id_table for discovered device.
+ * Find the pci device specified by addr, then call the remove() function
+ * for the currently loaded driver.
  *
  * @param addr
  *	The PCI Bus-Device-Function address to close.
@@ -486,7 +488,7 @@ int rte_eal_pci_probe_one(const struct rte_pci_addr *addr);
  *   - 0 on success.
  *   - Negative on error.
  */
-int rte_eal_pci_detach(const struct rte_pci_addr *addr);
+int rte_eal_pci_detach_driver(const struct rte_pci_addr *addr);
 
 /**
  * Dump the content of the PCI bus.
-- 
2.7.4

^ permalink raw reply related

* Re: Proposal for a new Committer model
From: Neil Horman @ 2016-11-23 20:13 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: Thomas Monjalon, dev, Mcnamara, John
In-Reply-To: <f5f38ed5-4902-80c9-e977-c3f782421ea0@intel.com>

On Wed, Nov 23, 2016 at 04:21:00PM +0000, Ferruh Yigit wrote:
> On 11/23/2016 3:33 PM, Neil Horman wrote:
> > On Wed, Nov 23, 2016 at 02:01:44PM +0000, Ferruh Yigit wrote:
> >> On 11/23/2016 1:48 PM, Neil Horman wrote:
> >>> On Tue, Nov 22, 2016 at 08:56:23PM +0000, Ferruh Yigit wrote:
> >>>> On 11/22/2016 7:52 PM, Neil Horman wrote:
> >>>>> On Mon, Nov 21, 2016 at 09:52:41AM +0100, Thomas Monjalon wrote:
> >>>>>> 2016-11-18 13:09, Neil Horman:
> >>>>>>> A) Further promote subtree maintainership.  This was a conversation that I
> >>>>>>> proposed some time ago, but my proposed granularity was discarded in favor
> >>>>>>> of something that hasn't worked as well (in my opinion).  That is to say a
> >>>>>>> few driver pmds (i40e and fm10k come to mind) have their own tree that
> >>>>>>> send pull requests to Thomas.
> >>>>>>
> >>>>>> Yes we tried this fine granularity and stated that it was not working well.
> >>>>>> We are now using the bigger granularity that you describe below.
> >>>>>>
> >>>>> Ok, thats good, but that must be _very_ new.  Looking at your git tree, I see no
> >>>>> merge commits.  How are you pulling from those subtrees?
> >>>>
> >>>> next-net tree is active for last three releases.
> >>>>
> >>> What!?  What is the purpose of holding patches in a subtree for multiple
> >>> releases?  
> >>
> >> :) Of course not holding them in the sub-tree.
> >>
> > Ok, glad that we're on the same page.
> > 
> >> Briefly, process is:
> >> - sub-tree gets patches during merge window
> >> - sub-tree first merged into main tree in -rc1 and later in -r2
> >>
> >> next-net tree is actively in use for last three releases, and driver/net
> >> patches delegated to this tree. You can see different commiters in main
> >> tree.
> >>
> >>> If a given changeset isn't ready for merge to Thomas tree the people
> >>> working on it should clone the subtree to some place they can all collaborate on
> >>> it.  Once it goes into a subtree there needs to be a defined workflow to get it
> >>> into the canonical tree that Thomas maintains on a regular, short time frame.
> >>> to do less is to confuse the process for everyone involved, and slow people
> >>> down, rather than accelerate their work.
> >>>
> >>>> I guess following is the first commit to the sub-tree:
> >>>> http://dpdk.org/ml/archives/dev/2016-February/032580.html
> >>>>
> >>>> sub-trees rebase on top of main tree regularly, that is why there is no
> >>>> merge commit.
> >>>>
> >>> I'm not asking about merge commits in the sub-tree, I'm asking about merge
> >>> commits in thomas's tree.
> >>
> >> Same, talking about Thomas' tree.
> >>
> >>>  There should be a merge commit every time he pulls
> >>> from a sub-tree (unless its a fast-forward I think, but with multiple subtrees
> >>> and commits going to thomas directly, that should never really happen).  
> >>
> >> That is what happening. Since sub-tree's rebase on top of main tree,
> >> when Thomas merges, it is just plain fast-forward. So it is allowed to
> >> re-write to history in sub-trees.
> >>
> > ok, I see what you're saying here, but I still don't see how this results in no
> > merge commits.  From what I can see we have at least 4 subtrees (next-crypto,
> > next-net, next-eventdev, next-virtio).  If you rebase all on lastest version of
> > thomas's tree, and then they all make changes and send a pull request, the first
> > to be merged will, by definition be a fast forward.  The remaining three
> > however, cannot be, because the prior merge has advanced the HEAD commit in
> > Thomas's tree such that its divergent from the subsequent tree to be merged.  So there
> > should be some merge commits in Thomas's tree.
> 
> This is simple indeed, all can do fast-forward, because all sub-trees
> touch to different files.
> 
> Currently:
> next-net: drivers/net/* [except virtio and vhost]
> next-crypto: drivers/crypto/*
> next-virtio: drivers/net/virtio/*, drivers/net/vhost/*
> 
> Common files are in main tree, when all rebased on top of it, they all
> can be merged as fast-forward.
> 
Fast forward-ability isn't determined by only touching orthogonal files, its
completely dependent on the relative HEAD and base pointers of each branch.  If
you send a pull request for your subtree on branch A from commit B to commit C,
the merge will resolve as a fast forward, if and only if, the HEAD commit of the
branch that the receiver is pulling to matches the base commit of the branch
being pulled (that is to say, commit B). If the receiving branch has any
additional commits on top of it, then the branches have diverged (even if the
applied patches don't touch a common set of files), and as a result a merge
commit is created (which may be empty if there are no conflicts).  Given that
there are no merge commits in Thomas tree, I conclude that you are either:

1) Not sending pull requests to Thomas - ie, just sending him a series of
patches to apply

2) Rebasing your work immediately prior to sending a pull request, resulting in
a fast-forward

Can either you or thomas provide some detail as to how you are doing patch
management between trees (details of the commands you use are what I would be
interested in). It sounds to me like there may be some optimization to be made
here before we even make changes to the subtrees.

Best
Neil

> > 
> > The only way I see around that, is if the merges are serialized (i.e. if you
> > provide an order to the subtrees and each subtree rebases from thomas prior to
> > applying its patches, then merges back to thomas's tree).  Thats rather defeating
> > of the purpose of parallel trees though.  You can all rebase, but then you
> > operate independently of each other.  Thats how we realize a speedup here
> > 
> > 
> > Neil
> > 
> 
> 

^ permalink raw reply

* Re: Proposal for a new Committer model
From: Neil Horman @ 2016-11-23 20:19 UTC (permalink / raw)
  To: Yuanhan Liu
  Cc: Mcnamara, John, Thomas Monjalon, dev@dpdk.org, Jerin Jacob,
	Stephen Hemminger
In-Reply-To: <20161123154120.GB5048@yliu-dev.sh.intel.com>

On Wed, Nov 23, 2016 at 11:41:20PM +0800, Yuanhan Liu wrote:
> On Wed, Nov 23, 2016 at 09:11:54AM -0500, Neil Horman wrote:
> > > Could we define some of the potential subtrees now and look to introduce them in the this release cycle? EAL and the Core libs, as suggested by Thomas, seem like 2 obvious ones.
> > > 
> > Sure, I'd suggest the following:
> 
> I would pull the git history to see which components are in
> active status in last release (or even, in last few release).
> And try to make a sub-tree if corresponding component is hot.
> 
> # the 2nd volume shows how many patches prefixed with a related component
> [yliu@yliu-dev ~/dpdk]$ git log --oneline v16.07..v16.11 | awk '{print $2}' | \
> 		        sort | uniq -c  | sort -nr | head -30 | nl
>      1       52 doc:
>      2       40 net/ixgbe/base:
>      3       38 app/test:
>      4       37 kni:
>      5       27 vhost:
>      6       27 net/virtio:
>      7       27 net/mlx5:
>      8       26 app/testpmd:
>      9       25 net/i40e:
>     10       23 net/pcap:
>     11       22 net/bnxt:
>     12       20 net/enic:
>     13       18 net/qede:
>     14       17 net/thunderx:
>     15       16 net/qede/base:
>     16       16 eal:
>     17       15 net/ixgbe:
>     18       14 net:
>     19       14 crypto/qat:
>     20       13 scripts:
>     21       13 net/bnx2x:
>     22       12 net/i40e/base:
>     23       12 examples/ipsec-secgw:
>     24       11 mbuf:
>     25       11 hash:
>     26       10 lib:
>     27       10 examples/ip_pipeline:
>     28       10 ethdev:
>     29        9 pci:
>     30        7 net/vmxnet3:
>     ...
>     46        3 pdump:
>     47        3 net/virtio_user:
>     48        3 net/ring:
>     49        3 net/nfp:
>     50        3 net/mlx:
>     51        3 net/ena:
>     52        3 net/e1000:
>     53        3 net/bonding:
>     ...
>     56        2 sched:
>     57        2 port:
>     ...
>     65        1 timer:
>     66        1 remove
>     67        1 pmdinfogen:
>     68        1 net/igb:
>     69        1 net/enic/base:
>     70        1 meter:
>     ...
>     84        1 cfgfile:
>     85        1 app/procinfo:
>     86        1 app/proc_info:
>     87        1 acl:
> 
> Something obvious is that:
> 
> - "doc" deserves a sub-tree, and John is a perfect committer for that
>   if he's willing to.
> 
> - generally, I'd agree with Neil that most (if not all) pmds may need
>   a sub-tree. While, some others may not, for example, net/ring, net/pcap.
> 
No, thats the opposite of what I think.  I think all net pmds should flow
through a single subtree, all crypto pmds through another, etc.

>   For those non-active pmds, I think it's okay to let the generic
>   pmd committer to cover them.
> 
Not sure what you're getting at here.  Low volume pms (or any library) can still
go through a subtree.  The goal is to fragmet the commit work so one person
doesn't have to do it all.

> - it's not that wise to me to list all the components we have so far
>   and make a sub-tree for each of them.
> 
I think you misunderstood the organization of my last note.  I agree with you
here.  When I listed the core and listed several libraries under it, my intent
was to create a core subtree that accepted patches for all of those libraries.

>   For example, some components like librte_{port, pdump, cfgfile, acl,
>   and etc} just have few (or even, just one) commits in last release.
>   It makes no sense to me to introduce a tree for each of them.
> 
Yes, this is what I was saying in my last note.

> Another thought is we could also create sub-trees based on category
> but not on components like Neil suggested, especially that EAL looks
> way too big to be maintained in one tree. Instead, it could be something
> like:
> 
> - a tree for BSD
> 
This gets tricky, because then several libraries will be covered by multiple
trees, and that leads to merge conflicts.

> - a tree for ARM (and some other trees for other platforms)
> 
> - a tree for mem related (mempool, mbuf, hugepage, etc)
> 
> - a tree for BUS
> 
> - ...
> 
> 
> Last but not the least, I think it's general good to have more and
> more trees in the end. But I don't think it's a good idea to go
> radically and create all those trees once (say in one release).
> 
> Something I would like to suggest is one or two (or a bit more) at
> a release. For example, if I remember them well, we have next-net
> tree at 16.04, and next-virtio (including vhost) at 16.07, and a
> recent one, next-crypto at 16.11.
> 
I'm not sure what you mean by this.  -next trees rather by definition should e
rebased on a release to start at the head of thomas's tree and add commits from
there based on their subject area.

Neil

> 	--yliu
> 
> 
> > 	* net-pmds:
> > 		- all network pmds located under drivers/net
> > 		- librte_net
> > 		- libtre_ether
> > 		- librte_ip_frag
> > 		- librte_pdump
> > 		- librte_port
> > 	* crypto-pmds:
> > 		- all crypto pmds located under drivers/crypto
> > 		- librte_cryptodev
> > 	* eal:
> > 		- librte_eal
> > 	* core:
> > 		- librte_cfgfile
> > 		- librte_cmdline
> > 		- librte_compat
> > 		- librte_kvargs
> > 		- librte_kni
> > 		- librte_compat
> > 	* misc:
> > 		- librte_acl
> > 		- librte_distributor
> > 		- librte_hash
> > 		- librte_jobstats
> > 		- librte_lpm
> > 		- librte_meter
> > 		- librte_pipeline
> > 		- librte_power
> > 		- librte_reorder
> > 		- librte_ring
> > 		- librte_sched
> > 		- librte_table
> > 		- librte_timer
> > 		- librte_vhost
> > 
> > Thats just a rough stab mind, but perhaps it would get the ball rolling.  I'd be
> > willing to take maintainership of one of these subtrees if there is consensus
> > around my doing so.
> 

^ permalink raw reply

* Re: [dpdk-stable] [PATCH] Revert "bonding: use existing enslaved device queues"
From: Jan Blunck @ 2016-11-23 20:35 UTC (permalink / raw)
  To: Ilya Maximets
  Cc: Ferruh Yigit, Bruce Richardson, Declan Doherty, Eric Kinzie, dev,
	Heetae Ahn, Yuanhan Liu, Bernard Iremonger, stable,
	Thomas Monjalon
In-Reply-To: <a3b86743-2b05-9c27-d795-424b54ca8460@samsung.com>

On Mon, Nov 21, 2016 at 2:11 PM, Ilya Maximets <i.maximets@samsung.com> wrote:
> To be clear, I still insist on applying this path as is.
>

That is very kind of you. Please see the patches that I've send in
reply to this thread which are required additionally to the revert you
send.

Happy Thanksgiving,
Jan


> Best regards, Ilya Maximets.
>
> On 21.11.2016 15:49, Ilya Maximets wrote:
>> On 21.11.2016 14:39, Jan Blunck wrote:
>>> Ferruh,
>>>
>>> I've been working on a patch but was distracted by other stuff and
>>> therefore haven't tested it yet.
>>
>> Jan, on what patch are you working? I don't understand.
>>
>>>
>>> Stay tuned,
>>> Jan
>>>
>>> On Mon, Nov 21, 2016 at 12:30 PM, Ferruh Yigit <ferruh.yigit@intel.com> wrote:
>>>>
>>>> Is there an update for this patch? Is a consensus reached?
>>
>> Ferruh, I didn't receive any response on my e-mails. I've pinged this thread
>> few times, but didn't receive any feedback and I have no idea what patch Jan
>> talking about.
>>
>> Best regards, Ilya Maximets.
>>

^ permalink raw reply

* [PATCH] doc: introduce PVP reference benchmark
From: Maxime Coquelin @ 2016-11-23 21:00 UTC (permalink / raw)
  To: yuanhan.liu, thomas.monjalon, john.mcnamara, zhiyong.yang, dev
  Cc: fbaudin, Maxime Coquelin

Having reference benchmarks is important in order to obtain
reproducible performance figures.

This patch describes required steps to configure a PVP setup
using testpmd in both host and guest.

Not relying on external vSwitch ease integration in a CI loop by
not being impacted by DPDK API changes.

Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
---
 doc/guides/howto/img/pvp_2nics.svg           | 556 +++++++++++++++++++++++++++
 doc/guides/howto/index.rst                   |   1 +
 doc/guides/howto/pvp_reference_benchmark.rst | 389 +++++++++++++++++++
 3 files changed, 946 insertions(+)
 create mode 100644 doc/guides/howto/img/pvp_2nics.svg
 create mode 100644 doc/guides/howto/pvp_reference_benchmark.rst

diff --git a/doc/guides/howto/img/pvp_2nics.svg b/doc/guides/howto/img/pvp_2nics.svg
new file mode 100644
index 0000000..517a800
--- /dev/null
+++ b/doc/guides/howto/img/pvp_2nics.svg
@@ -0,0 +1,556 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="127.46428mm"
+   height="139.41411mm"
+   viewBox="0 0 451.64508 493.987"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.92pre2 r"
+   sodipodi:docname="pvp_2nics.svg"
+   inkscape:export-filename="/home/max/Pictures/dpdk/pvp/pvp.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs4">
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4760"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4762"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4642"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4644"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker10370"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path10372"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker10306"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path10308"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker9757"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend"
+       inkscape:collect="always">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path9759"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lstart"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path4224"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lend"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path4227"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lend-1"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4227-27"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lstart-9"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4224-3"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker9757-0"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path9759-6"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lstart-6"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4224-0"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lend-62"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4227-6"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker10370-7"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path10372-9"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker9757-2"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path9759-0"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lstart-9-2"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4224-3-3"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lend-1-7"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4227-27-5"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.49497475"
+     inkscape:cx="206.7485"
+     inkscape:cy="227.93958"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:object-nodes="true"
+     inkscape:window-width="1916"
+     inkscape:window-height="1040"
+     inkscape:window-x="0"
+     inkscape:window-y="38"
+     inkscape:window-maximized="0"
+     inkscape:snap-grids="true"
+     inkscape:snap-to-guides="true"
+     inkscape:snap-others="false"
+     inkscape:snap-nodes="false"
+     inkscape:snap-global="false" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-5.3301459,-7.348317)">
+    <rect
+       style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.78969002;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect4140"
+       width="434.38919"
+       height="75.295639"
+       x="21.691195"
+       y="404.59354" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="421.47873"
+       y="501.3353"
+       id="text4142"><tspan
+         sodipodi:role="line"
+         id="tspan4144"
+         x="421.47873"
+         y="501.3353"
+         style="font-size:25px;line-height:125%">TE</tspan></text>
+    <rect
+       style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.46599996;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect4146"
+       width="92.934036"
+       height="32.324883"
+       x="182.57764"
+       y="372.03574" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="183.5878"
+       y="397.28958"
+       id="text4148"><tspan
+         sodipodi:role="line"
+         id="tspan4150"
+         x="183.5878"
+         y="397.28958"
+         style="font-size:25px">10G NIC</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="166.92024"
+       y="451.33276"
+       id="text4152"><tspan
+         sodipodi:role="line"
+         id="tspan4154"
+         x="166.92024"
+         y="451.33276">Moongen</tspan></text>
+    <rect
+       style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.39882457;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect4156"
+       width="449.73071"
+       height="244.32167"
+       x="6.0295582"
+       y="29.046324" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="405.31628"
+       y="25.048317"
+       id="text4158"><tspan
+         sodipodi:role="line"
+         id="tspan4160"
+         x="405.31628"
+         y="25.048317"
+         style="font-size:25px">DUT</tspan></text>
+    <rect
+       style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.14168489;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect4162"
+       width="418.69415"
+       height="107.50462"
+       x="19.038134"
+       y="41.044758" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="395.38812"
+       y="66.496857"
+       id="text4164"><tspan
+         sodipodi:role="line"
+         id="tspan4166"
+         x="395.38812"
+         y="66.496857"
+         style="font-size:25px">VM</tspan></text>
+    <rect
+       style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.46599996;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect4146-3"
+       width="92.934036"
+       height="32.324883"
+       x="183.0827"
+       y="274.05093" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="184.09286"
+       y="299.30475"
+       id="text4148-6"><tspan
+         sodipodi:role="line"
+         id="tspan4150-7"
+         x="184.09286"
+         y="299.30475"
+         style="font-size:25px">10G NIC</tspan></text>
+    <rect
+       style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.4804399;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect4189"
+       width="398.00476"
+       height="65.451302"
+       x="26.901583"
+       y="82.647781" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:25px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="30.683046"
+       y="108.31288"
+       id="text4191"><tspan
+         sodipodi:role="line"
+         id="tspan4193"
+         x="30.683046"
+         y="108.31288">TestPMD</tspan><tspan
+         sodipodi:role="line"
+         x="30.683046"
+         y="139.56288"
+         id="tspan10476">(macswap)</tspan></text>
+    <rect
+       style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.49124122;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect4189-5"
+       width="397.22263"
+       height="66.152573"
+       x="29.743357"
+       y="207.6543" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:25px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="42.720772"
+       y="231.14902"
+       id="text4191-3"><tspan
+         sodipodi:role="line"
+         id="tspan4193-5"
+         x="42.720772"
+         y="231.14902">TestPMD </tspan><tspan
+         sodipodi:role="line"
+         x="42.720772"
+         y="262.39902"
+         id="tspan9747">(io)</tspan></text>
+    <path
+       style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.97838062px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
+       d="M 202.56669,371.44487 V 308.37034"
+       id="path4218"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.97297633px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart)"
+       d="M 252.03098,369.63533 V 307.25568"
+       id="path4218-9"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.92982113px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend-1)"
+       d="M 198.63811,207.44389 V 150.47507"
+       id="path4218-0"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.95360273px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart-9)"
+       d="M 255.56859,206.9303 V 147.01008"
+       id="path4218-9-6"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3, 1;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker9757)"
+       d="M 199.50513,271.00921 V 207.3696"
+       id="path9749"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3, 1;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker10370)"
+       d="M 255.56859,270.56991 V 206.9303"
+       id="path9749-2"
+       inkscape:connector-curvature="0" />
+    <rect
+       style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.46599996;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect4146-36"
+       width="92.934036"
+       height="32.324883"
+       x="304.05591"
+       y="372.52954" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="305.06607"
+       y="397.78339"
+       id="text4148-7"><tspan
+         sodipodi:role="line"
+         id="tspan4150-5"
+         x="305.06607"
+         y="397.78339"
+         style="font-size:25px">10G NIC</tspan></text>
+    <rect
+       style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.46599996;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect4146-3-3"
+       width="92.934036"
+       height="32.324883"
+       x="306.07623"
+       y="273.53461" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="307.0864"
+       y="298.78842"
+       id="text4148-6-5"><tspan
+         sodipodi:role="line"
+         id="tspan4150-7-6"
+         x="307.0864"
+         y="298.78842"
+         style="font-size:25px">10G NIC</tspan></text>
+    <path
+       style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.97838062px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend-62)"
+       d="M 323.7504,370.24835 V 307.17382"
+       id="path4218-1"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.97297633px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart-6)"
+       d="M 373.21469,368.43881 V 306.05916"
+       id="path4218-9-8"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.92982113px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend-1-7)"
+       d="M 324.93036,207.24894 V 150.28012"
+       id="path4218-0-9"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.95360273px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart-9-2)"
+       d="M 381.86084,206.73535 V 146.81513"
+       id="path4218-9-6-2"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3, 1;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker9757-2)"
+       d="M 325.79738,270.81426 V 207.17465"
+       id="path9749-28"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3, 1;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker10370-7)"
+       d="M 381.86084,270.37496 V 206.73535"
+       id="path9749-2-9"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:2, 1;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker4642)"
+       d="M 198.57143,148.79077 V 95.93363 h 182.85714 v 50"
+       id="path3748"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.01005316;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:2.02010632, 1.01005316;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker4760)"
+       d="m 325.70774,148.78714 v -32.84999 h -70.7012 v 30.70761"
+       id="path4634"
+       inkscape:connector-curvature="0" />
+  </g>
+</svg>
diff --git a/doc/guides/howto/index.rst b/doc/guides/howto/index.rst
index 5575b27..712a9f3 100644
--- a/doc/guides/howto/index.rst
+++ b/doc/guides/howto/index.rst
@@ -38,3 +38,4 @@ HowTo Guides
     lm_bond_virtio_sriov
     lm_virtio_vhost_user
     flow_bifurcation
+    pvp_reference_benchmark
diff --git a/doc/guides/howto/pvp_reference_benchmark.rst b/doc/guides/howto/pvp_reference_benchmark.rst
new file mode 100644
index 0000000..042c6aa
--- /dev/null
+++ b/doc/guides/howto/pvp_reference_benchmark.rst
@@ -0,0 +1,389 @@
+..  BSD LICENSE
+    Copyright(c) 2016 Red Hat, Inc. All rights reserved.
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+    * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+    * Neither the name of Intel Corporation nor the names of its
+    contributors may be used to endorse or promote products derived
+    from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+PVP reference benchmark setup using testpmd
+===========================================
+
+This guide lists the steps required to setup PVP benchmark using testpmd as a
+simple forwarder between NICs and Vhost interfaces. The goal of this setup is
+to have a reference PVP benchmark not using external vSwitches (OVS, VPP, ...),
+making easier to obtain reproducible results and easing continuous integration
+testing.
+
+The guide covers two way for launching the VM, either by calling directly QEMU
+command line, or by relying on libvirt. It has been tested working with DPDK
+v16.11, using RHEL7 for both host and guest.
+
+Setup overview
+..............
+
+.. figure:: img/pvp_2nics.svg
+
+  PVP setup using 2 NICs
+
+In this diagram, each red arrow represents one logical core. This use-case
+requires 6 dedicated logical cores. A setup consisting in doing forwarding
+with a single NIC is also possible, requiring 3 logical cores. 
+
+Host setup
+..........
+
+In this setup, we isolate 6 cores (from CPU2 to CPU7) in a same NUMA node. Two
+cores are assigned to the VM vCPUs running testpmd, four are assigned to
+testpmd on host.
+
+Host tuning
+~~~~~~~~~~~
+
+#. Append these options to Kernel command line:
+
+   .. code-block:: console
+
+    intel_pstate=disable mce=ignore_ce default_hugepagesz=1G hugepagesz=1G hugepages=6 isolcpus=2-7 rcu_nocbs=2-7 nohz_full=2-7 iommu=pt intel_iommu=on
+
+#. Disable hyper-threads at runtime if necessary and BIOS not accessible:
+
+   .. code-block:: console
+
+    cat /sys/devices/system/cpu/cpu*[0-9]/topology/thread_siblings_list \
+        | sort | uniq \
+        | awk -F, '{system("echo 0 > /sys/devices/system/cpu/cpu"$2"/online")}'
+
+#. Disable NMIs:
+
+   .. code-block:: console
+
+    echo 0 > /proc/sys/kernel/nmi_watchdog
+
+#. Exclude isolated CPUs from the writeback cpumask:
+
+   .. code-block:: console
+
+    echo ffffff03 > /sys/bus/workqueue/devices/writeback/cpumask
+
+#. Isolate CPUs from IRQs:
+
+   .. code-block:: console
+
+    clear_mask=0xfc #Isolate CPU2 to CPU7 from IRQs
+    for i in /proc/irq/*/smp_affinity
+    do
+     echo "obase=16;$(( 0x$(cat $i) & ~$clear_mask ))" | bc > $i
+    done
+
+Qemu build
+~~~~~~~~~~
+
+   .. code-block:: console
+
+    git clone git://dpdk.org/dpdk
+    cd dpdk
+    export RTE_SDK=$PWD
+    make install T=x86_64-native-linuxapp-gcc DESTDIR=install
+
+DPDK build
+~~~~~~~~~~
+
+   .. code-block:: console
+
+    git clone git://dpdk.org/dpdk
+    cd dpdk
+    export RTE_SDK=$PWD
+    make install T=x86_64-native-linuxapp-gcc DESTDIR=install
+
+Testpmd launch
+~~~~~~~~~~~~~~
+
+#. Assign NICs to DPDK:
+
+   .. code-block:: console
+
+    modprobe vfio-pci
+    $RTE_SDK/install/sbin/dpdk-devbind -b vfio-pci 0000:11:00.0 0000:11:00.1
+
+*Note: Sandy Bridge family seems to have some limitations wrt its IOMMU,
+giving poor performance results. To achieve good performance on these machines,
+consider using UIO instead.*
+
+#. Launch testpmd application:
+
+   .. code-block:: console
+
+    $RTE_SDK/install/bin/testpmd -l 0,2,3,4,5 --socket-mem=1024 -n 4 \
+        --vdev 'net_vhost0,iface=/tmp/vhost-user1' \
+        --vdev 'net_vhost1,iface=/tmp/vhost-user2' -- \
+        --portmask=f --disable-hw-vlan -i --rxq=1 --txq=1
+        --nb-cores=4 --forward-mode=io
+
+#. In testpmd interactive mode, set the portlist to obtin the right chaining:
+
+   .. code-block:: console
+
+    set portlist 0,2,1,3
+    start
+
+VM launch
+~~~~~~~~~
+
+The VM may be launched ezither by calling directly QEMU, or by using libvirt.
+
+#. Qemu way:
+
+Launch QEMU with two Virtio-net devices paired to the vhost-user sockets created by testpmd:
+
+   .. code-block:: console
+
+    <QEMU path>/bin/x86_64-softmmu/qemu-system-x86_64 \
+        -enable-kvm -cpu host -m 3072 -smp 3 \
+        -chardev socket,id=char0,path=/tmp/vhost-user1 \
+        -netdev type=vhost-user,id=mynet1,chardev=char0,vhostforce \
+        -device virtio-net-pci,netdev=mynet1,mac=52:54:00:02:d9:01,addr=0x10 \
+        -chardev socket,id=char1,path=/tmp/vhost-user2 \
+        -netdev type=vhost-user,id=mynet2,chardev=char1,vhostforce \
+        -device virtio-net-pci,netdev=mynet2,mac=52:54:00:02:d9:02,addr=0x11 \
+        -object memory-backend-file,id=mem,size=3072M,mem-path=/dev/hugepages,share=on \
+        -numa node,memdev=mem -mem-prealloc \
+        -net user,hostfwd=tcp::1002$1-:22 -net nic \
+        -qmp unix:/tmp/qmp.socket,server,nowait \
+        -monitor stdio <vm_image>.qcow2
+
+You can use this qmp-vcpu-pin script to pin vCPUs:
+
+   .. code-block:: python
+
+    #!/usr/bin/python
+    # QEMU vCPU pinning tool
+    #
+    # Copyright (C) 2016 Red Hat Inc.
+    #
+    # Authors:
+    #  Maxime Coquelin <maxime.coquelin@redhat.com>
+    #
+    # This work is licensed under the terms of the GNU GPL, version 2.  See
+    # the COPYING file in the top-level directory
+    import argparse
+    import json
+    import os
+
+    from subprocess import call
+    from qmp import QEMUMonitorProtocol
+
+    pinned = []
+
+    parser = argparse.ArgumentParser(description='Pin QEMU vCPUs to physical CPUs')
+    parser.add_argument('-s', '--server', type=str, required=True,
+                        help='QMP server path or address:port')
+    parser.add_argument('cpu', type=int, nargs='+',
+                        help='Physical CPUs IDs')
+    args = parser.parse_args()
+
+    devnull = open(os.devnull, 'w')
+
+    srv = QEMUMonitorProtocol(args.server)
+    srv.connect()
+
+    for vcpu in srv.command('query-cpus'):
+        vcpuid = vcpu['CPU']
+        tid = vcpu['thread_id']
+        if tid in pinned:
+            print 'vCPU{}\'s tid {} already pinned, skipping'.format(vcpuid, tid)
+            continue
+
+        cpuid = args.cpu[vcpuid % len(args.cpu)]
+        print 'Pin vCPU {} (tid {}) to physical CPU {}'.format(vcpuid, tid, cpuid)
+        try:
+            call(['taskset', '-pc', str(cpuid), str(tid)], stdout=devnull)
+            pinned.append(tid)
+        except OSError:
+            print 'Failed to pin vCPU{} to CPU{}'.format(vcpuid, cpuid)
+
+
+That can be used this way, for example to pin 3 vCPUs to CPUs 1, 6 and 7:
+
+   .. code-block:: console
+
+    export PYTHONPATH=$PYTHONPATH:<QEMU path>/scripts/qmp
+    ./qmp-vcpu-pin -s /tmp/qmp.socket 1 6 7
+
+#. Libvirt way:
+
+Some initial steps are required for libvirt to be able to connect to testpmd's
+sockets.
+
+First, SELinux policy needs to be set to permissiven, as testpmd is run as root
+(reboot required):
+
+   .. code-block:: console
+
+    cat /etc/selinux/config
+
+    # This file controls the state of SELinux on the system.
+    # SELINUX= can take one of these three values:
+    #     enforcing - SELinux security policy is enforced.
+    #     permissive - SELinux prints warnings instead of enforcing.
+    #     disabled - No SELinux policy is loaded.
+    SELINUX=permissive
+    # SELINUXTYPE= can take one of three two values:
+    #     targeted - Targeted processes are protected,
+    #     minimum - Modification of targeted policy. Only selected processes are protected. 
+    #     mls - Multi Level Security protection.
+    SELINUXTYPE=targeted
+
+
+Also, Qemu needs to be run as root, which has to be specified in /etc/libvirt/qemu.conf:
+
+   .. code-block:: console
+
+    user = "root"
+
+Once the domain created, following snippset is an extract of most important
+information (hugepages, vCPU pinning, Virtio PCI devices):
+
+   .. code-block:: xml
+
+    <domain type='kvm'>
+      <memory unit='KiB'>3145728</memory>
+      <currentMemory unit='KiB'>3145728</currentMemory>
+      <memoryBacking>
+        <hugepages>
+          <page size='1048576' unit='KiB' nodeset='0'/>
+        </hugepages>
+        <locked/>
+      </memoryBacking>
+      <vcpu placement='static'>3</vcpu>
+      <cputune>
+        <vcpupin vcpu='0' cpuset='1'/>
+        <vcpupin vcpu='1' cpuset='6'/>
+        <vcpupin vcpu='2' cpuset='7'/>
+        <emulatorpin cpuset='0'/>
+      </cputune>
+      <numatune>
+        <memory mode='strict' nodeset='0'/>
+      </numatune>
+      <os>
+        <type arch='x86_64' machine='pc-i440fx-rhel7.0.0'>hvm</type>
+        <boot dev='hd'/>
+      </os>
+      <cpu mode='host-passthrough'>
+        <topology sockets='1' cores='3' threads='1'/>
+        <numa>
+          <cell id='0' cpus='0-2' memory='3145728' unit='KiB' memAccess='shared'/>
+        </numa>
+      </cpu>
+      <devices>
+        <interface type='vhostuser'>
+          <mac address='56:48:4f:53:54:01'/>
+          <source type='unix' path='/tmp/vhost-user1' mode='client'/>
+          <model type='virtio'/>
+          <driver name='vhost' rx_queue_size='256' />
+          <address type='pci' domain='0x0000' bus='0x00' slot='0x10' function='0x0'/>
+        </interface>
+        <interface type='vhostuser'>
+          <mac address='56:48:4f:53:54:02'/>
+          <source type='unix' path='/tmp/vhost-user2' mode='client'/>
+          <model type='virtio'/>
+          <driver name='vhost' rx_queue_size='256' />
+          <address type='pci' domain='0x0000' bus='0x00' slot='0x11' function='0x0'/>
+        </interface>
+      </devices>
+    </domain>
+
+Guest setup
+...........
+
+Guest tuning
+~~~~~~~~~~~~
+
+#. Append these options to Kernel command line:
+
+   .. code-block:: console
+
+    default_hugepagesz=1G hugepagesz=1G hugepages=1 intel_iommu=on iommu=pt isolcpus=1,2 rcu_nocbs=1,2 nohz_full=1,2
+
+#. Disable NMIs:
+
+   .. code-block:: console
+
+    echo 0 > /proc/sys/kernel/nmi_watchdog
+
+#. Exclude isolated CPU1 and CPU2 from the writeback wq cpumask:
+
+   .. code-block:: console
+
+    echo 1 > /sys/bus/workqueue/devices/writeback/cpumask
+
+#. Isolate CPUs from IRQs:
+
+   .. code-block:: console
+
+    clear_mask=0x6 #Isolate CPU1 and CPU2 from IRQs
+    for i in /proc/irq/*/smp_affinity
+    do
+      echo "obase=16;$(( 0x$(cat $i) & ~$clear_mask ))" | bc > $i
+    done
+
+DPDK build
+~~~~~~~~~~
+
+   .. code-block:: console
+
+    git clone git://dpdk.org/dpdk
+    cd dpdk
+    export RTE_SDK=$PWD
+    make install T=x86_64-native-linuxapp-gcc DESTDIR=install
+
+Testpmd launch
+~~~~~~~~~~~~~~
+
+Probe vfio module without iommu:
+
+   .. code-block:: console
+
+    modprobe -r vfio_iommu_type1
+    modprobe -r vfio
+    modprobe  vfio enable_unsafe_noiommu_mode=1
+    cat /sys/module/vfio/parameters/enable_unsafe_noiommu_mode
+    modprobe vfio-pci
+
+Bind virtio-net devices to DPDK:
+
+   .. code-block:: console
+
+    $RTE_SDK/tools/dpdk-devbind.py -b vfio-pci 0000:00:10.0 0000:00:11.0
+
+Start testpmd:
+
+   .. code-block:: console
+
+    $RTE_SDK/install/bin/testpmd -l 0,1,2 --socket-mem 1024 -n 4 \
+        --proc-type auto --file-prefix pg -- \
+        --portmask=3 --forward-mode=macswap --port-topology=chained \
+        --disable-hw-vlan --disable-rss -i --rxq=1 --txq=1 \
+        --rxd=256 --txd=256 --nb-cores=2 --auto-start
-- 
2.9.3

^ permalink raw reply related

* [PATCH 00/16] e1000 base code update
From: Wenzhuo Lu @ 2016-11-23 17:22 UTC (permalink / raw)
  To: dev

Updated e1000 base code to fix several bugs and support
i219 NICs.

Wenzhuo Lu (16):
  e1000/base: increased ULP timer
  e1000/base: increase PHY PLL clock gate timing
  e1000/base: try more times to get HW mailbox lock
  e1000/base: add getting HW version support for i354
  e1000/base: expose e1000_write_vfta_i350
  e1000/base: add max RX jumbo frame define
  e1000/base: restore link speed after ULP exit
  e1000/base: clear ULP configuration register on ULP exit
  e1000/base: increase LANPHYPC low duration
  e1000/base: workaround for ULP entry flow
  e1000/base: enable new i219 devices
  e1000/base: always request clock during K1 at 1G link speed
  e1000/base: ability to force K1-off disabled
  e1000/base: support more i219 devices
  e1000/base: update readme
  e1000: add new i219 devices

 drivers/net/e1000/base/README          |   4 +-
 drivers/net/e1000/base/e1000_82575.c   |   1 -
 drivers/net/e1000/base/e1000_82575.h   |   1 +
 drivers/net/e1000/base/e1000_api.c     |  19 +
 drivers/net/e1000/base/e1000_defines.h |   9 +
 drivers/net/e1000/base/e1000_hw.h      |  21 +-
 drivers/net/e1000/base/e1000_ich8lan.c | 865 +++++++++++++++++++++++++++++++--
 drivers/net/e1000/base/e1000_ich8lan.h |  21 +-
 drivers/net/e1000/base/e1000_mbx.c     |  36 +-
 drivers/net/e1000/base/e1000_nvm.c     |   1 +
 drivers/net/e1000/base/e1000_regs.h    |   7 +
 drivers/net/e1000/em_ethdev.c          |  34 +-
 12 files changed, 949 insertions(+), 70 deletions(-)

-- 
1.9.3

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox