DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework
@ 2014-10-29  8:49 Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 01/25] eal/pci: Add a new flag indicating a driver can detach devices at runtime Tetsuya Mukawa
                   ` (28 more replies)
  0 siblings, 29 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

This patch series adds a dynamic port hotplug framework to DPDK.
With the patches, DPDK apps can attach or detach ports at runtime.

The basic concept of the port hotplug is like followings.
- DPDK apps must have resposibility to manage ports.
  DPDK apps only know which ports are attached or detached at the moment.
  To manage ports by DPDK apps, the port hotplug framework is implemented.
  For example, when DPDK apps call port attach function, attached port number
  will be returned. Also DPDK apps can detach port by port number.
- Kernel support is needed for attaching or detaching physical device ports.
  To attach new device, the device will be recognized by kernel at first and
  controlled by kernel driver. Then user can bind the device to igb_uio
  by 'dpdk_nic_bind.py'. Finally, DPDK apps can call the port hotplug
  functions to attach ports.
  For detaching, steps are vice versa.
- Before detach ports, ports must be stopped and closed.
  DPDK application must call rte_eth_dev_stop() and rte_eth_dev_close() before
  detaching ports. These function will call finalization codes of PMDs.
  But so far, no PMD has such a finalization code.
  It means PMDs are needed to be fixed to support the port hotplug.
  'RTE_PCI_DRV_DETACHABLE' is a new flag indicating a PMD supports detaching.
  Without this flag, detaching will be failed.
- Mustn't affect legacy DPDK apps.
  No DPDK EAL behavior is changed, if the port hotplug functions are't called.
  So all legacy DPDK apps can still work without modifications.

And few limitations.
- The port hotplug functions are not thread safe.
  DPDK apps should handle it.
- Only support Linux and igb_uio so far.
  BSD and VFIO is not supported. I will send VFIO patches at least, but I don't
  have a plan to submit BSD patch so far.

The patch series are for DPDK EAL. I will send following patches later.
- Patches for PMDs.
  Each PMD need to be fixed to free resources allocated by the PMD.
  I will send a pcap PMD patch for the example of fixing virtual PMDs.
  Also I will send a workaround patch for physical PMDs. But it will be just a
  workaround to test the port hotplug. I guess patching to physical PMDs must
  be carefully. I don't have test resources, so I just send a workaround so far.
  Anyway, if you want to test this RFC patches, em PMD is the only physical PMD
  you can test so far.
- Patches for testpmd
  I will send patches for testpmd to handle port hotplug framework at runtime.
  It may be an example of how DPDK apps should be fixed to handle port hotplug.
  With the patch, testpmd can handle like following commands.
  testpmd> port attach p 0000:02:00.0
  testpmd> port attach v eth_pcap0,iface=eth0
  testpmd> port detach p 0
  testpmd> port detach v 1
  To attche ports, stop streamings first. Also to detach port, stop streamings,
  stop port and close port first. The limitation of port hotplug is only that
  port must be stopped and closed before detacing. Above additional limitations
  are come from current implementation of testpmd.
  --------------------------------------------------------------------------
  Here is an example of attaching and detaching ports by testpmd.
  $ ./tools/dpdk_nic_bind.p --status
  (make sure there are no devices under igb_uio by 'dpdk_nic_bind.py'.)
  $ sudo ./testpmd -c f -n 4 -- -i
  (on other terminal, bind a device to igb_uio.)
  testpmd> port attach p [pci address]
  testpmd> port attach v eth_pcap0,iface=eth1
  testpmd> port start all
  testpmd> start
  testpmd> stop
  testpmd> port stop 0
  testpmd> port close 0
  testpmd> port detach p 0
  (on other terminal, unbind a device from igb_uio.)

Thanks,
Tetsuya Mukawa


Tetsuya Mukawa (25):
  eal/pci: Add a new flag indicating a driver can detach devices at
    runtime.
  ethdev: Remove assumption that port will not be detached
  eal/pci: Replace pci address comparison code by eal_compare_pci_addr
  ethdev: Add rte_eth_dev_free to free specified device
  eal,ethdev: Add function pointer for closing a device
  ethdev: Add rte_eth_dev_shutdown for closing PCI devices.
  ethdev: Add functions to know which port is attached or detached
  ethdev: Add rte_eth_dev_get_addr_by_port
  ethdev: Add rte_eth_dev_get_port_by_addr
  ethdev: Add rte_eth_dev_get_name_by_port
  ethdev: Add rte_eth_dev_check_detachable
  ethdev: Change scope of rte_eth_dev_allocated to global
  eal/pci: Prevent double registration for devargs_list
  eal/pci: Add rte_eal_devargs_remove
  eal/pci: Add probe and close function for virtual drivers
  eal/pci: Add port hotplug functions for virtual devices.
  eal/linux/pci: Add functions for unmapping igb_uio resources
  eal/pci: Prevent double registrations for pci_device_list
  eal/pci: Change scope of rte_eal_pci_scan to global
  eal/pci: Add rte_eal_pci_close_one_driver
  eal/pci: Fix pci_probe_all_drivers to share code with closing function
  eal/pci: Add pci_close_all_drivers
  eal/pci: Add rte_eal_pci_probe_one and rte_eal_pci_close_one
  eal/pci: Add port hotplug functions for physical devices.
  eal: Enable port hotplug framework in Linux

 config/common_linuxapp                             |   5 +
 lib/librte_eal/bsdapp/eal/eal_pci.c                |  16 +-
 lib/librte_eal/common/eal_common_dev.c             | 208 ++++++++++++
 lib/librte_eal/common/eal_common_devargs.c         |  45 +++
 lib/librte_eal/common/eal_common_pci.c             | 107 +++++-
 lib/librte_eal/common/include/eal_private.h        |  22 ++
 lib/librte_eal/common/include/rte_dev.h            |  60 ++++
 lib/librte_eal/common/include/rte_devargs.h        |  18 +
 lib/librte_eal/common/include/rte_pci.h            |  64 ++++
 lib/librte_eal/linuxapp/eal/Makefile               |   1 +
 lib/librte_eal/linuxapp/eal/eal_pci.c              | 119 +++++--
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c          |  58 +++-
 lib/librte_eal/linuxapp/eal/include/eal_pci_init.h |   7 +
 lib/librte_ether/rte_ethdev.c                      | 371 +++++++++++++++------
 lib/librte_ether/rte_ethdev.h                      | 100 ++++++
 15 files changed, 1046 insertions(+), 155 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 01/25] eal/pci: Add a new flag indicating a driver can detach devices at runtime.
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 02/25] ethdev: Remove assumption that port will not be detached Tetsuya Mukawa
                   ` (27 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

This patch adds "RTE_PCI_DRV_DETACHABLE" to drv_flags of rte_pci_driver
structure. The flags indicates the driver can detach devices at runtime.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/include/rte_pci.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 66ed793..b819539 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -199,6 +199,8 @@ 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 capablity */
+#define RTE_PCI_DRV_DETACHABLE	0x0010
 
 /**< Internal use only - Macro used by pci addr parsing functions **/
 #define GET_PCIADDR_FIELD(in, fd, lim, dlm)                   \
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 02/25] ethdev: Remove assumption that port will not be detached
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 01/25] eal/pci: Add a new flag indicating a driver can detach devices at runtime Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29 15:14   ` Bruce Richardson
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 03/25] eal/pci: Replace pci address comparison code by eal_compare_pci_addr Tetsuya Mukawa
                   ` (26 subsequent siblings)
  28 siblings, 1 reply; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

To remove assumption, do like followings.

- Add 'attached' member to rte_eth_dev structure.
  This member is used for indicating the port is attached, or not.
- Delete nb_ports, and fix rte_eth_dev_count().
  The value was used for counting attached ports and also used for indicating
  maximum attached port number. But if some ports are detached, these 2 values
  may not be equal. So delete nb_ports, and fix rte_eth_dev_count() to count
  how many ports are attached actually.
- Add rte_eth_dev_allocate_new_port().
  This function is used for allocating new port.
- Add rte_eth_dev_validate_port().
  This function is used for check whether the port number is valid and the
  port is attached.
- Replace port validation codes to rte_eth_dev_validate_port().
  nb_ports is deleted in this patch, so use rte_eth_dev_validate_port() to
  validate a port.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 247 +++++++++++++++++++++++-------------------
 lib/librte_ether/rte_ethdev.h |   5 +
 2 files changed, 143 insertions(+), 109 deletions(-)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index ff1c769..93d5a42 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -109,7 +109,6 @@
 static const char *MZ_RTE_ETH_DEV_DATA = "rte_eth_dev_data";
 struct rte_eth_dev rte_eth_devices[RTE_MAX_ETHPORTS];
 static struct rte_eth_dev_data *rte_eth_dev_data = NULL;
-static uint8_t nb_ports = 0;
 
 /* spinlock for eth device callbacks */
 static rte_spinlock_t rte_eth_dev_cb_lock = RTE_SPINLOCK_INITIALIZER;
@@ -201,19 +200,33 @@ rte_eth_dev_allocated(const char *name)
 {
 	unsigned i;
 
-	for (i = 0; i < nb_ports; i++) {
-		if (strcmp(rte_eth_devices[i].data->name, name) == 0)
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
+		if (rte_eth_devices[i].attached && strcmp(
+				rte_eth_dev_data[i].name, name) == 0)
 			return &rte_eth_devices[i];
-	}
+
 	return NULL;
 }
 
+static uint8_t
+rte_eth_dev_allocate_new_port(void)
+{
+	unsigned i;
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
+		if (!rte_eth_devices[i].attached)
+			return i;
+	return RTE_MAX_ETHPORTS;
+}
+
 struct rte_eth_dev *
 rte_eth_dev_allocate(const char *name)
 {
+	uint8_t port_id;
 	struct rte_eth_dev *eth_dev;
 
-	if (nb_ports == RTE_MAX_ETHPORTS) {
+	port_id = rte_eth_dev_allocate_new_port();
+	if (port_id >= RTE_MAX_ETHPORTS) {
 		PMD_DEBUG_TRACE("Reached maximum number of Ethernet ports\n");
 		return NULL;
 	}
@@ -226,10 +239,11 @@ rte_eth_dev_allocate(const char *name)
 		return NULL;
 	}
 
-	eth_dev = &rte_eth_devices[nb_ports];
-	eth_dev->data = &rte_eth_dev_data[nb_ports];
+	eth_dev = &rte_eth_devices[port_id];
+	eth_dev->data = &rte_eth_dev_data[port_id];
 	snprintf(eth_dev->data->name, sizeof(eth_dev->data->name), "%s", name);
-	eth_dev->data->port_id = nb_ports++;
+	eth_dev->data->port_id = port_id;
+	eth_dev->attached = 1;
 	return eth_dev;
 }
 
@@ -283,7 +297,7 @@ rte_eth_dev_init(struct rte_pci_driver *pci_drv,
 			(unsigned) pci_dev->id.device_id);
 	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
 		rte_free(eth_dev->data->dev_private);
-	nb_ports--;
+	eth_dev->attached = 0;
 	return diag;
 }
 
@@ -308,10 +322,19 @@ rte_eth_driver_register(struct eth_driver *eth_drv)
 	rte_eal_pci_register(&eth_drv->pci_drv);
 }
 
+static int
+rte_eth_dev_validate_port(uint8_t port_id)
+{
+	if (port_id >= RTE_MAX_ETHPORTS)
+		return 1;
+
+	return !rte_eth_devices[port_id].attached;
+}
+
 int
 rte_eth_dev_socket_id(uint8_t port_id)
 {
-	if (port_id >= nb_ports)
+	if (rte_eth_dev_validate_port(port_id))
 		return -1;
 	return rte_eth_devices[port_id].pci_dev->numa_node;
 }
@@ -319,7 +342,13 @@ rte_eth_dev_socket_id(uint8_t port_id)
 uint8_t
 rte_eth_dev_count(void)
 {
-	return (nb_ports);
+	unsigned i;
+	uint8_t nb_ports = 0;
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
+		if (rte_eth_devices[i].attached)
+			nb_ports++;
+	return nb_ports;
 }
 
 static int
@@ -369,7 +398,7 @@ rte_eth_dev_rx_queue_start(uint8_t port_id, uint16_t rx_queue_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -395,7 +424,7 @@ rte_eth_dev_rx_queue_stop(uint8_t port_id, uint16_t rx_queue_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -421,7 +450,7 @@ rte_eth_dev_tx_queue_start(uint8_t port_id, uint16_t tx_queue_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -447,7 +476,7 @@ rte_eth_dev_tx_queue_stop(uint8_t port_id, uint16_t tx_queue_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -662,7 +691,7 @@ rte_eth_dev_configure(uint8_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports || port_id >= RTE_MAX_ETHPORTS) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -846,7 +875,7 @@ rte_eth_dev_start(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%" PRIu8 "\n", port_id);
 		return (-EINVAL);
 	}
@@ -881,7 +910,7 @@ rte_eth_dev_stop(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_RET();
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%" PRIu8 "\n", port_id);
 		return;
 	}
@@ -909,7 +938,7 @@ rte_eth_dev_set_link_up(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -928,7 +957,7 @@ rte_eth_dev_set_link_down(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -947,7 +976,7 @@ rte_eth_dev_close(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_RET();
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -975,7 +1004,7 @@ rte_eth_rx_queue_setup(uint8_t port_id, uint16_t rx_queue_id,
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -1048,7 +1077,7 @@ rte_eth_tx_queue_setup(uint8_t port_id, uint16_t tx_queue_id,
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= RTE_MAX_ETHPORTS || port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -1081,7 +1110,7 @@ rte_eth_promiscuous_enable(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1097,7 +1126,7 @@ rte_eth_promiscuous_disable(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1113,7 +1142,7 @@ rte_eth_promiscuous_get(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -1;
 	}
@@ -1127,7 +1156,7 @@ rte_eth_allmulticast_enable(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1143,7 +1172,7 @@ rte_eth_allmulticast_disable(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1159,7 +1188,7 @@ rte_eth_allmulticast_get(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -1;
 	}
@@ -1187,7 +1216,7 @@ rte_eth_link_get(uint8_t port_id, struct rte_eth_link *eth_link)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1207,7 +1236,7 @@ rte_eth_link_get_nowait(uint8_t port_id, struct rte_eth_link *eth_link)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1227,7 +1256,7 @@ rte_eth_stats_get(uint8_t port_id, struct rte_eth_stats *stats)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1244,7 +1273,7 @@ rte_eth_stats_reset(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1265,7 +1294,7 @@ rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstats *xstats,
 	uint64_t val;
 	char *stats_ptr;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -1;
 	}
@@ -1334,7 +1363,7 @@ rte_eth_xstats_reset(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1356,7 +1385,7 @@ set_queue_stats_mapping(uint8_t port_id, uint16_t queue_id, uint8_t stat_idx,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -1391,7 +1420,7 @@ rte_eth_dev_info_get(uint8_t port_id, struct rte_eth_dev_info *dev_info)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1411,7 +1440,7 @@ rte_eth_macaddr_get(uint8_t port_id, struct ether_addr *mac_addr)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1425,7 +1454,7 @@ rte_eth_dev_get_mtu(uint8_t port_id, uint16_t *mtu)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1441,7 +1470,7 @@ rte_eth_dev_set_mtu(uint8_t port_id, uint16_t mtu)
 	int ret;
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1461,7 +1490,7 @@ rte_eth_dev_vlan_filter(uint8_t port_id, uint16_t vlan_id, int on)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1486,7 +1515,7 @@ rte_eth_dev_set_vlan_strip_on_queue(uint8_t port_id, uint16_t rx_queue_id, int o
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1508,7 +1537,7 @@ rte_eth_dev_set_vlan_ether_type(uint8_t port_id, uint16_t tpid)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1528,7 +1557,7 @@ rte_eth_dev_set_vlan_offload(uint8_t port_id, int offload_mask)
 	int mask = 0;
 	int cur, org = 0;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1573,7 +1602,7 @@ rte_eth_dev_get_vlan_offload(uint8_t port_id)
 	struct rte_eth_dev *dev;
 	int ret = 0;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1597,7 +1626,7 @@ rte_eth_dev_set_vlan_pvid(uint8_t port_id, uint16_t pvid, int on)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1615,7 +1644,7 @@ rte_eth_dev_fdir_add_signature_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1649,7 +1678,7 @@ rte_eth_dev_fdir_update_signature_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1683,7 +1712,7 @@ rte_eth_dev_fdir_remove_signature_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1714,7 +1743,7 @@ rte_eth_dev_fdir_get_infos(uint8_t port_id, struct rte_eth_fdir *fdir)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1739,7 +1768,7 @@ rte_eth_dev_fdir_add_perfect_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1779,7 +1808,7 @@ rte_eth_dev_fdir_update_perfect_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1817,7 +1846,7 @@ rte_eth_dev_fdir_remove_perfect_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1853,7 +1882,7 @@ rte_eth_dev_fdir_set_masks(uint8_t port_id, struct rte_fdir_masks *fdir_mask)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1873,7 +1902,7 @@ rte_eth_dev_flow_ctrl_get(uint8_t port_id, struct rte_eth_fc_conf *fc_conf)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1889,7 +1918,7 @@ rte_eth_dev_flow_ctrl_set(uint8_t port_id, struct rte_eth_fc_conf *fc_conf)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1909,7 +1938,7 @@ rte_eth_dev_priority_flow_ctrl_set(uint8_t port_id, struct rte_eth_pfc_conf *pfc
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1933,7 +1962,7 @@ rte_eth_dev_rss_reta_update(uint8_t port_id, struct rte_eth_rss_reta *reta_conf)
 	uint16_t max_rxq;
 	uint8_t i,j;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1985,7 +2014,7 @@ rte_eth_dev_rss_reta_query(uint8_t port_id, struct rte_eth_rss_reta *reta_conf)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2006,7 +2035,7 @@ rte_eth_dev_rss_hash_update(uint8_t port_id, struct rte_eth_rss_conf *rss_conf)
 	struct rte_eth_dev *dev;
 	uint16_t rss_hash_protos;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2028,7 +2057,7 @@ rte_eth_dev_rss_hash_conf_get(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2043,7 +2072,7 @@ rte_eth_dev_udp_tunnel_add(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -2069,7 +2098,7 @@ rte_eth_dev_udp_tunnel_delete(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -2094,7 +2123,7 @@ rte_eth_led_on(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2109,7 +2138,7 @@ rte_eth_led_off(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2149,7 +2178,7 @@ rte_eth_dev_mac_addr_add(uint8_t port_id, struct ether_addr *addr,
 	int index;
 	uint64_t pool_mask;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2200,7 +2229,7 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 	struct rte_eth_dev *dev;
 	int index;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2231,7 +2260,7 @@ rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 	struct rte_eth_dev *dev;
 	struct rte_eth_dev_info dev_info;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("set VF RX mode:Invalid port_id=%d\n",
 				port_id);
 		return (-ENODEV);
@@ -2286,7 +2315,7 @@ rte_eth_dev_uc_hash_table_set(uint8_t port_id, struct ether_addr *addr,
 	int ret;
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("unicast hash setting:Invalid port_id=%d\n",
 			port_id);
 		return (-ENODEV);
@@ -2339,7 +2368,7 @@ rte_eth_dev_uc_all_hash_table_set(uint8_t port_id, uint8_t on)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("unicast hash setting:Invalid port_id=%d\n",
 			port_id);
 		return (-ENODEV);
@@ -2358,7 +2387,7 @@ rte_eth_dev_set_vf_rx(uint8_t port_id,uint16_t vf, uint8_t on)
 	struct rte_eth_dev *dev;
 	struct rte_eth_dev_info dev_info;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2384,7 +2413,7 @@ rte_eth_dev_set_vf_tx(uint8_t port_id,uint16_t vf, uint8_t on)
 	struct rte_eth_dev *dev;
 	struct rte_eth_dev_info dev_info;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("set pool tx:Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2409,7 +2438,7 @@ rte_eth_dev_set_vf_vlan_filter(uint8_t port_id, uint16_t vlan_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("VF VLAN filter:invalid port id=%d\n",
 				port_id);
 		return (-ENODEV);
@@ -2440,7 +2469,7 @@ int rte_eth_set_queue_rate_limit(uint8_t port_id, uint16_t queue_idx,
 	struct rte_eth_dev_info dev_info;
 	struct rte_eth_link link;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("set queue rate limit:invalid port id=%d\n",
 				port_id);
 		return -ENODEV;
@@ -2477,7 +2506,7 @@ int rte_eth_set_vf_rate_limit(uint8_t port_id, uint16_t vf, uint16_t tx_rate,
 	if (q_msk == 0)
 		return 0;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("set VF rate limit:invalid port id=%d\n",
 				port_id);
 		return -ENODEV;
@@ -2511,7 +2540,7 @@ rte_eth_mirror_rule_set(uint8_t port_id,
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2552,7 +2581,7 @@ rte_eth_mirror_rule_reset(uint8_t port_id, uint8_t rule_id)
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2577,7 +2606,7 @@ rte_eth_rx_burst(uint8_t port_id, uint16_t queue_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return 0;
 	}
@@ -2597,7 +2626,7 @@ rte_eth_tx_burst(uint8_t port_id, uint16_t queue_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return 0;
 	}
@@ -2617,7 +2646,7 @@ rte_eth_rx_queue_count(uint8_t port_id, uint16_t queue_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return 0;
 	}
@@ -2631,7 +2660,7 @@ rte_eth_rx_descriptor_done(uint8_t port_id, uint16_t queue_id, uint16_t offset)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2652,7 +2681,7 @@ rte_eth_dev_callback_register(uint8_t port_id,
 
 	if (!cb_fn)
 		return (-EINVAL);
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -2692,7 +2721,7 @@ rte_eth_dev_callback_unregister(uint8_t port_id,
 
 	if (!cb_fn)
 		return (-EINVAL);
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -2752,7 +2781,7 @@ int rte_eth_dev_bypass_init(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2772,7 +2801,7 @@ rte_eth_dev_bypass_state_show(uint8_t port_id, uint32_t *state)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2791,7 +2820,7 @@ rte_eth_dev_bypass_state_set(uint8_t port_id, uint32_t *new_state)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2811,7 +2840,7 @@ rte_eth_dev_bypass_event_show(uint8_t port_id, uint32_t event, uint32_t *state)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2831,7 +2860,7 @@ rte_eth_dev_bypass_event_store(uint8_t port_id, uint32_t event, uint32_t state)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2851,7 +2880,7 @@ rte_eth_dev_wd_timeout_store(uint8_t port_id, uint32_t timeout)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2871,7 +2900,7 @@ rte_eth_dev_bypass_ver_show(uint8_t port_id, uint32_t *ver)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2891,7 +2920,7 @@ rte_eth_dev_bypass_wd_timeout_show(uint8_t port_id, uint32_t *wd_timeout)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2911,7 +2940,7 @@ rte_eth_dev_bypass_wd_reset(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2933,7 +2962,7 @@ rte_eth_dev_add_syn_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -2948,7 +2977,7 @@ rte_eth_dev_remove_syn_filter(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -2967,7 +2996,7 @@ rte_eth_dev_get_syn_filter(uint8_t port_id,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -2983,7 +3012,7 @@ rte_eth_dev_add_ethertype_filter(uint8_t port_id, uint16_t index,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3004,7 +3033,7 @@ rte_eth_dev_remove_ethertype_filter(uint8_t port_id,  uint16_t index)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3023,7 +3052,7 @@ rte_eth_dev_get_ethertype_filter(uint8_t port_id, uint16_t index,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3040,7 +3069,7 @@ rte_eth_dev_add_2tuple_filter(uint8_t port_id, uint16_t index,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3062,7 +3091,7 @@ rte_eth_dev_remove_2tuple_filter(uint8_t port_id, uint16_t index)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3081,7 +3110,7 @@ rte_eth_dev_get_2tuple_filter(uint8_t port_id, uint16_t index,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3097,7 +3126,7 @@ rte_eth_dev_add_5tuple_filter(uint8_t port_id, uint16_t index,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3120,7 +3149,7 @@ rte_eth_dev_remove_5tuple_filter(uint8_t port_id, uint16_t index)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3139,7 +3168,7 @@ rte_eth_dev_get_5tuple_filter(uint8_t port_id, uint16_t index,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3156,7 +3185,7 @@ rte_eth_dev_add_flex_filter(uint8_t port_id, uint16_t index,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3171,7 +3200,7 @@ rte_eth_dev_remove_flex_filter(uint8_t port_id, uint16_t index)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3190,7 +3219,7 @@ rte_eth_dev_get_flex_filter(uint8_t port_id, uint16_t index,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3206,7 +3235,7 @@ rte_eth_dev_filter_supported(uint8_t port_id, enum rte_filter_type filter_type)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3223,7 +3252,7 @@ rte_eth_dev_filter_ctrl(uint8_t port_id, enum rte_filter_type filter_type,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 8bf274d..5d3956a 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1534,6 +1534,7 @@ struct eth_dev_ops {
  * process, while the actual configuration data for the device is shared.
  */
 struct rte_eth_dev {
+	uint8_t attached; /**< Flag indicating the port is attached */
 	eth_rx_burst_t rx_pkt_burst; /**< Pointer to PMD receive function. */
 	eth_tx_burst_t tx_pkt_burst; /**< Pointer to PMD transmit function. */
 	struct rte_eth_dev_data *data;  /**< Pointer to device data */
@@ -1606,6 +1607,10 @@ extern struct rte_eth_dev rte_eth_devices[];
  * initialized by the [matching] Ethernet driver during the PCI probing phase.
  * All devices whose port identifier is in the range
  * [0,  rte_eth_dev_count() - 1] can be operated on by network applications.
+ * immediately after invoking rte_eal_init().
+ * If the application unplugs a port using hotplug function, The enabled port
+ * numbers may be noncontiguous. In the case, the applications need to manage
+ * enabled port by themselves.
  *
  * @return
  *   - The total number of usable Ethernet devices.
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 03/25] eal/pci: Replace pci address comparison code by eal_compare_pci_addr
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 01/25] eal/pci: Add a new flag indicating a driver can detach devices at runtime Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 02/25] ethdev: Remove assumption that port will not be detached Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29 16:28   ` Bruce Richardson
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 04/25] ethdev: Add rte_eth_dev_free to free specified device Tetsuya Mukawa
                   ` (25 subsequent siblings)
  28 siblings, 1 reply; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

This patch replaces pci_addr_comparison() and memcmp() of pci addresses by
eal_compare_pci_addr().

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/bsdapp/eal/eal_pci.c       | 16 +---------------
 lib/librte_eal/common/eal_common_pci.c    |  2 +-
 lib/librte_eal/common/include/rte_pci.h   | 29 +++++++++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c     | 16 +---------------
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c |  2 +-
 5 files changed, 33 insertions(+), 32 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 54fcaf0..2576fa7 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -270,20 +270,6 @@ pci_uio_map_resource(struct rte_pci_device *dev)
 	return (0);
 }
 
-/* Compare two PCI device addresses. */
-static int
-pci_addr_comparison(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
-{
-	uint64_t dev_addr = (addr->domain << 24) + (addr->bus << 16) + (addr->devid << 8) + addr->function;
-	uint64_t dev_addr2 = (addr2->domain << 24) + (addr2->bus << 16) + (addr2->devid << 8) + addr2->function;
-
-	if (dev_addr > dev_addr2)
-		return 1;
-	else
-		return 0;
-}
-
-
 /* Scan one pci sysfs entry, and fill the devices list from it. */
 static int
 pci_scan_one(int dev_pci_fd, struct pci_conf *conf)
@@ -358,7 +344,7 @@ pci_scan_one(int dev_pci_fd, struct pci_conf *conf)
 		struct rte_pci_device *dev2 = NULL;
 
 		TAILQ_FOREACH(dev2, &pci_device_list, next) {
-			if (pci_addr_comparison(&dev->addr, &dev2->addr))
+			if (eal_compare_pci_addr(&dev->addr, &dev2->addr))
 				continue;
 			else {
 				TAILQ_INSERT_BEFORE(dev2, dev, next);
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index f3c7f71..f01f258 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -93,7 +93,7 @@ static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
 		if (devargs->type != RTE_DEVTYPE_BLACKLISTED_PCI &&
 			devargs->type != RTE_DEVTYPE_WHITELISTED_PCI)
 			continue;
-		if (!memcmp(&dev->addr, &devargs->pci.addr, sizeof(dev->addr)))
+		if (eal_compare_pci_addr(&dev->addr, &devargs->pci.addr))
 			return devargs;
 	}
 	return NULL;
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index b819539..fe374a8 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -261,6 +261,35 @@ eal_parse_pci_DomBDF(const char *input, struct rte_pci_addr *dev_addr)
 }
 #undef GET_PCIADDR_FIELD
 
+/* Compare two PCI device addresses. */
+/**
+ * Utility function to compare two PCI device addresses.
+ *
+ * @param addr
+ *	The PCI Bus-Device-Function address to compare
+ * @param addr2
+ *	The PCI Bus-Device-Function address to compare
+ * @return
+ *  0 on equal PCI address.
+ *  Positive on addr is greater than addr2.
+ *  Negative on addr is less than addr2.
+ */
+static inline int
+eal_compare_pci_addr(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
+{
+	uint64_t dev_addr = (addr->domain << 24) + (addr->bus << 16) +
+					(addr->devid << 8) + addr->function;
+	uint64_t dev_addr2 = (addr2->domain << 24) + (addr2->bus << 16) +
+					(addr2->devid << 8) + addr2->function;
+
+	if (dev_addr > dev_addr2)
+		return 1;
+	else if (dev_addr < dev_addr2)
+		return -1;
+	else
+		return 0;
+}
+
 /**
  * Probe the PCI bus for registered drivers.
  *
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 5fe3961..862b93a 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -186,20 +186,6 @@ error:
 	return -1;
 }
 
-/* Compare two PCI device addresses. */
-static int
-pci_addr_comparison(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
-{
-	uint64_t dev_addr = (addr->domain << 24) + (addr->bus << 16) + (addr->devid << 8) + addr->function;
-	uint64_t dev_addr2 = (addr2->domain << 24) + (addr2->bus << 16) + (addr2->devid << 8) + addr2->function;
-
-	if (dev_addr > dev_addr2)
-		return 1;
-	else
-		return 0;
-}
-
-
 /* 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,
@@ -292,7 +278,7 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
 		struct rte_pci_device *dev2 = NULL;
 
 		TAILQ_FOREACH(dev2, &pci_device_list, next) {
-			if (pci_addr_comparison(&dev->addr, &dev2->addr))
+			if (eal_compare_pci_addr(&dev->addr, &dev2->addr) != 0)
 				continue;
 			else {
 				TAILQ_INSERT_BEFORE(dev2, dev, next);
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
index 7e62266..f0deeba 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
@@ -120,7 +120,7 @@ pci_uio_map_secondary(struct rte_pci_device *dev)
 	TAILQ_FOREACH(uio_res, pci_res_list, next) {
 
 		/* skip this element if it doesn't match our PCI address */
-		if (memcmp(&uio_res->pci_addr, &dev->addr, sizeof(dev->addr)))
+		if (eal_compare_pci_addr(&uio_res->pci_addr, &dev->addr))
 			continue;
 
 		for (i = 0; i != uio_res->nb_maps; i++) {
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 04/25] ethdev: Add rte_eth_dev_free to free specified device
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (2 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 03/25] eal/pci: Replace pci address comparison code by eal_compare_pci_addr Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 05/25] eal, ethdev: Add function pointer for closing a device Tetsuya Mukawa
                   ` (24 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

This patch adds rte_eth_dev_free(). The function is used for changing a
attached status of the device that has specified name.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 16 ++++++++++++++++
 lib/librte_ether/rte_ethdev.h | 11 +++++++++++
 2 files changed, 27 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 93d5a42..aea6627 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -247,6 +247,22 @@ rte_eth_dev_allocate(const char *name)
 	return eth_dev;
 }
 
+struct rte_eth_dev *
+rte_eth_dev_free(const char *name)
+{
+	struct rte_eth_dev *eth_dev;
+
+	eth_dev = rte_eth_dev_allocated(name);
+	if (eth_dev == NULL) {
+		PMD_DEBUG_TRACE("Ethernet Device with name %s doesn't exist!\n",
+				name);
+		return NULL;
+	}
+
+	eth_dev->attached = 0;
+	return eth_dev;
+}
+
 static int
 rte_eth_dev_init(struct rte_pci_driver *pci_drv,
 		 struct rte_pci_device *pci_dev)
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 5d3956a..dfaeaee 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1629,6 +1629,17 @@ extern uint8_t rte_eth_dev_count(void);
  */
 struct rte_eth_dev *rte_eth_dev_allocate(const char *name);
 
+/**
+ * Function for internal use by dummy drivers primarily, e.g. ring-based
+ * driver.
+ * Free the specified ethdev and returns the pointer to that slot.
+ *
+ * @param	name	Unique identifier name for each Ethernet device
+ * @return
+ *   - Slot in the rte_dev_devices array for the freed device;
+ */
+struct rte_eth_dev *rte_eth_dev_free(const char *name);
+
 struct eth_driver;
 /**
  * @internal
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 05/25] eal, ethdev: Add function pointer for closing a device
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (3 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 04/25] ethdev: Add rte_eth_dev_free to free specified device Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 06/25] ethdev: Add rte_eth_dev_shutdown for closing PCI devices Tetsuya Mukawa
                   ` (23 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch adds function pointer to rte_pci_driver and eth_driver
structure. These function pointers are used when ports are detached.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/include/rte_pci.h | 7 +++++++
 lib/librte_ether/rte_ethdev.h           | 4 ++++
 2 files changed, 11 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index fe374a8..74720d1 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -181,12 +181,19 @@ struct rte_pci_driver;
 typedef int (pci_devinit_t)(struct rte_pci_driver *, struct rte_pci_device *);
 
 /**
+ * Shutdown function for the driver called during hotplugging.
+ */
+typedef int (pci_devshutdown_t)(
+		struct rte_pci_driver *, struct rte_pci_device *);
+
+/**
  * A structure describing a PCI driver.
  */
 struct rte_pci_driver {
 	TAILQ_ENTRY(rte_pci_driver) next;       /**< Next in list. */
 	const char *name;                       /**< Driver name. */
 	pci_devinit_t *devinit;                 /**< Device init. function. */
+	pci_devshutdown_t *devshutdown;         /**< Device shutdown function. */
 	struct rte_pci_id *id_table;            /**< ID table, NULL terminated. */
 	uint32_t drv_flags;                     /**< Flags contolling handling of device. */
 };
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index dfaeaee..99cc8ce 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1676,6 +1676,9 @@ struct eth_driver;
 typedef int (*eth_dev_init_t)(struct eth_driver  *eth_drv,
 			      struct rte_eth_dev *eth_dev);
 
+typedef int (*eth_dev_shutdown_t)(struct eth_driver  *eth_drv,
+				  struct rte_eth_dev *eth_dev);
+
 /**
  * @internal
  * The structure associated with a PMD Ethernet driver.
@@ -1692,6 +1695,7 @@ typedef int (*eth_dev_init_t)(struct eth_driver  *eth_drv,
 struct eth_driver {
 	struct rte_pci_driver pci_drv;    /**< The PMD is also a PCI driver. */
 	eth_dev_init_t eth_dev_init;      /**< Device init function. */
+	eth_dev_shutdown_t eth_dev_shutdown;/**< Device shutdown function. */
 	unsigned int dev_private_size;    /**< Size of device private data. */
 };
 
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 06/25] ethdev: Add rte_eth_dev_shutdown for closing PCI devices.
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (4 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 05/25] eal, ethdev: Add function pointer for closing a device Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 07/25] ethdev: Add functions to know which port is attached or detached Tetsuya Mukawa
                   ` (22 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

rte_eth_dev_shutdown() is called when PCI device is closed.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index aea6627..752e3e4 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -317,6 +317,42 @@ rte_eth_dev_init(struct rte_pci_driver *pci_drv,
 	return diag;
 }
 
+static int
+rte_eth_dev_shutdown(struct rte_pci_driver *pci_drv,
+		 struct rte_pci_device *pci_dev)
+{
+	struct eth_driver *eth_drv;
+	struct rte_eth_dev *eth_dev;
+	char ethdev_name[RTE_ETH_NAME_MAX_LEN];
+
+	/* Create unique Ethernet device name using PCI address */
+	snprintf(ethdev_name, RTE_ETH_NAME_MAX_LEN, "%d:%d.%d",
+			pci_dev->addr.bus, pci_dev->addr.devid,
+			pci_dev->addr.function);
+
+	eth_dev = rte_eth_dev_free(ethdev_name);
+	if (eth_dev == NULL)
+		return -ENODEV;
+
+	eth_drv = (struct eth_driver *)pci_drv;
+
+	/* Invoke PMD device shutdown function */
+	if (*eth_drv->eth_dev_shutdown)
+		(*eth_drv->eth_dev_shutdown)(eth_drv, eth_dev);
+
+	/* init user callbacks */
+	TAILQ_INIT(&(eth_dev->callbacks));
+
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+		rte_free(eth_dev->data->dev_private);
+
+	eth_dev->pci_dev = NULL;
+	eth_dev->driver = NULL;
+	eth_dev->data = NULL;
+
+	return 0;
+}
+
 /**
  * Register an Ethernet [Poll Mode] driver.
  *
@@ -335,6 +371,7 @@ void
 rte_eth_driver_register(struct eth_driver *eth_drv)
 {
 	eth_drv->pci_drv.devinit = rte_eth_dev_init;
+	eth_drv->pci_drv.devshutdown = rte_eth_dev_shutdown;
 	rte_eal_pci_register(&eth_drv->pci_drv);
 }
 
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 07/25] ethdev: Add functions to know which port is attached or detached
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (5 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 06/25] ethdev: Add rte_eth_dev_shutdown for closing PCI devices Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 08/25] ethdev: Add rte_eth_dev_get_addr_by_port Tetsuya Mukawa
                   ` (21 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch adds rte_eth_dev_save() and rte_eth_dev_get_changed_port().
rte_eth_dev_save() is used for saving current rte_eth_dev structures.
rte_eth_dev_get_changed_port() receives the rte_eth_dev structures, then
compare these with current values to know which port is actually
attached or detached.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 18 ++++++++++++++++++
 lib/librte_ether/rte_ethdev.h | 21 +++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 752e3e4..d296285 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -404,6 +404,24 @@ rte_eth_dev_count(void)
 	return nb_ports;
 }
 
+void
+rte_eth_dev_save(struct rte_eth_dev *devs)
+{
+	/* save current rte_eth_devices */
+	memcpy(devs, rte_eth_devices,
+			sizeof(struct rte_eth_dev) * RTE_MAX_ETHPORTS);
+}
+
+int
+rte_eth_dev_get_changed_port(struct rte_eth_dev *devs, uint8_t *port_id)
+{
+	/* check which port was attached or detached */
+	for (*port_id = 0; *port_id < RTE_MAX_ETHPORTS; (*port_id)++, devs++)
+		if (rte_eth_devices[*port_id].attached ^ devs->attached)
+			return 0;
+	return 1;
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 99cc8ce..106ba5c 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1618,6 +1618,27 @@ extern struct rte_eth_dev rte_eth_devices[];
 extern uint8_t rte_eth_dev_count(void);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Copies current ethdev structures to the specified pointer.
+ *
+ * @param	devs	The pointer to the ethdev structures
+ */
+extern void rte_eth_dev_save(struct rte_eth_dev *devs);
+
+/**
+ * Function for internal use by port hotplug functions.
+ * Compare the specified ethdev structures with currrents. Then
+ * if there is a port which status is changed, fill the specified pointer
+ * with the port id of that port.
+ * @param	devs	The pointer to the ethdev structures
+ * @param	port_id	The pointer to the port id
+ * @return
+ *   - 0 on success, negative on error
+ */
+extern int rte_eth_dev_get_changed_port(
+		struct rte_eth_dev *devs, uint8_t *port_id);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 08/25] ethdev: Add rte_eth_dev_get_addr_by_port
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (6 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 07/25] ethdev: Add functions to know which port is attached or detached Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 09/25] ethdev: Add rte_eth_dev_get_port_by_addr Tetsuya Mukawa
                   ` (20 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The function returns a pci address of a ethdev specified by port
identifier.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 12 ++++++++++++
 lib/librte_ether/rte_ethdev.h | 13 +++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index d296285..c04061d 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -422,6 +422,18 @@ rte_eth_dev_get_changed_port(struct rte_eth_dev *devs, uint8_t *port_id)
 	return 1;
 }
 
+int
+rte_eth_dev_get_addr_by_port(uint8_t port_id, struct rte_pci_addr *addr)
+{
+	if (rte_eth_dev_validate_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return 1;
+	}
+
+	*addr = rte_eth_devices[port_id].pci_dev->addr;
+	return 0;
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 106ba5c..e87e7cc 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1639,6 +1639,19 @@ extern int rte_eth_dev_get_changed_port(
 		struct rte_eth_dev *devs, uint8_t *port_id);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Returns a pci address of a ethdev specified by port identifier.
+ * @param	port_id
+ *   The port identifier of the Ethernet device
+ * @param	addr
+ *   The pointer to the pci address
+ * @return
+ *   - 0 on success, negative on error
+ */
+extern int rte_eth_dev_get_addr_by_port(
+		uint8_t port_id, struct rte_pci_addr *addr);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 09/25] ethdev: Add rte_eth_dev_get_port_by_addr
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (7 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 08/25] ethdev: Add rte_eth_dev_get_addr_by_port Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 10/25] ethdev: Add rte_eth_dev_get_name_by_port Tetsuya Mukawa
                   ` (19 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The function returns a port identifier of a ethdev specified by pci
address.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 13 +++++++++++++
 lib/librte_ether/rte_ethdev.h | 13 +++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index c04061d..fb3094a 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -434,6 +434,19 @@ rte_eth_dev_get_addr_by_port(uint8_t port_id, struct rte_pci_addr *addr)
 	return 0;
 }
 
+int
+rte_eth_dev_get_port_by_addr(struct rte_pci_addr *addr, uint8_t *port_id)
+{
+	struct rte_pci_addr *tmp;
+
+	for (*port_id = 0; *port_id < RTE_MAX_ETHPORTS; (*port_id)++) {
+		tmp = &rte_eth_devices[*port_id].pci_dev->addr;
+		if (eal_compare_pci_addr(tmp, addr))
+			return 0;
+	}
+	return -1;
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index e87e7cc..8a9d1d5 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1652,6 +1652,19 @@ extern int rte_eth_dev_get_addr_by_port(
 		uint8_t port_id, struct rte_pci_addr *addr);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Returns a port identifier of a ethdev specified by pci address.
+ * @param	addr
+ *   The pointer to the pci address of the Ethernet device.
+ * @param	port_id
+ *   The pointer to the port identifier
+ * @return
+ *   - 0 on success, negative on error
+ */
+extern int rte_eth_dev_get_port_by_addr(
+		struct rte_pci_addr *addr, uint8_t *port_id);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 10/25] ethdev: Add rte_eth_dev_get_name_by_port
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (8 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 09/25] ethdev: Add rte_eth_dev_get_port_by_addr Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 11/25] ethdev: Add rte_eth_dev_check_detachable Tetsuya Mukawa
                   ` (18 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The function returns a unique identifier name of a ethdev specified by
port identifier.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 17 +++++++++++++++++
 lib/librte_ether/rte_ethdev.h | 12 ++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index fb3094a..dea28c2 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -447,6 +447,23 @@ rte_eth_dev_get_port_by_addr(struct rte_pci_addr *addr, uint8_t *port_id)
 	return -1;
 }
 
+int
+rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
+{
+	char *tmp;
+
+	if (rte_eth_dev_validate_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return 1;
+	}
+
+	/* shouldn't check 'rte_eth_devices[i].data',
+	 * because it might be overwritten by VDEV PMD */
+	tmp = rte_eth_dev_data[port_id].name;
+	strncpy(name, tmp, strlen(tmp) + 1);
+	return 0;
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 8a9d1d5..11853f5 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1665,6 +1665,18 @@ extern int rte_eth_dev_get_port_by_addr(
 		struct rte_pci_addr *addr, uint8_t *port_id);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Returns a unique identifier name of a ethdev specified by port identifier.
+ * @param	port_id
+ *   The port identifier.
+ * @param	name
+ *  The pointer to the Unique identifier name for each Ethernet device
+ * @return
+ *   - 0 on success, negative on error
+ */
+extern int rte_eth_dev_get_name_by_port(uint8_t port_id, char *name);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 11/25] ethdev: Add rte_eth_dev_check_detachable
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (9 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 10/25] ethdev: Add rte_eth_dev_get_name_by_port Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 12/25] ethdev: Change scope of rte_eth_dev_allocated to global Tetsuya Mukawa
                   ` (17 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The function returns whether a PMD supports detach function, or not.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c |  9 +++++++++
 lib/librte_ether/rte_ethdev.h | 11 +++++++++++
 2 files changed, 20 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index dea28c2..92a846a 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -464,6 +464,15 @@ rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
 	return 0;
 }
 
+int
+rte_eth_dev_check_detachable(uint8_t port_id)
+{
+	uint32_t drv_flags;
+
+	drv_flags = rte_eth_devices[port_id].driver->pci_drv.drv_flags;
+	return !!(drv_flags & RTE_PCI_DRV_DETACHABLE);
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 11853f5..5cc438c 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1677,6 +1677,17 @@ extern int rte_eth_dev_get_port_by_addr(
 extern int rte_eth_dev_get_name_by_port(uint8_t port_id, char *name);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Check whether or not, a PMD that is handling the ethdev specified by port
+ * identifier can support detach function.
+ * @param	port_id
+ *   The port identifier
+ * @return
+ *   - 0 on supporting detach function, negative on not supporting
+ */
+extern int rte_eth_dev_check_detachable(uint8_t port_id);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 12/25] ethdev: Change scope of rte_eth_dev_allocated to global
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (10 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 11/25] ethdev: Add rte_eth_dev_check_detachable Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 13/25] eal/pci: Prevent double registration for devargs_list Tetsuya Mukawa
                   ` (16 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

This function is used by virtual PMDs to support port hotplug framework.
So change scope of the function to global.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c |  2 +-
 lib/librte_ether/rte_ethdev.h | 10 ++++++++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 92a846a..9a71e9d 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -195,7 +195,7 @@ rte_eth_dev_data_alloc(void)
 				RTE_MAX_ETHPORTS * sizeof(*rte_eth_dev_data));
 }
 
-static struct rte_eth_dev *
+struct rte_eth_dev *
 rte_eth_dev_allocated(const char *name)
 {
 	unsigned i;
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 5cc438c..c3e8ff8 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1688,6 +1688,16 @@ extern int rte_eth_dev_get_name_by_port(uint8_t port_id, char *name);
 extern int rte_eth_dev_check_detachable(uint8_t port_id);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Returns a ethdev slot specified by the unique identifier name.
+ * @param	name
+ *  The pointer to the Unique identifier name for each Ethernet device
+ * @return
+ *   - The pointer to the ethdev slot, on success. NULL on error
+ */
+extern struct rte_eth_dev *rte_eth_dev_allocated(const char *name);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 13/25] eal/pci: Prevent double registration for devargs_list
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (11 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 12/25] ethdev: Change scope of rte_eth_dev_allocated to global Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 14/25] eal/pci: Add rte_eal_devargs_remove Tetsuya Mukawa
                   ` (15 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch fixes rte_eal_devargs_add() not to register same device twice.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_devargs.c | 32 ++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index 4c7d11a..aaa6901 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -44,6 +44,32 @@
 struct rte_devargs_list devargs_list =
 	TAILQ_HEAD_INITIALIZER(devargs_list);
 
+
+/* find a entry specified by pci address or device name */
+static struct rte_devargs *
+rte_eal_devargs_find(enum rte_devtype devtype, void *args)
+{
+	struct rte_devargs *devargs;
+
+	TAILQ_FOREACH(devargs, &devargs_list, next) {
+		switch (devtype) {
+		case RTE_DEVTYPE_WHITELISTED_PCI:
+		case RTE_DEVTYPE_BLACKLISTED_PCI:
+			if (eal_compare_pci_addr(&devargs->pci.addr, args) == 0)
+				goto found;
+			break;
+		case RTE_DEVTYPE_VIRTUAL:
+			if (memcmp(&devargs->virtual.drv_name, args,
+					strlen((char *)args)) == 0)
+				goto found;
+			break;
+		}
+	}
+	return NULL;
+found:
+	return devargs;
+}
+
 /* store a whitelist parameter for later parsing */
 int
 rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str)
@@ -101,6 +127,12 @@ rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str)
 		break;
 	}
 
+	/* make sure there is no same entry */
+	if (rte_eal_devargs_find(devtype, &devargs->pci.addr)) {
+		RTE_LOG(ERR, EAL, "device already registered: <%s>\n", buf);
+		return -1;
+	}
+
 	TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
 	return 0;
 }
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 14/25] eal/pci: Add rte_eal_devargs_remove
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (12 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 13/25] eal/pci: Prevent double registration for devargs_list Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 15/25] eal/pci: Add probe and close function for virtual drivers Tetsuya Mukawa
                   ` (14 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The function removes a specified devargs from devargs_list.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_devargs.c  | 13 +++++++++++++
 lib/librte_eal/common/include/rte_devargs.h | 18 ++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index aaa6901..0916cf8 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -137,6 +137,19 @@ rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str)
 	return 0;
 }
 
+/* remove it from the devargs_list */
+void
+rte_eal_devargs_remove(enum rte_devtype devtype, void *args)
+{
+	struct rte_devargs *devargs;
+
+	devargs = rte_eal_devargs_find(devtype, args);
+	if (devargs == NULL)
+		return;
+
+	TAILQ_REMOVE(&devargs_list, devargs, next);
+}
+
 /* count the number of devices of a specified type */
 unsigned int
 rte_eal_devargs_type_count(enum rte_devtype devtype)
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
index 9f9c98f..57842b3 100644
--- a/lib/librte_eal/common/include/rte_devargs.h
+++ b/lib/librte_eal/common/include/rte_devargs.h
@@ -123,6 +123,24 @@ extern struct rte_devargs_list devargs_list;
 int rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str);
 
 /**
+ * Remove a device form the user device list
+ *
+ * For PCI devices, the format of arguments string is "PCI_ADDR". It shouldn't
+ * involves parameters for the device. Example: "08:00.1".
+ *
+ * For virtual devices, the format of arguments string is "DRIVER_NAME*". It
+ * shouldn't involves parameters for the device. Example: "eth_ring". The
+ * validity of the driver name is not checked by this function, it is done
+ * when closing the drivers.
+ *
+ * @param devtype
+ *   The type of the device.
+ * @param name
+ *   The name of the device.
+ */
+void rte_eal_devargs_remove(enum rte_devtype devtype, void *args);
+
+/**
  * Count the number of user devices of a specified type
  *
  * @param devtype
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 15/25] eal/pci: Add probe and close function for virtual drivers
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (13 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 14/25] eal/pci: Add rte_eal_devargs_remove Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 16/25] eal/pci: Add port hotplug functions for virtual devices Tetsuya Mukawa
                   ` (13 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch adds rte_eal_dev_init_one() and rte_eal_dev_close_one().
These are used for attaching and detaching virtual devices.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_dev.c  | 74 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h |  6 +++
 lib/librte_eal/linuxapp/eal/Makefile    |  1 +
 3 files changed, 81 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index eae5656..183d65b 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -32,10 +32,13 @@
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <stdio.h>
+#include <limits.h>
 #include <string.h>
 #include <inttypes.h>
 #include <sys/queue.h>
 
+#include <rte_ethdev.h>
 #include <rte_dev.h>
 #include <rte_devargs.h>
 #include <rte_debug.h>
@@ -107,3 +110,74 @@ rte_eal_dev_init(void)
 	}
 	return 0;
 }
+
+/* So far, linux only supports DPDK hotplug function. */
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+
+#define INVOKE_PROBE	(0)
+#define INVOKE_CLOSE	(1)
+
+static void
+rte_eal_dev_invoke(struct rte_driver *driver,
+		struct rte_devargs *devargs, int type)
+{
+	switch (type) {
+	case INVOKE_PROBE:
+		driver->init(devargs->virtual.drv_name, devargs->args);
+		break;
+	case INVOKE_CLOSE:
+		driver->close(devargs->virtual.drv_name, devargs->args);
+		break;
+	}
+}
+
+static int
+rte_eal_dev_find_and_invoke(const char *name, int type)
+{
+	struct rte_devargs *devargs;
+	struct rte_driver *driver;
+
+	/* call the init function for each virtual device */
+	TAILQ_FOREACH(devargs, &devargs_list, next) {
+
+		if (devargs->type != RTE_DEVTYPE_VIRTUAL)
+			continue;
+
+		if (strncmp(name, devargs->virtual.drv_name, strlen(name)))
+			continue;
+
+		TAILQ_FOREACH(driver, &dev_driver_list, next) {
+			if (driver->type != PMD_VDEV)
+				continue;
+
+			/* search a driver prefix in virtual device name */
+			if (!strncmp(driver->name, devargs->virtual.drv_name,
+					strlen(driver->name))) {
+				rte_eal_dev_invoke(driver, devargs, type);
+				break;
+			}
+		}
+
+		if (driver == NULL) {
+			RTE_LOG(WARNING, EAL, "no driver found for %s\n",
+				  devargs->virtual.drv_name);
+		}
+		return 0;
+	}
+	return 1;
+}
+
+/* find and initialize the driver of specified virtual device */
+static int
+rte_eal_dev_init_one(const char *name)
+{
+	return rte_eal_dev_find_and_invoke(name, INVOKE_PROBE);
+}
+
+/* find and finalize the driver of specified virtual device */
+static int
+rte_eal_dev_close_one(const char *name)
+{
+	return rte_eal_dev_find_and_invoke(name, INVOKE_CLOSE);
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index f7e3a10..71d40c3 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -57,6 +57,11 @@ TAILQ_HEAD(rte_driver_list, rte_driver);
 typedef int (rte_dev_init_t)(const char *name, const char *args);
 
 /**
+ * Close function called for each device driver once.
+ */
+typedef int (rte_dev_close_t)(const char *name, const char *args);
+
+/**
  * Driver type enumeration
  */
 enum pmd_type {
@@ -72,6 +77,7 @@ struct rte_driver {
 	enum pmd_type type;		   /**< PMD Driver type */
 	const char *name;                   /**< Driver name. */
 	rte_dev_init_t *init;              /**< Device init. function. */
+	rte_dev_close_t *close;            /**< Device close. function. */
 };
 
 /**
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index c99433e..27e9b48 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -40,6 +40,7 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
 CFLAGS += -I$(RTE_SDK)/lib/librte_ring
 CFLAGS += -I$(RTE_SDK)/lib/librte_mempool
 CFLAGS += -I$(RTE_SDK)/lib/librte_malloc
+CFLAGS += -I$(RTE_SDK)/lib/librte_mbuf
 CFLAGS += -I$(RTE_SDK)/lib/librte_ether
 CFLAGS += -I$(RTE_SDK)/lib/librte_ivshmem
 CFLAGS += -I$(RTE_SDK)/lib/librte_pmd_ring
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 16/25] eal/pci: Add port hotplug functions for virtual devices.
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (14 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 15/25] eal/pci: Add probe and close function for virtual drivers Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 17/25] eal/linux/pci: Add functions for unmapping igb_uio resources Tetsuya Mukawa
                   ` (12 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch adds rte_eal_dev_attach_vdev() and rte_eal_dev_detach_vdev().

rte_eal_dev_attach_vdev() receives virtual device name and parameters,
and returns an attached port number.
rte_eal_dev_detach_vdev() receives a port number, and returns device
name actually detached.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_dev.c  | 76 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h | 29 +++++++++++++
 2 files changed, 105 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 183d65b..0518e3c 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -180,4 +180,80 @@ rte_eal_dev_close_one(const char *name)
 {
 	return rte_eal_dev_find_and_invoke(name, INVOKE_CLOSE);
 }
+
+static void
+get_vdev_name(char *vdevargs)
+{
+	char *sep;
+
+	/* set the first ',' to '\0' to split name and arguments */
+	sep = strchr(vdevargs, ',');
+	if (sep != NULL)
+		sep[0] = '\0';
+}
+
+/* attach the new virtual device, then store port_id of the device */
+int
+rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id)
+{
+	char *args;
+	uint8_t new_port_id;
+	struct rte_eth_dev devs[RTE_MAX_ETHPORTS];
+
+	args = strdup(vdevargs);
+	if (args == NULL)
+		return -1;
+
+	/* save current port status */
+	rte_eth_dev_save(devs);
+	/* add the vdevargs to devargs_list */
+	if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, args))
+		goto err0;
+	/* parse vdevargs, then retrieve device name */
+	get_vdev_name(args);
+	/* walk around dev_driver_list to find the driver of the device,
+	 * then invoke probe function o the driver */
+	if (rte_eal_dev_init_one(args))
+		goto err1;
+	/* get port_id enabled by above procedures */
+	if (rte_eth_dev_get_changed_port(devs, &new_port_id))
+		goto err1;
+
+	free(args);
+	*port_id = new_port_id;
+	return 0;
+err1:
+	rte_eal_devargs_remove(RTE_DEVTYPE_VIRTUAL, args);
+err0:
+	RTE_LOG(ERR, EAL, "Drver, cannot detach the device\n");
+	free(args);
+	return -1;
+}
+
+/* detach the new virtual device, then store the name of the device */
+int
+rte_eal_dev_detach_vdev(uint8_t port_id, char *vdevname)
+{
+	char name[RTE_ETH_NAME_MAX_LEN];
+
+	/* check whether the driver supports detach feature, or not */
+	if (!rte_eth_dev_check_detachable(port_id))
+		goto err;
+
+	/* get device name by port id */
+	if (rte_eth_dev_get_name_by_port(port_id, name))
+		goto err;
+	/* walk around dev_driver_list to find the driver of the device,
+	 * then invoke close function o the driver */
+	if (rte_eal_dev_close_one(name))
+		goto err;
+	/* remove the vdevname from devargs_list */
+	rte_eal_devargs_remove(RTE_DEVTYPE_VIRTUAL, name);
+
+	strncpy(vdevname, name, sizeof(name));
+	return 0;
+err:
+	RTE_LOG(ERR, EAL, "Drver, cannot detach the device\n");
+	return -1;
+}
 #endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 71d40c3..159d5a5 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -98,6 +98,35 @@ void rte_eal_driver_register(struct rte_driver *driver);
  */
 void rte_eal_driver_unregister(struct rte_driver *driver);
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+
+/**
+ * Attach a new virtual device.
+ *
+ * @param vdevargs
+ *   A pointer to a strings array describing the new device
+ *   to be attached.
+ * @param port_id
+ *  A pointer to a port identifier actually attached.
+ * @return
+ *  0 on success and port_id is filled, negative on error
+ */
+int rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id);
+
+/**
+ * Detach a virtual device.
+ *
+ * @param port_id
+ *   The port identifier of the virtual device to detach.
+ * @param addr
+ *  A pointer to a virtual device name actually detached.
+ * @return
+ *  0 on success and vdevname is filled, negative on error
+ */
+int rte_eal_dev_detach_vdev(uint8_t port_id, char *vdevname);
+
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /**
  * Initalize all the registered drivers in this process
  */
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 17/25] eal/linux/pci: Add functions for unmapping igb_uio resources
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (15 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 16/25] eal/pci: Add port hotplug functions for virtual devices Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 18/25] eal/pci: Prevent double registrations for pci_device_list Tetsuya Mukawa
                   ` (11 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch adds functions for unmapping igb_uio resources. The patch is only
for Linux and igb_uio environment. VFIO and BSD are not supported.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/linuxapp/eal/eal_pci.c              | 32 +++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c          | 56 ++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/include/eal_pci_init.h |  7 +++
 3 files changed, 95 insertions(+)

diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 862b93a..57a5887 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -123,6 +123,22 @@ fail:
 	return NULL;
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+/* unmap a particular resource */
+void
+pci_unmap_resource(void *requested_addr, size_t size)
+{
+	/* Unmap the PCI memory resource of device */
+	if (munmap(requested_addr, size)) {
+		RTE_LOG(ERR, EAL, "%s(): cannot munmap(%p, 0x%lx): %s\n",
+			__func__, requested_addr, (unsigned long)size,
+			strerror(errno));
+	} else
+		RTE_LOG(DEBUG, EAL, "  PCI memory mapped at %p\n",
+				requested_addr);
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /* parse the "resource" sysfs file */
 #define IORESOURCE_MEM  0x00000200
 
@@ -493,6 +509,22 @@ pci_map_device(struct rte_pci_device *dev)
 	return 0;
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+static void
+pci_unmap_device(struct rte_pci_device *dev)
+{
+	/* try unmapping the NIC resources using VFIO if it exists */
+#ifdef VFIO_PRESENT
+	if (pci_vfio_is_enabled()) {
+		RTE_LOG(ERR, EAL, "%s() doesn't support vfio yet.\n",
+				__func__);
+		return;
+	}
+#endif
+	pci_uio_unmap_resource(dev);
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /*
  * If vendor/device ID match, call the devinit() function of the
  * driver.
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
index f0deeba..ff48eb9 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
@@ -395,6 +395,62 @@ pci_uio_map_resource(struct rte_pci_device *dev)
 	return 0;
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+static void
+pci_uio_unmap(struct mapped_pci_resource *uio_res)
+{
+	int i;
+
+	for (i = 0; i != uio_res->nb_maps; i++)
+		pci_unmap_resource(uio_res->maps[i].addr,
+				(size_t)uio_res->maps[i].size);
+}
+
+static struct mapped_pci_resource *
+pci_uio_find_resource(struct rte_pci_device *dev)
+{
+	struct mapped_pci_resource *uio_res;
+
+	TAILQ_FOREACH(uio_res, pci_res_list, next) {
+
+		/* skip this element if it doesn't match our PCI address */
+		if (!eal_compare_pci_addr(&uio_res->pci_addr, &dev->addr))
+			return uio_res;
+	}
+	return NULL;
+}
+
+/* unmap the PCI resource of a PCI device in virtual memory */
+void
+pci_uio_unmap_resource(struct rte_pci_device *dev)
+{
+	struct mapped_pci_resource *uio_res;
+
+	/* find an entry for the device */
+	uio_res = pci_uio_find_resource(dev);
+	if (uio_res == NULL)
+		return;
+
+	/* secondary processes - just free maps */
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return pci_uio_unmap(uio_res);
+
+	TAILQ_REMOVE(pci_res_list, uio_res, next);
+
+	/* unmap all resources */
+	pci_uio_unmap(uio_res);
+
+	/* free uio resource */
+	rte_free(uio_res);
+
+	/* close fd if in primary process */
+	close(dev->intr_handle.fd);
+
+	dev->intr_handle.fd = -1;
+	dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /*
  * parse a sysfs file containing one integer value
  * different to the eal version, as it needs to work with 64-bit values
diff --git a/lib/librte_eal/linuxapp/eal/include/eal_pci_init.h b/lib/librte_eal/linuxapp/eal/include/eal_pci_init.h
index d758bee..ab9c16b 100644
--- a/lib/librte_eal/linuxapp/eal/include/eal_pci_init.h
+++ b/lib/librte_eal/linuxapp/eal/include/eal_pci_init.h
@@ -65,6 +65,13 @@ void *pci_map_resource(void *requested_addr, int fd, off_t offset,
 /* map IGB_UIO resource prototype */
 int pci_uio_map_resource(struct rte_pci_device *dev);
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+void pci_unmap_resource(void *requested_addr, size_t size);
+
+/* unmap IGB_UIO resource prototype */
+void pci_uio_unmap_resource(struct rte_pci_device *dev);
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 #ifdef VFIO_PRESENT
 
 #define VFIO_MAX_GROUPS 64
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 18/25] eal/pci: Prevent double registrations for pci_device_list
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (16 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 17/25] eal/linux/pci: Add functions for unmapping igb_uio resources Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 19/25] eal/pci: Change scope of rte_eal_pci_scan to global Tetsuya Mukawa
                   ` (10 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch fixes pci_scan_one() not to register same pci devices twice.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/linuxapp/eal/eal_pci.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 57a5887..c70e8ea 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -292,14 +292,17 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
 	}
 	else {
 		struct rte_pci_device *dev2 = NULL;
+		int ret;
 
 		TAILQ_FOREACH(dev2, &pci_device_list, next) {
-			if (eal_compare_pci_addr(&dev->addr, &dev2->addr) != 0)
+			ret = eal_compare_pci_addr(&dev->addr, &dev2->addr);
+			if (ret > 0)
 				continue;
-			else {
+			else if (ret < 0) {
 				TAILQ_INSERT_BEFORE(dev2, dev, next);
 				return 0;
-			}
+			} else	/* already registered */
+				return 0;
 		}
 		TAILQ_INSERT_TAIL(&pci_device_list, dev, next);
 	}
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 19/25] eal/pci: Change scope of rte_eal_pci_scan to global
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (17 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 18/25] eal/pci: Prevent double registrations for pci_device_list Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 20/25] eal/pci: Add rte_eal_pci_close_one_driver Tetsuya Mukawa
                   ` (9 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The function is called by port hotplug framework, so change scope of the
function to global.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/include/eal_private.h | 11 +++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c       |  6 +++---
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/common/include/eal_private.h b/lib/librte_eal/common/include/eal_private.h
index 232fcec..a1127ab 100644
--- a/lib/librte_eal/common/include/eal_private.h
+++ b/lib/librte_eal/common/include/eal_private.h
@@ -154,6 +154,17 @@ struct rte_pci_driver;
 struct rte_pci_device;
 
 /**
+ * Scan the content of the PCI bus, and the devices in the devices
+ * list
+ *
+ * This function is private to EAL.
+ *
+ * @return
+ *  0 on success, negative on error
+ */
+int rte_eal_pci_scan(void);
+
+/**
  * Mmap memory for single PCI device
  *
  * This function is private to EAL.
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index c70e8ea..4521c33 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -361,8 +361,8 @@ error:
  * Scan the content of the PCI bus, and the devices in the devices
  * list
  */
-static int
-pci_scan(void)
+int
+rte_eal_pci_scan(void)
 {
 	struct dirent *e;
 	DIR *dir;
@@ -612,7 +612,7 @@ rte_eal_pci_init(void)
 	if (internal_config.no_pci)
 		return 0;
 
-	if (pci_scan() < 0) {
+	if (rte_eal_pci_scan() < 0) {
 		RTE_LOG(ERR, EAL, "%s(): Cannot scan PCI bus\n", __func__);
 		return -1;
 	}
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 20/25] eal/pci: Add rte_eal_pci_close_one_driver
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (18 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 19/25] eal/pci: Change scope of rte_eal_pci_scan to global Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 21/25] eal/pci: Fix pci_probe_all_drivers to share code with closing function Tetsuya Mukawa
                   ` (8 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The function is used for closing the specified driver and device.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/include/eal_private.h | 11 ++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c       | 58 +++++++++++++++++++++++++++++
 2 files changed, 69 insertions(+)

diff --git a/lib/librte_eal/common/include/eal_private.h b/lib/librte_eal/common/include/eal_private.h
index a1127ab..b2776cc 100644
--- a/lib/librte_eal/common/include/eal_private.h
+++ b/lib/librte_eal/common/include/eal_private.h
@@ -176,6 +176,17 @@ int rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr,
 		struct rte_pci_device *dev);
 
 /**
+ * Munmap memory for single PCI device
+ *
+ * This function is private to EAL.
+ *
+ * @return
+ *   0 on success, negative on error
+ */
+int rte_eal_pci_close_one_driver(struct rte_pci_driver *dr,
+		struct rte_pci_device *dev);
+
+/**
  * Init tail queues for non-EAL library structures. This is to allow
  * the rings, mempools, etc. lists to be shared among multiple processes
  *
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 4521c33..5dd15af 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -599,6 +599,64 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d
 	return 1;
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+/*
+ * If vendor/device ID match, call the devshutdown() function of the
+ * driver.
+ */
+int
+rte_eal_pci_close_one_driver(struct rte_pci_driver *dr,
+		struct rte_pci_device *dev)
+{
+	struct rte_pci_id *id_table;
+
+	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;
+
+		RTE_LOG(DEBUG, EAL,
+				"PCI device "PCI_PRI_FMT" on NUMA socket %i\n",
+				loc->domain, loc->bus, loc->devid,
+				loc->function, dev->numa_node);
+
+		RTE_LOG(DEBUG, EAL, "  remove driver: %x:%x %s\n",
+				dev->id.vendor_id, dev->id.device_id,
+				dr->name);
+
+		/* call the driver devshutdown() function */
+		if (dr->devshutdown && (dr->devshutdown(dr, dev) < 0))
+			return -1;	/* negative value is an error */
+
+		/* clear driver structure */
+		dev->driver = NULL;
+
+		if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
+			/* unmap resources for devices that use igb_uio */
+			pci_unmap_device(dev);
+
+		return 0;
+	}
+	/* return positive value if driver is not found */
+	return 1;
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /* Init the PCI EAL subsystem */
 int
 rte_eal_pci_init(void)
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 21/25] eal/pci: Fix pci_probe_all_drivers to share code with closing function
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (19 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 20/25] eal/pci: Add rte_eal_pci_close_one_driver Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 22/25] eal/pci: Add pci_close_all_drivers Tetsuya Mukawa
                   ` (7 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

pci_close_all_drivers() will be implemented after the patch.
To share a part of code between thses 2 functions, The patch fixes
pci_probe_all_drivers() first.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_pci.c | 28 ++++++++++++++++++++--------
 1 file changed, 20 insertions(+), 8 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index f01f258..1e3efea 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -99,19 +99,20 @@ static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
 	return NULL;
 }
 
-/*
- * If vendor/device ID match, call the devinit() function of all
- * registered driver for the given device. Return -1 if initialization
- * failed, return 1 if no driver is found for this device.
- */
+#define INVOKE_PROBE	(0)
+
 static int
-pci_probe_all_drivers(struct rte_pci_device *dev)
+pci_invoke_all_drivers(struct rte_pci_device *dev, int type)
 {
 	struct rte_pci_driver *dr = NULL;
-	int rc;
+	int rc = 0;
 
 	TAILQ_FOREACH(dr, &pci_driver_list, next) {
-		rc = rte_eal_pci_probe_one_driver(dr, dev);
+		switch (type) {
+		case INVOKE_PROBE:
+			rc = rte_eal_pci_probe_one_driver(dr, dev);
+			break;
+		}
 		if (rc < 0)
 			/* negative value is an error */
 			return -1;
@@ -124,6 +125,17 @@ pci_probe_all_drivers(struct rte_pci_device *dev)
 }
 
 /*
+ * If vendor/device ID match, call the devinit() 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_probe_all_drivers(struct rte_pci_device *dev)
+{
+	return pci_invoke_all_drivers(dev, INVOKE_PROBE);
+}
+
+/*
  * Scan the content of the PCI bus, and call the devinit() function for
  * all registered drivers that have a matching entry in its id_table
  * for discovered devices.
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 22/25] eal/pci: Add pci_close_all_drivers
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (20 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 21/25] eal/pci: Fix pci_probe_all_drivers to share code with closing function Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 23/25] eal/pci: Add rte_eal_pci_probe_one and rte_eal_pci_close_one Tetsuya Mukawa
                   ` (6 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The function tries to find a driver for the specified device, and then
close the driver.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_pci.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index 1e3efea..b404ee0 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -100,6 +100,7 @@ static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
 }
 
 #define INVOKE_PROBE	(0)
+#define INVOKE_CLOSE	(1)
 
 static int
 pci_invoke_all_drivers(struct rte_pci_device *dev, int type)
@@ -112,6 +113,11 @@ pci_invoke_all_drivers(struct rte_pci_device *dev, int type)
 		case INVOKE_PROBE:
 			rc = rte_eal_pci_probe_one_driver(dr, dev);
 			break;
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+		case INVOKE_CLOSE:
+			rc = rte_eal_pci_close_one_driver(dr, dev);
+			break;
+#endif
 		}
 		if (rc < 0)
 			/* negative value is an error */
@@ -135,6 +141,19 @@ pci_probe_all_drivers(struct rte_pci_device *dev)
 	return pci_invoke_all_drivers(dev, INVOKE_PROBE);
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+/*
+ * If vendor/device ID match, call the devclose() 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_close_all_drivers(struct rte_pci_device *dev)
+{
+	return pci_invoke_all_drivers(dev, INVOKE_CLOSE);
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /*
  * Scan the content of the PCI bus, and call the devinit() function for
  * all registered drivers that have a matching entry in its id_table
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 23/25] eal/pci: Add rte_eal_pci_probe_one and rte_eal_pci_close_one
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (21 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 22/25] eal/pci: Add pci_close_all_drivers Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 24/25] eal/pci: Add port hotplug functions for physical devices Tetsuya Mukawa
                   ` (5 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The functions are used for probe and close a device.
First the function tries to find a device that has the specfied PCI address.
Then, probe or close the device.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_pci.c  | 58 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_pci.h | 26 +++++++++++++++
 2 files changed, 84 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index b404ee0..5ff7b49 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -152,6 +152,64 @@ pci_close_all_drivers(struct rte_pci_device *dev)
 {
 	return pci_invoke_all_drivers(dev, INVOKE_CLOSE);
 }
+
+static int
+rte_eal_pci_invoke_one(struct rte_pci_addr *addr, int type)
+{
+	struct rte_pci_device *dev = NULL;
+	int ret = 0;
+
+	TAILQ_FOREACH(dev, &pci_device_list, next) {
+		if (eal_compare_pci_addr(&dev->addr, addr))
+			continue;
+
+		switch (type) {
+		case INVOKE_PROBE:
+			ret = pci_probe_all_drivers(dev);
+			break;
+		case INVOKE_CLOSE:
+			ret = pci_close_all_drivers(dev);
+			break;
+		}
+		if (ret < 0)
+			goto invoke_err_return;
+		if (type == INVOKE_CLOSE)
+			goto remove_dev;
+		return 0;
+	}
+
+	return -1;
+
+invoke_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);
+	return -1;
+
+remove_dev:
+	TAILQ_REMOVE(&pci_device_list, dev, next);
+	return 0;
+}
+
+/*
+ * Find the pci device specified by pci address, then invoke probe function of
+ * the driver of the devive.
+ */
+int
+rte_eal_pci_probe_one(struct rte_pci_addr *addr)
+{
+	return rte_eal_pci_invoke_one(addr, INVOKE_PROBE);
+}
+
+/*
+ * Find the pci device specified by pci address, then invoke close function of
+ * the driver of the devive.
+ */
+int
+rte_eal_pci_close_one(struct rte_pci_addr *addr)
+{
+	return rte_eal_pci_invoke_one(addr, INVOKE_CLOSE);
+}
 #endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
 
 /*
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 74720d1..33300be 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -311,6 +311,32 @@ eal_compare_pci_addr(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
 int rte_eal_pci_probe(void);
 
 /**
+ * Probe the single PCI device.
+ *
+ * Scan the content of the PCI bus, and find the pci device specified by pci
+ * addrrss, then call the probe() function for registered driver that has a
+ * matching entry in its id_table for discovered device.
+ *
+ * @return
+ *   - 0 on success.
+ *   - Negative on error.
+ */
+int rte_eal_pci_probe_one(struct rte_pci_addr *addr);
+
+/**
+ * Close the single PCI device.
+ *
+ * Scan the content of the PCI bus, and find the pci device specified by pci
+ * addrrss, then call the close() function for registered driver that has a
+ * matching entry in its id_table for discovered device.
+ *
+ * @return
+ *   - 0 on success.
+ *   - Negative on error.
+ */
+int rte_eal_pci_close_one(struct rte_pci_addr *addr);
+
+/**
  * Dump the content of the PCI bus.
  *
  * @param f
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 24/25] eal/pci: Add port hotplug functions for physical devices.
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (22 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 23/25] eal/pci: Add rte_eal_pci_probe_one and rte_eal_pci_close_one Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 25/25] eal: Enable port hotplug framework in Linux Tetsuya Mukawa
                   ` (4 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch adds rte_eal_dev_attach_pdev() and rte_eal_dev_detach_pdev().

rte_eal_dev_attach_pdev() receives a PCI address of the device and
returns an attached port number.
rte_eal_dev_detach_pdev() receives a port number, and returns a PCI
address actually detached.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_dev.c  | 58 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h | 25 ++++++++++++++
 2 files changed, 83 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 0518e3c..c2d5cd6 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -181,6 +181,64 @@ rte_eal_dev_close_one(const char *name)
 	return rte_eal_dev_find_and_invoke(name, INVOKE_CLOSE);
 }
 
+/* attach the new physical device, then store port_id of the device */
+int
+rte_eal_dev_attach_pdev(struct rte_pci_addr *addr, uint8_t *port_id)
+{
+	uint8_t new_port_id;
+	struct rte_eth_dev devs[RTE_MAX_ETHPORTS];
+
+	/* save current port status */
+	rte_eth_dev_save(devs);
+	/* re-construct pci_device_list */
+	if (rte_eal_pci_scan())
+		goto err;
+	/* invoke probe func of the driver can handle the new device */
+	if (rte_eal_pci_probe_one(addr))
+		goto err;
+	/* get port_id enabled by above procedures */
+	if (rte_eth_dev_get_changed_port(devs, &new_port_id))
+		goto err;
+
+	*port_id = new_port_id;
+	return 0;
+err:
+	RTE_LOG(ERR, EAL, "Drver, cannot attach the device\n");
+	return -1;
+}
+
+/* detach the new physical device, then store pci_addr of the device */
+int
+rte_eal_dev_detach_pdev(uint8_t port_id, struct rte_pci_addr *addr)
+{
+	struct rte_pci_addr freed_addr;
+	struct rte_pci_addr vp;
+
+	/* check whether the driver supports detach feature, or not */
+	if (!rte_eth_dev_check_detachable(port_id))
+		goto err;
+
+	/* get pci address by port id */
+	if (rte_eth_dev_get_addr_by_port(port_id, &freed_addr))
+		goto err;
+
+	/* Zerod pci addr means the port comes from virtual device */
+	vp.domain = vp.bus = vp.devid = vp.function = 0;
+	if (eal_compare_pci_addr(&vp, &freed_addr) == 0)
+		goto err;
+
+	/* invoke close func of the driver,
+	 * also remove the device from pci_device_list */
+	if (rte_eal_pci_close_one(&freed_addr))
+		goto err;
+
+	*addr = freed_addr;
+	return 0;
+err:
+	RTE_LOG(ERR, EAL, "Drver, cannot detach the device\n");
+	return -1;
+}
+
 static void
 get_vdev_name(char *vdevargs)
 {
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 159d5a5..26d7526 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -101,6 +101,19 @@ void rte_eal_driver_unregister(struct rte_driver *driver);
 #if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
 
 /**
+ * Attach a new physical device.
+ *
+ * @param addr
+ *   A pointer to a pci address structure describing the new
+ *   device to be attached.
+ * @param port_id
+ *  A pointer to a port identifier actually attached.
+ * @return
+ *  0 on success and port_id is filled, negative on error
+ */
+int rte_eal_dev_attach_pdev(struct rte_pci_addr *addr, uint8_t *port_id);
+
+/**
  * Attach a new virtual device.
  *
  * @param vdevargs
@@ -114,6 +127,18 @@ void rte_eal_driver_unregister(struct rte_driver *driver);
 int rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id);
 
 /**
+ * Detach a physical device.
+ *
+ * @param port_id
+ *   The port identifier of the physical device to detach.
+ * @param addr
+ *  A pointer to a pci address structure actually detached.
+ * @return
+ *  0 on success and addr is filled, negative on error
+ */
+int rte_eal_dev_detach_pdev(uint8_t port_id, struct rte_pci_addr *addr);
+
+/**
  * Detach a virtual device.
  *
  * @param port_id
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH 25/25] eal: Enable port hotplug framework in Linux
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (23 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 24/25] eal/pci: Add port hotplug functions for physical devices Tetsuya Mukawa
@ 2014-10-29  8:49 ` Tetsuya Mukawa
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (3 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-29  8:49 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch enables CONFIG_RTE_LIBRTE_EAL_HOTPLUG in Linux configuration.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 config/common_linuxapp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/config/common_linuxapp b/config/common_linuxapp
index c5751bd..f94ec65 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -144,6 +144,11 @@ CONFIG_RTE_LIBRTE_EAL_LINUXAPP=y
 CONFIG_RTE_LIBRTE_EAL_BAREMETAL=n
 
 #
+# Compile Environment Abstraction Layer to support hotplug
+#
+CONFIG_RTE_LIBRTE_EAL_HOTPLUG=y
+
+#
 # Compile Environment Abstraction Layer to support Vmware TSC map
 #
 CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=y
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [dpdk-dev] [RFC PATCH 02/25] ethdev: Remove assumption that port will not be detached
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 02/25] ethdev: Remove assumption that port will not be detached Tetsuya Mukawa
@ 2014-10-29 15:14   ` Bruce Richardson
  2014-10-30  7:24     ` Tetsuya Mukawa
  0 siblings, 1 reply; 176+ messages in thread
From: Bruce Richardson @ 2014-10-29 15:14 UTC (permalink / raw)
  To: Tetsuya Mukawa; +Cc: dev, nakajima.yoshihiro, masutani.hitoshi

On Wed, Oct 29, 2014 at 05:49:13PM +0900, Tetsuya Mukawa wrote:
> To remove assumption, do like followings.
> 
> - Add 'attached' member to rte_eth_dev structure.
>   This member is used for indicating the port is attached, or not.
> - Delete nb_ports, and fix rte_eth_dev_count().
>   The value was used for counting attached ports and also used for indicating
>   maximum attached port number. But if some ports are detached, these 2 values
>   may not be equal. So delete nb_ports, and fix rte_eth_dev_count() to count
>   how many ports are attached actually.
> - Add rte_eth_dev_allocate_new_port().
>   This function is used for allocating new port.
> - Add rte_eth_dev_validate_port().
>   This function is used for check whether the port number is valid and the
>   port is attached.
> - Replace port validation codes to rte_eth_dev_validate_port().
>   nb_ports is deleted in this patch, so use rte_eth_dev_validate_port() to
>   validate a port.
> 
> Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
> ---
>  lib/librte_ether/rte_ethdev.c | 247 +++++++++++++++++++++++-------------------
>  lib/librte_ether/rte_ethdev.h |   5 +
>  2 files changed, 143 insertions(+), 109 deletions(-)
> 
> diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
> index ff1c769..93d5a42 100644
> --- a/lib/librte_ether/rte_ethdev.c
> +++ b/lib/librte_ether/rte_ethdev.c
> @@ -109,7 +109,6 @@
>  static const char *MZ_RTE_ETH_DEV_DATA = "rte_eth_dev_data";
>  struct rte_eth_dev rte_eth_devices[RTE_MAX_ETHPORTS];
>  static struct rte_eth_dev_data *rte_eth_dev_data = NULL;
> -static uint8_t nb_ports = 0;
>  
>  /* spinlock for eth device callbacks */
>  static rte_spinlock_t rte_eth_dev_cb_lock = RTE_SPINLOCK_INITIALIZER;
> @@ -201,19 +200,33 @@ rte_eth_dev_allocated(const char *name)
>  {
>  	unsigned i;
>  
> -	for (i = 0; i < nb_ports; i++) {
> -		if (strcmp(rte_eth_devices[i].data->name, name) == 0)
> +	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
> +		if (rte_eth_devices[i].attached && strcmp(
> +				rte_eth_dev_data[i].name, name) == 0)
>  			return &rte_eth_devices[i];
> -	}
> +
>  	return NULL;
>  }
>  
> +static uint8_t
> +rte_eth_dev_allocate_new_port(void)
> +{
> +	unsigned i;
> +
> +	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
> +		if (!rte_eth_devices[i].attached)
> +			return i;
> +	return RTE_MAX_ETHPORTS;
> +}
> +
>  struct rte_eth_dev *
>  rte_eth_dev_allocate(const char *name)
>  {
> +	uint8_t port_id;
>  	struct rte_eth_dev *eth_dev;
>  
> -	if (nb_ports == RTE_MAX_ETHPORTS) {
> +	port_id = rte_eth_dev_allocate_new_port();
> +	if (port_id >= RTE_MAX_ETHPORTS) {
>  		PMD_DEBUG_TRACE("Reached maximum number of Ethernet ports\n");
>  		return NULL;
>  	}
> @@ -226,10 +239,11 @@ rte_eth_dev_allocate(const char *name)
>  		return NULL;
>  	}
>  
> -	eth_dev = &rte_eth_devices[nb_ports];
> -	eth_dev->data = &rte_eth_dev_data[nb_ports];
> +	eth_dev = &rte_eth_devices[port_id];
> +	eth_dev->data = &rte_eth_dev_data[port_id];
>  	snprintf(eth_dev->data->name, sizeof(eth_dev->data->name), "%s", name);
> -	eth_dev->data->port_id = nb_ports++;
> +	eth_dev->data->port_id = port_id;
> +	eth_dev->attached = 1;
>  	return eth_dev;
>  }
>  
> @@ -283,7 +297,7 @@ rte_eth_dev_init(struct rte_pci_driver *pci_drv,
>  			(unsigned) pci_dev->id.device_id);
>  	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
>  		rte_free(eth_dev->data->dev_private);
> -	nb_ports--;
> +	eth_dev->attached = 0;
>  	return diag;
>  }
>  
> @@ -308,10 +322,19 @@ rte_eth_driver_register(struct eth_driver *eth_drv)
>  	rte_eal_pci_register(&eth_drv->pci_drv);
>  }
>  
> +static int
> +rte_eth_dev_validate_port(uint8_t port_id)
> +{
> +	if (port_id >= RTE_MAX_ETHPORTS)
> +		return 1;
> +
> +	return !rte_eth_devices[port_id].attached;
> +}
> +
>  int
>  rte_eth_dev_socket_id(uint8_t port_id)
>  {
> -	if (port_id >= nb_ports)
> +	if (rte_eth_dev_validate_port(port_id))
>  		return -1;
>  	return rte_eth_devices[port_id].pci_dev->numa_node;
>  }
> @@ -319,7 +342,13 @@ rte_eth_dev_socket_id(uint8_t port_id)
>  uint8_t
>  rte_eth_dev_count(void)
>  {
> -	return (nb_ports);
> +	unsigned i;
> +	uint8_t nb_ports = 0;
> +
> +	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
> +		if (rte_eth_devices[i].attached)
> +			nb_ports++;
> +	return nb_ports;
>  }
>  

Given that apps may regularly use eth_dev_count, might it not be worthwhile to retain the nb_ports local variable to make this API call just be a variable read. The other APIs to enable/disable individual ports could easily just inc/dec this var as they do so.

/Bruce

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [dpdk-dev] [RFC PATCH 03/25] eal/pci: Replace pci address comparison code by eal_compare_pci_addr
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 03/25] eal/pci: Replace pci address comparison code by eal_compare_pci_addr Tetsuya Mukawa
@ 2014-10-29 16:28   ` Bruce Richardson
  0 siblings, 0 replies; 176+ messages in thread
From: Bruce Richardson @ 2014-10-29 16:28 UTC (permalink / raw)
  To: Tetsuya Mukawa; +Cc: dev, nakajima.yoshihiro, masutani.hitoshi

On Wed, Oct 29, 2014 at 05:49:14PM +0900, Tetsuya Mukawa wrote:
> This patch replaces pci_addr_comparison() and memcmp() of pci addresses by
> eal_compare_pci_addr().
> 
> Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>

Looks like a good cleanup.

Acked-by: Bruce Richardson <bruce.richardson@intel.com>

> ---
>  lib/librte_eal/bsdapp/eal/eal_pci.c       | 16 +---------------
>  lib/librte_eal/common/eal_common_pci.c    |  2 +-
>  lib/librte_eal/common/include/rte_pci.h   | 29 +++++++++++++++++++++++++++++
>  lib/librte_eal/linuxapp/eal/eal_pci.c     | 16 +---------------
>  lib/librte_eal/linuxapp/eal/eal_pci_uio.c |  2 +-
>  5 files changed, 33 insertions(+), 32 deletions(-)
> 
> diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
> index 54fcaf0..2576fa7 100644
> --- a/lib/librte_eal/bsdapp/eal/eal_pci.c
> +++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
> @@ -270,20 +270,6 @@ pci_uio_map_resource(struct rte_pci_device *dev)
>  	return (0);
>  }
>  
> -/* Compare two PCI device addresses. */
> -static int
> -pci_addr_comparison(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
> -{
> -	uint64_t dev_addr = (addr->domain << 24) + (addr->bus << 16) + (addr->devid << 8) + addr->function;
> -	uint64_t dev_addr2 = (addr2->domain << 24) + (addr2->bus << 16) + (addr2->devid << 8) + addr2->function;
> -
> -	if (dev_addr > dev_addr2)
> -		return 1;
> -	else
> -		return 0;
> -}
> -
> -
>  /* Scan one pci sysfs entry, and fill the devices list from it. */
>  static int
>  pci_scan_one(int dev_pci_fd, struct pci_conf *conf)
> @@ -358,7 +344,7 @@ pci_scan_one(int dev_pci_fd, struct pci_conf *conf)
>  		struct rte_pci_device *dev2 = NULL;
>  
>  		TAILQ_FOREACH(dev2, &pci_device_list, next) {
> -			if (pci_addr_comparison(&dev->addr, &dev2->addr))
> +			if (eal_compare_pci_addr(&dev->addr, &dev2->addr))
>  				continue;
>  			else {
>  				TAILQ_INSERT_BEFORE(dev2, dev, next);
> diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
> index f3c7f71..f01f258 100644
> --- a/lib/librte_eal/common/eal_common_pci.c
> +++ b/lib/librte_eal/common/eal_common_pci.c
> @@ -93,7 +93,7 @@ static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
>  		if (devargs->type != RTE_DEVTYPE_BLACKLISTED_PCI &&
>  			devargs->type != RTE_DEVTYPE_WHITELISTED_PCI)
>  			continue;
> -		if (!memcmp(&dev->addr, &devargs->pci.addr, sizeof(dev->addr)))
> +		if (eal_compare_pci_addr(&dev->addr, &devargs->pci.addr))
>  			return devargs;
>  	}
>  	return NULL;
> diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
> index b819539..fe374a8 100644
> --- a/lib/librte_eal/common/include/rte_pci.h
> +++ b/lib/librte_eal/common/include/rte_pci.h
> @@ -261,6 +261,35 @@ eal_parse_pci_DomBDF(const char *input, struct rte_pci_addr *dev_addr)
>  }
>  #undef GET_PCIADDR_FIELD
>  
> +/* Compare two PCI device addresses. */
> +/**
> + * Utility function to compare two PCI device addresses.
> + *
> + * @param addr
> + *	The PCI Bus-Device-Function address to compare
> + * @param addr2
> + *	The PCI Bus-Device-Function address to compare
> + * @return
> + *  0 on equal PCI address.
> + *  Positive on addr is greater than addr2.
> + *  Negative on addr is less than addr2.
> + */
> +static inline int
> +eal_compare_pci_addr(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
> +{
> +	uint64_t dev_addr = (addr->domain << 24) + (addr->bus << 16) +
> +					(addr->devid << 8) + addr->function;
> +	uint64_t dev_addr2 = (addr2->domain << 24) + (addr2->bus << 16) +
> +					(addr2->devid << 8) + addr2->function;
> +
> +	if (dev_addr > dev_addr2)
> +		return 1;
> +	else if (dev_addr < dev_addr2)
> +		return -1;
> +	else
> +		return 0;
> +}
> +
>  /**
>   * Probe the PCI bus for registered drivers.
>   *
> diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
> index 5fe3961..862b93a 100644
> --- a/lib/librte_eal/linuxapp/eal/eal_pci.c
> +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
> @@ -186,20 +186,6 @@ error:
>  	return -1;
>  }
>  
> -/* Compare two PCI device addresses. */
> -static int
> -pci_addr_comparison(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
> -{
> -	uint64_t dev_addr = (addr->domain << 24) + (addr->bus << 16) + (addr->devid << 8) + addr->function;
> -	uint64_t dev_addr2 = (addr2->domain << 24) + (addr2->bus << 16) + (addr2->devid << 8) + addr2->function;
> -
> -	if (dev_addr > dev_addr2)
> -		return 1;
> -	else
> -		return 0;
> -}
> -
> -
>  /* 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,
> @@ -292,7 +278,7 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
>  		struct rte_pci_device *dev2 = NULL;
>  
>  		TAILQ_FOREACH(dev2, &pci_device_list, next) {
> -			if (pci_addr_comparison(&dev->addr, &dev2->addr))
> +			if (eal_compare_pci_addr(&dev->addr, &dev2->addr) != 0)
>  				continue;
>  			else {
>  				TAILQ_INSERT_BEFORE(dev2, dev, next);
> diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
> index 7e62266..f0deeba 100644
> --- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
> +++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
> @@ -120,7 +120,7 @@ pci_uio_map_secondary(struct rte_pci_device *dev)
>  	TAILQ_FOREACH(uio_res, pci_res_list, next) {
>  
>  		/* skip this element if it doesn't match our PCI address */
> -		if (memcmp(&uio_res->pci_addr, &dev->addr, sizeof(dev->addr)))
> +		if (eal_compare_pci_addr(&uio_res->pci_addr, &dev->addr))
>  			continue;
>  
>  		for (i = 0; i != uio_res->nb_maps; i++) {
> -- 
> 1.9.1
> 

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [dpdk-dev] [RFC PATCH 02/25] ethdev: Remove assumption that port will not be detached
  2014-10-29 15:14   ` Bruce Richardson
@ 2014-10-30  7:24     ` Tetsuya Mukawa
  0 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-10-30  7:24 UTC (permalink / raw)
  To: Bruce Richardson; +Cc: dev, nakajima.yoshihiro, masutani.hitoshi

(2014/10/30 0:14), Bruce Richardson wrote:
> Given that apps may regularly use eth_dev_count, might it not be
> worthwhile to retain the nb_ports local variable to make this API call
> just be a variable read. The other APIs to enable/disable individual
> ports could easily just inc/dec this var as they do so.
>
> /Bruce 
I agree with your suggestion. I will change like above.

Thanks,
Tetsuya

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (24 preceding siblings ...)
  2014-10-29  8:49 ` [dpdk-dev] [RFC PATCH 25/25] eal: Enable port hotplug framework in Linux Tetsuya Mukawa
@ 2014-11-04  3:45 ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 01/28] eal/pci: Add a new flag indicating a driver can detach devices at runtime Tetsuya Mukawa
                     ` (28 more replies)
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                   ` (2 subsequent siblings)
  28 siblings, 29 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

This patch series adds a dynamic port hotplug framework to DPDK.
With the patches, DPDK apps can attach or detach ports at runtime.

The basic concept of the port hotplug is like followings.
- DPDK apps must have resposibility to manage ports.
  DPDK apps only know which ports are attached or detached at the moment.
  The port hotplug framework is implemented to allow DPDK apps to manage ports.
  For example, when DPDK apps call port attach function, attached port number
  will be returned. Also DPDK apps can detach port by port number.
- Kernel support is needed for attaching or detaching physical device ports.
  To attach new device, the device will be recognized by kernel at first and
  controlled by kernel driver. Then user can bind the device to igb_uio
  by 'dpdk_nic_bind.py'. Finally, DPDK apps can call the port hotplug
  functions to attach ports.
  For detaching, steps are vice versa.
- Before detach ports, ports must be stopped and closed.
  DPDK application must call rte_eth_dev_stop() and rte_eth_dev_close() before
  detaching ports. These function will call finalization codes of PMDs.
  But so far, no PMD frees all resources allocated by initialization.
  It means PMDs are needed to be fixed to support the port hotplug.
  'RTE_PCI_DRV_DETACHABLE' is a new flag indicating a PMD supports detaching.
  Without this flag, detaching will be failed.
- Mustn't affect legacy DPDK apps.
  No DPDK EAL behavior is changed, if the port hotplug functions are't called.
  So all legacy DPDK apps can still work without modifications.

And few limitations.
- The port hotplug functions are not thread safe.
  DPDK apps should handle it.
- Only support Linux and igb_uio so far.
  BSD and VFIO is not supported. I will send VFIO patches at least, but I don't
  have a plan to submit BSD patch so far.


Here is port hotplug APIs.
-------------------------------------------------------------------------------
/**
 * Attach a new physical device.
 *
 * @param addr
 *   A pointer to a pci address structure describing the new
 *   device to be attached.
 * @param port_id
 *  A pointer to a port identifier actually attached.
 * @return
 *  0 on success and port_id is filled, negative on error
 */
int rte_eal_dev_attach_pdev(struct rte_pci_addr *addr, uint8_t *port_id);

/**
 * Attach a new virtual device.
 *
 * @param vdevargs
 *   A pointer to a strings array describing the new device
 *   to be attached.
 * @param port_id
 *  A pointer to a port identifier actually attached.
 * @return
 *  0 on success and port_id is filled, negative on error
 */
int rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id);

/**
 * Detach a physical device.
 *
 * @param port_id
 *   The port identifier of the physical device to detach.
 * @param addr
 *  A pointer to a pci address structure actually detached.
 * @return
 *  0 on success and addr is filled, negative on error
 */
int rte_eal_dev_detach_pdev(uint8_t port_id, struct rte_pci_addr *addr);

/**
 * Detach a virtual device.
 *
 * @param port_id
 *   The port identifier of the virtual device to detach.
 * @param addr
 *  A pointer to a virtual device name actually detached.
 * @return
 *  0 on success and vdevname is filled, negative on error
 */
int rte_eal_dev_detach_vdev(uint8_t port_id, char *vdevname);
-------------------------------------------------------------------------------

This patch series are for DPDK EAL. To use port hotplug function by DPDK apps,
each PMD should be fixed to support 'RTE_PCI_DRV_DETACHABLE' flag. I've already
sent an example patch for pcap PMD.

Also I've sent patch for testpmd. The patch is an example of fixing legacy DPDK
apps to support hot plug framework.

Thanks,
Tetsuya Mukawa

Changes included in v2:
- remove 'rte_eth_dev_validate_port()', and cleanup codes.

Tetsuya Mukawa (25):
  eal/pci: Add a new flag indicating a driver can detach devices at
    runtime.
  ethdev: Remove assumption that port will not be detached
  eal/pci: Replace pci address comparison code by eal_compare_pci_addr
  ethdev: Add rte_eth_dev_free to free specified device
  eal,ethdev: Add function pointer for closing a device
  ethdev: Add rte_eth_dev_shutdown for closing PCI devices.
  ethdev: Add functions to know which port is attached or detached
  ethdev: Add rte_eth_dev_get_addr_by_port
  ethdev: Add rte_eth_dev_get_port_by_addr
  ethdev: Add rte_eth_dev_get_name_by_port
  ethdev: Add rte_eth_dev_check_detachable
  ethdev: Change scope of rte_eth_dev_allocated to global
  eal/pci: Prevent double registration for devargs_list
  eal/pci: Add rte_eal_devargs_remove
  eal/pci: Add probe and close function for virtual drivers
  eal/pci: Add port hotplug functions for virtual devices.
  eal/linux/pci: Add functions for unmapping igb_uio resources
  eal/pci: Prevent double registrations for pci_device_list
  eal/pci: Change scope of rte_eal_pci_scan to global
  eal/pci: Add rte_eal_pci_close_one_driver
  eal/pci: Fix pci_probe_all_drivers to share code with closing function
  eal/pci: Add pci_close_all_drivers
  eal/pci: Add rte_eal_pci_probe_one and rte_eal_pci_close_one
  eal/pci: Add port hotplug functions for physical devices.
  eal: Enable port hotplug framework in Linux

 config/common_linuxapp                             |   5 +
 lib/librte_eal/bsdapp/eal/eal_pci.c                |  16 +-
 lib/librte_eal/common/eal_common_dev.c             | 208 ++++++++++++
 lib/librte_eal/common/eal_common_devargs.c         |  45 +++
 lib/librte_eal/common/eal_common_pci.c             | 107 +++++-
 lib/librte_eal/common/include/eal_private.h        |  22 ++
 lib/librte_eal/common/include/rte_dev.h            |  60 ++++
 lib/librte_eal/common/include/rte_devargs.h        |  18 +
 lib/librte_eal/common/include/rte_pci.h            |  64 ++++
 lib/librte_eal/linuxapp/eal/Makefile               |   1 +
 lib/librte_eal/linuxapp/eal/eal_pci.c              | 119 +++++--
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c          |  58 +++-
 lib/librte_eal/linuxapp/eal/include/eal_pci_init.h |   7 +
 lib/librte_ether/rte_ethdev.c                      | 371 +++++++++++++++------
 lib/librte_ether/rte_ethdev.h                      | 100 ++++++
 15 files changed, 1046 insertions(+), 155 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 01/28] eal/pci: Add a new flag indicating a driver can detach devices at runtime.
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 02/28] ethdev: Remove assumption that port will not be detached Tetsuya Mukawa
                     ` (27 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

This patch adds "RTE_PCI_DRV_DETACHABLE" to drv_flags of rte_pci_driver
structure. The flags indicates the driver can detach devices at runtime.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/include/rte_pci.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 66ed793..b819539 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -199,6 +199,8 @@ 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 capablity */
+#define RTE_PCI_DRV_DETACHABLE	0x0010
 
 /**< Internal use only - Macro used by pci addr parsing functions **/
 #define GET_PCIADDR_FIELD(in, fd, lim, dlm)                   \
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 02/28] ethdev: Remove assumption that port will not be detached
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 01/28] eal/pci: Add a new flag indicating a driver can detach devices at runtime Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 03/28] eal/pci: Replace pci address comparison code by eal_compare_pci_addr Tetsuya Mukawa
                     ` (26 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

To remove assumption, do like followings.

- Add 'attached' member to rte_eth_dev structure.
  This member is used for indicating the port is attached, or not.
- Add rte_eth_dev_allocate_new_port().
  This function is used for allocating new port.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 24 ++++++++++++++++++++----
 lib/librte_ether/rte_ethdev.h |  5 +++++
 2 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index ff1c769..e37a25a 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -208,12 +208,25 @@ rte_eth_dev_allocated(const char *name)
 	return NULL;
 }
 
+static uint8_t
+rte_eth_dev_allocate_new_port(void)
+{
+	unsigned i;
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
+		if (!rte_eth_devices[i].attached)
+			return i;
+	return RTE_MAX_ETHPORTS;
+}
+
 struct rte_eth_dev *
 rte_eth_dev_allocate(const char *name)
 {
+	uint8_t port_id;
 	struct rte_eth_dev *eth_dev;
 
-	if (nb_ports == RTE_MAX_ETHPORTS) {
+	port_id = rte_eth_dev_allocate_new_port();
+	if (port_id == RTE_MAX_ETHPORTS) {
 		PMD_DEBUG_TRACE("Reached maximum number of Ethernet ports\n");
 		return NULL;
 	}
@@ -226,10 +239,12 @@ rte_eth_dev_allocate(const char *name)
 		return NULL;
 	}
 
-	eth_dev = &rte_eth_devices[nb_ports];
-	eth_dev->data = &rte_eth_dev_data[nb_ports];
+	eth_dev = &rte_eth_devices[port_id];
+	eth_dev->data = &rte_eth_dev_data[port_id];
 	snprintf(eth_dev->data->name, sizeof(eth_dev->data->name), "%s", name);
-	eth_dev->data->port_id = nb_ports++;
+	eth_dev->data->port_id = port_id;
+	eth_dev->attached = 1;
+	nb_ports++;
 	return eth_dev;
 }
 
@@ -283,6 +298,7 @@ rte_eth_dev_init(struct rte_pci_driver *pci_drv,
 			(unsigned) pci_dev->id.device_id);
 	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
 		rte_free(eth_dev->data->dev_private);
+	eth_dev->attached = 0;
 	nb_ports--;
 	return diag;
 }
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 8bf274d..5d3956a 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1534,6 +1534,7 @@ struct eth_dev_ops {
  * process, while the actual configuration data for the device is shared.
  */
 struct rte_eth_dev {
+	uint8_t attached; /**< Flag indicating the port is attached */
 	eth_rx_burst_t rx_pkt_burst; /**< Pointer to PMD receive function. */
 	eth_tx_burst_t tx_pkt_burst; /**< Pointer to PMD transmit function. */
 	struct rte_eth_dev_data *data;  /**< Pointer to device data */
@@ -1606,6 +1607,10 @@ extern struct rte_eth_dev rte_eth_devices[];
  * initialized by the [matching] Ethernet driver during the PCI probing phase.
  * All devices whose port identifier is in the range
  * [0,  rte_eth_dev_count() - 1] can be operated on by network applications.
+ * immediately after invoking rte_eal_init().
+ * If the application unplugs a port using hotplug function, The enabled port
+ * numbers may be noncontiguous. In the case, the applications need to manage
+ * enabled port by themselves.
  *
  * @return
  *   - The total number of usable Ethernet devices.
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 03/28] eal/pci: Replace pci address comparison code by eal_compare_pci_addr
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 01/28] eal/pci: Add a new flag indicating a driver can detach devices at runtime Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 02/28] ethdev: Remove assumption that port will not be detached Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 04/28] ethdev: Add rte_eth_dev_free to free specified device Tetsuya Mukawa
                     ` (25 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

This patch replaces pci_addr_comparison() and memcmp() of pci addresses by
eal_compare_pci_addr().

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/bsdapp/eal/eal_pci.c       | 16 +---------------
 lib/librte_eal/common/eal_common_pci.c    |  2 +-
 lib/librte_eal/common/include/rte_pci.h   | 29 +++++++++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c     | 16 +---------------
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c |  2 +-
 5 files changed, 33 insertions(+), 32 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 54fcaf0..2576fa7 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -270,20 +270,6 @@ pci_uio_map_resource(struct rte_pci_device *dev)
 	return (0);
 }
 
-/* Compare two PCI device addresses. */
-static int
-pci_addr_comparison(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
-{
-	uint64_t dev_addr = (addr->domain << 24) + (addr->bus << 16) + (addr->devid << 8) + addr->function;
-	uint64_t dev_addr2 = (addr2->domain << 24) + (addr2->bus << 16) + (addr2->devid << 8) + addr2->function;
-
-	if (dev_addr > dev_addr2)
-		return 1;
-	else
-		return 0;
-}
-
-
 /* Scan one pci sysfs entry, and fill the devices list from it. */
 static int
 pci_scan_one(int dev_pci_fd, struct pci_conf *conf)
@@ -358,7 +344,7 @@ pci_scan_one(int dev_pci_fd, struct pci_conf *conf)
 		struct rte_pci_device *dev2 = NULL;
 
 		TAILQ_FOREACH(dev2, &pci_device_list, next) {
-			if (pci_addr_comparison(&dev->addr, &dev2->addr))
+			if (eal_compare_pci_addr(&dev->addr, &dev2->addr))
 				continue;
 			else {
 				TAILQ_INSERT_BEFORE(dev2, dev, next);
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index f3c7f71..f01f258 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -93,7 +93,7 @@ static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
 		if (devargs->type != RTE_DEVTYPE_BLACKLISTED_PCI &&
 			devargs->type != RTE_DEVTYPE_WHITELISTED_PCI)
 			continue;
-		if (!memcmp(&dev->addr, &devargs->pci.addr, sizeof(dev->addr)))
+		if (eal_compare_pci_addr(&dev->addr, &devargs->pci.addr))
 			return devargs;
 	}
 	return NULL;
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index b819539..fe374a8 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -261,6 +261,35 @@ eal_parse_pci_DomBDF(const char *input, struct rte_pci_addr *dev_addr)
 }
 #undef GET_PCIADDR_FIELD
 
+/* Compare two PCI device addresses. */
+/**
+ * Utility function to compare two PCI device addresses.
+ *
+ * @param addr
+ *	The PCI Bus-Device-Function address to compare
+ * @param addr2
+ *	The PCI Bus-Device-Function address to compare
+ * @return
+ *  0 on equal PCI address.
+ *  Positive on addr is greater than addr2.
+ *  Negative on addr is less than addr2.
+ */
+static inline int
+eal_compare_pci_addr(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
+{
+	uint64_t dev_addr = (addr->domain << 24) + (addr->bus << 16) +
+					(addr->devid << 8) + addr->function;
+	uint64_t dev_addr2 = (addr2->domain << 24) + (addr2->bus << 16) +
+					(addr2->devid << 8) + addr2->function;
+
+	if (dev_addr > dev_addr2)
+		return 1;
+	else if (dev_addr < dev_addr2)
+		return -1;
+	else
+		return 0;
+}
+
 /**
  * Probe the PCI bus for registered drivers.
  *
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 5fe3961..862b93a 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -186,20 +186,6 @@ error:
 	return -1;
 }
 
-/* Compare two PCI device addresses. */
-static int
-pci_addr_comparison(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
-{
-	uint64_t dev_addr = (addr->domain << 24) + (addr->bus << 16) + (addr->devid << 8) + addr->function;
-	uint64_t dev_addr2 = (addr2->domain << 24) + (addr2->bus << 16) + (addr2->devid << 8) + addr2->function;
-
-	if (dev_addr > dev_addr2)
-		return 1;
-	else
-		return 0;
-}
-
-
 /* 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,
@@ -292,7 +278,7 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
 		struct rte_pci_device *dev2 = NULL;
 
 		TAILQ_FOREACH(dev2, &pci_device_list, next) {
-			if (pci_addr_comparison(&dev->addr, &dev2->addr))
+			if (eal_compare_pci_addr(&dev->addr, &dev2->addr) != 0)
 				continue;
 			else {
 				TAILQ_INSERT_BEFORE(dev2, dev, next);
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
index 7e62266..f0deeba 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
@@ -120,7 +120,7 @@ pci_uio_map_secondary(struct rte_pci_device *dev)
 	TAILQ_FOREACH(uio_res, pci_res_list, next) {
 
 		/* skip this element if it doesn't match our PCI address */
-		if (memcmp(&uio_res->pci_addr, &dev->addr, sizeof(dev->addr)))
+		if (eal_compare_pci_addr(&uio_res->pci_addr, &dev->addr))
 			continue;
 
 		for (i = 0; i != uio_res->nb_maps; i++) {
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 04/28] ethdev: Add rte_eth_dev_free to free specified device
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (2 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 03/28] eal/pci: Replace pci address comparison code by eal_compare_pci_addr Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 05/28] eal, ethdev: Add function pointer for closing a device Tetsuya Mukawa
                     ` (24 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

This patch adds rte_eth_dev_free(). The function is used for changing a
attached status of the device that has specified name.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 16 ++++++++++++++++
 lib/librte_ether/rte_ethdev.h | 11 +++++++++++
 2 files changed, 27 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index e37a25a..efd631b 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -248,6 +248,22 @@ rte_eth_dev_allocate(const char *name)
 	return eth_dev;
 }
 
+struct rte_eth_dev *
+rte_eth_dev_free(const char *name)
+{
+	struct rte_eth_dev *eth_dev;
+
+	eth_dev = rte_eth_dev_allocated(name);
+	if (eth_dev == NULL) {
+		PMD_DEBUG_TRACE("Ethernet Device with name %s doesn't exist!\n",
+				name);
+		return NULL;
+	}
+
+	eth_dev->attached = 0;
+	return eth_dev;
+}
+
 static int
 rte_eth_dev_init(struct rte_pci_driver *pci_drv,
 		 struct rte_pci_device *pci_dev)
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 5d3956a..dfaeaee 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1629,6 +1629,17 @@ extern uint8_t rte_eth_dev_count(void);
  */
 struct rte_eth_dev *rte_eth_dev_allocate(const char *name);
 
+/**
+ * Function for internal use by dummy drivers primarily, e.g. ring-based
+ * driver.
+ * Free the specified ethdev and returns the pointer to that slot.
+ *
+ * @param	name	Unique identifier name for each Ethernet device
+ * @return
+ *   - Slot in the rte_dev_devices array for the freed device;
+ */
+struct rte_eth_dev *rte_eth_dev_free(const char *name);
+
 struct eth_driver;
 /**
  * @internal
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 05/28] eal, ethdev: Add function pointer for closing a device
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (3 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 04/28] ethdev: Add rte_eth_dev_free to free specified device Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 06/28] ethdev: Add rte_eth_dev_shutdown for closing PCI devices Tetsuya Mukawa
                     ` (23 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch adds function pointer to rte_pci_driver and eth_driver
structure. These function pointers are used when ports are detached.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/include/rte_pci.h | 7 +++++++
 lib/librte_ether/rte_ethdev.h           | 4 ++++
 2 files changed, 11 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index fe374a8..74720d1 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -181,12 +181,19 @@ struct rte_pci_driver;
 typedef int (pci_devinit_t)(struct rte_pci_driver *, struct rte_pci_device *);
 
 /**
+ * Shutdown function for the driver called during hotplugging.
+ */
+typedef int (pci_devshutdown_t)(
+		struct rte_pci_driver *, struct rte_pci_device *);
+
+/**
  * A structure describing a PCI driver.
  */
 struct rte_pci_driver {
 	TAILQ_ENTRY(rte_pci_driver) next;       /**< Next in list. */
 	const char *name;                       /**< Driver name. */
 	pci_devinit_t *devinit;                 /**< Device init. function. */
+	pci_devshutdown_t *devshutdown;         /**< Device shutdown function. */
 	struct rte_pci_id *id_table;            /**< ID table, NULL terminated. */
 	uint32_t drv_flags;                     /**< Flags contolling handling of device. */
 };
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index dfaeaee..99cc8ce 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1676,6 +1676,9 @@ struct eth_driver;
 typedef int (*eth_dev_init_t)(struct eth_driver  *eth_drv,
 			      struct rte_eth_dev *eth_dev);
 
+typedef int (*eth_dev_shutdown_t)(struct eth_driver  *eth_drv,
+				  struct rte_eth_dev *eth_dev);
+
 /**
  * @internal
  * The structure associated with a PMD Ethernet driver.
@@ -1692,6 +1695,7 @@ typedef int (*eth_dev_init_t)(struct eth_driver  *eth_drv,
 struct eth_driver {
 	struct rte_pci_driver pci_drv;    /**< The PMD is also a PCI driver. */
 	eth_dev_init_t eth_dev_init;      /**< Device init function. */
+	eth_dev_shutdown_t eth_dev_shutdown;/**< Device shutdown function. */
 	unsigned int dev_private_size;    /**< Size of device private data. */
 };
 
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 06/28] ethdev: Add rte_eth_dev_shutdown for closing PCI devices.
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (4 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 05/28] eal, ethdev: Add function pointer for closing a device Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 07/28] ethdev: Add functions to know which port is attached or detached Tetsuya Mukawa
                     ` (22 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

rte_eth_dev_shutdown() is called when PCI device is closed.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index efd631b..b623e31 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -319,6 +319,42 @@ rte_eth_dev_init(struct rte_pci_driver *pci_drv,
 	return diag;
 }
 
+static int
+rte_eth_dev_shutdown(struct rte_pci_driver *pci_drv,
+		 struct rte_pci_device *pci_dev)
+{
+	struct eth_driver *eth_drv;
+	struct rte_eth_dev *eth_dev;
+	char ethdev_name[RTE_ETH_NAME_MAX_LEN];
+
+	/* Create unique Ethernet device name using PCI address */
+	snprintf(ethdev_name, RTE_ETH_NAME_MAX_LEN, "%d:%d.%d",
+			pci_dev->addr.bus, pci_dev->addr.devid,
+			pci_dev->addr.function);
+
+	eth_dev = rte_eth_dev_free(ethdev_name);
+	if (eth_dev == NULL)
+		return -ENODEV;
+
+	eth_drv = (struct eth_driver *)pci_drv;
+
+	/* Invoke PMD device shutdown function */
+	if (*eth_drv->eth_dev_shutdown)
+		(*eth_drv->eth_dev_shutdown)(eth_drv, eth_dev);
+
+	/* init user callbacks */
+	TAILQ_INIT(&(eth_dev->callbacks));
+
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+		rte_free(eth_dev->data->dev_private);
+
+	eth_dev->pci_dev = NULL;
+	eth_dev->driver = NULL;
+	eth_dev->data = NULL;
+
+	return 0;
+}
+
 /**
  * Register an Ethernet [Poll Mode] driver.
  *
@@ -337,6 +373,7 @@ void
 rte_eth_driver_register(struct eth_driver *eth_drv)
 {
 	eth_drv->pci_drv.devinit = rte_eth_dev_init;
+	eth_drv->pci_drv.devshutdown = rte_eth_dev_shutdown;
 	rte_eal_pci_register(&eth_drv->pci_drv);
 }
 
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 07/28] ethdev: Add functions to know which port is attached or detached
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (5 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 06/28] ethdev: Add rte_eth_dev_shutdown for closing PCI devices Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 08/28] ethdev: Add rte_eth_dev_get_addr_by_port Tetsuya Mukawa
                     ` (21 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch adds rte_eth_dev_save() and rte_eth_dev_get_changed_port().
rte_eth_dev_save() is used for saving current rte_eth_dev structures.
rte_eth_dev_get_changed_port() receives the rte_eth_dev structures, then
compare these with current values to know which port is actually
attached or detached.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 18 ++++++++++++++++++
 lib/librte_ether/rte_ethdev.h | 21 +++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index b623e31..939bf3b 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -391,6 +391,24 @@ rte_eth_dev_count(void)
 	return (nb_ports);
 }
 
+void
+rte_eth_dev_save(struct rte_eth_dev *devs)
+{
+	/* save current rte_eth_devices */
+	memcpy(devs, rte_eth_devices,
+			sizeof(struct rte_eth_dev) * RTE_MAX_ETHPORTS);
+}
+
+int
+rte_eth_dev_get_changed_port(struct rte_eth_dev *devs, uint8_t *port_id)
+{
+	/* check which port was attached or detached */
+	for (*port_id = 0; *port_id < RTE_MAX_ETHPORTS; (*port_id)++, devs++)
+		if (rte_eth_devices[*port_id].attached ^ devs->attached)
+			return 0;
+	return 1;
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 99cc8ce..106ba5c 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1618,6 +1618,27 @@ extern struct rte_eth_dev rte_eth_devices[];
 extern uint8_t rte_eth_dev_count(void);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Copies current ethdev structures to the specified pointer.
+ *
+ * @param	devs	The pointer to the ethdev structures
+ */
+extern void rte_eth_dev_save(struct rte_eth_dev *devs);
+
+/**
+ * Function for internal use by port hotplug functions.
+ * Compare the specified ethdev structures with currrents. Then
+ * if there is a port which status is changed, fill the specified pointer
+ * with the port id of that port.
+ * @param	devs	The pointer to the ethdev structures
+ * @param	port_id	The pointer to the port id
+ * @return
+ *   - 0 on success, negative on error
+ */
+extern int rte_eth_dev_get_changed_port(
+		struct rte_eth_dev *devs, uint8_t *port_id);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 08/28] ethdev: Add rte_eth_dev_get_addr_by_port
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (6 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 07/28] ethdev: Add functions to know which port is attached or detached Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 09/28] ethdev: Add rte_eth_dev_get_port_by_addr Tetsuya Mukawa
                     ` (20 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The function returns a pci address of a ethdev specified by port
identifier.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 12 ++++++++++++
 lib/librte_ether/rte_ethdev.h | 13 +++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 939bf3b..f59658a 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -409,6 +409,18 @@ rte_eth_dev_get_changed_port(struct rte_eth_dev *devs, uint8_t *port_id)
 	return 1;
 }
 
+int
+rte_eth_dev_get_addr_by_port(uint8_t port_id, struct rte_pci_addr *addr)
+{
+	if (port_id >= nb_ports) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -EINVAL;
+	}
+
+	*addr = rte_eth_devices[port_id].pci_dev->addr;
+	return 0;
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 106ba5c..e87e7cc 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1639,6 +1639,19 @@ extern int rte_eth_dev_get_changed_port(
 		struct rte_eth_dev *devs, uint8_t *port_id);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Returns a pci address of a ethdev specified by port identifier.
+ * @param	port_id
+ *   The port identifier of the Ethernet device
+ * @param	addr
+ *   The pointer to the pci address
+ * @return
+ *   - 0 on success, negative on error
+ */
+extern int rte_eth_dev_get_addr_by_port(
+		uint8_t port_id, struct rte_pci_addr *addr);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 09/28] ethdev: Add rte_eth_dev_get_port_by_addr
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (7 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 08/28] ethdev: Add rte_eth_dev_get_addr_by_port Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 10/28] ethdev: Add rte_eth_dev_get_name_by_port Tetsuya Mukawa
                     ` (19 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The function returns a port identifier of a ethdev specified by pci
address.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 13 +++++++++++++
 lib/librte_ether/rte_ethdev.h | 13 +++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index f59658a..48833f7 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -421,6 +421,19 @@ rte_eth_dev_get_addr_by_port(uint8_t port_id, struct rte_pci_addr *addr)
 	return 0;
 }
 
+int
+rte_eth_dev_get_port_by_addr(struct rte_pci_addr *addr, uint8_t *port_id)
+{
+	struct rte_pci_addr *tmp;
+
+	for (*port_id = 0; *port_id < RTE_MAX_ETHPORTS; (*port_id)++) {
+		tmp = &rte_eth_devices[*port_id].pci_dev->addr;
+		if (eal_compare_pci_addr(tmp, addr))
+			return 0;
+	}
+	return -1;
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index e87e7cc..8a9d1d5 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1652,6 +1652,19 @@ extern int rte_eth_dev_get_addr_by_port(
 		uint8_t port_id, struct rte_pci_addr *addr);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Returns a port identifier of a ethdev specified by pci address.
+ * @param	addr
+ *   The pointer to the pci address of the Ethernet device.
+ * @param	port_id
+ *   The pointer to the port identifier
+ * @return
+ *   - 0 on success, negative on error
+ */
+extern int rte_eth_dev_get_port_by_addr(
+		struct rte_pci_addr *addr, uint8_t *port_id);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 10/28] ethdev: Add rte_eth_dev_get_name_by_port
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (8 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 09/28] ethdev: Add rte_eth_dev_get_port_by_addr Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 11/28] ethdev: Add rte_eth_dev_check_detachable Tetsuya Mukawa
                     ` (18 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The function returns a unique identifier name of a ethdev specified by
port identifier.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 17 +++++++++++++++++
 lib/librte_ether/rte_ethdev.h | 12 ++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 48833f7..e3f2713 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -434,6 +434,23 @@ rte_eth_dev_get_port_by_addr(struct rte_pci_addr *addr, uint8_t *port_id)
 	return -1;
 }
 
+int
+rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
+{
+	char *tmp;
+
+	if (port_id >= nb_ports) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -EINVAL;
+	}
+
+	/* shouldn't check 'rte_eth_devices[i].data',
+	 * because it might be overwritten by VDEV PMD */
+	tmp = rte_eth_dev_data[port_id].name;
+	strncpy(name, tmp, strlen(tmp) + 1);
+	return 0;
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 8a9d1d5..11853f5 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1665,6 +1665,18 @@ extern int rte_eth_dev_get_port_by_addr(
 		struct rte_pci_addr *addr, uint8_t *port_id);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Returns a unique identifier name of a ethdev specified by port identifier.
+ * @param	port_id
+ *   The port identifier.
+ * @param	name
+ *  The pointer to the Unique identifier name for each Ethernet device
+ * @return
+ *   - 0 on success, negative on error
+ */
+extern int rte_eth_dev_get_name_by_port(uint8_t port_id, char *name);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 11/28] ethdev: Add rte_eth_dev_check_detachable
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (9 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 10/28] ethdev: Add rte_eth_dev_get_name_by_port Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 12/28] ethdev: Change scope of rte_eth_dev_allocated to global Tetsuya Mukawa
                     ` (17 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The function returns whether a PMD supports detach function, or not.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c |  9 +++++++++
 lib/librte_ether/rte_ethdev.h | 11 +++++++++++
 2 files changed, 20 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index e3f2713..17f3ae4 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -451,6 +451,15 @@ rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
 	return 0;
 }
 
+int
+rte_eth_dev_check_detachable(uint8_t port_id)
+{
+	uint32_t drv_flags;
+
+	drv_flags = rte_eth_devices[port_id].driver->pci_drv.drv_flags;
+	return !!(drv_flags & RTE_PCI_DRV_DETACHABLE);
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 11853f5..5cc438c 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1677,6 +1677,17 @@ extern int rte_eth_dev_get_port_by_addr(
 extern int rte_eth_dev_get_name_by_port(uint8_t port_id, char *name);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Check whether or not, a PMD that is handling the ethdev specified by port
+ * identifier can support detach function.
+ * @param	port_id
+ *   The port identifier
+ * @return
+ *   - 0 on supporting detach function, negative on not supporting
+ */
+extern int rte_eth_dev_check_detachable(uint8_t port_id);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 12/28] ethdev: Change scope of rte_eth_dev_allocated to global
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (10 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 11/28] ethdev: Add rte_eth_dev_check_detachable Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 13/28] eal/pci: Prevent double registration for devargs_list Tetsuya Mukawa
                     ` (16 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

This function is used by virtual PMDs to support port hotplug framework.
So change scope of the function to global.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c |  2 +-
 lib/librte_ether/rte_ethdev.h | 10 ++++++++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 17f3ae4..db78271 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -196,7 +196,7 @@ rte_eth_dev_data_alloc(void)
 				RTE_MAX_ETHPORTS * sizeof(*rte_eth_dev_data));
 }
 
-static struct rte_eth_dev *
+struct rte_eth_dev *
 rte_eth_dev_allocated(const char *name)
 {
 	unsigned i;
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 5cc438c..c3e8ff8 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1688,6 +1688,16 @@ extern int rte_eth_dev_get_name_by_port(uint8_t port_id, char *name);
 extern int rte_eth_dev_check_detachable(uint8_t port_id);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Returns a ethdev slot specified by the unique identifier name.
+ * @param	name
+ *  The pointer to the Unique identifier name for each Ethernet device
+ * @return
+ *   - The pointer to the ethdev slot, on success. NULL on error
+ */
+extern struct rte_eth_dev *rte_eth_dev_allocated(const char *name);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 13/28] eal/pci: Prevent double registration for devargs_list
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (11 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 12/28] ethdev: Change scope of rte_eth_dev_allocated to global Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 14/28] eal/pci: Add rte_eal_devargs_remove Tetsuya Mukawa
                     ` (15 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch fixes rte_eal_devargs_add() not to register same device twice.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_devargs.c | 32 ++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index 4c7d11a..aaa6901 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -44,6 +44,32 @@
 struct rte_devargs_list devargs_list =
 	TAILQ_HEAD_INITIALIZER(devargs_list);
 
+
+/* find a entry specified by pci address or device name */
+static struct rte_devargs *
+rte_eal_devargs_find(enum rte_devtype devtype, void *args)
+{
+	struct rte_devargs *devargs;
+
+	TAILQ_FOREACH(devargs, &devargs_list, next) {
+		switch (devtype) {
+		case RTE_DEVTYPE_WHITELISTED_PCI:
+		case RTE_DEVTYPE_BLACKLISTED_PCI:
+			if (eal_compare_pci_addr(&devargs->pci.addr, args) == 0)
+				goto found;
+			break;
+		case RTE_DEVTYPE_VIRTUAL:
+			if (memcmp(&devargs->virtual.drv_name, args,
+					strlen((char *)args)) == 0)
+				goto found;
+			break;
+		}
+	}
+	return NULL;
+found:
+	return devargs;
+}
+
 /* store a whitelist parameter for later parsing */
 int
 rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str)
@@ -101,6 +127,12 @@ rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str)
 		break;
 	}
 
+	/* make sure there is no same entry */
+	if (rte_eal_devargs_find(devtype, &devargs->pci.addr)) {
+		RTE_LOG(ERR, EAL, "device already registered: <%s>\n", buf);
+		return -1;
+	}
+
 	TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
 	return 0;
 }
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 14/28] eal/pci: Add rte_eal_devargs_remove
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (12 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 13/28] eal/pci: Prevent double registration for devargs_list Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 15/28] eal/pci: Add probe and close function for virtual drivers Tetsuya Mukawa
                     ` (14 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The function removes a specified devargs from devargs_list.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_devargs.c  | 13 +++++++++++++
 lib/librte_eal/common/include/rte_devargs.h | 18 ++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index aaa6901..0916cf8 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -137,6 +137,19 @@ rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str)
 	return 0;
 }
 
+/* remove it from the devargs_list */
+void
+rte_eal_devargs_remove(enum rte_devtype devtype, void *args)
+{
+	struct rte_devargs *devargs;
+
+	devargs = rte_eal_devargs_find(devtype, args);
+	if (devargs == NULL)
+		return;
+
+	TAILQ_REMOVE(&devargs_list, devargs, next);
+}
+
 /* count the number of devices of a specified type */
 unsigned int
 rte_eal_devargs_type_count(enum rte_devtype devtype)
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
index 9f9c98f..57842b3 100644
--- a/lib/librte_eal/common/include/rte_devargs.h
+++ b/lib/librte_eal/common/include/rte_devargs.h
@@ -123,6 +123,24 @@ extern struct rte_devargs_list devargs_list;
 int rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str);
 
 /**
+ * Remove a device form the user device list
+ *
+ * For PCI devices, the format of arguments string is "PCI_ADDR". It shouldn't
+ * involves parameters for the device. Example: "08:00.1".
+ *
+ * For virtual devices, the format of arguments string is "DRIVER_NAME*". It
+ * shouldn't involves parameters for the device. Example: "eth_ring". The
+ * validity of the driver name is not checked by this function, it is done
+ * when closing the drivers.
+ *
+ * @param devtype
+ *   The type of the device.
+ * @param name
+ *   The name of the device.
+ */
+void rte_eal_devargs_remove(enum rte_devtype devtype, void *args);
+
+/**
  * Count the number of user devices of a specified type
  *
  * @param devtype
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 15/28] eal/pci: Add probe and close function for virtual drivers
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (13 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 14/28] eal/pci: Add rte_eal_devargs_remove Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 16/28] eal/pci: Add port hotplug functions for virtual devices Tetsuya Mukawa
                     ` (13 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch adds rte_eal_dev_init_one() and rte_eal_dev_close_one().
These are used for attaching and detaching virtual devices.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_dev.c  | 74 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h |  6 +++
 lib/librte_eal/linuxapp/eal/Makefile    |  1 +
 3 files changed, 81 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index eae5656..183d65b 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -32,10 +32,13 @@
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <stdio.h>
+#include <limits.h>
 #include <string.h>
 #include <inttypes.h>
 #include <sys/queue.h>
 
+#include <rte_ethdev.h>
 #include <rte_dev.h>
 #include <rte_devargs.h>
 #include <rte_debug.h>
@@ -107,3 +110,74 @@ rte_eal_dev_init(void)
 	}
 	return 0;
 }
+
+/* So far, linux only supports DPDK hotplug function. */
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+
+#define INVOKE_PROBE	(0)
+#define INVOKE_CLOSE	(1)
+
+static void
+rte_eal_dev_invoke(struct rte_driver *driver,
+		struct rte_devargs *devargs, int type)
+{
+	switch (type) {
+	case INVOKE_PROBE:
+		driver->init(devargs->virtual.drv_name, devargs->args);
+		break;
+	case INVOKE_CLOSE:
+		driver->close(devargs->virtual.drv_name, devargs->args);
+		break;
+	}
+}
+
+static int
+rte_eal_dev_find_and_invoke(const char *name, int type)
+{
+	struct rte_devargs *devargs;
+	struct rte_driver *driver;
+
+	/* call the init function for each virtual device */
+	TAILQ_FOREACH(devargs, &devargs_list, next) {
+
+		if (devargs->type != RTE_DEVTYPE_VIRTUAL)
+			continue;
+
+		if (strncmp(name, devargs->virtual.drv_name, strlen(name)))
+			continue;
+
+		TAILQ_FOREACH(driver, &dev_driver_list, next) {
+			if (driver->type != PMD_VDEV)
+				continue;
+
+			/* search a driver prefix in virtual device name */
+			if (!strncmp(driver->name, devargs->virtual.drv_name,
+					strlen(driver->name))) {
+				rte_eal_dev_invoke(driver, devargs, type);
+				break;
+			}
+		}
+
+		if (driver == NULL) {
+			RTE_LOG(WARNING, EAL, "no driver found for %s\n",
+				  devargs->virtual.drv_name);
+		}
+		return 0;
+	}
+	return 1;
+}
+
+/* find and initialize the driver of specified virtual device */
+static int
+rte_eal_dev_init_one(const char *name)
+{
+	return rte_eal_dev_find_and_invoke(name, INVOKE_PROBE);
+}
+
+/* find and finalize the driver of specified virtual device */
+static int
+rte_eal_dev_close_one(const char *name)
+{
+	return rte_eal_dev_find_and_invoke(name, INVOKE_CLOSE);
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index f7e3a10..71d40c3 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -57,6 +57,11 @@ TAILQ_HEAD(rte_driver_list, rte_driver);
 typedef int (rte_dev_init_t)(const char *name, const char *args);
 
 /**
+ * Close function called for each device driver once.
+ */
+typedef int (rte_dev_close_t)(const char *name, const char *args);
+
+/**
  * Driver type enumeration
  */
 enum pmd_type {
@@ -72,6 +77,7 @@ struct rte_driver {
 	enum pmd_type type;		   /**< PMD Driver type */
 	const char *name;                   /**< Driver name. */
 	rte_dev_init_t *init;              /**< Device init. function. */
+	rte_dev_close_t *close;            /**< Device close. function. */
 };
 
 /**
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index c99433e..27e9b48 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -40,6 +40,7 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
 CFLAGS += -I$(RTE_SDK)/lib/librte_ring
 CFLAGS += -I$(RTE_SDK)/lib/librte_mempool
 CFLAGS += -I$(RTE_SDK)/lib/librte_malloc
+CFLAGS += -I$(RTE_SDK)/lib/librte_mbuf
 CFLAGS += -I$(RTE_SDK)/lib/librte_ether
 CFLAGS += -I$(RTE_SDK)/lib/librte_ivshmem
 CFLAGS += -I$(RTE_SDK)/lib/librte_pmd_ring
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 16/28] eal/pci: Add port hotplug functions for virtual devices.
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (14 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 15/28] eal/pci: Add probe and close function for virtual drivers Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 17/28] eal/linux/pci: Add functions for unmapping igb_uio resources Tetsuya Mukawa
                     ` (12 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch adds rte_eal_dev_attach_vdev() and rte_eal_dev_detach_vdev().

rte_eal_dev_attach_vdev() receives virtual device name and parameters,
and returns an attached port number.
rte_eal_dev_detach_vdev() receives a port number, and returns device
name actually detached.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_dev.c  | 76 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h | 29 +++++++++++++
 2 files changed, 105 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 183d65b..0518e3c 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -180,4 +180,80 @@ rte_eal_dev_close_one(const char *name)
 {
 	return rte_eal_dev_find_and_invoke(name, INVOKE_CLOSE);
 }
+
+static void
+get_vdev_name(char *vdevargs)
+{
+	char *sep;
+
+	/* set the first ',' to '\0' to split name and arguments */
+	sep = strchr(vdevargs, ',');
+	if (sep != NULL)
+		sep[0] = '\0';
+}
+
+/* attach the new virtual device, then store port_id of the device */
+int
+rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id)
+{
+	char *args;
+	uint8_t new_port_id;
+	struct rte_eth_dev devs[RTE_MAX_ETHPORTS];
+
+	args = strdup(vdevargs);
+	if (args == NULL)
+		return -1;
+
+	/* save current port status */
+	rte_eth_dev_save(devs);
+	/* add the vdevargs to devargs_list */
+	if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, args))
+		goto err0;
+	/* parse vdevargs, then retrieve device name */
+	get_vdev_name(args);
+	/* walk around dev_driver_list to find the driver of the device,
+	 * then invoke probe function o the driver */
+	if (rte_eal_dev_init_one(args))
+		goto err1;
+	/* get port_id enabled by above procedures */
+	if (rte_eth_dev_get_changed_port(devs, &new_port_id))
+		goto err1;
+
+	free(args);
+	*port_id = new_port_id;
+	return 0;
+err1:
+	rte_eal_devargs_remove(RTE_DEVTYPE_VIRTUAL, args);
+err0:
+	RTE_LOG(ERR, EAL, "Drver, cannot detach the device\n");
+	free(args);
+	return -1;
+}
+
+/* detach the new virtual device, then store the name of the device */
+int
+rte_eal_dev_detach_vdev(uint8_t port_id, char *vdevname)
+{
+	char name[RTE_ETH_NAME_MAX_LEN];
+
+	/* check whether the driver supports detach feature, or not */
+	if (!rte_eth_dev_check_detachable(port_id))
+		goto err;
+
+	/* get device name by port id */
+	if (rte_eth_dev_get_name_by_port(port_id, name))
+		goto err;
+	/* walk around dev_driver_list to find the driver of the device,
+	 * then invoke close function o the driver */
+	if (rte_eal_dev_close_one(name))
+		goto err;
+	/* remove the vdevname from devargs_list */
+	rte_eal_devargs_remove(RTE_DEVTYPE_VIRTUAL, name);
+
+	strncpy(vdevname, name, sizeof(name));
+	return 0;
+err:
+	RTE_LOG(ERR, EAL, "Drver, cannot detach the device\n");
+	return -1;
+}
 #endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 71d40c3..159d5a5 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -98,6 +98,35 @@ void rte_eal_driver_register(struct rte_driver *driver);
  */
 void rte_eal_driver_unregister(struct rte_driver *driver);
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+
+/**
+ * Attach a new virtual device.
+ *
+ * @param vdevargs
+ *   A pointer to a strings array describing the new device
+ *   to be attached.
+ * @param port_id
+ *  A pointer to a port identifier actually attached.
+ * @return
+ *  0 on success and port_id is filled, negative on error
+ */
+int rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id);
+
+/**
+ * Detach a virtual device.
+ *
+ * @param port_id
+ *   The port identifier of the virtual device to detach.
+ * @param addr
+ *  A pointer to a virtual device name actually detached.
+ * @return
+ *  0 on success and vdevname is filled, negative on error
+ */
+int rte_eal_dev_detach_vdev(uint8_t port_id, char *vdevname);
+
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /**
  * Initalize all the registered drivers in this process
  */
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 17/28] eal/linux/pci: Add functions for unmapping igb_uio resources
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (15 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 16/28] eal/pci: Add port hotplug functions for virtual devices Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 18/28] eal/pci: Prevent double registrations for pci_device_list Tetsuya Mukawa
                     ` (11 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch adds functions for unmapping igb_uio resources. The patch is only
for Linux and igb_uio environment. VFIO and BSD are not supported.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/linuxapp/eal/eal_pci.c              | 32 +++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c          | 56 ++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/include/eal_pci_init.h |  7 +++
 3 files changed, 95 insertions(+)

diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 862b93a..57a5887 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -123,6 +123,22 @@ fail:
 	return NULL;
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+/* unmap a particular resource */
+void
+pci_unmap_resource(void *requested_addr, size_t size)
+{
+	/* Unmap the PCI memory resource of device */
+	if (munmap(requested_addr, size)) {
+		RTE_LOG(ERR, EAL, "%s(): cannot munmap(%p, 0x%lx): %s\n",
+			__func__, requested_addr, (unsigned long)size,
+			strerror(errno));
+	} else
+		RTE_LOG(DEBUG, EAL, "  PCI memory mapped at %p\n",
+				requested_addr);
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /* parse the "resource" sysfs file */
 #define IORESOURCE_MEM  0x00000200
 
@@ -493,6 +509,22 @@ pci_map_device(struct rte_pci_device *dev)
 	return 0;
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+static void
+pci_unmap_device(struct rte_pci_device *dev)
+{
+	/* try unmapping the NIC resources using VFIO if it exists */
+#ifdef VFIO_PRESENT
+	if (pci_vfio_is_enabled()) {
+		RTE_LOG(ERR, EAL, "%s() doesn't support vfio yet.\n",
+				__func__);
+		return;
+	}
+#endif
+	pci_uio_unmap_resource(dev);
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /*
  * If vendor/device ID match, call the devinit() function of the
  * driver.
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
index f0deeba..ff48eb9 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
@@ -395,6 +395,62 @@ pci_uio_map_resource(struct rte_pci_device *dev)
 	return 0;
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+static void
+pci_uio_unmap(struct mapped_pci_resource *uio_res)
+{
+	int i;
+
+	for (i = 0; i != uio_res->nb_maps; i++)
+		pci_unmap_resource(uio_res->maps[i].addr,
+				(size_t)uio_res->maps[i].size);
+}
+
+static struct mapped_pci_resource *
+pci_uio_find_resource(struct rte_pci_device *dev)
+{
+	struct mapped_pci_resource *uio_res;
+
+	TAILQ_FOREACH(uio_res, pci_res_list, next) {
+
+		/* skip this element if it doesn't match our PCI address */
+		if (!eal_compare_pci_addr(&uio_res->pci_addr, &dev->addr))
+			return uio_res;
+	}
+	return NULL;
+}
+
+/* unmap the PCI resource of a PCI device in virtual memory */
+void
+pci_uio_unmap_resource(struct rte_pci_device *dev)
+{
+	struct mapped_pci_resource *uio_res;
+
+	/* find an entry for the device */
+	uio_res = pci_uio_find_resource(dev);
+	if (uio_res == NULL)
+		return;
+
+	/* secondary processes - just free maps */
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return pci_uio_unmap(uio_res);
+
+	TAILQ_REMOVE(pci_res_list, uio_res, next);
+
+	/* unmap all resources */
+	pci_uio_unmap(uio_res);
+
+	/* free uio resource */
+	rte_free(uio_res);
+
+	/* close fd if in primary process */
+	close(dev->intr_handle.fd);
+
+	dev->intr_handle.fd = -1;
+	dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /*
  * parse a sysfs file containing one integer value
  * different to the eal version, as it needs to work with 64-bit values
diff --git a/lib/librte_eal/linuxapp/eal/include/eal_pci_init.h b/lib/librte_eal/linuxapp/eal/include/eal_pci_init.h
index d758bee..ab9c16b 100644
--- a/lib/librte_eal/linuxapp/eal/include/eal_pci_init.h
+++ b/lib/librte_eal/linuxapp/eal/include/eal_pci_init.h
@@ -65,6 +65,13 @@ void *pci_map_resource(void *requested_addr, int fd, off_t offset,
 /* map IGB_UIO resource prototype */
 int pci_uio_map_resource(struct rte_pci_device *dev);
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+void pci_unmap_resource(void *requested_addr, size_t size);
+
+/* unmap IGB_UIO resource prototype */
+void pci_uio_unmap_resource(struct rte_pci_device *dev);
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 #ifdef VFIO_PRESENT
 
 #define VFIO_MAX_GROUPS 64
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 18/28] eal/pci: Prevent double registrations for pci_device_list
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (16 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 17/28] eal/linux/pci: Add functions for unmapping igb_uio resources Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 19/28] eal/pci: Change scope of rte_eal_pci_scan to global Tetsuya Mukawa
                     ` (10 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch fixes pci_scan_one() not to register same pci devices twice.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/linuxapp/eal/eal_pci.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 57a5887..c70e8ea 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -292,14 +292,17 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
 	}
 	else {
 		struct rte_pci_device *dev2 = NULL;
+		int ret;
 
 		TAILQ_FOREACH(dev2, &pci_device_list, next) {
-			if (eal_compare_pci_addr(&dev->addr, &dev2->addr) != 0)
+			ret = eal_compare_pci_addr(&dev->addr, &dev2->addr);
+			if (ret > 0)
 				continue;
-			else {
+			else if (ret < 0) {
 				TAILQ_INSERT_BEFORE(dev2, dev, next);
 				return 0;
-			}
+			} else	/* already registered */
+				return 0;
 		}
 		TAILQ_INSERT_TAIL(&pci_device_list, dev, next);
 	}
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 19/28] eal/pci: Change scope of rte_eal_pci_scan to global
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (17 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 18/28] eal/pci: Prevent double registrations for pci_device_list Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 20/28] eal/pci: Add rte_eal_pci_close_one_driver Tetsuya Mukawa
                     ` (9 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The function is called by port hotplug framework, so change scope of the
function to global.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/include/eal_private.h | 11 +++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c       |  6 +++---
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/common/include/eal_private.h b/lib/librte_eal/common/include/eal_private.h
index 232fcec..a1127ab 100644
--- a/lib/librte_eal/common/include/eal_private.h
+++ b/lib/librte_eal/common/include/eal_private.h
@@ -154,6 +154,17 @@ struct rte_pci_driver;
 struct rte_pci_device;
 
 /**
+ * Scan the content of the PCI bus, and the devices in the devices
+ * list
+ *
+ * This function is private to EAL.
+ *
+ * @return
+ *  0 on success, negative on error
+ */
+int rte_eal_pci_scan(void);
+
+/**
  * Mmap memory for single PCI device
  *
  * This function is private to EAL.
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index c70e8ea..4521c33 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -361,8 +361,8 @@ error:
  * Scan the content of the PCI bus, and the devices in the devices
  * list
  */
-static int
-pci_scan(void)
+int
+rte_eal_pci_scan(void)
 {
 	struct dirent *e;
 	DIR *dir;
@@ -612,7 +612,7 @@ rte_eal_pci_init(void)
 	if (internal_config.no_pci)
 		return 0;
 
-	if (pci_scan() < 0) {
+	if (rte_eal_pci_scan() < 0) {
 		RTE_LOG(ERR, EAL, "%s(): Cannot scan PCI bus\n", __func__);
 		return -1;
 	}
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 20/28] eal/pci: Add rte_eal_pci_close_one_driver
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (18 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 19/28] eal/pci: Change scope of rte_eal_pci_scan to global Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 21/28] eal/pci: Fix pci_probe_all_drivers to share code with closing function Tetsuya Mukawa
                     ` (8 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The function is used for closing the specified driver and device.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/include/eal_private.h | 11 ++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c       | 58 +++++++++++++++++++++++++++++
 2 files changed, 69 insertions(+)

diff --git a/lib/librte_eal/common/include/eal_private.h b/lib/librte_eal/common/include/eal_private.h
index a1127ab..b2776cc 100644
--- a/lib/librte_eal/common/include/eal_private.h
+++ b/lib/librte_eal/common/include/eal_private.h
@@ -176,6 +176,17 @@ int rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr,
 		struct rte_pci_device *dev);
 
 /**
+ * Munmap memory for single PCI device
+ *
+ * This function is private to EAL.
+ *
+ * @return
+ *   0 on success, negative on error
+ */
+int rte_eal_pci_close_one_driver(struct rte_pci_driver *dr,
+		struct rte_pci_device *dev);
+
+/**
  * Init tail queues for non-EAL library structures. This is to allow
  * the rings, mempools, etc. lists to be shared among multiple processes
  *
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 4521c33..5dd15af 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -599,6 +599,64 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d
 	return 1;
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+/*
+ * If vendor/device ID match, call the devshutdown() function of the
+ * driver.
+ */
+int
+rte_eal_pci_close_one_driver(struct rte_pci_driver *dr,
+		struct rte_pci_device *dev)
+{
+	struct rte_pci_id *id_table;
+
+	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;
+
+		RTE_LOG(DEBUG, EAL,
+				"PCI device "PCI_PRI_FMT" on NUMA socket %i\n",
+				loc->domain, loc->bus, loc->devid,
+				loc->function, dev->numa_node);
+
+		RTE_LOG(DEBUG, EAL, "  remove driver: %x:%x %s\n",
+				dev->id.vendor_id, dev->id.device_id,
+				dr->name);
+
+		/* call the driver devshutdown() function */
+		if (dr->devshutdown && (dr->devshutdown(dr, dev) < 0))
+			return -1;	/* negative value is an error */
+
+		/* clear driver structure */
+		dev->driver = NULL;
+
+		if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
+			/* unmap resources for devices that use igb_uio */
+			pci_unmap_device(dev);
+
+		return 0;
+	}
+	/* return positive value if driver is not found */
+	return 1;
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /* Init the PCI EAL subsystem */
 int
 rte_eal_pci_init(void)
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 21/28] eal/pci: Fix pci_probe_all_drivers to share code with closing function
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (19 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 20/28] eal/pci: Add rte_eal_pci_close_one_driver Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 22/28] eal/pci: Add pci_close_all_drivers Tetsuya Mukawa
                     ` (7 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

pci_close_all_drivers() will be implemented after the patch.
To share a part of code between thses 2 functions, The patch fixes
pci_probe_all_drivers() first.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_pci.c | 28 ++++++++++++++++++++--------
 1 file changed, 20 insertions(+), 8 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index f01f258..1e3efea 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -99,19 +99,20 @@ static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
 	return NULL;
 }
 
-/*
- * If vendor/device ID match, call the devinit() function of all
- * registered driver for the given device. Return -1 if initialization
- * failed, return 1 if no driver is found for this device.
- */
+#define INVOKE_PROBE	(0)
+
 static int
-pci_probe_all_drivers(struct rte_pci_device *dev)
+pci_invoke_all_drivers(struct rte_pci_device *dev, int type)
 {
 	struct rte_pci_driver *dr = NULL;
-	int rc;
+	int rc = 0;
 
 	TAILQ_FOREACH(dr, &pci_driver_list, next) {
-		rc = rte_eal_pci_probe_one_driver(dr, dev);
+		switch (type) {
+		case INVOKE_PROBE:
+			rc = rte_eal_pci_probe_one_driver(dr, dev);
+			break;
+		}
 		if (rc < 0)
 			/* negative value is an error */
 			return -1;
@@ -124,6 +125,17 @@ pci_probe_all_drivers(struct rte_pci_device *dev)
 }
 
 /*
+ * If vendor/device ID match, call the devinit() 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_probe_all_drivers(struct rte_pci_device *dev)
+{
+	return pci_invoke_all_drivers(dev, INVOKE_PROBE);
+}
+
+/*
  * Scan the content of the PCI bus, and call the devinit() function for
  * all registered drivers that have a matching entry in its id_table
  * for discovered devices.
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 22/28] eal/pci: Add pci_close_all_drivers
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (20 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 21/28] eal/pci: Fix pci_probe_all_drivers to share code with closing function Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 23/28] eal/pci: Add rte_eal_pci_probe_one and rte_eal_pci_close_one Tetsuya Mukawa
                     ` (6 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The function tries to find a driver for the specified device, and then
close the driver.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_pci.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index 1e3efea..b404ee0 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -100,6 +100,7 @@ static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
 }
 
 #define INVOKE_PROBE	(0)
+#define INVOKE_CLOSE	(1)
 
 static int
 pci_invoke_all_drivers(struct rte_pci_device *dev, int type)
@@ -112,6 +113,11 @@ pci_invoke_all_drivers(struct rte_pci_device *dev, int type)
 		case INVOKE_PROBE:
 			rc = rte_eal_pci_probe_one_driver(dr, dev);
 			break;
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+		case INVOKE_CLOSE:
+			rc = rte_eal_pci_close_one_driver(dr, dev);
+			break;
+#endif
 		}
 		if (rc < 0)
 			/* negative value is an error */
@@ -135,6 +141,19 @@ pci_probe_all_drivers(struct rte_pci_device *dev)
 	return pci_invoke_all_drivers(dev, INVOKE_PROBE);
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+/*
+ * If vendor/device ID match, call the devclose() 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_close_all_drivers(struct rte_pci_device *dev)
+{
+	return pci_invoke_all_drivers(dev, INVOKE_CLOSE);
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /*
  * Scan the content of the PCI bus, and call the devinit() function for
  * all registered drivers that have a matching entry in its id_table
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 23/28] eal/pci: Add rte_eal_pci_probe_one and rte_eal_pci_close_one
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (21 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 22/28] eal/pci: Add pci_close_all_drivers Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 24/28] eal/pci: Add port hotplug functions for physical devices Tetsuya Mukawa
                     ` (5 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The functions are used for probe and close a device.
First the function tries to find a device that has the specfied PCI address.
Then, probe or close the device.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_pci.c  | 58 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_pci.h | 26 +++++++++++++++
 2 files changed, 84 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index b404ee0..5ff7b49 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -152,6 +152,64 @@ pci_close_all_drivers(struct rte_pci_device *dev)
 {
 	return pci_invoke_all_drivers(dev, INVOKE_CLOSE);
 }
+
+static int
+rte_eal_pci_invoke_one(struct rte_pci_addr *addr, int type)
+{
+	struct rte_pci_device *dev = NULL;
+	int ret = 0;
+
+	TAILQ_FOREACH(dev, &pci_device_list, next) {
+		if (eal_compare_pci_addr(&dev->addr, addr))
+			continue;
+
+		switch (type) {
+		case INVOKE_PROBE:
+			ret = pci_probe_all_drivers(dev);
+			break;
+		case INVOKE_CLOSE:
+			ret = pci_close_all_drivers(dev);
+			break;
+		}
+		if (ret < 0)
+			goto invoke_err_return;
+		if (type == INVOKE_CLOSE)
+			goto remove_dev;
+		return 0;
+	}
+
+	return -1;
+
+invoke_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);
+	return -1;
+
+remove_dev:
+	TAILQ_REMOVE(&pci_device_list, dev, next);
+	return 0;
+}
+
+/*
+ * Find the pci device specified by pci address, then invoke probe function of
+ * the driver of the devive.
+ */
+int
+rte_eal_pci_probe_one(struct rte_pci_addr *addr)
+{
+	return rte_eal_pci_invoke_one(addr, INVOKE_PROBE);
+}
+
+/*
+ * Find the pci device specified by pci address, then invoke close function of
+ * the driver of the devive.
+ */
+int
+rte_eal_pci_close_one(struct rte_pci_addr *addr)
+{
+	return rte_eal_pci_invoke_one(addr, INVOKE_CLOSE);
+}
 #endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
 
 /*
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 74720d1..33300be 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -311,6 +311,32 @@ eal_compare_pci_addr(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
 int rte_eal_pci_probe(void);
 
 /**
+ * Probe the single PCI device.
+ *
+ * Scan the content of the PCI bus, and find the pci device specified by pci
+ * addrrss, then call the probe() function for registered driver that has a
+ * matching entry in its id_table for discovered device.
+ *
+ * @return
+ *   - 0 on success.
+ *   - Negative on error.
+ */
+int rte_eal_pci_probe_one(struct rte_pci_addr *addr);
+
+/**
+ * Close the single PCI device.
+ *
+ * Scan the content of the PCI bus, and find the pci device specified by pci
+ * addrrss, then call the close() function for registered driver that has a
+ * matching entry in its id_table for discovered device.
+ *
+ * @return
+ *   - 0 on success.
+ *   - Negative on error.
+ */
+int rte_eal_pci_close_one(struct rte_pci_addr *addr);
+
+/**
  * Dump the content of the PCI bus.
  *
  * @param f
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 24/28] eal/pci: Add port hotplug functions for physical devices.
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (22 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 23/28] eal/pci: Add rte_eal_pci_probe_one and rte_eal_pci_close_one Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 25/28] eal: Enable port hotplug framework in Linux Tetsuya Mukawa
                     ` (4 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch adds rte_eal_dev_attach_pdev() and rte_eal_dev_detach_pdev().

rte_eal_dev_attach_pdev() receives a PCI address of the device and
returns an attached port number.
rte_eal_dev_detach_pdev() receives a port number, and returns a PCI
address actually detached.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_dev.c  | 58 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h | 25 ++++++++++++++
 2 files changed, 83 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 0518e3c..c2d5cd6 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -181,6 +181,64 @@ rte_eal_dev_close_one(const char *name)
 	return rte_eal_dev_find_and_invoke(name, INVOKE_CLOSE);
 }
 
+/* attach the new physical device, then store port_id of the device */
+int
+rte_eal_dev_attach_pdev(struct rte_pci_addr *addr, uint8_t *port_id)
+{
+	uint8_t new_port_id;
+	struct rte_eth_dev devs[RTE_MAX_ETHPORTS];
+
+	/* save current port status */
+	rte_eth_dev_save(devs);
+	/* re-construct pci_device_list */
+	if (rte_eal_pci_scan())
+		goto err;
+	/* invoke probe func of the driver can handle the new device */
+	if (rte_eal_pci_probe_one(addr))
+		goto err;
+	/* get port_id enabled by above procedures */
+	if (rte_eth_dev_get_changed_port(devs, &new_port_id))
+		goto err;
+
+	*port_id = new_port_id;
+	return 0;
+err:
+	RTE_LOG(ERR, EAL, "Drver, cannot attach the device\n");
+	return -1;
+}
+
+/* detach the new physical device, then store pci_addr of the device */
+int
+rte_eal_dev_detach_pdev(uint8_t port_id, struct rte_pci_addr *addr)
+{
+	struct rte_pci_addr freed_addr;
+	struct rte_pci_addr vp;
+
+	/* check whether the driver supports detach feature, or not */
+	if (!rte_eth_dev_check_detachable(port_id))
+		goto err;
+
+	/* get pci address by port id */
+	if (rte_eth_dev_get_addr_by_port(port_id, &freed_addr))
+		goto err;
+
+	/* Zerod pci addr means the port comes from virtual device */
+	vp.domain = vp.bus = vp.devid = vp.function = 0;
+	if (eal_compare_pci_addr(&vp, &freed_addr) == 0)
+		goto err;
+
+	/* invoke close func of the driver,
+	 * also remove the device from pci_device_list */
+	if (rte_eal_pci_close_one(&freed_addr))
+		goto err;
+
+	*addr = freed_addr;
+	return 0;
+err:
+	RTE_LOG(ERR, EAL, "Drver, cannot detach the device\n");
+	return -1;
+}
+
 static void
 get_vdev_name(char *vdevargs)
 {
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 159d5a5..26d7526 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -101,6 +101,19 @@ void rte_eal_driver_unregister(struct rte_driver *driver);
 #if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
 
 /**
+ * Attach a new physical device.
+ *
+ * @param addr
+ *   A pointer to a pci address structure describing the new
+ *   device to be attached.
+ * @param port_id
+ *  A pointer to a port identifier actually attached.
+ * @return
+ *  0 on success and port_id is filled, negative on error
+ */
+int rte_eal_dev_attach_pdev(struct rte_pci_addr *addr, uint8_t *port_id);
+
+/**
  * Attach a new virtual device.
  *
  * @param vdevargs
@@ -114,6 +127,18 @@ void rte_eal_driver_unregister(struct rte_driver *driver);
 int rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id);
 
 /**
+ * Detach a physical device.
+ *
+ * @param port_id
+ *   The port identifier of the physical device to detach.
+ * @param addr
+ *  A pointer to a pci address structure actually detached.
+ * @return
+ *  0 on success and addr is filled, negative on error
+ */
+int rte_eal_dev_detach_pdev(uint8_t port_id, struct rte_pci_addr *addr);
+
+/**
  * Detach a virtual device.
  *
  * @param port_id
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 25/28] eal: Enable port hotplug framework in Linux
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (23 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 24/28] eal/pci: Add port hotplug functions for physical devices Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 26/28] librte_pmd_pcap: Add support for port hotplug Tetsuya Mukawa
                     ` (3 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch enables CONFIG_RTE_LIBRTE_EAL_HOTPLUG in Linux configuration.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 config/common_linuxapp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/config/common_linuxapp b/config/common_linuxapp
index c5751bd..f94ec65 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -144,6 +144,11 @@ CONFIG_RTE_LIBRTE_EAL_LINUXAPP=y
 CONFIG_RTE_LIBRTE_EAL_BAREMETAL=n
 
 #
+# Compile Environment Abstraction Layer to support hotplug
+#
+CONFIG_RTE_LIBRTE_EAL_HOTPLUG=y
+
+#
 # Compile Environment Abstraction Layer to support Vmware TSC map
 #
 CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=y
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 26/28] librte_pmd_pcap: Add support for port hotplug
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (24 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 25/28] eal: Enable port hotplug framework in Linux Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 27/28] testpmd: Add support for the port hotplug framework Tetsuya Mukawa
                     ` (2 subsequent siblings)
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

This patch adds finalization code to free resources allocated by the
PMD.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_pmd_pcap/rte_eth_pcap.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/lib/librte_pmd_pcap/rte_eth_pcap.c b/lib/librte_pmd_pcap/rte_eth_pcap.c
index f12d1e7..90fc065 100644
--- a/lib/librte_pmd_pcap/rte_eth_pcap.c
+++ b/lib/librte_pmd_pcap/rte_eth_pcap.c
@@ -499,6 +499,13 @@ static struct eth_dev_ops ops = {
 		.stats_reset = eth_stats_reset,
 };
 
+static struct eth_driver rte_pcap_pmd = {
+	.pci_drv = {
+		.name = "rte_pcap_pmd",
+		.drv_flags = RTE_PCI_DRV_DETACHABLE,
+	},
+};
+
 /*
  * Function handler that opens the pcap file for reading a stores a
  * reference of it for use it later on.
@@ -743,6 +750,7 @@ rte_pmd_init_internals(const char *name, const unsigned nb_rx_queues,
 	(*eth_dev)->data = data;
 	(*eth_dev)->dev_ops = &ops;
 	(*eth_dev)->pci_dev = pci_dev;
+	(*eth_dev)->driver = &rte_pcap_pmd;
 
 	return 0;
 
@@ -927,10 +935,33 @@ rte_pmd_pcap_devinit(const char *name, const char *params)
 
 }
 
+static int
+rte_pmd_pcap_devclose(const char *name, const char *params __rte_unused)
+{
+	struct rte_eth_dev *eth_dev = NULL;
+
+	RTE_LOG(INFO, PMD, "Closing pcap ethdev on numa socket %u\n",
+			rte_socket_id());
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocated(name);
+	if (eth_dev == NULL)
+		return -1;
+
+	rte_free(eth_dev->data->dev_private);
+	rte_free(eth_dev->data);
+	rte_free(eth_dev->pci_dev);
+
+	rte_eth_dev_free(name);
+
+	return 0;
+}
+
 static struct rte_driver pmd_pcap_drv = {
 	.name = "eth_pcap",
 	.type = PMD_VDEV,
 	.init = rte_pmd_pcap_devinit,
+	.close = rte_pmd_pcap_devclose,
 };
 
 PMD_REGISTER_DRIVER(pmd_pcap_drv);
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 27/28] testpmd: Add support for the port hotplug framework
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (25 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 26/28] librte_pmd_pcap: Add support for port hotplug Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 28/28] librte_pmd_e1000: Add workaround to test " Tetsuya Mukawa
  2014-11-18  8:55   ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

The patch introduces following commands.
- port [attach|detach] [p|v] [ident]
 - attach: attaching a port
 - detach: detaching a port
 - p: physical port
 - v: virtual port
 - ident: pci address of physical device.
          Or device name and paramerters of virtual device.
         (ex. 0000:02:00.0, eth_pcap0,iface=eth0)

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 app/test-pmd/cmdline.c    | 139 +++++++++++++++++++++++-----
 app/test-pmd/config.c     |  54 +++++++----
 app/test-pmd/parameters.c |  21 +++--
 app/test-pmd/testpmd.c    | 225 ++++++++++++++++++++++++++++++++++++----------
 app/test-pmd/testpmd.h    |  17 ++++
 5 files changed, 364 insertions(+), 92 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 47162e9..85e4c24 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -545,6 +545,12 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"port close (port_id|all)\n"
 			"    Close all ports or port_id.\n\n"
 
+			"port add (p|a) (ident)\n"
+			"    Add physical or virtual dev by pci address or virtual device name\n\n"
+
+			"port del (p|a) (port_id)\n"
+			"    Del physical or virtual dev by port_id\n\n"
+
 			"port config (port_id|all)"
 			" speed (10|100|1000|10000|40000|auto)"
 			" duplex (half|full|auto)\n"
@@ -791,6 +797,101 @@ cmdline_parse_inst_t cmd_operate_specific_port = {
 	},
 };
 
+/* *** attach a specificied port *** */
+struct cmd_operate_attach_port_result {
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t keyword;
+	cmdline_fixed_string_t type;
+	cmdline_fixed_string_t identifier;
+};
+
+static void cmd_operate_attach_port_parsed(void *parsed_result,
+				__attribute__((unused)) struct cmdline *cl,
+				__attribute__((unused)) void *data)
+{
+	struct cmd_operate_attach_port_result *res = parsed_result;
+
+	if (!strcmp(res->keyword, "attach"))
+		attach_port(res->type, res->identifier);
+	else
+		printf("Unknown parameter\n");
+}
+
+cmdline_parse_token_string_t cmd_operate_attach_port_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_operate_attach_port_keyword =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,
+			keyword, "attach");
+cmdline_parse_token_string_t cmd_operate_attach_port_type =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,
+			type, "p#v");
+
+cmdline_parse_token_string_t cmd_operate_attach_port_identifier =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,
+			identifier, NULL);
+
+cmdline_parse_inst_t cmd_operate_attach_port = {
+	.f = cmd_operate_attach_port_parsed,
+	.data = NULL,
+	.help_str = "port attach p|v ident p: physical, v: virtual, "
+		"ident: pci address or virtual dev name",
+	.tokens = {
+		(void *)&cmd_operate_attach_port_port,
+		(void *)&cmd_operate_attach_port_keyword,
+		(void *)&cmd_operate_attach_port_type,
+		(void *)&cmd_operate_attach_port_identifier,
+		NULL,
+	},
+};
+
+/* *** detach a specificied port *** */
+struct cmd_operate_detach_port_result {
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t keyword;
+	cmdline_fixed_string_t type;
+	uint8_t port_id;
+};
+
+static void cmd_operate_detach_port_parsed(void *parsed_result,
+				__attribute__((unused)) struct cmdline *cl,
+				__attribute__((unused)) void *data)
+{
+	struct cmd_operate_detach_port_result *res = parsed_result;
+
+	if (!strcmp(res->keyword, "detach"))
+		detach_port(res->type, res->port_id);
+	else
+		printf("Unknown parameter\n");
+}
+
+cmdline_parse_token_string_t cmd_operate_detach_port_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_port_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_operate_detach_port_keyword =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_port_result,
+			keyword, "detach");
+cmdline_parse_token_string_t cmd_operate_detach_port_type =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_port_result,
+			type, "p#v");
+
+cmdline_parse_token_num_t cmd_operate_detach_port_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_operate_detach_port_result,
+			port_id, UINT8);
+
+cmdline_parse_inst_t cmd_operate_detach_port = {
+	.f = cmd_operate_detach_port_parsed,
+	.data = NULL,
+	.help_str = "port detach p|v port_id p: physical, v: virtual",
+	.tokens = {
+		(void *)&cmd_operate_detach_port_port,
+		(void *)&cmd_operate_detach_port_keyword,
+		(void *)&cmd_operate_detach_port_type,
+		(void *)&cmd_operate_detach_port_port_id,
+		NULL,
+	},
+};
+
 /* *** configure speed for all ports *** */
 struct cmd_config_speed_all {
 	cmdline_fixed_string_t port;
@@ -845,7 +946,7 @@ cmd_config_speed_all_parsed(void *parsed_result,
 		return;
 	}
 
-	for (pid = 0; pid < nb_ports; pid++) {
+	FOREACH_PORT(pid, ports) {
 		ports[pid].dev_conf.link_speed = link_speed;
 		ports[pid].dev_conf.link_duplex = link_duplex;
 	}
@@ -913,10 +1014,8 @@ cmd_config_speed_specific_parsed(void *parsed_result,
 		return;
 	}
 
-	if (res->id >= nb_ports) {
-		printf("Port id %d must be less than %d\n", res->id, nb_ports);
+	if (port_id_is_invalid(res->id))
 		return;
-	}
 
 	if (!strcmp(res->value1, "10"))
 		link_speed = ETH_LINK_SPEED_10;
@@ -3689,10 +3788,8 @@ static void cmd_set_bond_mac_addr_parsed(void *parsed_result,
 	struct cmd_set_bond_mac_addr_result *res = parsed_result;
 	int ret;
 
-	if (res->port_num >= nb_ports) {
-		printf("Port id %d must be less than %d\n", res->port_num, nb_ports);
+	if (port_id_is_invalid(res->port_num))
 		return;
-	}
 
 	ret = rte_eth_bond_mac_address_set(res->port_num, &res->address);
 
@@ -3870,7 +3967,7 @@ static void cmd_set_promisc_mode_parsed(void *parsed_result,
 
 	/* all ports */
 	if (allports) {
-		for (i = 0; i < nb_ports; i++) {
+		FOREACH_PORT(i, ports) {
 			if (enable)
 				rte_eth_promiscuous_enable(i);
 			else
@@ -3950,7 +4047,7 @@ static void cmd_set_allmulti_mode_parsed(void *parsed_result,
 
 	/* all ports */
 	if (allports) {
-		for (i = 0; i < nb_ports; i++) {
+		FOREACH_PORT(i, ports) {
 			if (enable)
 				rte_eth_allmulticast_enable(i);
 			else
@@ -5135,25 +5232,25 @@ static void cmd_showportall_parsed(void *parsed_result,
 	struct cmd_showportall_result *res = parsed_result;
 	if (!strcmp(res->show, "clear")) {
 		if (!strcmp(res->what, "stats"))
-			for (i = 0; i < nb_ports; i++)
+			FOREACH_PORT(i, ports)
 				nic_stats_clear(i);
 		else if (!strcmp(res->what, "xstats"))
-			for (i = 0; i < nb_ports; i++)
+			FOREACH_PORT(i, ports)
 				nic_xstats_clear(i);
 	} else if (!strcmp(res->what, "info"))
-		for (i = 0; i < nb_ports; i++)
+		FOREACH_PORT(i, ports)
 			port_infos_display(i);
 	else if (!strcmp(res->what, "stats"))
-		for (i = 0; i < nb_ports; i++)
+		FOREACH_PORT(i, ports)
 			nic_stats_display(i);
 	else if (!strcmp(res->what, "xstats"))
-		for (i = 0; i < nb_ports; i++)
+		FOREACH_PORT(i, ports)
 			nic_xstats_display(i);
 	else if (!strcmp(res->what, "fdir"))
-		for (i = 0; i < nb_ports; i++)
+		FOREACH_PORT(i, ports)
 			fdir_get_infos(i);
 	else if (!strcmp(res->what, "stat_qmap"))
-		for (i = 0; i < nb_ports; i++)
+		FOREACH_PORT(i, ports)
 			nic_stats_mapping_display(i);
 }
 
@@ -7715,6 +7812,8 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_set_qmap,
 	(cmdline_parse_inst_t *)&cmd_operate_port,
 	(cmdline_parse_inst_t *)&cmd_operate_specific_port,
+	(cmdline_parse_inst_t *)&cmd_operate_attach_port,
+	(cmdline_parse_inst_t *)&cmd_operate_detach_port,
 	(cmdline_parse_inst_t *)&cmd_config_speed_all,
 	(cmdline_parse_inst_t *)&cmd_config_speed_specific,
 	(cmdline_parse_inst_t *)&cmd_config_rx_tx,
@@ -7784,7 +7883,7 @@ prompt(void)
 static void
 cmd_reconfig_device_queue(portid_t id, uint8_t dev, uint8_t queue)
 {
-	if (id < nb_ports) {
+	if (!_port_id_is_invalid(id)) {
 		/* check if need_reconfig has been set to 1 */
 		if (ports[id].need_reconfig == 0)
 			ports[id].need_reconfig = dev;
@@ -7794,7 +7893,7 @@ cmd_reconfig_device_queue(portid_t id, uint8_t dev, uint8_t queue)
 	} else {
 		portid_t pid;
 
-		for (pid = 0; pid < nb_ports; pid++) {
+		FOREACH_PORT(pid, ports) {
 			/* check if need_reconfig has been set to 1 */
 			if (ports[pid].need_reconfig == 0)
 				ports[pid].need_reconfig = dev;
@@ -7812,10 +7911,8 @@ bypass_is_supported(portid_t port_id)
 	struct rte_port   *port;
 	struct rte_pci_id *pci_id;
 
-	if (port_id >= nb_ports) {
-		printf("\tPort id must be less than %d.\n", nb_ports);
+	if (port_id_is_invalid(port_id))
 		return 0;
-	}
 
 	/* Get the device id. */
 	port    = &ports[port_id];
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index 9bc08f4..02c8829 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -114,11 +114,15 @@ nic_stats_display(portid_t port_id)
 	struct rte_eth_stats stats;
 	struct rte_port *port = &ports[port_id];
 	uint8_t i;
+	portid_t pid;
 
 	static const char *nic_stats_border = "########################";
 
-	if (port_id >= nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+	if (port_id_is_invalid(port_id)) {
+		printf("Valid port range is [0");
+		FOREACH_PORT(pid, ports)
+			printf(", %d", pid);
+		printf("]\n");
 		return;
 	}
 	rte_eth_stats_get(port_id, &stats);
@@ -191,8 +195,13 @@ nic_stats_display(portid_t port_id)
 void
 nic_stats_clear(portid_t port_id)
 {
-	if (port_id >= nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+	portid_t pid;
+
+	if (port_id_is_invalid(port_id)) {
+		printf("Valid port range is [0");
+		FOREACH_PORT(pid, ports)
+			printf(", %d", pid);
+		printf("]\n");
 		return;
 	}
 	rte_eth_stats_reset(port_id);
@@ -239,11 +248,15 @@ nic_stats_mapping_display(portid_t port_id)
 {
 	struct rte_port *port = &ports[port_id];
 	uint16_t i;
+	portid_t pid;
 
 	static const char *nic_stats_mapping_border = "########################";
 
-	if (port_id >= nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+	if (port_id_is_invalid(port_id)) {
+		printf("Valid port range is [0");
+		FOREACH_PORT(pid, ports)
+			printf(", %d", pid);
+		printf("]\n");
 		return;
 	}
 
@@ -291,9 +304,13 @@ port_infos_display(portid_t port_id)
 	int vlan_offload;
 	struct rte_mempool * mp;
 	static const char *info_border = "*********************";
+	portid_t pid;
 
-	if (port_id >= nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+	if (port_id_is_invalid(port_id)) {
+		printf("Valid port range is [0");
+		FOREACH_PORT(pid, ports)
+			printf(", %d", pid);
+		printf("]\n");
 		return;
 	}
 	port = &ports[port_id];
@@ -346,14 +363,23 @@ port_infos_display(portid_t port_id)
 }
 
 int
-port_id_is_invalid(portid_t port_id)
+_port_id_is_invalid(portid_t port_id)
 {
-	if (port_id < nb_ports)
+	if (ports[port_id].enabled)
 		return 0;
-	printf("Invalid port %d (must be < nb_ports=%d)\n", port_id, nb_ports);
 	return 1;
 }
 
+int
+port_id_is_invalid(portid_t port_id)
+{
+	if (_port_id_is_invalid(port_id)) {
+		printf("Invalid port %d\n", port_id);
+		return 1;
+	}
+	return 0;
+}
+
 static int
 vlan_id_is_invalid(uint16_t vlan_id)
 {
@@ -1386,12 +1412,8 @@ set_fwd_ports_list(unsigned int *portlist, unsigned int nb_pt)
  again:
 	for (i = 0; i < nb_pt; i++) {
 		port_id = (portid_t) portlist[i];
-		if (port_id >= nb_ports) {
-			printf("Invalid port id %u >= %u\n",
-			       (unsigned int) port_id,
-			       (unsigned int) nb_ports);
+		if (port_id_is_invalid(port_id))
 			return;
-		}
 		if (record_now)
 			fwd_ports_ids[i] = port_id;
 	}
diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
index 9573a43..06d0eeb 100644
--- a/app/test-pmd/parameters.c
+++ b/app/test-pmd/parameters.c
@@ -375,6 +375,7 @@ parse_portnuma_config(const char *q_arg)
 	};
 	unsigned long int_fld[_NUM_FLD];
 	char *str_fld[_NUM_FLD];
+	portid_t pid;
 
 	/* reset from value set at definition */
 	while ((p = strchr(p0,'(')) != NULL) {
@@ -396,8 +397,11 @@ parse_portnuma_config(const char *q_arg)
 				return -1;
 		}
 		port_id = (uint8_t)int_fld[FLD_PORT];
-		if (port_id >= nb_ports) {
-			printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+		if (port_id_is_invalid(port_id)) {
+			printf("Valid port range is [0");
+			FOREACH_PORT(pid, ports)
+				printf(", %d", pid);
+			printf("]\n");
 			return -1;
 		}
 		socket_id = (uint8_t)int_fld[FLD_SOCKET];
@@ -428,6 +432,7 @@ parse_ringnuma_config(const char *q_arg)
 	};
 	unsigned long int_fld[_NUM_FLD];
 	char *str_fld[_NUM_FLD];
+	portid_t pid;
 	#define RX_RING_ONLY 0x1
 	#define TX_RING_ONLY 0x2
 	#define RXTX_RING    0x3
@@ -452,8 +457,11 @@ parse_ringnuma_config(const char *q_arg)
 				return -1;
 		}
 		port_id = (uint8_t)int_fld[FLD_PORT];
-		if (port_id >= nb_ports) {
-			printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+		if (port_id_is_invalid(port_id)) {
+			printf("Valid port range is [0");
+			FOREACH_PORT(pid, ports)
+				printf(", %d", pid);
+			printf("]\n");
 			return -1;
 		}
 		socket_id = (uint8_t)int_fld[FLD_SOCKET];
@@ -670,12 +678,11 @@ launch_args_parse(int argc, char** argv)
 #endif
 			if (!strcmp(lgopts[opt_idx].name, "nb-ports")) {
 				n = atoi(optarg);
-				if (n > 0 && n <= nb_ports)
+				if (n > 0 && !_port_id_is_invalid(n))
 					nb_fwd_ports = (uint8_t) n;
 				else
 					rte_exit(EXIT_FAILURE,
-						 "nb-ports should be > 0 and <= %d\n",
-						 nb_ports);
+						 "Invalid port %d\n", n);
 			}
 			if (!strcmp(lgopts[opt_idx].name, "nb-cores")) {
 				n = atoi(optarg);
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index f76406f..3ef8007 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -71,6 +71,7 @@
 #include <rte_pci.h>
 #include <rte_ether.h>
 #include <rte_ethdev.h>
+#include <rte_dev.h>
 #include <rte_string_fns.h>
 #ifdef RTE_LIBRTE_PMD_XENVIRT
 #include <rte_eth_xenvirt.h>
@@ -315,7 +316,7 @@ uint16_t nb_rx_queue_stats_mappings = 0;
 
 /* Forward function declarations */
 static void map_port_queue_stats_mapping_registers(uint8_t pi, struct rte_port *port);
-static void check_all_ports_link_status(uint8_t port_num, uint32_t port_mask);
+static void check_all_ports_link_status(uint32_t port_mask);
 
 /*
  * Check if all the ports are started.
@@ -552,7 +553,8 @@ init_config(void)
 				+ RTE_TEST_TX_DESC_MAX + MAX_PKT_BURST;
 
 		if (!numa_support)
-			nb_mbuf_per_pool = (nb_mbuf_per_pool * nb_ports);
+			nb_mbuf_per_pool =
+				(nb_mbuf_per_pool * RTE_MAX_ETHPORTS);
 	}
 
 	if (!numa_support) {
@@ -565,14 +567,19 @@ init_config(void)
 
 	/* Configuration of Ethernet ports. */
 	ports = rte_zmalloc("testpmd: ports",
-			    sizeof(struct rte_port) * nb_ports,
+			    sizeof(struct rte_port) * RTE_MAX_ETHPORTS,
 			    CACHE_LINE_SIZE);
 	if (ports == NULL) {
-		rte_exit(EXIT_FAILURE, "rte_zmalloc(%d struct rte_port) "
-							"failed\n", nb_ports);
+		rte_exit(EXIT_FAILURE,
+				"rte_zmalloc(%d struct rte_port) failed\n",
+				RTE_MAX_ETHPORTS);
 	}
 
-	for (pid = 0; pid < nb_ports; pid++) {
+	/* enabled allocated ports */
+	for (pid = 0; pid < nb_ports; pid++)
+		ports[pid].enabled = 1;
+
+	FOREACH_PORT(pid, ports) {
 		port = &ports[pid];
 		rte_eth_dev_info_get(pid, &port->dev_info);
 
@@ -602,8 +609,7 @@ init_config(void)
 			nb_mbuf_per_pool = nb_mbuf_per_pool/nb_ports;
 
 		for (i = 0; i < MAX_SOCKET; i++) {
-			nb_mbuf = (nb_mbuf_per_pool *
-						port_per_socket[i]);
+			nb_mbuf = (nb_mbuf_per_pool * RTE_MAX_ETHPORTS);
 			if (nb_mbuf)
 				mbuf_pool_create(mbuf_data_size,
 						nb_mbuf,i);
@@ -635,14 +641,6 @@ reconfig(portid_t new_port_id)
 	struct rte_port *port;
 
 	/* Reconfiguration of Ethernet ports. */
-	ports = rte_realloc(ports,
-			    sizeof(struct rte_port) * nb_ports,
-			    CACHE_LINE_SIZE);
-	if (ports == NULL) {
-		rte_exit(EXIT_FAILURE, "rte_realloc(%d struct rte_port) failed\n",
-				nb_ports);
-	}
-
 	port = &ports[new_port_id];
 	rte_eth_dev_info_get(new_port_id, &port->dev_info);
 
@@ -662,7 +660,7 @@ init_fwd_streams(void)
 	streamid_t sm_id, nb_fwd_streams_new;
 
 	/* set socket id according to numa or not */
-	for (pid = 0; pid < nb_ports; pid++) {
+	FOREACH_PORT(pid, ports) {
 		port = &ports[pid];
 		if (nb_rxq > port->dev_info.max_rx_queues) {
 			printf("Fail: nb_rxq(%d) is greater than "
@@ -1263,7 +1261,7 @@ all_ports_started(void)
 	portid_t pi;
 	struct rte_port *port;
 
-	for (pi = 0; pi < nb_ports; pi++) {
+	FOREACH_PORT(pi, ports) {
 		port = &ports[pi];
 		/* Check if there is a port which is not started */
 		if (port->port_status != RTE_PORT_STARTED)
@@ -1275,6 +1273,45 @@ all_ports_started(void)
 }
 
 int
+all_ports_stopped(void)
+{
+	portid_t pi;
+	struct rte_port *port;
+
+	FOREACH_PORT(pi, ports) {
+		port = &ports[pi];
+		if (port->port_status != RTE_PORT_STOPPED)
+			return 0;
+	}
+
+	return 1;
+}
+
+int
+port_is_started(portid_t port_id)
+{
+	if (port_id_is_invalid(port_id))
+		return 0;
+
+	if (ports[port_id].port_status != RTE_PORT_STARTED)
+		return 0;
+
+	return 1;
+}
+
+static int
+port_is_closed(portid_t port_id)
+{
+	if (port_id_is_invalid(port_id))
+		return 0;
+
+	if (ports[port_id].port_status != RTE_PORT_CLOSED)
+		return 0;
+
+	return 1;
+}
+
+int
 start_port(portid_t pid)
 {
 	int diag, need_check_link_status = 0;
@@ -1295,8 +1332,8 @@ start_port(portid_t pid)
 
 	if(dcb_config)
 		dcb_test = 1;
-	for (pi = 0; pi < nb_ports; pi++) {
-		if (pid < nb_ports && pid != pi)
+	FOREACH_PORT(pi, ports) {
+		if (!_port_id_is_invalid(pid) && pid != pi)
 			continue;
 
 		port = &ports[pi];
@@ -1420,7 +1457,7 @@ start_port(portid_t pid)
 	}
 
 	if (need_check_link_status && !no_link_check)
-		check_all_ports_link_status(nb_ports, RTE_PORT_ALL);
+		check_all_ports_link_status(RTE_PORT_ALL);
 	else
 		printf("Please stop the ports first\n");
 
@@ -1445,8 +1482,8 @@ stop_port(portid_t pid)
 	}
 	printf("Stopping ports...\n");
 
-	for (pi = 0; pi < nb_ports; pi++) {
-		if (pid < nb_ports && pid != pi)
+	FOREACH_PORT(pi, ports) {
+		if (!_port_id_is_invalid(pid) && pid != pi)
 			continue;
 
 		port = &ports[pi];
@@ -1462,7 +1499,7 @@ stop_port(portid_t pid)
 		need_check_link_status = 1;
 	}
 	if (need_check_link_status && !no_link_check)
-		check_all_ports_link_status(nb_ports, RTE_PORT_ALL);
+		check_all_ports_link_status(RTE_PORT_ALL);
 
 	printf("Done\n");
 }
@@ -1480,8 +1517,8 @@ close_port(portid_t pid)
 
 	printf("Closing ports...\n");
 
-	for (pi = 0; pi < nb_ports; pi++) {
-		if (pid < nb_ports && pid != pi)
+	FOREACH_PORT(pi, ports) {
+		if (!_port_id_is_invalid(pid) && pid != pi)
 			continue;
 
 		port = &ports[pi];
@@ -1501,31 +1538,124 @@ close_port(portid_t pid)
 	printf("Done\n");
 }
 
-int
-all_ports_stopped(void)
+
+static inline int
+attach_physical_device_port(char *identifier, uint8_t *pi)
 {
-	portid_t pi;
-	struct rte_port *port;
+	struct rte_pci_addr addr;
 
-	for (pi = 0; pi < nb_ports; pi++) {
-		port = &ports[pi];
-		if (port->port_status != RTE_PORT_STOPPED)
-			return 0;
+	if (eal_parse_pci_DomBDF(identifier, &addr) != 0) {
+		printf("invalid PCI identifier <%s>\n", identifier);
+		return -1;
 	}
+	return rte_eal_dev_attach_pdev(&addr, pi);
+}
 
-	return 1;
+static inline int
+attach_virtual_device_port(char *identifier, uint8_t *pi)
+{
+	return rte_eal_dev_attach_vdev(identifier, pi);
 }
 
-int
-port_is_started(portid_t port_id)
+static inline int
+detach_physical_device_port(uint8_t pi, char *identifier)
 {
-	if (port_id_is_invalid(port_id))
+	struct rte_pci_addr addr;
+
+	if (rte_eal_dev_detach_pdev(pi, &addr))
 		return -1;
 
-	if (ports[port_id].port_status != RTE_PORT_STARTED)
-		return 0;
+	snprintf(identifier, RTE_ETH_NAME_MAX_LEN, "%04x.%02x.%02x.%d",
+			addr.domain, addr.bus, addr.devid, addr.function);
+	return 0;
+}
 
-	return 1;
+static inline int
+detach_virtual_device_port(uint8_t pi, char *identifier)
+{
+	return rte_eal_dev_detach_vdev(pi, identifier);
+}
+
+void
+attach_port(char *type, char *identifier)
+{
+	portid_t i, j, pi = 0;
+
+	printf("Attaching a new port...\n");
+
+	if (test_done == 0) {
+		printf("Please stop forwarding first\n");
+		return;
+	}
+
+	if (strncmp(type, "p", 1) == 0) {
+		if (attach_physical_device_port(identifier, &pi))
+			return;
+	} else if (strncmp(type, "v", 1) == 0) {
+		if (attach_virtual_device_port(identifier, &pi))
+			return;
+	}
+
+	ports[pi].enabled = 1;
+	reconfig(pi);
+	rte_eth_promiscuous_enable(pi);
+
+	nb_ports = rte_eth_dev_count();
+
+	/* set_default_fwd_ports_config(); */
+	i = 0;
+	FOREACH_PORT(j, ports) {
+		fwd_ports_ids[i] = j;
+		i++;
+	}
+	nb_cfg_ports = nb_ports;
+	nb_fwd_ports++;
+
+	ports[pi].port_status = RTE_PORT_STOPPED;
+
+	printf("Port %d is attached. Now total ports is %d\n", pi, nb_ports);
+	printf("Done\n");
+}
+
+void
+detach_port(char *type, uint8_t port_id)
+{
+	portid_t i, pi = 0;
+	char name[RTE_ETH_NAME_MAX_LEN];
+
+	printf("Detaching a port...\n");
+
+	if (!port_is_closed(port_id)) {
+		printf("Please close port first\n");
+		return;
+	}
+
+	if (strncmp(type, "p", 1) == 0) {
+		if (detach_physical_device_port(port_id, name))
+			return;
+	} else if (strncmp(type, "v", 1) == 0) {
+		if (detach_virtual_device_port(port_id, name))
+			return;
+	}
+
+	ports[port_id].enabled = 0;
+	rte_eth_promiscuous_disable(pi);
+
+	nb_ports = rte_eth_dev_count();
+
+	/* set_default_fwd_ports_config(); */
+	i = 0;
+	FOREACH_PORT(pi, ports) {
+		fwd_ports_ids[i] = pi;
+		i++;
+	}
+	nb_cfg_ports = nb_ports;
+	nb_fwd_ports--;
+
+	printf("Port '%s' is detached. Now total ports is %d\n",
+			name, nb_ports);
+	printf("Done\n");
+	return;
 }
 
 void
@@ -1533,7 +1663,7 @@ pmd_test_exit(void)
 {
 	portid_t pt_id;
 
-	for (pt_id = 0; pt_id < nb_ports; pt_id++) {
+	FOREACH_PORT(pt_id, ports) {
 		printf("Stopping port %d...", pt_id);
 		fflush(stdout);
 		rte_eth_dev_close(pt_id);
@@ -1552,7 +1682,7 @@ struct pmd_test_command {
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -1563,7 +1693,7 @@ check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
 	fflush(stdout);
 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		FOREACH_PORT(portid, ports) {
 			if ((port_mask & (1 << portid)) == 0)
 				continue;
 			memset(&link, 0, sizeof(link));
@@ -1687,7 +1817,7 @@ init_port_config(void)
 	portid_t pid;
 	struct rte_port *port;
 
-	for (pid = 0; pid < nb_ports; pid++) {
+	FOREACH_PORT(pid, ports) {
 		port = &ports[pid];
 		port->dev_conf.rxmode = rx_mode;
 		port->dev_conf.fdir_conf = fdir_conf;
@@ -1869,8 +1999,7 @@ main(int argc, char** argv)
 		rte_panic("Cannot init EAL\n");
 
 	nb_ports = (portid_t) rte_eth_dev_count();
-	if (nb_ports == 0)
-		rte_exit(EXIT_FAILURE, "No probed ethernet devices - "
+		RTE_LOG(WARNING, EAL, "No probed ethernet devices - "
 							"check that "
 			  "CONFIG_RTE_LIBRTE_IGB_PMD=y and that "
 			  "CONFIG_RTE_LIBRTE_EM_PMD=y and that "
@@ -1897,7 +2026,7 @@ main(int argc, char** argv)
 		rte_exit(EXIT_FAILURE, "Start ports failed\n");
 
 	/* set all ports to promiscuous mode by default */
-	for (port_id = 0; port_id < nb_ports; port_id++)
+	FOREACH_PORT(port_id, ports)
 		rte_eth_promiscuous_enable(port_id);
 
 #ifdef RTE_LIBRTE_CMDLINE
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 9cbfeac..b79bd1f 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -133,6 +133,7 @@ struct fwd_stream {
  *   Bit 11: Insert VLAN Label
  */
 struct rte_port {
+	uint8_t                 enabled;    /**< Port enabled or not */
 	struct rte_eth_dev_info dev_info;   /**< PCI info + driver name */
 	struct rte_eth_conf     dev_conf;   /**< Port configuration. */
 	struct ether_addr       eth_addr;   /**< Port ethernet address */
@@ -157,6 +158,19 @@ struct rte_port {
 	struct rte_eth_txconf   tx_conf;    /**< tx configuration */
 };
 
+static portid_t __rte_unused
+find_next_port(portid_t p, struct rte_port *ports, int size)
+{
+	while ((ports[p].enabled == 0) && (p < size))
+		p++;
+	return p;
+}
+
+#define FOREACH_PORT(p, ports) \
+	for (p = find_next_port(0, ports, RTE_MAX_ETHPORTS); \
+	    p < RTE_MAX_ETHPORTS; \
+	    p = find_next_port(p + 1, ports, RTE_MAX_ETHPORTS))
+
 /**
  * The data structure associated with each forwarding logical core.
  * The logical cores are internally numbered by a core index from 0 to
@@ -512,6 +526,8 @@ int init_port_dcb_config(portid_t pid,struct dcb_config *dcb_conf);
 int start_port(portid_t pid);
 void stop_port(portid_t pid);
 void close_port(portid_t pid);
+void attach_port(char *type, char *identifier);
+void detach_port(char *type, uint8_t port_id);
 int all_ports_stopped(void);
 int port_is_started(portid_t port_id);
 void pmd_test_exit(void);
@@ -550,6 +566,7 @@ void get_ethertype_filter(uint8_t port_id, uint16_t index);
 void get_2tuple_filter(uint8_t port_id, uint16_t index);
 void get_5tuple_filter(uint8_t port_id, uint16_t index);
 void get_flex_filter(uint8_t port_id, uint16_t index);
+int _port_id_is_invalid(portid_t port_id);
 int port_id_is_invalid(portid_t port_id);
 int rx_queue_id_is_invalid(queueid_t rxq_id);
 int tx_queue_id_is_invalid(queueid_t txq_id);
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [RFC PATCH v2 28/28] librte_pmd_e1000: Add workaround to test the port hotplug framework.
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (26 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 27/28] testpmd: Add support for the port hotplug framework Tetsuya Mukawa
@ 2014-11-04  3:45   ` Tetsuya Mukawa
  2014-11-18  8:55   ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-04  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

This patch is for testing the port hotplug framework.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_pmd_e1000/em_ethdev.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/librte_pmd_e1000/em_ethdev.c b/lib/librte_pmd_e1000/em_ethdev.c
index 3f2897e..90ec2d7 100644
--- a/lib/librte_pmd_e1000/em_ethdev.c
+++ b/lib/librte_pmd_e1000/em_ethdev.c
@@ -286,7 +286,8 @@ static struct eth_driver rte_em_pmd = {
 	{
 		.name = "rte_em_pmd",
 		.id_table = pci_id_em_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC
+			| RTE_PCI_DRV_DETACHABLE,
 	},
 	.eth_dev_init = eth_em_dev_init,
 	.dev_private_size = sizeof(struct e1000_adapter),
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
                     ` (27 preceding siblings ...)
  2014-11-04  3:45   ` [dpdk-dev] [RFC PATCH v2 28/28] librte_pmd_e1000: Add workaround to test " Tetsuya Mukawa
@ 2014-11-18  8:55   ` Tetsuya Mukawa
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-18  8:55 UTC (permalink / raw)
  To: dev

Hi Folks,

I may not be able to attend todays conference call because it will be
midnight in my country.
So I just collect up current status of this function.

- I've received a email that let me know some bugs and suggestions in my
RFC. Now I am fixing it.
- Anyway, to use this function, we need to change PMDs. But still I
don't have implementations for physical PMDs.
- If there is someone who can develop hotplug function together, it's nice!

Thanks,
Tetsuya


(2014/11/04 12:45), Tetsuya Mukawa wrote:
> This patch series adds a dynamic port hotplug framework to DPDK.
> With the patches, DPDK apps can attach or detach ports at runtime.
>
> The basic concept of the port hotplug is like followings.
> - DPDK apps must have resposibility to manage ports.
>   DPDK apps only know which ports are attached or detached at the moment.
>   The port hotplug framework is implemented to allow DPDK apps to manage ports.
>   For example, when DPDK apps call port attach function, attached port number
>   will be returned. Also DPDK apps can detach port by port number.
> - Kernel support is needed for attaching or detaching physical device ports.
>   To attach new device, the device will be recognized by kernel at first and
>   controlled by kernel driver. Then user can bind the device to igb_uio
>   by 'dpdk_nic_bind.py'. Finally, DPDK apps can call the port hotplug
>   functions to attach ports.
>   For detaching, steps are vice versa.
> - Before detach ports, ports must be stopped and closed.
>   DPDK application must call rte_eth_dev_stop() and rte_eth_dev_close() before
>   detaching ports. These function will call finalization codes of PMDs.
>   But so far, no PMD frees all resources allocated by initialization.
>   It means PMDs are needed to be fixed to support the port hotplug.
>   'RTE_PCI_DRV_DETACHABLE' is a new flag indicating a PMD supports detaching.
>   Without this flag, detaching will be failed.
> - Mustn't affect legacy DPDK apps.
>   No DPDK EAL behavior is changed, if the port hotplug functions are't called.
>   So all legacy DPDK apps can still work without modifications.
>
> And few limitations.
> - The port hotplug functions are not thread safe.
>   DPDK apps should handle it.
> - Only support Linux and igb_uio so far.
>   BSD and VFIO is not supported. I will send VFIO patches at least, but I don't
>   have a plan to submit BSD patch so far.
>
>
> Here is port hotplug APIs.
> -------------------------------------------------------------------------------
> /**
>  * Attach a new physical device.
>  *
>  * @param addr
>  *   A pointer to a pci address structure describing the new
>  *   device to be attached.
>  * @param port_id
>  *  A pointer to a port identifier actually attached.
>  * @return
>  *  0 on success and port_id is filled, negative on error
>  */
> int rte_eal_dev_attach_pdev(struct rte_pci_addr *addr, uint8_t *port_id);
>
> /**
>  * Attach a new virtual device.
>  *
>  * @param vdevargs
>  *   A pointer to a strings array describing the new device
>  *   to be attached.
>  * @param port_id
>  *  A pointer to a port identifier actually attached.
>  * @return
>  *  0 on success and port_id is filled, negative on error
>  */
> int rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id);
>
> /**
>  * Detach a physical device.
>  *
>  * @param port_id
>  *   The port identifier of the physical device to detach.
>  * @param addr
>  *  A pointer to a pci address structure actually detached.
>  * @return
>  *  0 on success and addr is filled, negative on error
>  */
> int rte_eal_dev_detach_pdev(uint8_t port_id, struct rte_pci_addr *addr);
>
> /**
>  * Detach a virtual device.
>  *
>  * @param port_id
>  *   The port identifier of the virtual device to detach.
>  * @param addr
>  *  A pointer to a virtual device name actually detached.
>  * @return
>  *  0 on success and vdevname is filled, negative on error
>  */
> int rte_eal_dev_detach_vdev(uint8_t port_id, char *vdevname);
> -------------------------------------------------------------------------------
>
> This patch series are for DPDK EAL. To use port hotplug function by DPDK apps,
> each PMD should be fixed to support 'RTE_PCI_DRV_DETACHABLE' flag. I've already
> sent an example patch for pcap PMD.
>
> Also I've sent patch for testpmd. The patch is an example of fixing legacy DPDK
> apps to support hot plug framework.
>
> Thanks,
> Tetsuya Mukawa
>
> Changes included in v2:
> - remove 'rte_eth_dev_validate_port()', and cleanup codes.
>
> Tetsuya Mukawa (25):
>   eal/pci: Add a new flag indicating a driver can detach devices at
>     runtime.
>   ethdev: Remove assumption that port will not be detached
>   eal/pci: Replace pci address comparison code by eal_compare_pci_addr
>   ethdev: Add rte_eth_dev_free to free specified device
>   eal,ethdev: Add function pointer for closing a device
>   ethdev: Add rte_eth_dev_shutdown for closing PCI devices.
>   ethdev: Add functions to know which port is attached or detached
>   ethdev: Add rte_eth_dev_get_addr_by_port
>   ethdev: Add rte_eth_dev_get_port_by_addr
>   ethdev: Add rte_eth_dev_get_name_by_port
>   ethdev: Add rte_eth_dev_check_detachable
>   ethdev: Change scope of rte_eth_dev_allocated to global
>   eal/pci: Prevent double registration for devargs_list
>   eal/pci: Add rte_eal_devargs_remove
>   eal/pci: Add probe and close function for virtual drivers
>   eal/pci: Add port hotplug functions for virtual devices.
>   eal/linux/pci: Add functions for unmapping igb_uio resources
>   eal/pci: Prevent double registrations for pci_device_list
>   eal/pci: Change scope of rte_eal_pci_scan to global
>   eal/pci: Add rte_eal_pci_close_one_driver
>   eal/pci: Fix pci_probe_all_drivers to share code with closing function
>   eal/pci: Add pci_close_all_drivers
>   eal/pci: Add rte_eal_pci_probe_one and rte_eal_pci_close_one
>   eal/pci: Add port hotplug functions for physical devices.
>   eal: Enable port hotplug framework in Linux
>
>  config/common_linuxapp                             |   5 +
>  lib/librte_eal/bsdapp/eal/eal_pci.c                |  16 +-
>  lib/librte_eal/common/eal_common_dev.c             | 208 ++++++++++++
>  lib/librte_eal/common/eal_common_devargs.c         |  45 +++
>  lib/librte_eal/common/eal_common_pci.c             | 107 +++++-
>  lib/librte_eal/common/include/eal_private.h        |  22 ++
>  lib/librte_eal/common/include/rte_dev.h            |  60 ++++
>  lib/librte_eal/common/include/rte_devargs.h        |  18 +
>  lib/librte_eal/common/include/rte_pci.h            |  64 ++++
>  lib/librte_eal/linuxapp/eal/Makefile               |   1 +
>  lib/librte_eal/linuxapp/eal/eal_pci.c              | 119 +++++--
>  lib/librte_eal/linuxapp/eal/eal_pci_uio.c          |  58 +++-
>  lib/librte_eal/linuxapp/eal/include/eal_pci_init.h |   7 +
>  lib/librte_ether/rte_ethdev.c                      | 371 +++++++++++++++------
>  lib/librte_ether/rte_ethdev.h                      | 100 ++++++
>  15 files changed, 1046 insertions(+), 155 deletions(-)
>

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 00/25] Port Hotplug Framework
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (25 preceding siblings ...)
  2014-11-04  3:45 ` [dpdk-dev] [RFC PATCH v2 00/25] Port Hotplug Framework Tetsuya Mukawa
@ 2014-11-20  9:06 ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 01/25] eal/pci: Add a new flag indicating a driver can detach devices at runtime Tetsuya Mukawa
                     ` (30 more replies)
  2014-11-20  9:22 ` [dpdk-dev] [PATCH] librte_pmd_pcap: " Tetsuya Mukawa
  2014-11-20  9:22 ` [dpdk-dev] [PATCH] testpmd: " Tetsuya Mukawa
  28 siblings, 31 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

This patch series adds a dynamic port hotplug framework to DPDK.
With the patches, DPDK apps can attach or detach ports at runtime.

The basic concept of the port hotplug is like followings.
- DPDK apps must have resposibility to manage ports.
  DPDK apps only know which ports are attached or detached at the moment.
  The port hotplug framework is implemented to allow DPDK apps to manage ports.
  For example, when DPDK apps call port attach function, attached port number
  will be returned. Also DPDK apps can detach port by port number.
- Kernel support is needed for attaching or detaching physical device ports.
  To attach new device, the device will be recognized by kernel at first and
  controlled by kernel driver. Then user can bind the device to igb_uio
  by 'dpdk_nic_bind.py'. Finally, DPDK apps can call the port hotplug
  functions to attach ports.
  For detaching, steps are vice versa.
- Before detach ports, ports must be stopped and closed.
  DPDK application must call rte_eth_dev_stop() and rte_eth_dev_close() before
  detaching ports. These function will call finalization codes of PMDs.
  But so far, no PMD frees all resources allocated by initialization.
  It means PMDs are needed to be fixed to support the port hotplug.
  'RTE_PCI_DRV_DETACHABLE' is a new flag indicating a PMD supports detaching.
  Without this flag, detaching will be failed.
- Mustn't affect legacy DPDK apps.
  No DPDK EAL behavior is changed, if the port hotplug functions are't called.
  So all legacy DPDK apps can still work without modifications.

And few limitations.
- The port hotplug functions are not thread safe.
  DPDK apps should handle it.
- Only support Linux and igb_uio so far.
  BSD and VFIO is not supported. I will send VFIO patches at least, but I don't
  have a plan to submit BSD patch so far.


Here is port hotplug APIs.
-------------------------------------------------------------------------------
/**
 * Attach a new physical device.
 *
 * @param addr
 *   A pointer to a pci address structure describing the new
 *   device to be attached.
 * @param port_id
 *  A pointer to a port identifier actually attached.
 * @return
 *  0 on success and port_id is filled, negative on error
 */
int rte_eal_dev_attach_pdev(struct rte_pci_addr *addr, uint8_t *port_id);

/**
 * Attach a new virtual device.
 *
 * @param vdevargs
 *   A pointer to a strings array describing the new device
 *   to be attached.
 * @param port_id
 *  A pointer to a port identifier actually attached.
 * @return
 *  0 on success and port_id is filled, negative on error
 */
int rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id);

/**
 * Detach a physical device.
 *
 * @param port_id
 *   The port identifier of the physical device to detach.
 * @param addr
 *  A pointer to a pci address structure actually detached.
 * @return
 *  0 on success and addr is filled, negative on error
 */
int rte_eal_dev_detach_pdev(uint8_t port_id, struct rte_pci_addr *addr);

/**
 * Detach a virtual device.
 *
 * @param port_id
 *   The port identifier of the virtual device to detach.
 * @param addr
 *  A pointer to a virtual device name actually detached.
 * @return
 *  0 on success and vdevname is filled, negative on error
 */
int rte_eal_dev_detach_vdev(uint8_t port_id, char *vdevname);
-------------------------------------------------------------------------------

This patch series are for DPDK EAL. To use port hotplug function by DPDK apps,
each PMD should be fixed to support 'RTE_PCI_DRV_DETACHABLE' flag. Please check
a patch for pcap PMD.

Also please check testpmd patch. It will show you how to fix your legacy
applications to support port hotplug feature.


PATCH v1 Chages:
 - Fix error checking code of librte_eth APIs.
 - Fix issue that port from pcap PMD cannot be detached correctly.
 - Fix issue that testpmd could hang after forwarding, if attaching and detaching
   is repeatedly.
 - Fix if-condition of rte_eth_dev_get_port_by_addr().
   (Thanks to Mark Enright)

RFC PATCH v2 Changes:
- remove 'rte_eth_dev_validate_port()', and cleanup codes.


Tetsuya Mukawa (25):
  eal/pci: Add a new flag indicating a driver can detach devices at
    runtime.
  ethdev: Remove assumption that port will not be detached
  eal/pci: Replace pci address comparison code by eal_compare_pci_addr
  ethdev: Add rte_eth_dev_free to free specified device
  eal,ethdev: Add function pointer for closing a device
  ethdev: Add rte_eth_dev_shutdown for closing PCI devices.
  ethdev: Add functions to know which port is attached or detached
  ethdev: Add rte_eth_dev_get_addr_by_port
  ethdev: Add rte_eth_dev_get_port_by_addr
  ethdev: Add rte_eth_dev_get_name_by_port
  ethdev: Add rte_eth_dev_check_detachable
  ethdev: Change scope of rte_eth_dev_allocated to global
  eal/pci: Prevent double registration for devargs_list
  eal/pci: Add rte_eal_devargs_remove
  eal/pci: Add probe and close function for virtual drivers
  eal/pci: Add port hotplug functions for virtual devices.
  eal/linux/pci: Add functions for unmapping igb_uio resources
  eal/pci: Prevent double registrations for pci_device_list
  eal/pci: Change scope of rte_eal_pci_scan to global
  eal/pci: Add rte_eal_pci_close_one_driver
  eal/pci: Fix pci_probe_all_drivers to share code with closing function
  eal/pci: Add pci_close_all_drivers
  eal/pci: Add rte_eal_pci_probe_one and rte_eal_pci_close_one
  eal/pci: Add port hotplug functions for physical devices.
  eal: Enable port hotplug framework in Linux

 config/common_linuxapp                             |   5 +
 lib/librte_eal/bsdapp/eal/eal_pci.c                |  16 +-
 lib/librte_eal/common/eal_common_dev.c             | 208 ++++++++++++
 lib/librte_eal/common/eal_common_devargs.c         |  45 +++
 lib/librte_eal/common/eal_common_pci.c             | 107 +++++-
 lib/librte_eal/common/include/eal_private.h        |  22 ++
 lib/librte_eal/common/include/rte_dev.h            |  60 ++++
 lib/librte_eal/common/include/rte_devargs.h        |  18 +
 lib/librte_eal/common/include/rte_pci.h            |  64 ++++
 lib/librte_eal/linuxapp/eal/Makefile               |   1 +
 lib/librte_eal/linuxapp/eal/eal_pci.c              | 119 +++++--
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c          |  58 +++-
 lib/librte_eal/linuxapp/eal/include/eal_pci_init.h |   7 +
 lib/librte_ether/rte_ethdev.c                      | 365 +++++++++++++++------
 lib/librte_ether/rte_ethdev.h                      | 100 ++++++
 15 files changed, 1044 insertions(+), 151 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 01/25] eal/pci: Add a new flag indicating a driver can detach devices at runtime.
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 02/25] ethdev: Remove assumption that port will not be detached Tetsuya Mukawa
                     ` (29 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

This patch adds "RTE_PCI_DRV_DETACHABLE" to drv_flags of rte_pci_driver
structure. The flags indicates the driver can detach devices at runtime.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/include/rte_pci.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 66ed793..b819539 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -199,6 +199,8 @@ 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 capablity */
+#define RTE_PCI_DRV_DETACHABLE	0x0010
 
 /**< Internal use only - Macro used by pci addr parsing functions **/
 #define GET_PCIADDR_FIELD(in, fd, lim, dlm)                   \
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 02/25] ethdev: Remove assumption that port will not be detached
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 01/25] eal/pci: Add a new flag indicating a driver can detach devices at runtime Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 03/25] eal/pci: Replace pci address comparison code by eal_compare_pci_addr Tetsuya Mukawa
                     ` (28 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

To remove assumption, do like followings.

- Add 'attached' member to rte_eth_dev structure.
  This member is used for indicating the port is attached, or not.
- Add rte_eth_dev_allocate_new_port().
  This function is used for allocating new port.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 236 +++++++++++++++++++++++-------------------
 lib/librte_ether/rte_ethdev.h |   5 +
 2 files changed, 136 insertions(+), 105 deletions(-)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 8c65d72..446c53a 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -201,19 +201,33 @@ rte_eth_dev_allocated(const char *name)
 {
 	unsigned i;
 
-	for (i = 0; i < nb_ports; i++) {
-		if (strcmp(rte_eth_devices[i].data->name, name) == 0)
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (rte_eth_devices[i].attached && strcmp(
+				rte_eth_devices[i].data->name, name) == 0)
 			return &rte_eth_devices[i];
 	}
 	return NULL;
 }
 
+static uint8_t
+rte_eth_dev_allocate_new_port(void)
+{
+	unsigned i;
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
+		if (!rte_eth_devices[i].attached)
+			return i;
+	return RTE_MAX_ETHPORTS;
+}
+
 struct rte_eth_dev *
 rte_eth_dev_allocate(const char *name)
 {
+	uint8_t port_id;
 	struct rte_eth_dev *eth_dev;
 
-	if (nb_ports == RTE_MAX_ETHPORTS) {
+	port_id = rte_eth_dev_allocate_new_port();
+	if (port_id == RTE_MAX_ETHPORTS) {
 		PMD_DEBUG_TRACE("Reached maximum number of Ethernet ports\n");
 		return NULL;
 	}
@@ -226,10 +240,12 @@ rte_eth_dev_allocate(const char *name)
 		return NULL;
 	}
 
-	eth_dev = &rte_eth_devices[nb_ports];
-	eth_dev->data = &rte_eth_dev_data[nb_ports];
+	eth_dev = &rte_eth_devices[port_id];
+	eth_dev->data = &rte_eth_dev_data[port_id];
 	snprintf(eth_dev->data->name, sizeof(eth_dev->data->name), "%s", name);
-	eth_dev->data->port_id = nb_ports++;
+	eth_dev->data->port_id = port_id;
+	eth_dev->attached = 1;
+	nb_ports++;
 	return eth_dev;
 }
 
@@ -283,6 +299,7 @@ rte_eth_dev_init(struct rte_pci_driver *pci_drv,
 			(unsigned) pci_dev->id.device_id);
 	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
 		rte_free(eth_dev->data->dev_private);
+	eth_dev->attached = 0;
 	nb_ports--;
 	return diag;
 }
@@ -308,10 +325,19 @@ rte_eth_driver_register(struct eth_driver *eth_drv)
 	rte_eal_pci_register(&eth_drv->pci_drv);
 }
 
+static int
+rte_eth_dev_validate_port(uint8_t port_id)
+{
+	if (port_id >= RTE_MAX_ETHPORTS)
+		return 1;
+
+	return !rte_eth_devices[port_id].attached;
+}
+
 int
 rte_eth_dev_socket_id(uint8_t port_id)
 {
-	if (port_id >= nb_ports)
+	if (rte_eth_dev_validate_port(port_id))
 		return -1;
 	return rte_eth_devices[port_id].pci_dev->numa_node;
 }
@@ -369,7 +395,7 @@ rte_eth_dev_rx_queue_start(uint8_t port_id, uint16_t rx_queue_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -395,7 +421,7 @@ rte_eth_dev_rx_queue_stop(uint8_t port_id, uint16_t rx_queue_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -421,7 +447,7 @@ rte_eth_dev_tx_queue_start(uint8_t port_id, uint16_t tx_queue_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -447,7 +473,7 @@ rte_eth_dev_tx_queue_stop(uint8_t port_id, uint16_t tx_queue_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -662,7 +688,7 @@ rte_eth_dev_configure(uint8_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports || port_id >= RTE_MAX_ETHPORTS) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -847,7 +873,7 @@ rte_eth_dev_start(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%" PRIu8 "\n", port_id);
 		return (-EINVAL);
 	}
@@ -882,7 +908,7 @@ rte_eth_dev_stop(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_RET();
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%" PRIu8 "\n", port_id);
 		return;
 	}
@@ -910,7 +936,7 @@ rte_eth_dev_set_link_up(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -929,7 +955,7 @@ rte_eth_dev_set_link_down(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -948,7 +974,7 @@ rte_eth_dev_close(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_RET();
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -976,7 +1002,7 @@ rte_eth_rx_queue_setup(uint8_t port_id, uint16_t rx_queue_id,
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -1049,7 +1075,7 @@ rte_eth_tx_queue_setup(uint8_t port_id, uint16_t tx_queue_id,
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= RTE_MAX_ETHPORTS || port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -1082,7 +1108,7 @@ rte_eth_promiscuous_enable(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1098,7 +1124,7 @@ rte_eth_promiscuous_disable(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1114,7 +1140,7 @@ rte_eth_promiscuous_get(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -1;
 	}
@@ -1128,7 +1154,7 @@ rte_eth_allmulticast_enable(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1144,7 +1170,7 @@ rte_eth_allmulticast_disable(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1160,7 +1186,7 @@ rte_eth_allmulticast_get(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -1;
 	}
@@ -1188,7 +1214,7 @@ rte_eth_link_get(uint8_t port_id, struct rte_eth_link *eth_link)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1208,7 +1234,7 @@ rte_eth_link_get_nowait(uint8_t port_id, struct rte_eth_link *eth_link)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1228,7 +1254,7 @@ rte_eth_stats_get(uint8_t port_id, struct rte_eth_stats *stats)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1245,7 +1271,7 @@ rte_eth_stats_reset(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1266,7 +1292,7 @@ rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstats *xstats,
 	uint64_t val;
 	char *stats_ptr;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -1;
 	}
@@ -1335,7 +1361,7 @@ rte_eth_xstats_reset(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1357,7 +1383,7 @@ set_queue_stats_mapping(uint8_t port_id, uint16_t queue_id, uint8_t stat_idx,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -1392,7 +1418,7 @@ rte_eth_dev_info_get(uint8_t port_id, struct rte_eth_dev_info *dev_info)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1412,7 +1438,7 @@ rte_eth_macaddr_get(uint8_t port_id, struct ether_addr *mac_addr)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1426,7 +1452,7 @@ rte_eth_dev_get_mtu(uint8_t port_id, uint16_t *mtu)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1442,7 +1468,7 @@ rte_eth_dev_set_mtu(uint8_t port_id, uint16_t mtu)
 	int ret;
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1462,7 +1488,7 @@ rte_eth_dev_vlan_filter(uint8_t port_id, uint16_t vlan_id, int on)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1487,7 +1513,7 @@ rte_eth_dev_set_vlan_strip_on_queue(uint8_t port_id, uint16_t rx_queue_id, int o
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1509,7 +1535,7 @@ rte_eth_dev_set_vlan_ether_type(uint8_t port_id, uint16_t tpid)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1529,7 +1555,7 @@ rte_eth_dev_set_vlan_offload(uint8_t port_id, int offload_mask)
 	int mask = 0;
 	int cur, org = 0;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1574,7 +1600,7 @@ rte_eth_dev_get_vlan_offload(uint8_t port_id)
 	struct rte_eth_dev *dev;
 	int ret = 0;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1598,7 +1624,7 @@ rte_eth_dev_set_vlan_pvid(uint8_t port_id, uint16_t pvid, int on)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1616,7 +1642,7 @@ rte_eth_dev_fdir_add_signature_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1650,7 +1676,7 @@ rte_eth_dev_fdir_update_signature_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1684,7 +1710,7 @@ rte_eth_dev_fdir_remove_signature_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1715,7 +1741,7 @@ rte_eth_dev_fdir_get_infos(uint8_t port_id, struct rte_eth_fdir *fdir)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1740,7 +1766,7 @@ rte_eth_dev_fdir_add_perfect_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1780,7 +1806,7 @@ rte_eth_dev_fdir_update_perfect_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1818,7 +1844,7 @@ rte_eth_dev_fdir_remove_perfect_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1854,7 +1880,7 @@ rte_eth_dev_fdir_set_masks(uint8_t port_id, struct rte_fdir_masks *fdir_mask)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1874,7 +1900,7 @@ rte_eth_dev_flow_ctrl_get(uint8_t port_id, struct rte_eth_fc_conf *fc_conf)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1890,7 +1916,7 @@ rte_eth_dev_flow_ctrl_set(uint8_t port_id, struct rte_eth_fc_conf *fc_conf)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1910,7 +1936,7 @@ rte_eth_dev_priority_flow_ctrl_set(uint8_t port_id, struct rte_eth_pfc_conf *pfc
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1934,7 +1960,7 @@ rte_eth_dev_rss_reta_update(uint8_t port_id, struct rte_eth_rss_reta *reta_conf)
 	uint16_t max_rxq;
 	uint8_t i,j;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1986,7 +2012,7 @@ rte_eth_dev_rss_reta_query(uint8_t port_id, struct rte_eth_rss_reta *reta_conf)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2007,7 +2033,7 @@ rte_eth_dev_rss_hash_update(uint8_t port_id, struct rte_eth_rss_conf *rss_conf)
 	struct rte_eth_dev *dev;
 	uint16_t rss_hash_protos;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2029,7 +2055,7 @@ rte_eth_dev_rss_hash_conf_get(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2044,7 +2070,7 @@ rte_eth_dev_udp_tunnel_add(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -2070,7 +2096,7 @@ rte_eth_dev_udp_tunnel_delete(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -2095,7 +2121,7 @@ rte_eth_led_on(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2110,7 +2136,7 @@ rte_eth_led_off(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2150,7 +2176,7 @@ rte_eth_dev_mac_addr_add(uint8_t port_id, struct ether_addr *addr,
 	int index;
 	uint64_t pool_mask;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2201,7 +2227,7 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 	struct rte_eth_dev *dev;
 	int index;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2235,7 +2261,7 @@ rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 	struct rte_eth_dev *dev;
 	struct rte_eth_dev_info dev_info;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("set VF RX mode:Invalid port_id=%d\n",
 				port_id);
 		return (-ENODEV);
@@ -2290,7 +2316,7 @@ rte_eth_dev_uc_hash_table_set(uint8_t port_id, struct ether_addr *addr,
 	int ret;
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("unicast hash setting:Invalid port_id=%d\n",
 			port_id);
 		return (-ENODEV);
@@ -2343,7 +2369,7 @@ rte_eth_dev_uc_all_hash_table_set(uint8_t port_id, uint8_t on)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("unicast hash setting:Invalid port_id=%d\n",
 			port_id);
 		return (-ENODEV);
@@ -2362,7 +2388,7 @@ rte_eth_dev_set_vf_rx(uint8_t port_id,uint16_t vf, uint8_t on)
 	struct rte_eth_dev *dev;
 	struct rte_eth_dev_info dev_info;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2388,7 +2414,7 @@ rte_eth_dev_set_vf_tx(uint8_t port_id,uint16_t vf, uint8_t on)
 	struct rte_eth_dev *dev;
 	struct rte_eth_dev_info dev_info;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("set pool tx:Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2413,7 +2439,7 @@ rte_eth_dev_set_vf_vlan_filter(uint8_t port_id, uint16_t vlan_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("VF VLAN filter:invalid port id=%d\n",
 				port_id);
 		return (-ENODEV);
@@ -2444,7 +2470,7 @@ int rte_eth_set_queue_rate_limit(uint8_t port_id, uint16_t queue_idx,
 	struct rte_eth_dev_info dev_info;
 	struct rte_eth_link link;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("set queue rate limit:invalid port id=%d\n",
 				port_id);
 		return -ENODEV;
@@ -2481,7 +2507,7 @@ int rte_eth_set_vf_rate_limit(uint8_t port_id, uint16_t vf, uint16_t tx_rate,
 	if (q_msk == 0)
 		return 0;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("set VF rate limit:invalid port id=%d\n",
 				port_id);
 		return -ENODEV;
@@ -2515,7 +2541,7 @@ rte_eth_mirror_rule_set(uint8_t port_id,
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2556,7 +2582,7 @@ rte_eth_mirror_rule_reset(uint8_t port_id, uint8_t rule_id)
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2581,7 +2607,7 @@ rte_eth_rx_burst(uint8_t port_id, uint16_t queue_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return 0;
 	}
@@ -2601,7 +2627,7 @@ rte_eth_tx_burst(uint8_t port_id, uint16_t queue_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return 0;
 	}
@@ -2621,7 +2647,7 @@ rte_eth_rx_queue_count(uint8_t port_id, uint16_t queue_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return 0;
 	}
@@ -2635,7 +2661,7 @@ rte_eth_rx_descriptor_done(uint8_t port_id, uint16_t queue_id, uint16_t offset)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2656,7 +2682,7 @@ rte_eth_dev_callback_register(uint8_t port_id,
 
 	if (!cb_fn)
 		return (-EINVAL);
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -2696,7 +2722,7 @@ rte_eth_dev_callback_unregister(uint8_t port_id,
 
 	if (!cb_fn)
 		return (-EINVAL);
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -2756,7 +2782,7 @@ int rte_eth_dev_bypass_init(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2776,7 +2802,7 @@ rte_eth_dev_bypass_state_show(uint8_t port_id, uint32_t *state)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2795,7 +2821,7 @@ rte_eth_dev_bypass_state_set(uint8_t port_id, uint32_t *new_state)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2815,7 +2841,7 @@ rte_eth_dev_bypass_event_show(uint8_t port_id, uint32_t event, uint32_t *state)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2835,7 +2861,7 @@ rte_eth_dev_bypass_event_store(uint8_t port_id, uint32_t event, uint32_t state)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2855,7 +2881,7 @@ rte_eth_dev_wd_timeout_store(uint8_t port_id, uint32_t timeout)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2875,7 +2901,7 @@ rte_eth_dev_bypass_ver_show(uint8_t port_id, uint32_t *ver)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2895,7 +2921,7 @@ rte_eth_dev_bypass_wd_timeout_show(uint8_t port_id, uint32_t *wd_timeout)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2915,7 +2941,7 @@ rte_eth_dev_bypass_wd_reset(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2937,7 +2963,7 @@ rte_eth_dev_add_syn_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -2952,7 +2978,7 @@ rte_eth_dev_remove_syn_filter(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -2971,7 +2997,7 @@ rte_eth_dev_get_syn_filter(uint8_t port_id,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -2987,7 +3013,7 @@ rte_eth_dev_add_ethertype_filter(uint8_t port_id, uint16_t index,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3008,7 +3034,7 @@ rte_eth_dev_remove_ethertype_filter(uint8_t port_id,  uint16_t index)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3027,7 +3053,7 @@ rte_eth_dev_get_ethertype_filter(uint8_t port_id, uint16_t index,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3044,7 +3070,7 @@ rte_eth_dev_add_2tuple_filter(uint8_t port_id, uint16_t index,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3066,7 +3092,7 @@ rte_eth_dev_remove_2tuple_filter(uint8_t port_id, uint16_t index)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3085,7 +3111,7 @@ rte_eth_dev_get_2tuple_filter(uint8_t port_id, uint16_t index,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3101,7 +3127,7 @@ rte_eth_dev_add_5tuple_filter(uint8_t port_id, uint16_t index,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3124,7 +3150,7 @@ rte_eth_dev_remove_5tuple_filter(uint8_t port_id, uint16_t index)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3143,7 +3169,7 @@ rte_eth_dev_get_5tuple_filter(uint8_t port_id, uint16_t index,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3160,7 +3186,7 @@ rte_eth_dev_add_flex_filter(uint8_t port_id, uint16_t index,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3175,7 +3201,7 @@ rte_eth_dev_remove_flex_filter(uint8_t port_id, uint16_t index)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3194,7 +3220,7 @@ rte_eth_dev_get_flex_filter(uint8_t port_id, uint16_t index,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3210,7 +3236,7 @@ rte_eth_dev_filter_supported(uint8_t port_id, enum rte_filter_type filter_type)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3227,7 +3253,7 @@ rte_eth_dev_filter_ctrl(uint8_t port_id, enum rte_filter_type filter_type,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id)) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index c29525b..2cd1c43 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1554,6 +1554,7 @@ struct eth_dev_ops {
  * process, while the actual configuration data for the device is shared.
  */
 struct rte_eth_dev {
+	uint8_t attached; /**< Flag indicating the port is attached */
 	eth_rx_burst_t rx_pkt_burst; /**< Pointer to PMD receive function. */
 	eth_tx_burst_t tx_pkt_burst; /**< Pointer to PMD transmit function. */
 	struct rte_eth_dev_data *data;  /**< Pointer to device data */
@@ -1626,6 +1627,10 @@ extern struct rte_eth_dev rte_eth_devices[];
  * initialized by the [matching] Ethernet driver during the PCI probing phase.
  * All devices whose port identifier is in the range
  * [0,  rte_eth_dev_count() - 1] can be operated on by network applications.
+ * immediately after invoking rte_eal_init().
+ * If the application unplugs a port using hotplug function, The enabled port
+ * numbers may be noncontiguous. In the case, the applications need to manage
+ * enabled port by themselves.
  *
  * @return
  *   - The total number of usable Ethernet devices.
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 03/25] eal/pci: Replace pci address comparison code by eal_compare_pci_addr
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 01/25] eal/pci: Add a new flag indicating a driver can detach devices at runtime Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 02/25] ethdev: Remove assumption that port will not be detached Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 04/25] ethdev: Add rte_eth_dev_free to free specified device Tetsuya Mukawa
                     ` (27 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

This patch replaces pci_addr_comparison() and memcmp() of pci addresses by
eal_compare_pci_addr().

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/bsdapp/eal/eal_pci.c       | 16 +---------------
 lib/librte_eal/common/eal_common_pci.c    |  2 +-
 lib/librte_eal/common/include/rte_pci.h   | 29 +++++++++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c     | 16 +---------------
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c |  2 +-
 5 files changed, 33 insertions(+), 32 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 74ecce7..7eda513 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -270,20 +270,6 @@ pci_uio_map_resource(struct rte_pci_device *dev)
 	return (0);
 }
 
-/* Compare two PCI device addresses. */
-static int
-pci_addr_comparison(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
-{
-	uint64_t dev_addr = (addr->domain << 24) + (addr->bus << 16) + (addr->devid << 8) + addr->function;
-	uint64_t dev_addr2 = (addr2->domain << 24) + (addr2->bus << 16) + (addr2->devid << 8) + addr2->function;
-
-	if (dev_addr > dev_addr2)
-		return 1;
-	else
-		return 0;
-}
-
-
 /* Scan one pci sysfs entry, and fill the devices list from it. */
 static int
 pci_scan_one(int dev_pci_fd, struct pci_conf *conf)
@@ -358,7 +344,7 @@ pci_scan_one(int dev_pci_fd, struct pci_conf *conf)
 		struct rte_pci_device *dev2 = NULL;
 
 		TAILQ_FOREACH(dev2, &pci_device_list, next) {
-			if (pci_addr_comparison(&dev->addr, &dev2->addr))
+			if (eal_compare_pci_addr(&dev->addr, &dev2->addr))
 				continue;
 			else {
 				TAILQ_INSERT_BEFORE(dev2, dev, next);
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index f3c7f71..f01f258 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -93,7 +93,7 @@ static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
 		if (devargs->type != RTE_DEVTYPE_BLACKLISTED_PCI &&
 			devargs->type != RTE_DEVTYPE_WHITELISTED_PCI)
 			continue;
-		if (!memcmp(&dev->addr, &devargs->pci.addr, sizeof(dev->addr)))
+		if (eal_compare_pci_addr(&dev->addr, &devargs->pci.addr))
 			return devargs;
 	}
 	return NULL;
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index b819539..fe374a8 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -261,6 +261,35 @@ eal_parse_pci_DomBDF(const char *input, struct rte_pci_addr *dev_addr)
 }
 #undef GET_PCIADDR_FIELD
 
+/* Compare two PCI device addresses. */
+/**
+ * Utility function to compare two PCI device addresses.
+ *
+ * @param addr
+ *	The PCI Bus-Device-Function address to compare
+ * @param addr2
+ *	The PCI Bus-Device-Function address to compare
+ * @return
+ *  0 on equal PCI address.
+ *  Positive on addr is greater than addr2.
+ *  Negative on addr is less than addr2.
+ */
+static inline int
+eal_compare_pci_addr(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
+{
+	uint64_t dev_addr = (addr->domain << 24) + (addr->bus << 16) +
+					(addr->devid << 8) + addr->function;
+	uint64_t dev_addr2 = (addr2->domain << 24) + (addr2->bus << 16) +
+					(addr2->devid << 8) + addr2->function;
+
+	if (dev_addr > dev_addr2)
+		return 1;
+	else if (dev_addr < dev_addr2)
+		return -1;
+	else
+		return 0;
+}
+
 /**
  * Probe the PCI bus for registered drivers.
  *
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index ddb0535..78df974 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -186,20 +186,6 @@ error:
 	return -1;
 }
 
-/* Compare two PCI device addresses. */
-static int
-pci_addr_comparison(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
-{
-	uint64_t dev_addr = (addr->domain << 24) + (addr->bus << 16) + (addr->devid << 8) + addr->function;
-	uint64_t dev_addr2 = (addr2->domain << 24) + (addr2->bus << 16) + (addr2->devid << 8) + addr2->function;
-
-	if (dev_addr > dev_addr2)
-		return 1;
-	else
-		return 0;
-}
-
-
 /* 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,
@@ -292,7 +278,7 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
 		struct rte_pci_device *dev2 = NULL;
 
 		TAILQ_FOREACH(dev2, &pci_device_list, next) {
-			if (pci_addr_comparison(&dev->addr, &dev2->addr))
+			if (eal_compare_pci_addr(&dev->addr, &dev2->addr) != 0)
 				continue;
 			else {
 				TAILQ_INSERT_BEFORE(dev2, dev, next);
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
index 7e62266..f0deeba 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
@@ -120,7 +120,7 @@ pci_uio_map_secondary(struct rte_pci_device *dev)
 	TAILQ_FOREACH(uio_res, pci_res_list, next) {
 
 		/* skip this element if it doesn't match our PCI address */
-		if (memcmp(&uio_res->pci_addr, &dev->addr, sizeof(dev->addr)))
+		if (eal_compare_pci_addr(&uio_res->pci_addr, &dev->addr))
 			continue;
 
 		for (i = 0; i != uio_res->nb_maps; i++) {
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 04/25] ethdev: Add rte_eth_dev_free to free specified device
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (2 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 03/25] eal/pci: Replace pci address comparison code by eal_compare_pci_addr Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 05/25] eal, ethdev: Add function pointer for closing a device Tetsuya Mukawa
                     ` (26 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

This patch adds rte_eth_dev_free(). The function is used for changing a
attached status of the device that has specified name.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 17 +++++++++++++++++
 lib/librte_ether/rte_ethdev.h | 11 +++++++++++
 2 files changed, 28 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 446c53a..f217e14 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -249,6 +249,23 @@ rte_eth_dev_allocate(const char *name)
 	return eth_dev;
 }
 
+struct rte_eth_dev *
+rte_eth_dev_free(const char *name)
+{
+	struct rte_eth_dev *eth_dev;
+
+	eth_dev = rte_eth_dev_allocated(name);
+	if (eth_dev == NULL) {
+		PMD_DEBUG_TRACE("Ethernet Device with name %s doesn't exist!\n",
+				name);
+		return NULL;
+	}
+
+	eth_dev->attached = 0;
+	nb_ports--;
+	return eth_dev;
+}
+
 static int
 rte_eth_dev_init(struct rte_pci_driver *pci_drv,
 		 struct rte_pci_device *pci_dev)
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 2cd1c43..548467c 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1649,6 +1649,17 @@ extern uint8_t rte_eth_dev_count(void);
  */
 struct rte_eth_dev *rte_eth_dev_allocate(const char *name);
 
+/**
+ * Function for internal use by dummy drivers primarily, e.g. ring-based
+ * driver.
+ * Free the specified ethdev and returns the pointer to that slot.
+ *
+ * @param	name	Unique identifier name for each Ethernet device
+ * @return
+ *   - Slot in the rte_dev_devices array for the freed device;
+ */
+struct rte_eth_dev *rte_eth_dev_free(const char *name);
+
 struct eth_driver;
 /**
  * @internal
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 05/25] eal, ethdev: Add function pointer for closing a device
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (3 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 04/25] ethdev: Add rte_eth_dev_free to free specified device Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 06/25] ethdev: Add rte_eth_dev_shutdown for closing PCI devices Tetsuya Mukawa
                     ` (25 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch adds function pointer to rte_pci_driver and eth_driver
structure. These function pointers are used when ports are detached.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/include/rte_pci.h | 7 +++++++
 lib/librte_ether/rte_ethdev.h           | 4 ++++
 2 files changed, 11 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index fe374a8..74720d1 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -181,12 +181,19 @@ struct rte_pci_driver;
 typedef int (pci_devinit_t)(struct rte_pci_driver *, struct rte_pci_device *);
 
 /**
+ * Shutdown function for the driver called during hotplugging.
+ */
+typedef int (pci_devshutdown_t)(
+		struct rte_pci_driver *, struct rte_pci_device *);
+
+/**
  * A structure describing a PCI driver.
  */
 struct rte_pci_driver {
 	TAILQ_ENTRY(rte_pci_driver) next;       /**< Next in list. */
 	const char *name;                       /**< Driver name. */
 	pci_devinit_t *devinit;                 /**< Device init. function. */
+	pci_devshutdown_t *devshutdown;         /**< Device shutdown function. */
 	struct rte_pci_id *id_table;            /**< ID table, NULL terminated. */
 	uint32_t drv_flags;                     /**< Flags contolling handling of device. */
 };
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 548467c..558d4d3 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1696,6 +1696,9 @@ struct eth_driver;
 typedef int (*eth_dev_init_t)(struct eth_driver  *eth_drv,
 			      struct rte_eth_dev *eth_dev);
 
+typedef int (*eth_dev_shutdown_t)(struct eth_driver  *eth_drv,
+				  struct rte_eth_dev *eth_dev);
+
 /**
  * @internal
  * The structure associated with a PMD Ethernet driver.
@@ -1712,6 +1715,7 @@ typedef int (*eth_dev_init_t)(struct eth_driver  *eth_drv,
 struct eth_driver {
 	struct rte_pci_driver pci_drv;    /**< The PMD is also a PCI driver. */
 	eth_dev_init_t eth_dev_init;      /**< Device init function. */
+	eth_dev_shutdown_t eth_dev_shutdown;/**< Device shutdown function. */
 	unsigned int dev_private_size;    /**< Size of device private data. */
 };
 
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 06/25] ethdev: Add rte_eth_dev_shutdown for closing PCI devices.
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (4 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 05/25] eal, ethdev: Add function pointer for closing a device Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 07/25] ethdev: Add functions to know which port is attached or detached Tetsuya Mukawa
                     ` (24 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

rte_eth_dev_shutdown() is called when PCI device is closed.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index f217e14..c9f82d9 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -321,6 +321,42 @@ rte_eth_dev_init(struct rte_pci_driver *pci_drv,
 	return diag;
 }
 
+static int
+rte_eth_dev_shutdown(struct rte_pci_driver *pci_drv,
+		 struct rte_pci_device *pci_dev)
+{
+	struct eth_driver *eth_drv;
+	struct rte_eth_dev *eth_dev;
+	char ethdev_name[RTE_ETH_NAME_MAX_LEN];
+
+	/* Create unique Ethernet device name using PCI address */
+	snprintf(ethdev_name, RTE_ETH_NAME_MAX_LEN, "%d:%d.%d",
+			pci_dev->addr.bus, pci_dev->addr.devid,
+			pci_dev->addr.function);
+
+	eth_dev = rte_eth_dev_free(ethdev_name);
+	if (eth_dev == NULL)
+		return -ENODEV;
+
+	eth_drv = (struct eth_driver *)pci_drv;
+
+	/* Invoke PMD device shutdown function */
+	if (*eth_drv->eth_dev_shutdown)
+		(*eth_drv->eth_dev_shutdown)(eth_drv, eth_dev);
+
+	/* init user callbacks */
+	TAILQ_INIT(&(eth_dev->callbacks));
+
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+		rte_free(eth_dev->data->dev_private);
+
+	eth_dev->pci_dev = NULL;
+	eth_dev->driver = NULL;
+	eth_dev->data = NULL;
+
+	return 0;
+}
+
 /**
  * Register an Ethernet [Poll Mode] driver.
  *
@@ -339,6 +375,7 @@ void
 rte_eth_driver_register(struct eth_driver *eth_drv)
 {
 	eth_drv->pci_drv.devinit = rte_eth_dev_init;
+	eth_drv->pci_drv.devshutdown = rte_eth_dev_shutdown;
 	rte_eal_pci_register(&eth_drv->pci_drv);
 }
 
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 07/25] ethdev: Add functions to know which port is attached or detached
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (5 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 06/25] ethdev: Add rte_eth_dev_shutdown for closing PCI devices Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 08/25] ethdev: Add rte_eth_dev_get_addr_by_port Tetsuya Mukawa
                     ` (23 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch adds rte_eth_dev_save() and rte_eth_dev_get_changed_port().
rte_eth_dev_save() is used for saving current rte_eth_dev structures.
rte_eth_dev_get_changed_port() receives the rte_eth_dev structures, then
compare these with current values to know which port is actually
attached or detached.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 18 ++++++++++++++++++
 lib/librte_ether/rte_ethdev.h | 21 +++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index c9f82d9..5e1b6b9 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -402,6 +402,24 @@ rte_eth_dev_count(void)
 	return (nb_ports);
 }
 
+void
+rte_eth_dev_save(struct rte_eth_dev *devs)
+{
+	/* save current rte_eth_devices */
+	memcpy(devs, rte_eth_devices,
+			sizeof(struct rte_eth_dev) * RTE_MAX_ETHPORTS);
+}
+
+int
+rte_eth_dev_get_changed_port(struct rte_eth_dev *devs, uint8_t *port_id)
+{
+	/* check which port was attached or detached */
+	for (*port_id = 0; *port_id < RTE_MAX_ETHPORTS; (*port_id)++, devs++)
+		if (rte_eth_devices[*port_id].attached ^ devs->attached)
+			return 0;
+	return 1;
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 558d4d3..683b79c 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1638,6 +1638,27 @@ extern struct rte_eth_dev rte_eth_devices[];
 extern uint8_t rte_eth_dev_count(void);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Copies current ethdev structures to the specified pointer.
+ *
+ * @param	devs	The pointer to the ethdev structures
+ */
+extern void rte_eth_dev_save(struct rte_eth_dev *devs);
+
+/**
+ * Function for internal use by port hotplug functions.
+ * Compare the specified ethdev structures with currrents. Then
+ * if there is a port which status is changed, fill the specified pointer
+ * with the port id of that port.
+ * @param	devs	The pointer to the ethdev structures
+ * @param	port_id	The pointer to the port id
+ * @return
+ *   - 0 on success, negative on error
+ */
+extern int rte_eth_dev_get_changed_port(
+		struct rte_eth_dev *devs, uint8_t *port_id);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 08/25] ethdev: Add rte_eth_dev_get_addr_by_port
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (6 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 07/25] ethdev: Add functions to know which port is attached or detached Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 09/25] ethdev: Add rte_eth_dev_get_port_by_addr Tetsuya Mukawa
                     ` (22 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The function returns a pci address of a ethdev specified by port
identifier.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 12 ++++++++++++
 lib/librte_ether/rte_ethdev.h | 13 +++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 5e1b6b9..fa75ea9 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -420,6 +420,18 @@ rte_eth_dev_get_changed_port(struct rte_eth_dev *devs, uint8_t *port_id)
 	return 1;
 }
 
+int
+rte_eth_dev_get_addr_by_port(uint8_t port_id, struct rte_pci_addr *addr)
+{
+	if (rte_eth_dev_validate_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -EINVAL;
+	}
+
+	*addr = rte_eth_devices[port_id].pci_dev->addr;
+	return 0;
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 683b79c..fd4aa5a 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1659,6 +1659,19 @@ extern int rte_eth_dev_get_changed_port(
 		struct rte_eth_dev *devs, uint8_t *port_id);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Returns a pci address of a ethdev specified by port identifier.
+ * @param	port_id
+ *   The port identifier of the Ethernet device
+ * @param	addr
+ *   The pointer to the pci address
+ * @return
+ *   - 0 on success, negative on error
+ */
+extern int rte_eth_dev_get_addr_by_port(
+		uint8_t port_id, struct rte_pci_addr *addr);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 09/25] ethdev: Add rte_eth_dev_get_port_by_addr
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (7 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 08/25] ethdev: Add rte_eth_dev_get_addr_by_port Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 10/25] ethdev: Add rte_eth_dev_get_name_by_port Tetsuya Mukawa
                     ` (21 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The function returns a port identifier of a ethdev specified by pci
address.

v3:
- Fix if-condition bug while comparing pci addresses.
- Add error checking codes.
Reported-by: Mark Enright <menrigh@brocade.com>

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 17 +++++++++++++++++
 lib/librte_ether/rte_ethdev.h | 13 +++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index fa75ea9..fa5b928 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -432,6 +432,23 @@ rte_eth_dev_get_addr_by_port(uint8_t port_id, struct rte_pci_addr *addr)
 	return 0;
 }
 
+int
+rte_eth_dev_get_port_by_addr(struct rte_pci_addr *addr, uint8_t *port_id)
+{
+	struct rte_pci_addr *tmp;
+
+	for (*port_id = 0; *port_id < RTE_MAX_ETHPORTS; (*port_id)++) {
+		if (!rte_eth_devices[*port_id].attached)
+			continue;
+		if (!rte_eth_devices[*port_id].pci_dev)
+			continue;
+		tmp = &rte_eth_devices[*port_id].pci_dev->addr;
+		if (eal_compare_pci_addr(tmp, addr) == 0)
+			return 0;
+	}
+	return -1;
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index fd4aa5a..8bdc8ae 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1672,6 +1672,19 @@ extern int rte_eth_dev_get_addr_by_port(
 		uint8_t port_id, struct rte_pci_addr *addr);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Returns a port identifier of a ethdev specified by pci address.
+ * @param	addr
+ *   The pointer to the pci address of the Ethernet device.
+ * @param	port_id
+ *   The pointer to the port identifier
+ * @return
+ *   - 0 on success, negative on error
+ */
+extern int rte_eth_dev_get_port_by_addr(
+		struct rte_pci_addr *addr, uint8_t *port_id);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 10/25] ethdev: Add rte_eth_dev_get_name_by_port
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (8 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 09/25] ethdev: Add rte_eth_dev_get_port_by_addr Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 11/25] ethdev: Add rte_eth_dev_check_detachable Tetsuya Mukawa
                     ` (20 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The function returns a unique identifier name of a ethdev specified by
port identifier.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 17 +++++++++++++++++
 lib/librte_ether/rte_ethdev.h | 12 ++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index fa5b928..372ab7d 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -449,6 +449,23 @@ rte_eth_dev_get_port_by_addr(struct rte_pci_addr *addr, uint8_t *port_id)
 	return -1;
 }
 
+int
+rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
+{
+	char *tmp;
+
+	if (rte_eth_dev_validate_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -EINVAL;
+	}
+
+	/* shouldn't check 'rte_eth_devices[i].data',
+	 * because it might be overwritten by VDEV PMD */
+	tmp = rte_eth_dev_data[port_id].name;
+	strncpy(name, tmp, strlen(tmp) + 1);
+	return 0;
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 8bdc8ae..2087daf 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1685,6 +1685,18 @@ extern int rte_eth_dev_get_port_by_addr(
 		struct rte_pci_addr *addr, uint8_t *port_id);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Returns a unique identifier name of a ethdev specified by port identifier.
+ * @param	port_id
+ *   The port identifier.
+ * @param	name
+ *  The pointer to the Unique identifier name for each Ethernet device
+ * @return
+ *   - 0 on success, negative on error
+ */
+extern int rte_eth_dev_get_name_by_port(uint8_t port_id, char *name);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 11/25] ethdev: Add rte_eth_dev_check_detachable
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (9 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 10/25] ethdev: Add rte_eth_dev_get_name_by_port Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 12/25] ethdev: Change scope of rte_eth_dev_allocated to global Tetsuya Mukawa
                     ` (19 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The function returns whether a PMD supports detach function, or not.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c |  9 +++++++++
 lib/librte_ether/rte_ethdev.h | 11 +++++++++++
 2 files changed, 20 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 372ab7d..0d2397b 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -466,6 +466,15 @@ rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
 	return 0;
 }
 
+int
+rte_eth_dev_check_detachable(uint8_t port_id)
+{
+	uint32_t drv_flags;
+
+	drv_flags = rte_eth_devices[port_id].driver->pci_drv.drv_flags;
+	return !!(drv_flags & RTE_PCI_DRV_DETACHABLE);
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 2087daf..49b4e9b 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1697,6 +1697,17 @@ extern int rte_eth_dev_get_port_by_addr(
 extern int rte_eth_dev_get_name_by_port(uint8_t port_id, char *name);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Check whether or not, a PMD that is handling the ethdev specified by port
+ * identifier can support detach function.
+ * @param	port_id
+ *   The port identifier
+ * @return
+ *   - 0 on supporting detach function, negative on not supporting
+ */
+extern int rte_eth_dev_check_detachable(uint8_t port_id);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 12/25] ethdev: Change scope of rte_eth_dev_allocated to global
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (10 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 11/25] ethdev: Add rte_eth_dev_check_detachable Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 13/25] eal/pci: Prevent double registration for devargs_list Tetsuya Mukawa
                     ` (18 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

This function is used by virtual PMDs to support port hotplug framework.
So change scope of the function to global.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c |  2 +-
 lib/librte_ether/rte_ethdev.h | 10 ++++++++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 0d2397b..c697d83 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -196,7 +196,7 @@ rte_eth_dev_data_alloc(void)
 				RTE_MAX_ETHPORTS * sizeof(*rte_eth_dev_data));
 }
 
-static struct rte_eth_dev *
+struct rte_eth_dev *
 rte_eth_dev_allocated(const char *name)
 {
 	unsigned i;
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 49b4e9b..0846bff 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1708,6 +1708,16 @@ extern int rte_eth_dev_get_name_by_port(uint8_t port_id, char *name);
 extern int rte_eth_dev_check_detachable(uint8_t port_id);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Returns a ethdev slot specified by the unique identifier name.
+ * @param	name
+ *  The pointer to the Unique identifier name for each Ethernet device
+ * @return
+ *   - The pointer to the ethdev slot, on success. NULL on error
+ */
+extern struct rte_eth_dev *rte_eth_dev_allocated(const char *name);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 13/25] eal/pci: Prevent double registration for devargs_list
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (11 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 12/25] ethdev: Change scope of rte_eth_dev_allocated to global Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 14/25] eal/pci: Add rte_eal_devargs_remove Tetsuya Mukawa
                     ` (17 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch fixes rte_eal_devargs_add() not to register same device twice.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_devargs.c | 32 ++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index 4c7d11a..aaa6901 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -44,6 +44,32 @@
 struct rte_devargs_list devargs_list =
 	TAILQ_HEAD_INITIALIZER(devargs_list);
 
+
+/* find a entry specified by pci address or device name */
+static struct rte_devargs *
+rte_eal_devargs_find(enum rte_devtype devtype, void *args)
+{
+	struct rte_devargs *devargs;
+
+	TAILQ_FOREACH(devargs, &devargs_list, next) {
+		switch (devtype) {
+		case RTE_DEVTYPE_WHITELISTED_PCI:
+		case RTE_DEVTYPE_BLACKLISTED_PCI:
+			if (eal_compare_pci_addr(&devargs->pci.addr, args) == 0)
+				goto found;
+			break;
+		case RTE_DEVTYPE_VIRTUAL:
+			if (memcmp(&devargs->virtual.drv_name, args,
+					strlen((char *)args)) == 0)
+				goto found;
+			break;
+		}
+	}
+	return NULL;
+found:
+	return devargs;
+}
+
 /* store a whitelist parameter for later parsing */
 int
 rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str)
@@ -101,6 +127,12 @@ rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str)
 		break;
 	}
 
+	/* make sure there is no same entry */
+	if (rte_eal_devargs_find(devtype, &devargs->pci.addr)) {
+		RTE_LOG(ERR, EAL, "device already registered: <%s>\n", buf);
+		return -1;
+	}
+
 	TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
 	return 0;
 }
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 14/25] eal/pci: Add rte_eal_devargs_remove
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (12 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 13/25] eal/pci: Prevent double registration for devargs_list Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 15/25] eal/pci: Add probe and close function for virtual drivers Tetsuya Mukawa
                     ` (16 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The function removes a specified devargs from devargs_list.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_devargs.c  | 13 +++++++++++++
 lib/librte_eal/common/include/rte_devargs.h | 18 ++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index aaa6901..0916cf8 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -137,6 +137,19 @@ rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str)
 	return 0;
 }
 
+/* remove it from the devargs_list */
+void
+rte_eal_devargs_remove(enum rte_devtype devtype, void *args)
+{
+	struct rte_devargs *devargs;
+
+	devargs = rte_eal_devargs_find(devtype, args);
+	if (devargs == NULL)
+		return;
+
+	TAILQ_REMOVE(&devargs_list, devargs, next);
+}
+
 /* count the number of devices of a specified type */
 unsigned int
 rte_eal_devargs_type_count(enum rte_devtype devtype)
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
index 9f9c98f..57842b3 100644
--- a/lib/librte_eal/common/include/rte_devargs.h
+++ b/lib/librte_eal/common/include/rte_devargs.h
@@ -123,6 +123,24 @@ extern struct rte_devargs_list devargs_list;
 int rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str);
 
 /**
+ * Remove a device form the user device list
+ *
+ * For PCI devices, the format of arguments string is "PCI_ADDR". It shouldn't
+ * involves parameters for the device. Example: "08:00.1".
+ *
+ * For virtual devices, the format of arguments string is "DRIVER_NAME*". It
+ * shouldn't involves parameters for the device. Example: "eth_ring". The
+ * validity of the driver name is not checked by this function, it is done
+ * when closing the drivers.
+ *
+ * @param devtype
+ *   The type of the device.
+ * @param name
+ *   The name of the device.
+ */
+void rte_eal_devargs_remove(enum rte_devtype devtype, void *args);
+
+/**
  * Count the number of user devices of a specified type
  *
  * @param devtype
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 15/25] eal/pci: Add probe and close function for virtual drivers
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (13 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 14/25] eal/pci: Add rte_eal_devargs_remove Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 16/25] eal/pci: Add port hotplug functions for virtual devices Tetsuya Mukawa
                     ` (15 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch adds rte_eal_dev_init_one() and rte_eal_dev_close_one().
These are used for attaching and detaching virtual devices.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_dev.c  | 74 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h |  6 +++
 lib/librte_eal/linuxapp/eal/Makefile    |  1 +
 3 files changed, 81 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index eae5656..183d65b 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -32,10 +32,13 @@
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <stdio.h>
+#include <limits.h>
 #include <string.h>
 #include <inttypes.h>
 #include <sys/queue.h>
 
+#include <rte_ethdev.h>
 #include <rte_dev.h>
 #include <rte_devargs.h>
 #include <rte_debug.h>
@@ -107,3 +110,74 @@ rte_eal_dev_init(void)
 	}
 	return 0;
 }
+
+/* So far, linux only supports DPDK hotplug function. */
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+
+#define INVOKE_PROBE	(0)
+#define INVOKE_CLOSE	(1)
+
+static void
+rte_eal_dev_invoke(struct rte_driver *driver,
+		struct rte_devargs *devargs, int type)
+{
+	switch (type) {
+	case INVOKE_PROBE:
+		driver->init(devargs->virtual.drv_name, devargs->args);
+		break;
+	case INVOKE_CLOSE:
+		driver->close(devargs->virtual.drv_name, devargs->args);
+		break;
+	}
+}
+
+static int
+rte_eal_dev_find_and_invoke(const char *name, int type)
+{
+	struct rte_devargs *devargs;
+	struct rte_driver *driver;
+
+	/* call the init function for each virtual device */
+	TAILQ_FOREACH(devargs, &devargs_list, next) {
+
+		if (devargs->type != RTE_DEVTYPE_VIRTUAL)
+			continue;
+
+		if (strncmp(name, devargs->virtual.drv_name, strlen(name)))
+			continue;
+
+		TAILQ_FOREACH(driver, &dev_driver_list, next) {
+			if (driver->type != PMD_VDEV)
+				continue;
+
+			/* search a driver prefix in virtual device name */
+			if (!strncmp(driver->name, devargs->virtual.drv_name,
+					strlen(driver->name))) {
+				rte_eal_dev_invoke(driver, devargs, type);
+				break;
+			}
+		}
+
+		if (driver == NULL) {
+			RTE_LOG(WARNING, EAL, "no driver found for %s\n",
+				  devargs->virtual.drv_name);
+		}
+		return 0;
+	}
+	return 1;
+}
+
+/* find and initialize the driver of specified virtual device */
+static int
+rte_eal_dev_init_one(const char *name)
+{
+	return rte_eal_dev_find_and_invoke(name, INVOKE_PROBE);
+}
+
+/* find and finalize the driver of specified virtual device */
+static int
+rte_eal_dev_close_one(const char *name)
+{
+	return rte_eal_dev_find_and_invoke(name, INVOKE_CLOSE);
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index f7e3a10..71d40c3 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -57,6 +57,11 @@ TAILQ_HEAD(rte_driver_list, rte_driver);
 typedef int (rte_dev_init_t)(const char *name, const char *args);
 
 /**
+ * Close function called for each device driver once.
+ */
+typedef int (rte_dev_close_t)(const char *name, const char *args);
+
+/**
  * Driver type enumeration
  */
 enum pmd_type {
@@ -72,6 +77,7 @@ struct rte_driver {
 	enum pmd_type type;		   /**< PMD Driver type */
 	const char *name;                   /**< Driver name. */
 	rte_dev_init_t *init;              /**< Device init. function. */
+	rte_dev_close_t *close;            /**< Device close. function. */
 };
 
 /**
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index c99433e..27e9b48 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -40,6 +40,7 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
 CFLAGS += -I$(RTE_SDK)/lib/librte_ring
 CFLAGS += -I$(RTE_SDK)/lib/librte_mempool
 CFLAGS += -I$(RTE_SDK)/lib/librte_malloc
+CFLAGS += -I$(RTE_SDK)/lib/librte_mbuf
 CFLAGS += -I$(RTE_SDK)/lib/librte_ether
 CFLAGS += -I$(RTE_SDK)/lib/librte_ivshmem
 CFLAGS += -I$(RTE_SDK)/lib/librte_pmd_ring
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 16/25] eal/pci: Add port hotplug functions for virtual devices.
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (14 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 15/25] eal/pci: Add probe and close function for virtual drivers Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 17/25] eal/linux/pci: Add functions for unmapping igb_uio resources Tetsuya Mukawa
                     ` (14 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch adds rte_eal_dev_attach_vdev() and rte_eal_dev_detach_vdev().

rte_eal_dev_attach_vdev() receives virtual device name and parameters,
and returns an attached port number.
rte_eal_dev_detach_vdev() receives a port number, and returns device
name actually detached.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_dev.c  | 76 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h | 29 +++++++++++++
 2 files changed, 105 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 183d65b..0518e3c 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -180,4 +180,80 @@ rte_eal_dev_close_one(const char *name)
 {
 	return rte_eal_dev_find_and_invoke(name, INVOKE_CLOSE);
 }
+
+static void
+get_vdev_name(char *vdevargs)
+{
+	char *sep;
+
+	/* set the first ',' to '\0' to split name and arguments */
+	sep = strchr(vdevargs, ',');
+	if (sep != NULL)
+		sep[0] = '\0';
+}
+
+/* attach the new virtual device, then store port_id of the device */
+int
+rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id)
+{
+	char *args;
+	uint8_t new_port_id;
+	struct rte_eth_dev devs[RTE_MAX_ETHPORTS];
+
+	args = strdup(vdevargs);
+	if (args == NULL)
+		return -1;
+
+	/* save current port status */
+	rte_eth_dev_save(devs);
+	/* add the vdevargs to devargs_list */
+	if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, args))
+		goto err0;
+	/* parse vdevargs, then retrieve device name */
+	get_vdev_name(args);
+	/* walk around dev_driver_list to find the driver of the device,
+	 * then invoke probe function o the driver */
+	if (rte_eal_dev_init_one(args))
+		goto err1;
+	/* get port_id enabled by above procedures */
+	if (rte_eth_dev_get_changed_port(devs, &new_port_id))
+		goto err1;
+
+	free(args);
+	*port_id = new_port_id;
+	return 0;
+err1:
+	rte_eal_devargs_remove(RTE_DEVTYPE_VIRTUAL, args);
+err0:
+	RTE_LOG(ERR, EAL, "Drver, cannot detach the device\n");
+	free(args);
+	return -1;
+}
+
+/* detach the new virtual device, then store the name of the device */
+int
+rte_eal_dev_detach_vdev(uint8_t port_id, char *vdevname)
+{
+	char name[RTE_ETH_NAME_MAX_LEN];
+
+	/* check whether the driver supports detach feature, or not */
+	if (!rte_eth_dev_check_detachable(port_id))
+		goto err;
+
+	/* get device name by port id */
+	if (rte_eth_dev_get_name_by_port(port_id, name))
+		goto err;
+	/* walk around dev_driver_list to find the driver of the device,
+	 * then invoke close function o the driver */
+	if (rte_eal_dev_close_one(name))
+		goto err;
+	/* remove the vdevname from devargs_list */
+	rte_eal_devargs_remove(RTE_DEVTYPE_VIRTUAL, name);
+
+	strncpy(vdevname, name, sizeof(name));
+	return 0;
+err:
+	RTE_LOG(ERR, EAL, "Drver, cannot detach the device\n");
+	return -1;
+}
 #endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 71d40c3..159d5a5 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -98,6 +98,35 @@ void rte_eal_driver_register(struct rte_driver *driver);
  */
 void rte_eal_driver_unregister(struct rte_driver *driver);
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+
+/**
+ * Attach a new virtual device.
+ *
+ * @param vdevargs
+ *   A pointer to a strings array describing the new device
+ *   to be attached.
+ * @param port_id
+ *  A pointer to a port identifier actually attached.
+ * @return
+ *  0 on success and port_id is filled, negative on error
+ */
+int rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id);
+
+/**
+ * Detach a virtual device.
+ *
+ * @param port_id
+ *   The port identifier of the virtual device to detach.
+ * @param addr
+ *  A pointer to a virtual device name actually detached.
+ * @return
+ *  0 on success and vdevname is filled, negative on error
+ */
+int rte_eal_dev_detach_vdev(uint8_t port_id, char *vdevname);
+
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /**
  * Initalize all the registered drivers in this process
  */
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 17/25] eal/linux/pci: Add functions for unmapping igb_uio resources
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (15 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 16/25] eal/pci: Add port hotplug functions for virtual devices Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 18/25] eal/pci: Prevent double registrations for pci_device_list Tetsuya Mukawa
                     ` (13 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch adds functions for unmapping igb_uio resources. The patch is only
for Linux and igb_uio environment. VFIO and BSD are not supported.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/linuxapp/eal/eal_pci.c              | 32 +++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c          | 56 ++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/include/eal_pci_init.h |  7 +++
 3 files changed, 95 insertions(+)

diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 78df974..d7293c7 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -123,6 +123,22 @@ fail:
 	return NULL;
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+/* unmap a particular resource */
+void
+pci_unmap_resource(void *requested_addr, size_t size)
+{
+	/* Unmap the PCI memory resource of device */
+	if (munmap(requested_addr, size)) {
+		RTE_LOG(ERR, EAL, "%s(): cannot munmap(%p, 0x%lx): %s\n",
+			__func__, requested_addr, (unsigned long)size,
+			strerror(errno));
+	} else
+		RTE_LOG(DEBUG, EAL, "  PCI memory mapped at %p\n",
+				requested_addr);
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /* parse the "resource" sysfs file */
 #define IORESOURCE_MEM  0x00000200
 
@@ -493,6 +509,22 @@ pci_map_device(struct rte_pci_device *dev)
 	return 0;
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+static void
+pci_unmap_device(struct rte_pci_device *dev)
+{
+	/* try unmapping the NIC resources using VFIO if it exists */
+#ifdef VFIO_PRESENT
+	if (pci_vfio_is_enabled()) {
+		RTE_LOG(ERR, EAL, "%s() doesn't support vfio yet.\n",
+				__func__);
+		return;
+	}
+#endif
+	pci_uio_unmap_resource(dev);
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /*
  * If vendor/device ID match, call the devinit() function of the
  * driver.
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
index f0deeba..ff48eb9 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
@@ -395,6 +395,62 @@ pci_uio_map_resource(struct rte_pci_device *dev)
 	return 0;
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+static void
+pci_uio_unmap(struct mapped_pci_resource *uio_res)
+{
+	int i;
+
+	for (i = 0; i != uio_res->nb_maps; i++)
+		pci_unmap_resource(uio_res->maps[i].addr,
+				(size_t)uio_res->maps[i].size);
+}
+
+static struct mapped_pci_resource *
+pci_uio_find_resource(struct rte_pci_device *dev)
+{
+	struct mapped_pci_resource *uio_res;
+
+	TAILQ_FOREACH(uio_res, pci_res_list, next) {
+
+		/* skip this element if it doesn't match our PCI address */
+		if (!eal_compare_pci_addr(&uio_res->pci_addr, &dev->addr))
+			return uio_res;
+	}
+	return NULL;
+}
+
+/* unmap the PCI resource of a PCI device in virtual memory */
+void
+pci_uio_unmap_resource(struct rte_pci_device *dev)
+{
+	struct mapped_pci_resource *uio_res;
+
+	/* find an entry for the device */
+	uio_res = pci_uio_find_resource(dev);
+	if (uio_res == NULL)
+		return;
+
+	/* secondary processes - just free maps */
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return pci_uio_unmap(uio_res);
+
+	TAILQ_REMOVE(pci_res_list, uio_res, next);
+
+	/* unmap all resources */
+	pci_uio_unmap(uio_res);
+
+	/* free uio resource */
+	rte_free(uio_res);
+
+	/* close fd if in primary process */
+	close(dev->intr_handle.fd);
+
+	dev->intr_handle.fd = -1;
+	dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /*
  * parse a sysfs file containing one integer value
  * different to the eal version, as it needs to work with 64-bit values
diff --git a/lib/librte_eal/linuxapp/eal/include/eal_pci_init.h b/lib/librte_eal/linuxapp/eal/include/eal_pci_init.h
index d758bee..ab9c16b 100644
--- a/lib/librte_eal/linuxapp/eal/include/eal_pci_init.h
+++ b/lib/librte_eal/linuxapp/eal/include/eal_pci_init.h
@@ -65,6 +65,13 @@ void *pci_map_resource(void *requested_addr, int fd, off_t offset,
 /* map IGB_UIO resource prototype */
 int pci_uio_map_resource(struct rte_pci_device *dev);
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+void pci_unmap_resource(void *requested_addr, size_t size);
+
+/* unmap IGB_UIO resource prototype */
+void pci_uio_unmap_resource(struct rte_pci_device *dev);
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 #ifdef VFIO_PRESENT
 
 #define VFIO_MAX_GROUPS 64
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 18/25] eal/pci: Prevent double registrations for pci_device_list
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (16 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 17/25] eal/linux/pci: Add functions for unmapping igb_uio resources Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 19/25] eal/pci: Change scope of rte_eal_pci_scan to global Tetsuya Mukawa
                     ` (12 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch fixes pci_scan_one() not to register same pci devices twice.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/linuxapp/eal/eal_pci.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index d7293c7..85cdd27 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -292,14 +292,17 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
 	}
 	else {
 		struct rte_pci_device *dev2 = NULL;
+		int ret;
 
 		TAILQ_FOREACH(dev2, &pci_device_list, next) {
-			if (eal_compare_pci_addr(&dev->addr, &dev2->addr) != 0)
+			ret = eal_compare_pci_addr(&dev->addr, &dev2->addr);
+			if (ret > 0)
 				continue;
-			else {
+			else if (ret < 0) {
 				TAILQ_INSERT_BEFORE(dev2, dev, next);
 				return 0;
-			}
+			} else	/* already registered */
+				return 0;
 		}
 		TAILQ_INSERT_TAIL(&pci_device_list, dev, next);
 	}
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 19/25] eal/pci: Change scope of rte_eal_pci_scan to global
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (17 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 18/25] eal/pci: Prevent double registrations for pci_device_list Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 20/25] eal/pci: Add rte_eal_pci_close_one_driver Tetsuya Mukawa
                     ` (11 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The function is called by port hotplug framework, so change scope of the
function to global.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/include/eal_private.h | 11 +++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c       |  6 +++---
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/common/include/eal_private.h b/lib/librte_eal/common/include/eal_private.h
index 232fcec..a1127ab 100644
--- a/lib/librte_eal/common/include/eal_private.h
+++ b/lib/librte_eal/common/include/eal_private.h
@@ -154,6 +154,17 @@ struct rte_pci_driver;
 struct rte_pci_device;
 
 /**
+ * Scan the content of the PCI bus, and the devices in the devices
+ * list
+ *
+ * This function is private to EAL.
+ *
+ * @return
+ *  0 on success, negative on error
+ */
+int rte_eal_pci_scan(void);
+
+/**
  * Mmap memory for single PCI device
  *
  * This function is private to EAL.
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 85cdd27..0317366 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -361,8 +361,8 @@ error:
  * Scan the content of the PCI bus, and the devices in the devices
  * list
  */
-static int
-pci_scan(void)
+int
+rte_eal_pci_scan(void)
 {
 	struct dirent *e;
 	DIR *dir;
@@ -612,7 +612,7 @@ rte_eal_pci_init(void)
 	if (internal_config.no_pci)
 		return 0;
 
-	if (pci_scan() < 0) {
+	if (rte_eal_pci_scan() < 0) {
 		RTE_LOG(ERR, EAL, "%s(): Cannot scan PCI bus\n", __func__);
 		return -1;
 	}
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 20/25] eal/pci: Add rte_eal_pci_close_one_driver
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (18 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 19/25] eal/pci: Change scope of rte_eal_pci_scan to global Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 21/25] eal/pci: Fix pci_probe_all_drivers to share code with closing function Tetsuya Mukawa
                     ` (10 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The function is used for closing the specified driver and device.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/include/eal_private.h | 11 ++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c       | 58 +++++++++++++++++++++++++++++
 2 files changed, 69 insertions(+)

diff --git a/lib/librte_eal/common/include/eal_private.h b/lib/librte_eal/common/include/eal_private.h
index a1127ab..b2776cc 100644
--- a/lib/librte_eal/common/include/eal_private.h
+++ b/lib/librte_eal/common/include/eal_private.h
@@ -176,6 +176,17 @@ int rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr,
 		struct rte_pci_device *dev);
 
 /**
+ * Munmap memory for single PCI device
+ *
+ * This function is private to EAL.
+ *
+ * @return
+ *   0 on success, negative on error
+ */
+int rte_eal_pci_close_one_driver(struct rte_pci_driver *dr,
+		struct rte_pci_device *dev);
+
+/**
  * Init tail queues for non-EAL library structures. This is to allow
  * the rings, mempools, etc. lists to be shared among multiple processes
  *
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 0317366..fbfef40 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -599,6 +599,64 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d
 	return 1;
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+/*
+ * If vendor/device ID match, call the devshutdown() function of the
+ * driver.
+ */
+int
+rte_eal_pci_close_one_driver(struct rte_pci_driver *dr,
+		struct rte_pci_device *dev)
+{
+	struct rte_pci_id *id_table;
+
+	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;
+
+		RTE_LOG(DEBUG, EAL,
+				"PCI device "PCI_PRI_FMT" on NUMA socket %i\n",
+				loc->domain, loc->bus, loc->devid,
+				loc->function, dev->numa_node);
+
+		RTE_LOG(DEBUG, EAL, "  remove driver: %x:%x %s\n",
+				dev->id.vendor_id, dev->id.device_id,
+				dr->name);
+
+		/* call the driver devshutdown() function */
+		if (dr->devshutdown && (dr->devshutdown(dr, dev) < 0))
+			return -1;	/* negative value is an error */
+
+		/* clear driver structure */
+		dev->driver = NULL;
+
+		if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
+			/* unmap resources for devices that use igb_uio */
+			pci_unmap_device(dev);
+
+		return 0;
+	}
+	/* return positive value if driver is not found */
+	return 1;
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /* Init the PCI EAL subsystem */
 int
 rte_eal_pci_init(void)
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 21/25] eal/pci: Fix pci_probe_all_drivers to share code with closing function
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (19 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 20/25] eal/pci: Add rte_eal_pci_close_one_driver Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 22/25] eal/pci: Add pci_close_all_drivers Tetsuya Mukawa
                     ` (9 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

pci_close_all_drivers() will be implemented after the patch.
To share a part of code between thses 2 functions, The patch fixes
pci_probe_all_drivers() first.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_pci.c | 28 ++++++++++++++++++++--------
 1 file changed, 20 insertions(+), 8 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index f01f258..1e3efea 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -99,19 +99,20 @@ static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
 	return NULL;
 }
 
-/*
- * If vendor/device ID match, call the devinit() function of all
- * registered driver for the given device. Return -1 if initialization
- * failed, return 1 if no driver is found for this device.
- */
+#define INVOKE_PROBE	(0)
+
 static int
-pci_probe_all_drivers(struct rte_pci_device *dev)
+pci_invoke_all_drivers(struct rte_pci_device *dev, int type)
 {
 	struct rte_pci_driver *dr = NULL;
-	int rc;
+	int rc = 0;
 
 	TAILQ_FOREACH(dr, &pci_driver_list, next) {
-		rc = rte_eal_pci_probe_one_driver(dr, dev);
+		switch (type) {
+		case INVOKE_PROBE:
+			rc = rte_eal_pci_probe_one_driver(dr, dev);
+			break;
+		}
 		if (rc < 0)
 			/* negative value is an error */
 			return -1;
@@ -124,6 +125,17 @@ pci_probe_all_drivers(struct rte_pci_device *dev)
 }
 
 /*
+ * If vendor/device ID match, call the devinit() 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_probe_all_drivers(struct rte_pci_device *dev)
+{
+	return pci_invoke_all_drivers(dev, INVOKE_PROBE);
+}
+
+/*
  * Scan the content of the PCI bus, and call the devinit() function for
  * all registered drivers that have a matching entry in its id_table
  * for discovered devices.
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 22/25] eal/pci: Add pci_close_all_drivers
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (20 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 21/25] eal/pci: Fix pci_probe_all_drivers to share code with closing function Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 23/25] eal/pci: Add rte_eal_pci_probe_one and rte_eal_pci_close_one Tetsuya Mukawa
                     ` (8 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The function tries to find a driver for the specified device, and then
close the driver.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_pci.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index 1e3efea..b404ee0 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -100,6 +100,7 @@ static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
 }
 
 #define INVOKE_PROBE	(0)
+#define INVOKE_CLOSE	(1)
 
 static int
 pci_invoke_all_drivers(struct rte_pci_device *dev, int type)
@@ -112,6 +113,11 @@ pci_invoke_all_drivers(struct rte_pci_device *dev, int type)
 		case INVOKE_PROBE:
 			rc = rte_eal_pci_probe_one_driver(dr, dev);
 			break;
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+		case INVOKE_CLOSE:
+			rc = rte_eal_pci_close_one_driver(dr, dev);
+			break;
+#endif
 		}
 		if (rc < 0)
 			/* negative value is an error */
@@ -135,6 +141,19 @@ pci_probe_all_drivers(struct rte_pci_device *dev)
 	return pci_invoke_all_drivers(dev, INVOKE_PROBE);
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+/*
+ * If vendor/device ID match, call the devclose() 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_close_all_drivers(struct rte_pci_device *dev)
+{
+	return pci_invoke_all_drivers(dev, INVOKE_CLOSE);
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /*
  * Scan the content of the PCI bus, and call the devinit() function for
  * all registered drivers that have a matching entry in its id_table
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 23/25] eal/pci: Add rte_eal_pci_probe_one and rte_eal_pci_close_one
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (21 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 22/25] eal/pci: Add pci_close_all_drivers Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 24/25] eal/pci: Add port hotplug functions for physical devices Tetsuya Mukawa
                     ` (7 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The functions are used for probe and close a device.
First the function tries to find a device that has the specfied PCI address.
Then, probe or close the device.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_pci.c  | 58 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_pci.h | 26 +++++++++++++++
 2 files changed, 84 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index b404ee0..5ff7b49 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -152,6 +152,64 @@ pci_close_all_drivers(struct rte_pci_device *dev)
 {
 	return pci_invoke_all_drivers(dev, INVOKE_CLOSE);
 }
+
+static int
+rte_eal_pci_invoke_one(struct rte_pci_addr *addr, int type)
+{
+	struct rte_pci_device *dev = NULL;
+	int ret = 0;
+
+	TAILQ_FOREACH(dev, &pci_device_list, next) {
+		if (eal_compare_pci_addr(&dev->addr, addr))
+			continue;
+
+		switch (type) {
+		case INVOKE_PROBE:
+			ret = pci_probe_all_drivers(dev);
+			break;
+		case INVOKE_CLOSE:
+			ret = pci_close_all_drivers(dev);
+			break;
+		}
+		if (ret < 0)
+			goto invoke_err_return;
+		if (type == INVOKE_CLOSE)
+			goto remove_dev;
+		return 0;
+	}
+
+	return -1;
+
+invoke_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);
+	return -1;
+
+remove_dev:
+	TAILQ_REMOVE(&pci_device_list, dev, next);
+	return 0;
+}
+
+/*
+ * Find the pci device specified by pci address, then invoke probe function of
+ * the driver of the devive.
+ */
+int
+rte_eal_pci_probe_one(struct rte_pci_addr *addr)
+{
+	return rte_eal_pci_invoke_one(addr, INVOKE_PROBE);
+}
+
+/*
+ * Find the pci device specified by pci address, then invoke close function of
+ * the driver of the devive.
+ */
+int
+rte_eal_pci_close_one(struct rte_pci_addr *addr)
+{
+	return rte_eal_pci_invoke_one(addr, INVOKE_CLOSE);
+}
 #endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
 
 /*
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 74720d1..33300be 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -311,6 +311,32 @@ eal_compare_pci_addr(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
 int rte_eal_pci_probe(void);
 
 /**
+ * Probe the single PCI device.
+ *
+ * Scan the content of the PCI bus, and find the pci device specified by pci
+ * addrrss, then call the probe() function for registered driver that has a
+ * matching entry in its id_table for discovered device.
+ *
+ * @return
+ *   - 0 on success.
+ *   - Negative on error.
+ */
+int rte_eal_pci_probe_one(struct rte_pci_addr *addr);
+
+/**
+ * Close the single PCI device.
+ *
+ * Scan the content of the PCI bus, and find the pci device specified by pci
+ * addrrss, then call the close() function for registered driver that has a
+ * matching entry in its id_table for discovered device.
+ *
+ * @return
+ *   - 0 on success.
+ *   - Negative on error.
+ */
+int rte_eal_pci_close_one(struct rte_pci_addr *addr);
+
+/**
  * Dump the content of the PCI bus.
  *
  * @param f
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 24/25] eal/pci: Add port hotplug functions for physical devices.
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (22 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 23/25] eal/pci: Add rte_eal_pci_probe_one and rte_eal_pci_close_one Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 25/25] eal: Enable port hotplug framework in Linux Tetsuya Mukawa
                     ` (6 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch adds rte_eal_dev_attach_pdev() and rte_eal_dev_detach_pdev().

rte_eal_dev_attach_pdev() receives a PCI address of the device and
returns an attached port number.
rte_eal_dev_detach_pdev() receives a port number, and returns a PCI
address actually detached.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_dev.c  | 58 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h | 25 ++++++++++++++
 2 files changed, 83 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 0518e3c..c2d5cd6 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -181,6 +181,64 @@ rte_eal_dev_close_one(const char *name)
 	return rte_eal_dev_find_and_invoke(name, INVOKE_CLOSE);
 }
 
+/* attach the new physical device, then store port_id of the device */
+int
+rte_eal_dev_attach_pdev(struct rte_pci_addr *addr, uint8_t *port_id)
+{
+	uint8_t new_port_id;
+	struct rte_eth_dev devs[RTE_MAX_ETHPORTS];
+
+	/* save current port status */
+	rte_eth_dev_save(devs);
+	/* re-construct pci_device_list */
+	if (rte_eal_pci_scan())
+		goto err;
+	/* invoke probe func of the driver can handle the new device */
+	if (rte_eal_pci_probe_one(addr))
+		goto err;
+	/* get port_id enabled by above procedures */
+	if (rte_eth_dev_get_changed_port(devs, &new_port_id))
+		goto err;
+
+	*port_id = new_port_id;
+	return 0;
+err:
+	RTE_LOG(ERR, EAL, "Drver, cannot attach the device\n");
+	return -1;
+}
+
+/* detach the new physical device, then store pci_addr of the device */
+int
+rte_eal_dev_detach_pdev(uint8_t port_id, struct rte_pci_addr *addr)
+{
+	struct rte_pci_addr freed_addr;
+	struct rte_pci_addr vp;
+
+	/* check whether the driver supports detach feature, or not */
+	if (!rte_eth_dev_check_detachable(port_id))
+		goto err;
+
+	/* get pci address by port id */
+	if (rte_eth_dev_get_addr_by_port(port_id, &freed_addr))
+		goto err;
+
+	/* Zerod pci addr means the port comes from virtual device */
+	vp.domain = vp.bus = vp.devid = vp.function = 0;
+	if (eal_compare_pci_addr(&vp, &freed_addr) == 0)
+		goto err;
+
+	/* invoke close func of the driver,
+	 * also remove the device from pci_device_list */
+	if (rte_eal_pci_close_one(&freed_addr))
+		goto err;
+
+	*addr = freed_addr;
+	return 0;
+err:
+	RTE_LOG(ERR, EAL, "Drver, cannot detach the device\n");
+	return -1;
+}
+
 static void
 get_vdev_name(char *vdevargs)
 {
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 159d5a5..26d7526 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -101,6 +101,19 @@ void rte_eal_driver_unregister(struct rte_driver *driver);
 #if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
 
 /**
+ * Attach a new physical device.
+ *
+ * @param addr
+ *   A pointer to a pci address structure describing the new
+ *   device to be attached.
+ * @param port_id
+ *  A pointer to a port identifier actually attached.
+ * @return
+ *  0 on success and port_id is filled, negative on error
+ */
+int rte_eal_dev_attach_pdev(struct rte_pci_addr *addr, uint8_t *port_id);
+
+/**
  * Attach a new virtual device.
  *
  * @param vdevargs
@@ -114,6 +127,18 @@ void rte_eal_driver_unregister(struct rte_driver *driver);
 int rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id);
 
 /**
+ * Detach a physical device.
+ *
+ * @param port_id
+ *   The port identifier of the physical device to detach.
+ * @param addr
+ *  A pointer to a pci address structure actually detached.
+ * @return
+ *  0 on success and addr is filled, negative on error
+ */
+int rte_eal_dev_detach_pdev(uint8_t port_id, struct rte_pci_addr *addr);
+
+/**
  * Detach a virtual device.
  *
  * @param port_id
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH 25/25] eal: Enable port hotplug framework in Linux
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (23 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 24/25] eal/pci: Add port hotplug functions for physical devices Tetsuya Mukawa
@ 2014-11-20  9:06   ` Tetsuya Mukawa
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                     ` (5 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:06 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch enables CONFIG_RTE_LIBRTE_EAL_HOTPLUG in Linux configuration.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 config/common_linuxapp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/config/common_linuxapp b/config/common_linuxapp
index 57b61c9..a2b1e36 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -144,6 +144,11 @@ CONFIG_RTE_LIBRTE_EAL_LINUXAPP=y
 CONFIG_RTE_LIBRTE_EAL_BAREMETAL=n
 
 #
+# Compile Environment Abstraction Layer to support hotplug
+#
+CONFIG_RTE_LIBRTE_EAL_HOTPLUG=y
+
+#
 # Compile Environment Abstraction Layer to support Vmware TSC map
 #
 CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=y
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH] librte_pmd_pcap: Add port hotplug support
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (26 preceding siblings ...)
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
@ 2014-11-20  9:22 ` Tetsuya Mukawa
  2014-11-20  9:22 ` [dpdk-dev] [PATCH] testpmd: " Tetsuya Mukawa
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:22 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

This patch adds finalization code to free resources allocated by the
PMD.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_pmd_pcap/rte_eth_pcap.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/lib/librte_pmd_pcap/rte_eth_pcap.c b/lib/librte_pmd_pcap/rte_eth_pcap.c
index f12d1e7..df8498f 100644
--- a/lib/librte_pmd_pcap/rte_eth_pcap.c
+++ b/lib/librte_pmd_pcap/rte_eth_pcap.c
@@ -499,6 +499,13 @@ static struct eth_dev_ops ops = {
 		.stats_reset = eth_stats_reset,
 };
 
+static struct eth_driver rte_pcap_pmd = {
+	.pci_drv = {
+		.name = "rte_pcap_pmd",
+		.drv_flags = RTE_PCI_DRV_DETACHABLE,
+	},
+};
+
 /*
  * Function handler that opens the pcap file for reading a stores a
  * reference of it for use it later on.
@@ -739,10 +746,13 @@ rte_pmd_init_internals(const char *name, const unsigned nb_rx_queues,
 	data->nb_tx_queues = (uint16_t)nb_tx_queues;
 	data->dev_link = pmd_link;
 	data->mac_addrs = &eth_addr;
+	strncpy(data->name,
+		(*eth_dev)->data->name, strlen((*eth_dev)->data->name));
 
 	(*eth_dev)->data = data;
 	(*eth_dev)->dev_ops = &ops;
 	(*eth_dev)->pci_dev = pci_dev;
+	(*eth_dev)->driver = &rte_pcap_pmd;
 
 	return 0;
 
@@ -927,10 +937,33 @@ rte_pmd_pcap_devinit(const char *name, const char *params)
 
 }
 
+static int
+rte_pmd_pcap_devclose(const char *name, const char *params __rte_unused)
+{
+	struct rte_eth_dev *eth_dev = NULL;
+
+	RTE_LOG(INFO, PMD, "Closing pcap ethdev on numa socket %u\n",
+			rte_socket_id());
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocated(name);
+	if (eth_dev == NULL)
+		return -1;
+
+	rte_free(eth_dev->data->dev_private);
+	rte_free(eth_dev->data);
+	rte_free(eth_dev->pci_dev);
+
+	rte_eth_dev_free(name);
+
+	return 0;
+}
+
 static struct rte_driver pmd_pcap_drv = {
 	.name = "eth_pcap",
 	.type = PMD_VDEV,
 	.init = rte_pmd_pcap_devinit,
+	.close = rte_pmd_pcap_devclose,
 };
 
 PMD_REGISTER_DRIVER(pmd_pcap_drv);
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH] testpmd: Add port hotplug support
  2014-10-29  8:49 [dpdk-dev] [RFC PATCH 00/25] Port Hotplug Framework Tetsuya Mukawa
                   ` (27 preceding siblings ...)
  2014-11-20  9:22 ` [dpdk-dev] [PATCH] librte_pmd_pcap: " Tetsuya Mukawa
@ 2014-11-20  9:22 ` Tetsuya Mukawa
  28 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-11-20  9:22 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch introduces following commands.
- port [attach|detach] [p|v] [ident]
 - attach: attaching a port
 - detach: detaching a port
 - p: physical port
 - v: virtual port
 - ident: pci address of physical device.
          Or device name and paramerters of virtual device.
         (ex. 0000:02:00.0, eth_pcap0,iface=eth0)

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 app/test-pmd/cmdline.c    | 139 +++++++++++++++++++++++-----
 app/test-pmd/config.c     |  54 +++++++----
 app/test-pmd/parameters.c |  21 +++--
 app/test-pmd/testpmd.c    | 226 ++++++++++++++++++++++++++++++++++++----------
 app/test-pmd/testpmd.h    |  17 ++++
 5 files changed, 366 insertions(+), 91 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 4c3fc76..980bd34 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -550,6 +550,12 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"port close (port_id|all)\n"
 			"    Close all ports or port_id.\n\n"
 
+			"port add (p|a) (ident)\n"
+			"    Add physical or virtual dev by pci address or virtual device name\n\n"
+
+			"port del (p|a) (port_id)\n"
+			"    Del physical or virtual dev by port_id\n\n"
+
 			"port config (port_id|all)"
 			" speed (10|100|1000|10000|40000|auto)"
 			" duplex (half|full|auto)\n"
@@ -796,6 +802,101 @@ cmdline_parse_inst_t cmd_operate_specific_port = {
 	},
 };
 
+/* *** attach a specificied port *** */
+struct cmd_operate_attach_port_result {
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t keyword;
+	cmdline_fixed_string_t type;
+	cmdline_fixed_string_t identifier;
+};
+
+static void cmd_operate_attach_port_parsed(void *parsed_result,
+				__attribute__((unused)) struct cmdline *cl,
+				__attribute__((unused)) void *data)
+{
+	struct cmd_operate_attach_port_result *res = parsed_result;
+
+	if (!strcmp(res->keyword, "attach"))
+		attach_port(res->type, res->identifier);
+	else
+		printf("Unknown parameter\n");
+}
+
+cmdline_parse_token_string_t cmd_operate_attach_port_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_operate_attach_port_keyword =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,
+			keyword, "attach");
+cmdline_parse_token_string_t cmd_operate_attach_port_type =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,
+			type, "p#v");
+
+cmdline_parse_token_string_t cmd_operate_attach_port_identifier =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,
+			identifier, NULL);
+
+cmdline_parse_inst_t cmd_operate_attach_port = {
+	.f = cmd_operate_attach_port_parsed,
+	.data = NULL,
+	.help_str = "port attach p|v ident p: physical, v: virtual, "
+		"ident: pci address or virtual dev name",
+	.tokens = {
+		(void *)&cmd_operate_attach_port_port,
+		(void *)&cmd_operate_attach_port_keyword,
+		(void *)&cmd_operate_attach_port_type,
+		(void *)&cmd_operate_attach_port_identifier,
+		NULL,
+	},
+};
+
+/* *** detach a specificied port *** */
+struct cmd_operate_detach_port_result {
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t keyword;
+	cmdline_fixed_string_t type;
+	uint8_t port_id;
+};
+
+static void cmd_operate_detach_port_parsed(void *parsed_result,
+				__attribute__((unused)) struct cmdline *cl,
+				__attribute__((unused)) void *data)
+{
+	struct cmd_operate_detach_port_result *res = parsed_result;
+
+	if (!strcmp(res->keyword, "detach"))
+		detach_port(res->type, res->port_id);
+	else
+		printf("Unknown parameter\n");
+}
+
+cmdline_parse_token_string_t cmd_operate_detach_port_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_port_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_operate_detach_port_keyword =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_port_result,
+			keyword, "detach");
+cmdline_parse_token_string_t cmd_operate_detach_port_type =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_port_result,
+			type, "p#v");
+
+cmdline_parse_token_num_t cmd_operate_detach_port_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_operate_detach_port_result,
+			port_id, UINT8);
+
+cmdline_parse_inst_t cmd_operate_detach_port = {
+	.f = cmd_operate_detach_port_parsed,
+	.data = NULL,
+	.help_str = "port detach p|v port_id p: physical, v: virtual",
+	.tokens = {
+		(void *)&cmd_operate_detach_port_port,
+		(void *)&cmd_operate_detach_port_keyword,
+		(void *)&cmd_operate_detach_port_type,
+		(void *)&cmd_operate_detach_port_port_id,
+		NULL,
+	},
+};
+
 /* *** configure speed for all ports *** */
 struct cmd_config_speed_all {
 	cmdline_fixed_string_t port;
@@ -850,7 +951,7 @@ cmd_config_speed_all_parsed(void *parsed_result,
 		return;
 	}
 
-	for (pid = 0; pid < nb_ports; pid++) {
+	FOREACH_PORT(pid, ports) {
 		ports[pid].dev_conf.link_speed = link_speed;
 		ports[pid].dev_conf.link_duplex = link_duplex;
 	}
@@ -918,10 +1019,8 @@ cmd_config_speed_specific_parsed(void *parsed_result,
 		return;
 	}
 
-	if (res->id >= nb_ports) {
-		printf("Port id %d must be less than %d\n", res->id, nb_ports);
+	if (port_id_is_invalid(res->id))
 		return;
-	}
 
 	if (!strcmp(res->value1, "10"))
 		link_speed = ETH_LINK_SPEED_10;
@@ -3694,10 +3793,8 @@ static void cmd_set_bond_mac_addr_parsed(void *parsed_result,
 	struct cmd_set_bond_mac_addr_result *res = parsed_result;
 	int ret;
 
-	if (res->port_num >= nb_ports) {
-		printf("Port id %d must be less than %d\n", res->port_num, nb_ports);
+	if (port_id_is_invalid(res->port_num))
 		return;
-	}
 
 	ret = rte_eth_bond_mac_address_set(res->port_num, &res->address);
 
@@ -3875,7 +3972,7 @@ static void cmd_set_promisc_mode_parsed(void *parsed_result,
 
 	/* all ports */
 	if (allports) {
-		for (i = 0; i < nb_ports; i++) {
+		FOREACH_PORT(i, ports) {
 			if (enable)
 				rte_eth_promiscuous_enable(i);
 			else
@@ -3955,7 +4052,7 @@ static void cmd_set_allmulti_mode_parsed(void *parsed_result,
 
 	/* all ports */
 	if (allports) {
-		for (i = 0; i < nb_ports; i++) {
+		FOREACH_PORT(i, ports) {
 			if (enable)
 				rte_eth_allmulticast_enable(i);
 			else
@@ -5140,25 +5237,25 @@ static void cmd_showportall_parsed(void *parsed_result,
 	struct cmd_showportall_result *res = parsed_result;
 	if (!strcmp(res->show, "clear")) {
 		if (!strcmp(res->what, "stats"))
-			for (i = 0; i < nb_ports; i++)
+			FOREACH_PORT(i, ports)
 				nic_stats_clear(i);
 		else if (!strcmp(res->what, "xstats"))
-			for (i = 0; i < nb_ports; i++)
+			FOREACH_PORT(i, ports)
 				nic_xstats_clear(i);
 	} else if (!strcmp(res->what, "info"))
-		for (i = 0; i < nb_ports; i++)
+		FOREACH_PORT(i, ports)
 			port_infos_display(i);
 	else if (!strcmp(res->what, "stats"))
-		for (i = 0; i < nb_ports; i++)
+		FOREACH_PORT(i, ports)
 			nic_stats_display(i);
 	else if (!strcmp(res->what, "xstats"))
-		for (i = 0; i < nb_ports; i++)
+		FOREACH_PORT(i, ports)
 			nic_xstats_display(i);
 	else if (!strcmp(res->what, "fdir"))
-		for (i = 0; i < nb_ports; i++)
+		FOREACH_PORT(i, ports)
 			fdir_get_infos(i);
 	else if (!strcmp(res->what, "stat_qmap"))
-		for (i = 0; i < nb_ports; i++)
+		FOREACH_PORT(i, ports)
 			nic_stats_mapping_display(i);
 }
 
@@ -7827,6 +7924,8 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_set_qmap,
 	(cmdline_parse_inst_t *)&cmd_operate_port,
 	(cmdline_parse_inst_t *)&cmd_operate_specific_port,
+	(cmdline_parse_inst_t *)&cmd_operate_attach_port,
+	(cmdline_parse_inst_t *)&cmd_operate_detach_port,
 	(cmdline_parse_inst_t *)&cmd_config_speed_all,
 	(cmdline_parse_inst_t *)&cmd_config_speed_specific,
 	(cmdline_parse_inst_t *)&cmd_config_rx_tx,
@@ -7897,7 +7996,7 @@ prompt(void)
 static void
 cmd_reconfig_device_queue(portid_t id, uint8_t dev, uint8_t queue)
 {
-	if (id < nb_ports) {
+	if (!_port_id_is_invalid(id)) {
 		/* check if need_reconfig has been set to 1 */
 		if (ports[id].need_reconfig == 0)
 			ports[id].need_reconfig = dev;
@@ -7907,7 +8006,7 @@ cmd_reconfig_device_queue(portid_t id, uint8_t dev, uint8_t queue)
 	} else {
 		portid_t pid;
 
-		for (pid = 0; pid < nb_ports; pid++) {
+		FOREACH_PORT(pid, ports) {
 			/* check if need_reconfig has been set to 1 */
 			if (ports[pid].need_reconfig == 0)
 				ports[pid].need_reconfig = dev;
@@ -7925,10 +8024,8 @@ bypass_is_supported(portid_t port_id)
 	struct rte_port   *port;
 	struct rte_pci_id *pci_id;
 
-	if (port_id >= nb_ports) {
-		printf("\tPort id must be less than %d.\n", nb_ports);
+	if (port_id_is_invalid(port_id))
 		return 0;
-	}
 
 	/* Get the device id. */
 	port    = &ports[port_id];
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index b102b72..8f83916 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -110,11 +110,15 @@ nic_stats_display(portid_t port_id)
 	struct rte_eth_stats stats;
 	struct rte_port *port = &ports[port_id];
 	uint8_t i;
+	portid_t pid;
 
 	static const char *nic_stats_border = "########################";
 
-	if (port_id >= nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+	if (port_id_is_invalid(port_id)) {
+		printf("Valid port range is [0");
+		FOREACH_PORT(pid, ports)
+			printf(", %d", pid);
+		printf("]\n");
 		return;
 	}
 	rte_eth_stats_get(port_id, &stats);
@@ -187,8 +191,13 @@ nic_stats_display(portid_t port_id)
 void
 nic_stats_clear(portid_t port_id)
 {
-	if (port_id >= nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+	portid_t pid;
+
+	if (port_id_is_invalid(port_id)) {
+		printf("Valid port range is [0");
+		FOREACH_PORT(pid, ports)
+			printf(", %d", pid);
+		printf("]\n");
 		return;
 	}
 	rte_eth_stats_reset(port_id);
@@ -235,11 +244,15 @@ nic_stats_mapping_display(portid_t port_id)
 {
 	struct rte_port *port = &ports[port_id];
 	uint16_t i;
+	portid_t pid;
 
 	static const char *nic_stats_mapping_border = "########################";
 
-	if (port_id >= nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+	if (port_id_is_invalid(port_id)) {
+		printf("Valid port range is [0");
+		FOREACH_PORT(pid, ports)
+			printf(", %d", pid);
+		printf("]\n");
 		return;
 	}
 
@@ -287,9 +300,13 @@ port_infos_display(portid_t port_id)
 	int vlan_offload;
 	struct rte_mempool * mp;
 	static const char *info_border = "*********************";
+	portid_t pid;
 
-	if (port_id >= nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+	if (port_id_is_invalid(port_id)) {
+		printf("Valid port range is [0");
+		FOREACH_PORT(pid, ports)
+			printf(", %d", pid);
+		printf("]\n");
 		return;
 	}
 	port = &ports[port_id];
@@ -342,14 +359,23 @@ port_infos_display(portid_t port_id)
 }
 
 int
-port_id_is_invalid(portid_t port_id)
+_port_id_is_invalid(portid_t port_id)
 {
-	if (port_id < nb_ports)
+	if (ports[port_id].enabled)
 		return 0;
-	printf("Invalid port %d (must be < nb_ports=%d)\n", port_id, nb_ports);
 	return 1;
 }
 
+int
+port_id_is_invalid(portid_t port_id)
+{
+	if (_port_id_is_invalid(port_id)) {
+		printf("Invalid port %d\n", port_id);
+		return 1;
+	}
+	return 0;
+}
+
 static int
 vlan_id_is_invalid(uint16_t vlan_id)
 {
@@ -1382,12 +1408,8 @@ set_fwd_ports_list(unsigned int *portlist, unsigned int nb_pt)
  again:
 	for (i = 0; i < nb_pt; i++) {
 		port_id = (portid_t) portlist[i];
-		if (port_id >= nb_ports) {
-			printf("Invalid port id %u >= %u\n",
-			       (unsigned int) port_id,
-			       (unsigned int) nb_ports);
+		if (port_id_is_invalid(port_id))
 			return;
-		}
 		if (record_now)
 			fwd_ports_ids[i] = port_id;
 	}
diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
index 9573a43..06d0eeb 100644
--- a/app/test-pmd/parameters.c
+++ b/app/test-pmd/parameters.c
@@ -375,6 +375,7 @@ parse_portnuma_config(const char *q_arg)
 	};
 	unsigned long int_fld[_NUM_FLD];
 	char *str_fld[_NUM_FLD];
+	portid_t pid;
 
 	/* reset from value set at definition */
 	while ((p = strchr(p0,'(')) != NULL) {
@@ -396,8 +397,11 @@ parse_portnuma_config(const char *q_arg)
 				return -1;
 		}
 		port_id = (uint8_t)int_fld[FLD_PORT];
-		if (port_id >= nb_ports) {
-			printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+		if (port_id_is_invalid(port_id)) {
+			printf("Valid port range is [0");
+			FOREACH_PORT(pid, ports)
+				printf(", %d", pid);
+			printf("]\n");
 			return -1;
 		}
 		socket_id = (uint8_t)int_fld[FLD_SOCKET];
@@ -428,6 +432,7 @@ parse_ringnuma_config(const char *q_arg)
 	};
 	unsigned long int_fld[_NUM_FLD];
 	char *str_fld[_NUM_FLD];
+	portid_t pid;
 	#define RX_RING_ONLY 0x1
 	#define TX_RING_ONLY 0x2
 	#define RXTX_RING    0x3
@@ -452,8 +457,11 @@ parse_ringnuma_config(const char *q_arg)
 				return -1;
 		}
 		port_id = (uint8_t)int_fld[FLD_PORT];
-		if (port_id >= nb_ports) {
-			printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+		if (port_id_is_invalid(port_id)) {
+			printf("Valid port range is [0");
+			FOREACH_PORT(pid, ports)
+				printf(", %d", pid);
+			printf("]\n");
 			return -1;
 		}
 		socket_id = (uint8_t)int_fld[FLD_SOCKET];
@@ -670,12 +678,11 @@ launch_args_parse(int argc, char** argv)
 #endif
 			if (!strcmp(lgopts[opt_idx].name, "nb-ports")) {
 				n = atoi(optarg);
-				if (n > 0 && n <= nb_ports)
+				if (n > 0 && !_port_id_is_invalid(n))
 					nb_fwd_ports = (uint8_t) n;
 				else
 					rte_exit(EXIT_FAILURE,
-						 "nb-ports should be > 0 and <= %d\n",
-						 nb_ports);
+						 "Invalid port %d\n", n);
 			}
 			if (!strcmp(lgopts[opt_idx].name, "nb-cores")) {
 				n = atoi(optarg);
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 12adafa..b245936 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -71,6 +71,7 @@
 #include <rte_pci.h>
 #include <rte_ether.h>
 #include <rte_ethdev.h>
+#include <rte_dev.h>
 #include <rte_string_fns.h>
 #ifdef RTE_LIBRTE_PMD_XENVIRT
 #include <rte_eth_xenvirt.h>
@@ -315,7 +316,7 @@ uint16_t nb_rx_queue_stats_mappings = 0;
 
 /* Forward function declarations */
 static void map_port_queue_stats_mapping_registers(uint8_t pi, struct rte_port *port);
-static void check_all_ports_link_status(uint8_t port_num, uint32_t port_mask);
+static void check_all_ports_link_status(uint32_t port_mask);
 
 /*
  * Check if all the ports are started.
@@ -552,7 +553,8 @@ init_config(void)
 				+ RTE_TEST_TX_DESC_MAX + MAX_PKT_BURST;
 
 		if (!numa_support)
-			nb_mbuf_per_pool = (nb_mbuf_per_pool * nb_ports);
+			nb_mbuf_per_pool =
+				(nb_mbuf_per_pool * RTE_MAX_ETHPORTS);
 	}
 
 	if (!numa_support) {
@@ -565,14 +567,19 @@ init_config(void)
 
 	/* Configuration of Ethernet ports. */
 	ports = rte_zmalloc("testpmd: ports",
-			    sizeof(struct rte_port) * nb_ports,
+			    sizeof(struct rte_port) * RTE_MAX_ETHPORTS,
 			    CACHE_LINE_SIZE);
 	if (ports == NULL) {
-		rte_exit(EXIT_FAILURE, "rte_zmalloc(%d struct rte_port) "
-							"failed\n", nb_ports);
+		rte_exit(EXIT_FAILURE,
+				"rte_zmalloc(%d struct rte_port) failed\n",
+				RTE_MAX_ETHPORTS);
 	}
 
-	for (pid = 0; pid < nb_ports; pid++) {
+	/* enabled allocated ports */
+	for (pid = 0; pid < nb_ports; pid++)
+		ports[pid].enabled = 1;
+
+	FOREACH_PORT(pid, ports) {
 		port = &ports[pid];
 		rte_eth_dev_info_get(pid, &port->dev_info);
 
@@ -602,8 +609,7 @@ init_config(void)
 			nb_mbuf_per_pool = nb_mbuf_per_pool/nb_ports;
 
 		for (i = 0; i < MAX_SOCKET; i++) {
-			nb_mbuf = (nb_mbuf_per_pool *
-						port_per_socket[i]);
+			nb_mbuf = (nb_mbuf_per_pool * RTE_MAX_ETHPORTS);
 			if (nb_mbuf)
 				mbuf_pool_create(mbuf_data_size,
 						nb_mbuf,i);
@@ -635,14 +641,6 @@ reconfig(portid_t new_port_id)
 	struct rte_port *port;
 
 	/* Reconfiguration of Ethernet ports. */
-	ports = rte_realloc(ports,
-			    sizeof(struct rte_port) * nb_ports,
-			    CACHE_LINE_SIZE);
-	if (ports == NULL) {
-		rte_exit(EXIT_FAILURE, "rte_realloc(%d struct rte_port) failed\n",
-				nb_ports);
-	}
-
 	port = &ports[new_port_id];
 	rte_eth_dev_info_get(new_port_id, &port->dev_info);
 
@@ -662,7 +660,7 @@ init_fwd_streams(void)
 	streamid_t sm_id, nb_fwd_streams_new;
 
 	/* set socket id according to numa or not */
-	for (pid = 0; pid < nb_ports; pid++) {
+	FOREACH_PORT(pid, ports) {
 		port = &ports[pid];
 		if (nb_rxq > port->dev_info.max_rx_queues) {
 			printf("Fail: nb_rxq(%d) is greater than "
@@ -1263,7 +1261,7 @@ all_ports_started(void)
 	portid_t pi;
 	struct rte_port *port;
 
-	for (pi = 0; pi < nb_ports; pi++) {
+	FOREACH_PORT(pi, ports) {
 		port = &ports[pi];
 		/* Check if there is a port which is not started */
 		if (port->port_status != RTE_PORT_STARTED)
@@ -1275,6 +1273,45 @@ all_ports_started(void)
 }
 
 int
+all_ports_stopped(void)
+{
+	portid_t pi;
+	struct rte_port *port;
+
+	FOREACH_PORT(pi, ports) {
+		port = &ports[pi];
+		if (port->port_status != RTE_PORT_STOPPED)
+			return 0;
+	}
+
+	return 1;
+}
+
+int
+port_is_started(portid_t port_id)
+{
+	if (port_id_is_invalid(port_id))
+		return 0;
+
+	if (ports[port_id].port_status != RTE_PORT_STARTED)
+		return 0;
+
+	return 1;
+}
+
+static int
+port_is_closed(portid_t port_id)
+{
+	if (port_id_is_invalid(port_id))
+		return 0;
+
+	if (ports[port_id].port_status != RTE_PORT_CLOSED)
+		return 0;
+
+	return 1;
+}
+
+int
 start_port(portid_t pid)
 {
 	int diag, need_check_link_status = 0;
@@ -1295,8 +1332,8 @@ start_port(portid_t pid)
 
 	if(dcb_config)
 		dcb_test = 1;
-	for (pi = 0; pi < nb_ports; pi++) {
-		if (pid < nb_ports && pid != pi)
+	FOREACH_PORT(pi, ports) {
+		if (!_port_id_is_invalid(pid) && pid != pi)
 			continue;
 
 		port = &ports[pi];
@@ -1420,7 +1457,7 @@ start_port(portid_t pid)
 	}
 
 	if (need_check_link_status && !no_link_check)
-		check_all_ports_link_status(nb_ports, RTE_PORT_ALL);
+		check_all_ports_link_status(RTE_PORT_ALL);
 	else
 		printf("Please stop the ports first\n");
 
@@ -1445,8 +1482,8 @@ stop_port(portid_t pid)
 	}
 	printf("Stopping ports...\n");
 
-	for (pi = 0; pi < nb_ports; pi++) {
-		if (pid < nb_ports && pid != pi)
+	FOREACH_PORT(pi, ports) {
+		if (!_port_id_is_invalid(pid) && pid != pi)
 			continue;
 
 		port = &ports[pi];
@@ -1462,7 +1499,7 @@ stop_port(portid_t pid)
 		need_check_link_status = 1;
 	}
 	if (need_check_link_status && !no_link_check)
-		check_all_ports_link_status(nb_ports, RTE_PORT_ALL);
+		check_all_ports_link_status(RTE_PORT_ALL);
 
 	printf("Done\n");
 }
@@ -1480,8 +1517,8 @@ close_port(portid_t pid)
 
 	printf("Closing ports...\n");
 
-	for (pi = 0; pi < nb_ports; pi++) {
-		if (pid < nb_ports && pid != pi)
+	FOREACH_PORT(pi, ports) {
+		if (!_port_id_is_invalid(pid) && pid != pi)
 			continue;
 
 		port = &ports[pi];
@@ -1501,31 +1538,126 @@ close_port(portid_t pid)
 	printf("Done\n");
 }
 
-int
-all_ports_stopped(void)
+
+static inline int
+attach_physical_device_port(char *identifier, uint8_t *pi)
 {
-	portid_t pi;
-	struct rte_port *port;
+	struct rte_pci_addr addr;
 
-	for (pi = 0; pi < nb_ports; pi++) {
-		port = &ports[pi];
-		if (port->port_status != RTE_PORT_STOPPED)
-			return 0;
+	if (eal_parse_pci_DomBDF(identifier, &addr) != 0) {
+		printf("invalid PCI identifier <%s>\n", identifier);
+		return -1;
 	}
+	return rte_eal_dev_attach_pdev(&addr, pi);
+}
 
-	return 1;
+static inline int
+attach_virtual_device_port(char *identifier, uint8_t *pi)
+{
+	return rte_eal_dev_attach_vdev(identifier, pi);
 }
 
-int
-port_is_started(portid_t port_id)
+static inline int
+detach_physical_device_port(uint8_t pi, char *identifier)
 {
-	if (port_id_is_invalid(port_id))
+	struct rte_pci_addr addr;
+
+	if (rte_eal_dev_detach_pdev(pi, &addr))
 		return -1;
 
-	if (ports[port_id].port_status != RTE_PORT_STARTED)
-		return 0;
+	snprintf(identifier, RTE_ETH_NAME_MAX_LEN, "%04x.%02x.%02x.%d",
+			addr.domain, addr.bus, addr.devid, addr.function);
+	return 0;
+}
 
-	return 1;
+static inline int
+detach_virtual_device_port(uint8_t pi, char *identifier)
+{
+	return rte_eal_dev_detach_vdev(pi, identifier);
+}
+
+void
+attach_port(char *type, char *identifier)
+{
+	portid_t i, j, pi = 0;
+
+	printf("Attaching a new port...\n");
+
+	if (test_done == 0) {
+		printf("Please stop forwarding first\n");
+		return;
+	}
+
+	if (strncmp(type, "p", 1) == 0) {
+		if (attach_physical_device_port(identifier, &pi))
+			return;
+	} else if (strncmp(type, "v", 1) == 0) {
+		if (attach_virtual_device_port(identifier, &pi))
+			return;
+	}
+
+	ports[pi].enabled = 1;
+	reconfig(pi);
+	rte_eth_promiscuous_enable(pi);
+
+	nb_ports = rte_eth_dev_count();
+
+	/* set_default_fwd_ports_config(); */
+	bzero(fwd_ports_ids, sizeof(fwd_ports_ids));
+	i = 0;
+	FOREACH_PORT(j, ports) {
+		fwd_ports_ids[i] = j;
+		i++;
+	}
+	nb_cfg_ports = nb_ports;
+	nb_fwd_ports++;
+
+	ports[pi].port_status = RTE_PORT_STOPPED;
+
+	printf("Port %d is attached. Now total ports is %d\n", pi, nb_ports);
+	printf("Done\n");
+}
+
+void
+detach_port(char *type, uint8_t port_id)
+{
+	portid_t i, pi = 0;
+	char name[RTE_ETH_NAME_MAX_LEN];
+
+	printf("Detaching a port...\n");
+
+	if (!port_is_closed(port_id)) {
+		printf("Please close port first\n");
+		return;
+	}
+
+	rte_eth_promiscuous_disable(port_id);
+
+	if (strncmp(type, "p", 1) == 0) {
+		if (detach_physical_device_port(port_id, name))
+			return;
+	} else if (strncmp(type, "v", 1) == 0) {
+		if (detach_virtual_device_port(port_id, name))
+			return;
+	}
+
+	ports[port_id].enabled = 0;
+	nb_ports = rte_eth_dev_count();
+
+	/* set_default_fwd_ports_config(); */
+	bzero(fwd_ports_ids, sizeof(fwd_ports_ids));
+	i = 0;
+	FOREACH_PORT(pi, ports) {
+		fwd_ports_ids[i] = pi;
+		i++;
+	}
+	nb_cfg_ports = nb_ports;
+	nb_fwd_ports--;
+
+	printf("Port '%s' is detached. Now total ports is %d\n",
+			name, nb_ports);
+	printf("Done\n");
+	return;
 }
 
 void
@@ -1533,7 +1665,7 @@ pmd_test_exit(void)
 {
 	portid_t pt_id;
 
-	for (pt_id = 0; pt_id < nb_ports; pt_id++) {
+	FOREACH_PORT(pt_id, ports) {
 		printf("Stopping port %d...", pt_id);
 		fflush(stdout);
 		rte_eth_dev_close(pt_id);
@@ -1552,7 +1684,7 @@ struct pmd_test_command {
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -1563,7 +1695,7 @@ check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
 	fflush(stdout);
 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		FOREACH_PORT(portid, ports) {
 			if ((port_mask & (1 << portid)) == 0)
 				continue;
 			memset(&link, 0, sizeof(link));
@@ -1687,7 +1819,7 @@ init_port_config(void)
 	portid_t pid;
 	struct rte_port *port;
 
-	for (pid = 0; pid < nb_ports; pid++) {
+	FOREACH_PORT(pid, ports) {
 		port = &ports[pid];
 		port->dev_conf.rxmode = rx_mode;
 		port->dev_conf.fdir_conf = fdir_conf;
@@ -1870,7 +2002,7 @@ main(int argc, char** argv)
 
 	nb_ports = (portid_t) rte_eth_dev_count();
 	if (nb_ports == 0)
-		rte_exit(EXIT_FAILURE, "No probed ethernet device\n");
+		RTE_LOG(WARNING, EAL, "No probed ethernet devices\n");
 
 	set_def_fwd_config();
 	if (nb_lcores == 0)
@@ -1892,7 +2024,7 @@ main(int argc, char** argv)
 		rte_exit(EXIT_FAILURE, "Start ports failed\n");
 
 	/* set all ports to promiscuous mode by default */
-	for (port_id = 0; port_id < nb_ports; port_id++)
+	FOREACH_PORT(port_id, ports)
 		rte_eth_promiscuous_enable(port_id);
 
 #ifdef RTE_LIBRTE_CMDLINE
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 9cbfeac..b79bd1f 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -133,6 +133,7 @@ struct fwd_stream {
  *   Bit 11: Insert VLAN Label
  */
 struct rte_port {
+	uint8_t                 enabled;    /**< Port enabled or not */
 	struct rte_eth_dev_info dev_info;   /**< PCI info + driver name */
 	struct rte_eth_conf     dev_conf;   /**< Port configuration. */
 	struct ether_addr       eth_addr;   /**< Port ethernet address */
@@ -157,6 +158,19 @@ struct rte_port {
 	struct rte_eth_txconf   tx_conf;    /**< tx configuration */
 };
 
+static portid_t __rte_unused
+find_next_port(portid_t p, struct rte_port *ports, int size)
+{
+	while ((ports[p].enabled == 0) && (p < size))
+		p++;
+	return p;
+}
+
+#define FOREACH_PORT(p, ports) \
+	for (p = find_next_port(0, ports, RTE_MAX_ETHPORTS); \
+	    p < RTE_MAX_ETHPORTS; \
+	    p = find_next_port(p + 1, ports, RTE_MAX_ETHPORTS))
+
 /**
  * The data structure associated with each forwarding logical core.
  * The logical cores are internally numbered by a core index from 0 to
@@ -512,6 +526,8 @@ int init_port_dcb_config(portid_t pid,struct dcb_config *dcb_conf);
 int start_port(portid_t pid);
 void stop_port(portid_t pid);
 void close_port(portid_t pid);
+void attach_port(char *type, char *identifier);
+void detach_port(char *type, uint8_t port_id);
 int all_ports_stopped(void);
 int port_is_started(portid_t port_id);
 void pmd_test_exit(void);
@@ -550,6 +566,7 @@ void get_ethertype_filter(uint8_t port_id, uint16_t index);
 void get_2tuple_filter(uint8_t port_id, uint16_t index);
 void get_5tuple_filter(uint8_t port_id, uint16_t index);
 void get_flex_filter(uint8_t port_id, uint16_t index);
+int _port_id_is_invalid(portid_t port_id);
 int port_id_is_invalid(portid_t port_id);
 int rx_queue_id_is_invalid(queueid_t rxq_id);
 int tx_queue_id_is_invalid(queueid_t txq_id);
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (24 preceding siblings ...)
  2014-11-20  9:06   ` [dpdk-dev] [PATCH 25/25] eal: Enable port hotplug framework in Linux Tetsuya Mukawa
@ 2014-12-09  3:42   ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 01/28] eal/pci: Add a new flag indicating a driver can detach devices at runtime Tetsuya Mukawa
                       ` (27 more replies)
  2014-12-09  3:44   ` [dpdk-dev] [PATCH v2] librte_pmd_pcap: Add port hotplug support Tetsuya Mukawa
                     ` (4 subsequent siblings)
  30 siblings, 28 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

This patch series adds a dynamic port hotplug framework to DPDK.
With the patches, DPDK apps can attach or detach ports at runtime.

The basic concept of the port hotplug is like followings.
- DPDK apps must have responsibility to manage ports.
  DPDK apps only know which ports are attached or detached at the moment.
  The port hotplug framework is implemented to allow DPDK apps to manage ports.
  For example, when DPDK apps call port attach function, attached port number
  will be returned. Also DPDK apps can detach port by port number.
- Kernel support is needed for attaching or detaching physical device ports.
  To attach new device, the device will be recognized by kernel at first and
  controlled by kernel driver. Then user can bind the device to igb_uio
  by 'dpdk_nic_bind.py'. Finally, DPDK apps can call the port hotplug
  functions to attach ports.
  For detaching, steps are vice versa.
- Before detach ports, ports must be stopped and closed.
  DPDK application must call rte_eth_dev_stop() and rte_eth_dev_close() before
  detaching ports. These function will call finalization codes of PMDs.
  But so far, no PMD frees all resources allocated by initialization.
  It means PMDs are needed to be fixed to support the port hotplug.
  'RTE_PCI_DRV_DETACHABLE' is a new flag indicating a PMD supports detaching.
  Without this flag, detaching will be failed.
- Mustn't affect legacy DPDK apps.
  No DPDK EAL behavior is changed, if the port hotplug functions are't called.
  So all legacy DPDK apps can still work without modifications.

And few limitations.
- The port hotplug functions are not thread safe.
  DPDK apps should handle it.
- Only support Linux and igb_uio so far.
  BSD and VFIO is not supported. I will send VFIO patches at least, but I don't
  have a plan to submit BSD patch so far.


Here is port hotplug APIs.
-------------------------------------------------------------------------------
/**
 * Attach a new device.
 *
 * @param devargs
 *   A pointer to a strings array describing the new device
 *   to be attached. The strings should be a pci address like
 *   '0000:01:00.0' or virtual device name like 'eth_pcap0'.
 * @param port_id
 *  A pointer to a port identifier actually attached.
 * @return
 *  0 on success and port_id is filled, negative on error
 */
int rte_eal_dev_attach(const char *devargs, uint8_t *port_id);

/**
 * Detach a device.
 *
 * @param port_id
 *   The port identifier of the device to detach.
 * @param addr
 *  A pointer to a device name actually detached.
 * @return
 *  0 on success and devname is filled, negative on error
 */
int rte_eal_dev_detach(uint8_t port_id, char *devname);
-------------------------------------------------------------------------------

This patch series are for DPDK EAL. To use port hotplug function by DPDK apps,
each PMD should be fixed to support 'RTE_PCI_DRV_DETACHABLE' flag. Please check
a patch for pcap PMD.

Also please check testpmd patch. It will show you how to fix your legacy
applications to support port hotplug feature.


PATCH v2 chages:
 - Replace rte_eal_dev_attach_pdev(), rte_eal_dev_detach_pdev,
   rte_eal_dev_attach_vdev() and rte_eal_dev_detach_vdev() to
   rte_eal_dev_attach() and rte_eal_dev_detach().
 - Add parameter values checking.
 - Refashion a few functions.
   (Thanks to Iremonger, Bernard)

PATCH v1 Chages:
 - Fix error checking code of librte_eth APIs.
 - Fix issue that port from pcap PMD cannot be detached correctly.
 - Fix issue that testpmd could hang after forwarding, if attaching and detaching
   is repeatedly.
 - Fix if-condition of rte_eth_dev_get_port_by_addr().
   (Thanks to Mark Enright)

RFC PATCH v2 Changes:
- remove 'rte_eth_dev_validate_port()', and cleanup codes.


Tetsuya Mukawa (28):
  eal/pci: Add a new flag indicating a driver can detach devices at
    runtime.
  ethdev: Remove assumption that port will not be detached
  eal/pci: Replace pci address comparison code by eal_compare_pci_addr
  ethdev: Add rte_eth_dev_free to free specified device
  eal,ethdev: Add function pointer for closing a device
  ethdev: Add rte_eth_dev_shutdown for closing PCI devices.
  ethdev: Add functions to know which port is attached or detached
  ethdev: Add rte_eth_dev_get_addr_by_port
  ethdev: Add rte_eth_dev_get_port_by_addr
  ethdev: Add rte_eth_dev_get_name_by_port
  ethdev: Add rte_eth_dev_check_detachable
  ethdev: Change scope of rte_eth_dev_allocated to global
  eal/pci: Prevent double registration for devargs_list
  eal/pci: Add rte_eal_devargs_remove
  eal/pci: Add probe and close function for virtual drivers
  eal/pci: Add port hotplug functions for virtual devices.
  eal/linux/pci: Add functions for unmapping igb_uio resources
  eal/pci: Prevent double registrations for pci_device_list
  eal/pci: Change scope of rte_eal_pci_scan to global
  eal/pci: Add rte_eal_pci_close_one_driver
  eal/pci: Fix pci_probe_all_drivers to share code with closing function
  eal/pci: Add pci_close_all_drivers
  eal/pci: Add rte_eal_pci_probe_one and rte_eal_pci_close_one
  eal/pci: Add port hotplug functions for physical devices.
  eal/pci: Remove pci_probe/close_all_drivers()
  eal/pci: Add rte_eal_dev_attach/detach() functions
  eal/pci: Remove rte_eal_dev_attach/detach_pdev() and
    rte_eal_dev_attach/detach_vdev()
  eal: Enable port hotplug framework in Linux

 app/test/virtual_pmd.c                       |   2 +-
 config/common_linuxapp                       |   5 +
 lib/librte_eal/bsdapp/eal/eal_pci.c          |  16 +-
 lib/librte_eal/common/eal_common_dev.c       | 250 ++++++++++++++++
 lib/librte_eal/common/eal_common_devargs.c   |  51 ++++
 lib/librte_eal/common/eal_common_pci.c       |  89 +++++-
 lib/librte_eal/common/eal_private.h          |  26 ++
 lib/librte_eal/common/include/rte_dev.h      |  36 +++
 lib/librte_eal/common/include/rte_devargs.h  |  18 ++
 lib/librte_eal/common/include/rte_pci.h      |  64 +++++
 lib/librte_eal/linuxapp/eal/Makefile         |   1 +
 lib/librte_eal/linuxapp/eal/eal_pci.c        | 125 ++++++--
 lib/librte_eal/linuxapp/eal/eal_pci_init.h   |   7 +
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c    |  67 ++++-
 lib/librte_ether/rte_ethdev.c                | 409 ++++++++++++++++++++-------
 lib/librte_ether/rte_ethdev.h                | 144 +++++++++-
 lib/librte_pmd_af_packet/rte_eth_af_packet.c |   2 +-
 lib/librte_pmd_bond/rte_eth_bond_api.c       |   2 +-
 lib/librte_pmd_pcap/rte_eth_pcap.c           |   2 +-
 lib/librte_pmd_ring/rte_eth_ring.c           |   2 +-
 lib/librte_pmd_xenvirt/rte_eth_xenvirt.c     |   2 +-
 21 files changed, 1159 insertions(+), 161 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 01/28] eal/pci: Add a new flag indicating a driver can detach devices at runtime.
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 02/28] ethdev: Remove assumption that port will not be detached Tetsuya Mukawa
                       ` (26 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

This patch adds "RTE_PCI_DRV_DETACHABLE" to drv_flags of rte_pci_driver
structure. The flags indicates the driver can detach devices at runtime.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/include/rte_pci.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 66ed793..b819539 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -199,6 +199,8 @@ 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 capablity */
+#define RTE_PCI_DRV_DETACHABLE	0x0010
 
 /**< Internal use only - Macro used by pci addr parsing functions **/
 #define GET_PCIADDR_FIELD(in, fd, lim, dlm)                   \
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 02/28] ethdev: Remove assumption that port will not be detached
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 01/28] eal/pci: Add a new flag indicating a driver can detach devices at runtime Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  5:07       ` Zhang, Helin
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 03/28] eal/pci: Replace pci address comparison code by eal_compare_pci_addr Tetsuya Mukawa
                       ` (25 subsequent siblings)
  27 siblings, 1 reply; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

To remove assumption, do like followings.

- Add 'attached' member to rte_eth_dev structure.
  This member is used for indicating the port is attached, or not.
- Add rte_eth_dev_allocate_new_port().
  This function is used for allocating new port.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 248 ++++++++++++++++++++++++------------------
 lib/librte_ether/rte_ethdev.h |   5 +
 2 files changed, 149 insertions(+), 104 deletions(-)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 95f2ceb..9f713ae 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -175,6 +175,16 @@ enum {
 	STAT_QMAP_RX
 };
 
+enum {
+	DEV_VALID = 0,
+	DEV_INVALID
+};
+
+enum {
+	DEV_DISCONNECTED = 0,
+	DEV_CONNECTED
+};
+
 static inline void
 rte_eth_dev_data_alloc(void)
 {
@@ -201,19 +211,34 @@ rte_eth_dev_allocated(const char *name)
 {
 	unsigned i;
 
-	for (i = 0; i < nb_ports; i++) {
-		if (strcmp(rte_eth_devices[i].data->name, name) == 0)
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if ((rte_eth_devices[i].attached == DEV_CONNECTED)
+				&& strcmp(rte_eth_devices[i].data->name,
+					name) == 0)
 			return &rte_eth_devices[i];
 	}
 	return NULL;
 }
 
+static uint8_t
+rte_eth_dev_allocate_new_port(void)
+{
+	unsigned i;
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
+		if (rte_eth_devices[i].attached == DEV_DISCONNECTED)
+			return i;
+	return RTE_MAX_ETHPORTS;
+}
+
 struct rte_eth_dev *
 rte_eth_dev_allocate(const char *name)
 {
+	uint8_t port_id;
 	struct rte_eth_dev *eth_dev;
 
-	if (nb_ports == RTE_MAX_ETHPORTS) {
+	port_id = rte_eth_dev_allocate_new_port();
+	if (port_id == RTE_MAX_ETHPORTS) {
 		PMD_DEBUG_TRACE("Reached maximum number of Ethernet ports\n");
 		return NULL;
 	}
@@ -226,10 +251,12 @@ rte_eth_dev_allocate(const char *name)
 		return NULL;
 	}
 
-	eth_dev = &rte_eth_devices[nb_ports];
-	eth_dev->data = &rte_eth_dev_data[nb_ports];
+	eth_dev = &rte_eth_devices[port_id];
+	eth_dev->data = &rte_eth_dev_data[port_id];
 	snprintf(eth_dev->data->name, sizeof(eth_dev->data->name), "%s", name);
-	eth_dev->data->port_id = nb_ports++;
+	eth_dev->data->port_id = port_id;
+	eth_dev->attached = DEV_CONNECTED;
+	nb_ports++;
 	return eth_dev;
 }
 
@@ -283,6 +310,7 @@ rte_eth_dev_init(struct rte_pci_driver *pci_drv,
 			(unsigned) pci_dev->id.device_id);
 	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
 		rte_free(eth_dev->data->dev_private);
+	eth_dev->attached = DEV_DISCONNECTED;
 	nb_ports--;
 	return diag;
 }
@@ -308,10 +336,22 @@ rte_eth_driver_register(struct eth_driver *eth_drv)
 	rte_eal_pci_register(&eth_drv->pci_drv);
 }
 
+static int
+rte_eth_dev_validate_port(uint8_t port_id)
+{
+	if (port_id >= RTE_MAX_ETHPORTS)
+		return DEV_INVALID;
+
+	if (rte_eth_devices[port_id].attached == DEV_CONNECTED)
+		return DEV_VALID;
+	else
+		return DEV_INVALID;
+}
+
 int
 rte_eth_dev_socket_id(uint8_t port_id)
 {
-	if (port_id >= nb_ports)
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID)
 		return -1;
 	return rte_eth_devices[port_id].pci_dev->numa_node;
 }
@@ -369,7 +409,7 @@ rte_eth_dev_rx_queue_start(uint8_t port_id, uint16_t rx_queue_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -395,7 +435,7 @@ rte_eth_dev_rx_queue_stop(uint8_t port_id, uint16_t rx_queue_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -421,7 +461,7 @@ rte_eth_dev_tx_queue_start(uint8_t port_id, uint16_t tx_queue_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -447,7 +487,7 @@ rte_eth_dev_tx_queue_stop(uint8_t port_id, uint16_t tx_queue_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -662,7 +702,7 @@ rte_eth_dev_configure(uint8_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports || port_id >= RTE_MAX_ETHPORTS) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -847,7 +887,7 @@ rte_eth_dev_start(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%" PRIu8 "\n", port_id);
 		return (-EINVAL);
 	}
@@ -882,7 +922,7 @@ rte_eth_dev_stop(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_RET();
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%" PRIu8 "\n", port_id);
 		return;
 	}
@@ -910,7 +950,7 @@ rte_eth_dev_set_link_up(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -929,7 +969,7 @@ rte_eth_dev_set_link_down(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -948,7 +988,7 @@ rte_eth_dev_close(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_RET();
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -976,7 +1016,7 @@ rte_eth_rx_queue_setup(uint8_t port_id, uint16_t rx_queue_id,
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -1049,7 +1089,7 @@ rte_eth_tx_queue_setup(uint8_t port_id, uint16_t tx_queue_id,
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= RTE_MAX_ETHPORTS || port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -1082,7 +1122,7 @@ rte_eth_promiscuous_enable(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1098,7 +1138,7 @@ rte_eth_promiscuous_disable(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1114,7 +1154,7 @@ rte_eth_promiscuous_get(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -1;
 	}
@@ -1128,7 +1168,7 @@ rte_eth_allmulticast_enable(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1144,7 +1184,7 @@ rte_eth_allmulticast_disable(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1160,7 +1200,7 @@ rte_eth_allmulticast_get(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -1;
 	}
@@ -1188,7 +1228,7 @@ rte_eth_link_get(uint8_t port_id, struct rte_eth_link *eth_link)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1208,7 +1248,7 @@ rte_eth_link_get_nowait(uint8_t port_id, struct rte_eth_link *eth_link)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1228,7 +1268,7 @@ rte_eth_stats_get(uint8_t port_id, struct rte_eth_stats *stats)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1245,7 +1285,7 @@ rte_eth_stats_reset(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1266,7 +1306,7 @@ rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstats *xstats,
 	uint64_t val;
 	char *stats_ptr;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -1;
 	}
@@ -1335,7 +1375,7 @@ rte_eth_xstats_reset(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1357,7 +1397,7 @@ set_queue_stats_mapping(uint8_t port_id, uint16_t queue_id, uint8_t stat_idx,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -1392,7 +1432,7 @@ rte_eth_dev_info_get(uint8_t port_id, struct rte_eth_dev_info *dev_info)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1412,7 +1452,7 @@ rte_eth_macaddr_get(uint8_t port_id, struct ether_addr *mac_addr)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1426,7 +1466,7 @@ rte_eth_dev_get_mtu(uint8_t port_id, uint16_t *mtu)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1442,7 +1482,7 @@ rte_eth_dev_set_mtu(uint8_t port_id, uint16_t mtu)
 	int ret;
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1462,7 +1502,7 @@ rte_eth_dev_vlan_filter(uint8_t port_id, uint16_t vlan_id, int on)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1487,7 +1527,7 @@ rte_eth_dev_set_vlan_strip_on_queue(uint8_t port_id, uint16_t rx_queue_id, int o
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1509,7 +1549,7 @@ rte_eth_dev_set_vlan_ether_type(uint8_t port_id, uint16_t tpid)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1529,7 +1569,7 @@ rte_eth_dev_set_vlan_offload(uint8_t port_id, int offload_mask)
 	int mask = 0;
 	int cur, org = 0;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1574,7 +1614,7 @@ rte_eth_dev_get_vlan_offload(uint8_t port_id)
 	struct rte_eth_dev *dev;
 	int ret = 0;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1598,7 +1638,7 @@ rte_eth_dev_set_vlan_pvid(uint8_t port_id, uint16_t pvid, int on)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1616,7 +1656,7 @@ rte_eth_dev_fdir_add_signature_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1650,7 +1690,7 @@ rte_eth_dev_fdir_update_signature_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1684,7 +1724,7 @@ rte_eth_dev_fdir_remove_signature_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1715,7 +1755,7 @@ rte_eth_dev_fdir_get_infos(uint8_t port_id, struct rte_eth_fdir *fdir)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1740,7 +1780,7 @@ rte_eth_dev_fdir_add_perfect_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1780,7 +1820,7 @@ rte_eth_dev_fdir_update_perfect_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1818,7 +1858,7 @@ rte_eth_dev_fdir_remove_perfect_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1854,7 +1894,7 @@ rte_eth_dev_fdir_set_masks(uint8_t port_id, struct rte_fdir_masks *fdir_mask)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1874,7 +1914,7 @@ rte_eth_dev_flow_ctrl_get(uint8_t port_id, struct rte_eth_fc_conf *fc_conf)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1890,7 +1930,7 @@ rte_eth_dev_flow_ctrl_set(uint8_t port_id, struct rte_eth_fc_conf *fc_conf)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1910,7 +1950,7 @@ rte_eth_dev_priority_flow_ctrl_set(uint8_t port_id, struct rte_eth_pfc_conf *pfc
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2019,7 +2059,7 @@ rte_eth_dev_rss_reta_query(uint8_t port_id,
 	struct rte_eth_dev *dev;
 	int ret;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -2040,7 +2080,7 @@ rte_eth_dev_rss_hash_update(uint8_t port_id, struct rte_eth_rss_conf *rss_conf)
 	struct rte_eth_dev *dev;
 	uint16_t rss_hash_protos;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2062,7 +2102,7 @@ rte_eth_dev_rss_hash_conf_get(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2077,7 +2117,7 @@ rte_eth_dev_udp_tunnel_add(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -2103,7 +2143,7 @@ rte_eth_dev_udp_tunnel_delete(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -2128,7 +2168,7 @@ rte_eth_led_on(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2143,7 +2183,7 @@ rte_eth_led_off(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2183,7 +2223,7 @@ rte_eth_dev_mac_addr_add(uint8_t port_id, struct ether_addr *addr,
 	int index;
 	uint64_t pool_mask;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2234,7 +2274,7 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 	struct rte_eth_dev *dev;
 	int index;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2268,7 +2308,7 @@ rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 	struct rte_eth_dev *dev;
 	struct rte_eth_dev_info dev_info;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("set VF RX mode:Invalid port_id=%d\n",
 				port_id);
 		return (-ENODEV);
@@ -2323,7 +2363,7 @@ rte_eth_dev_uc_hash_table_set(uint8_t port_id, struct ether_addr *addr,
 	int ret;
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("unicast hash setting:Invalid port_id=%d\n",
 			port_id);
 		return (-ENODEV);
@@ -2376,7 +2416,7 @@ rte_eth_dev_uc_all_hash_table_set(uint8_t port_id, uint8_t on)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("unicast hash setting:Invalid port_id=%d\n",
 			port_id);
 		return (-ENODEV);
@@ -2395,7 +2435,7 @@ rte_eth_dev_set_vf_rx(uint8_t port_id,uint16_t vf, uint8_t on)
 	struct rte_eth_dev *dev;
 	struct rte_eth_dev_info dev_info;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2421,7 +2461,7 @@ rte_eth_dev_set_vf_tx(uint8_t port_id,uint16_t vf, uint8_t on)
 	struct rte_eth_dev *dev;
 	struct rte_eth_dev_info dev_info;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("set pool tx:Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2446,7 +2486,7 @@ rte_eth_dev_set_vf_vlan_filter(uint8_t port_id, uint16_t vlan_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("VF VLAN filter:invalid port id=%d\n",
 				port_id);
 		return (-ENODEV);
@@ -2477,7 +2517,7 @@ int rte_eth_set_queue_rate_limit(uint8_t port_id, uint16_t queue_idx,
 	struct rte_eth_dev_info dev_info;
 	struct rte_eth_link link;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("set queue rate limit:invalid port id=%d\n",
 				port_id);
 		return -ENODEV;
@@ -2514,7 +2554,7 @@ int rte_eth_set_vf_rate_limit(uint8_t port_id, uint16_t vf, uint16_t tx_rate,
 	if (q_msk == 0)
 		return 0;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("set VF rate limit:invalid port id=%d\n",
 				port_id);
 		return -ENODEV;
@@ -2548,7 +2588,7 @@ rte_eth_mirror_rule_set(uint8_t port_id,
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2589,7 +2629,7 @@ rte_eth_mirror_rule_reset(uint8_t port_id, uint8_t rule_id)
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2614,7 +2654,7 @@ rte_eth_rx_burst(uint8_t port_id, uint16_t queue_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return 0;
 	}
@@ -2634,7 +2674,7 @@ rte_eth_tx_burst(uint8_t port_id, uint16_t queue_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return 0;
 	}
@@ -2654,7 +2694,7 @@ rte_eth_rx_queue_count(uint8_t port_id, uint16_t queue_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return 0;
 	}
@@ -2668,7 +2708,7 @@ rte_eth_rx_descriptor_done(uint8_t port_id, uint16_t queue_id, uint16_t offset)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2689,7 +2729,7 @@ rte_eth_dev_callback_register(uint8_t port_id,
 
 	if (!cb_fn)
 		return (-EINVAL);
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -2729,7 +2769,7 @@ rte_eth_dev_callback_unregister(uint8_t port_id,
 
 	if (!cb_fn)
 		return (-EINVAL);
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -2789,7 +2829,7 @@ int rte_eth_dev_bypass_init(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2809,7 +2849,7 @@ rte_eth_dev_bypass_state_show(uint8_t port_id, uint32_t *state)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2828,7 +2868,7 @@ rte_eth_dev_bypass_state_set(uint8_t port_id, uint32_t *new_state)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2848,7 +2888,7 @@ rte_eth_dev_bypass_event_show(uint8_t port_id, uint32_t event, uint32_t *state)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2868,7 +2908,7 @@ rte_eth_dev_bypass_event_store(uint8_t port_id, uint32_t event, uint32_t state)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2888,7 +2928,7 @@ rte_eth_dev_wd_timeout_store(uint8_t port_id, uint32_t timeout)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2908,7 +2948,7 @@ rte_eth_dev_bypass_ver_show(uint8_t port_id, uint32_t *ver)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2928,7 +2968,7 @@ rte_eth_dev_bypass_wd_timeout_show(uint8_t port_id, uint32_t *wd_timeout)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2948,7 +2988,7 @@ rte_eth_dev_bypass_wd_reset(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2970,7 +3010,7 @@ rte_eth_dev_add_syn_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -2985,7 +3025,7 @@ rte_eth_dev_remove_syn_filter(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3004,7 +3044,7 @@ rte_eth_dev_get_syn_filter(uint8_t port_id,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3020,7 +3060,7 @@ rte_eth_dev_add_ethertype_filter(uint8_t port_id, uint16_t index,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3041,7 +3081,7 @@ rte_eth_dev_remove_ethertype_filter(uint8_t port_id,  uint16_t index)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3060,7 +3100,7 @@ rte_eth_dev_get_ethertype_filter(uint8_t port_id, uint16_t index,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3077,7 +3117,7 @@ rte_eth_dev_add_2tuple_filter(uint8_t port_id, uint16_t index,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3099,7 +3139,7 @@ rte_eth_dev_remove_2tuple_filter(uint8_t port_id, uint16_t index)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3118,7 +3158,7 @@ rte_eth_dev_get_2tuple_filter(uint8_t port_id, uint16_t index,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3134,7 +3174,7 @@ rte_eth_dev_add_5tuple_filter(uint8_t port_id, uint16_t index,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3157,7 +3197,7 @@ rte_eth_dev_remove_5tuple_filter(uint8_t port_id, uint16_t index)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3176,7 +3216,7 @@ rte_eth_dev_get_5tuple_filter(uint8_t port_id, uint16_t index,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3193,7 +3233,7 @@ rte_eth_dev_add_flex_filter(uint8_t port_id, uint16_t index,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3208,7 +3248,7 @@ rte_eth_dev_remove_flex_filter(uint8_t port_id, uint16_t index)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3227,7 +3267,7 @@ rte_eth_dev_get_flex_filter(uint8_t port_id, uint16_t index,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3243,7 +3283,7 @@ rte_eth_dev_filter_supported(uint8_t port_id, enum rte_filter_type filter_type)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3260,7 +3300,7 @@ rte_eth_dev_filter_ctrl(uint8_t port_id, enum rte_filter_type filter_type,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index f66805d..257de86 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1565,6 +1565,7 @@ struct rte_eth_dev {
 	struct eth_dev_ops *dev_ops;    /**< Functions exported by PMD */
 	struct rte_pci_device *pci_dev; /**< PCI info. supplied by probing */
 	struct rte_eth_dev_cb_list callbacks; /**< User application callbacks */
+	uint8_t attached; /**< Flag indicating the port is attached */
 };
 
 struct rte_eth_dev_sriov {
@@ -1630,6 +1631,10 @@ extern struct rte_eth_dev rte_eth_devices[];
  * initialized by the [matching] Ethernet driver during the PCI probing phase.
  * All devices whose port identifier is in the range
  * [0,  rte_eth_dev_count() - 1] can be operated on by network applications.
+ * immediately after invoking rte_eal_init().
+ * If the application unplugs a port using hotplug function, The enabled port
+ * numbers may be noncontiguous. In the case, the applications need to manage
+ * enabled port by themselves.
  *
  * @return
  *   - The total number of usable Ethernet devices.
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 03/28] eal/pci: Replace pci address comparison code by eal_compare_pci_addr
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 01/28] eal/pci: Add a new flag indicating a driver can detach devices at runtime Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 02/28] ethdev: Remove assumption that port will not be detached Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 04/28] ethdev: Add rte_eth_dev_free to free specified device Tetsuya Mukawa
                       ` (24 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

This patch replaces pci_addr_comparison() and memcmp() of pci addresses by
eal_compare_pci_addr().

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/bsdapp/eal/eal_pci.c       | 16 +---------------
 lib/librte_eal/common/eal_common_pci.c    |  2 +-
 lib/librte_eal/common/include/rte_pci.h   | 29 +++++++++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c     | 16 +---------------
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c |  2 +-
 5 files changed, 33 insertions(+), 32 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 74ecce7..7eda513 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -270,20 +270,6 @@ pci_uio_map_resource(struct rte_pci_device *dev)
 	return (0);
 }
 
-/* Compare two PCI device addresses. */
-static int
-pci_addr_comparison(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
-{
-	uint64_t dev_addr = (addr->domain << 24) + (addr->bus << 16) + (addr->devid << 8) + addr->function;
-	uint64_t dev_addr2 = (addr2->domain << 24) + (addr2->bus << 16) + (addr2->devid << 8) + addr2->function;
-
-	if (dev_addr > dev_addr2)
-		return 1;
-	else
-		return 0;
-}
-
-
 /* Scan one pci sysfs entry, and fill the devices list from it. */
 static int
 pci_scan_one(int dev_pci_fd, struct pci_conf *conf)
@@ -358,7 +344,7 @@ pci_scan_one(int dev_pci_fd, struct pci_conf *conf)
 		struct rte_pci_device *dev2 = NULL;
 
 		TAILQ_FOREACH(dev2, &pci_device_list, next) {
-			if (pci_addr_comparison(&dev->addr, &dev2->addr))
+			if (eal_compare_pci_addr(&dev->addr, &dev2->addr))
 				continue;
 			else {
 				TAILQ_INSERT_BEFORE(dev2, dev, next);
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index f3c7f71..f01f258 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -93,7 +93,7 @@ static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
 		if (devargs->type != RTE_DEVTYPE_BLACKLISTED_PCI &&
 			devargs->type != RTE_DEVTYPE_WHITELISTED_PCI)
 			continue;
-		if (!memcmp(&dev->addr, &devargs->pci.addr, sizeof(dev->addr)))
+		if (eal_compare_pci_addr(&dev->addr, &devargs->pci.addr))
 			return devargs;
 	}
 	return NULL;
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index b819539..fe374a8 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -261,6 +261,35 @@ eal_parse_pci_DomBDF(const char *input, struct rte_pci_addr *dev_addr)
 }
 #undef GET_PCIADDR_FIELD
 
+/* Compare two PCI device addresses. */
+/**
+ * Utility function to compare two PCI device addresses.
+ *
+ * @param addr
+ *	The PCI Bus-Device-Function address to compare
+ * @param addr2
+ *	The PCI Bus-Device-Function address to compare
+ * @return
+ *  0 on equal PCI address.
+ *  Positive on addr is greater than addr2.
+ *  Negative on addr is less than addr2.
+ */
+static inline int
+eal_compare_pci_addr(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
+{
+	uint64_t dev_addr = (addr->domain << 24) + (addr->bus << 16) +
+					(addr->devid << 8) + addr->function;
+	uint64_t dev_addr2 = (addr2->domain << 24) + (addr2->bus << 16) +
+					(addr2->devid << 8) + addr2->function;
+
+	if (dev_addr > dev_addr2)
+		return 1;
+	else if (dev_addr < dev_addr2)
+		return -1;
+	else
+		return 0;
+}
+
 /**
  * Probe the PCI bus for registered drivers.
  *
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index b5f5410..23a69e9 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -200,20 +200,6 @@ error:
 	return -1;
 }
 
-/* Compare two PCI device addresses. */
-static int
-pci_addr_comparison(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
-{
-	uint64_t dev_addr = (addr->domain << 24) + (addr->bus << 16) + (addr->devid << 8) + addr->function;
-	uint64_t dev_addr2 = (addr2->domain << 24) + (addr2->bus << 16) + (addr2->devid << 8) + addr2->function;
-
-	if (dev_addr > dev_addr2)
-		return 1;
-	else
-		return 0;
-}
-
-
 /* 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,
@@ -306,7 +292,7 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
 		struct rte_pci_device *dev2 = NULL;
 
 		TAILQ_FOREACH(dev2, &pci_device_list, next) {
-			if (pci_addr_comparison(&dev->addr, &dev2->addr))
+			if (eal_compare_pci_addr(&dev->addr, &dev2->addr) != 0)
 				continue;
 			else {
 				TAILQ_INSERT_BEFORE(dev2, dev, next);
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
index e53f06b..1da3507 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
@@ -123,7 +123,7 @@ pci_uio_map_secondary(struct rte_pci_device *dev)
 	TAILQ_FOREACH(uio_res, pci_res_list, next) {
 
 		/* skip this element if it doesn't match our PCI address */
-		if (memcmp(&uio_res->pci_addr, &dev->addr, sizeof(dev->addr)))
+		if (eal_compare_pci_addr(&uio_res->pci_addr, &dev->addr))
 			continue;
 
 		for (i = 0; i != uio_res->nb_maps; i++) {
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 04/28] ethdev: Add rte_eth_dev_free to free specified device
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (2 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 03/28] eal/pci: Replace pci address comparison code by eal_compare_pci_addr Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 05/28] eal, ethdev: Add function pointer for closing a device Tetsuya Mukawa
                       ` (23 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

This patch adds rte_eth_dev_free(). The function is used for changing a
attached status of the device that has specified name.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 17 +++++++++++++++++
 lib/librte_ether/rte_ethdev.h | 11 +++++++++++
 2 files changed, 28 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 9f713ae..d5fdb03 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -260,6 +260,23 @@ rte_eth_dev_allocate(const char *name)
 	return eth_dev;
 }
 
+struct rte_eth_dev *
+rte_eth_dev_free(const char *name)
+{
+	struct rte_eth_dev *eth_dev;
+
+	eth_dev = rte_eth_dev_allocated(name);
+	if (eth_dev == NULL) {
+		PMD_DEBUG_TRACE("Ethernet Device with name %s doesn't exist!\n",
+				name);
+		return NULL;
+	}
+
+	eth_dev->attached = 0;
+	nb_ports--;
+	return eth_dev;
+}
+
 static int
 rte_eth_dev_init(struct rte_pci_driver *pci_drv,
 		 struct rte_pci_device *pci_dev)
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 257de86..fb1caea 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1653,6 +1653,17 @@ extern uint8_t rte_eth_dev_count(void);
  */
 struct rte_eth_dev *rte_eth_dev_allocate(const char *name);
 
+/**
+ * Function for internal use by dummy drivers primarily, e.g. ring-based
+ * driver.
+ * Free the specified ethdev and returns the pointer to that slot.
+ *
+ * @param	name	Unique identifier name for each Ethernet device
+ * @return
+ *   - Slot in the rte_dev_devices array for the freed device;
+ */
+struct rte_eth_dev *rte_eth_dev_free(const char *name);
+
 struct eth_driver;
 /**
  * @internal
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 05/28] eal, ethdev: Add function pointer for closing a device
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (3 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 04/28] ethdev: Add rte_eth_dev_free to free specified device Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 06/28] ethdev: Add rte_eth_dev_shutdown for closing PCI devices Tetsuya Mukawa
                       ` (22 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch adds function pointer to rte_pci_driver and eth_driver
structure. These function pointers are used when ports are detached.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/include/rte_pci.h |  7 +++++++
 lib/librte_ether/rte_ethdev.h           | 24 ++++++++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index fe374a8..74720d1 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -181,12 +181,19 @@ struct rte_pci_driver;
 typedef int (pci_devinit_t)(struct rte_pci_driver *, struct rte_pci_device *);
 
 /**
+ * Shutdown function for the driver called during hotplugging.
+ */
+typedef int (pci_devshutdown_t)(
+		struct rte_pci_driver *, struct rte_pci_device *);
+
+/**
  * A structure describing a PCI driver.
  */
 struct rte_pci_driver {
 	TAILQ_ENTRY(rte_pci_driver) next;       /**< Next in list. */
 	const char *name;                       /**< Driver name. */
 	pci_devinit_t *devinit;                 /**< Device init. function. */
+	pci_devshutdown_t *devshutdown;         /**< Device shutdown function. */
 	struct rte_pci_id *id_table;            /**< ID table, NULL terminated. */
 	uint32_t drv_flags;                     /**< Flags contolling handling of device. */
 };
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index fb1caea..b329e11 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1702,6 +1702,27 @@ typedef int (*eth_dev_init_t)(struct eth_driver  *eth_drv,
 
 /**
  * @internal
+ * Finalization function of an Ethernet driver invoked for each matching
+ * Ethernet PCI device detected during the PCI closing phase.
+ *
+ * @param eth_drv
+ *   The pointer to the [matching] Ethernet driver structure supplied by
+ *   the PMD when it registered itself.
+ * @param eth_dev
+ *   The *eth_dev* pointer is the address of the *rte_eth_dev* structure
+ *   associated with the matching device and which have been [automatically]
+ *   allocated in the *rte_eth_devices* array.
+ * @return
+ *   - 0: Success, the device is properly finalized by the driver.
+ *        In particular, the driver MUST free the *dev_ops* pointer
+ *        of the *eth_dev* structure.
+ *   - <0: Error code of the device initialization failure.
+ */
+typedef int (*eth_dev_shutdown_t)(struct eth_driver  *eth_drv,
+				  struct rte_eth_dev *eth_dev);
+
+/**
+ * @internal
  * The structure associated with a PMD Ethernet driver.
  *
  * Each Ethernet driver acts as a PCI driver and is represented by a generic
@@ -1711,11 +1732,14 @@ typedef int (*eth_dev_init_t)(struct eth_driver  *eth_drv,
  *
  * - The *eth_dev_init* function invoked for each matching PCI device.
  *
+ * - The *eth_dev_shutdown* function invoked for each matching PCI device.
+ *
  * - The size of the private data to allocate for each matching device.
  */
 struct eth_driver {
 	struct rte_pci_driver pci_drv;    /**< The PMD is also a PCI driver. */
 	eth_dev_init_t eth_dev_init;      /**< Device init function. */
+	eth_dev_shutdown_t eth_dev_shutdown;/**< Device shutdown function. */
 	unsigned int dev_private_size;    /**< Size of device private data. */
 };
 
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 06/28] ethdev: Add rte_eth_dev_shutdown for closing PCI devices.
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (4 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 05/28] eal, ethdev: Add function pointer for closing a device Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 07/28] ethdev: Add functions to know which port is attached or detached Tetsuya Mukawa
                       ` (21 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

rte_eth_dev_shutdown() is called when PCI device is closed.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index d5fdb03..51697e1 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -332,6 +332,42 @@ rte_eth_dev_init(struct rte_pci_driver *pci_drv,
 	return diag;
 }
 
+static int
+rte_eth_dev_shutdown(struct rte_pci_driver *pci_drv,
+		 struct rte_pci_device *pci_dev)
+{
+	struct eth_driver *eth_drv;
+	struct rte_eth_dev *eth_dev;
+	char ethdev_name[RTE_ETH_NAME_MAX_LEN];
+
+	/* Create unique Ethernet device name using PCI address */
+	snprintf(ethdev_name, RTE_ETH_NAME_MAX_LEN, "%d:%d.%d",
+			pci_dev->addr.bus, pci_dev->addr.devid,
+			pci_dev->addr.function);
+
+	eth_dev = rte_eth_dev_free(ethdev_name);
+	if (eth_dev == NULL)
+		return -ENODEV;
+
+	eth_drv = (struct eth_driver *)pci_drv;
+
+	/* Invoke PMD device shutdown function */
+	if (*eth_drv->eth_dev_shutdown)
+		(*eth_drv->eth_dev_shutdown)(eth_drv, eth_dev);
+
+	/* init user callbacks */
+	TAILQ_INIT(&(eth_dev->callbacks));
+
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+		rte_free(eth_dev->data->dev_private);
+
+	eth_dev->pci_dev = NULL;
+	eth_dev->driver = NULL;
+	eth_dev->data = NULL;
+
+	return 0;
+}
+
 /**
  * Register an Ethernet [Poll Mode] driver.
  *
@@ -350,6 +386,7 @@ void
 rte_eth_driver_register(struct eth_driver *eth_drv)
 {
 	eth_drv->pci_drv.devinit = rte_eth_dev_init;
+	eth_drv->pci_drv.devshutdown = rte_eth_dev_shutdown;
 	rte_eal_pci_register(&eth_drv->pci_drv);
 }
 
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 07/28] ethdev: Add functions to know which port is attached or detached
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (5 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 06/28] ethdev: Add rte_eth_dev_shutdown for closing PCI devices Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 08/28] ethdev: Add rte_eth_dev_get_addr_by_port Tetsuya Mukawa
                       ` (20 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch adds rte_eth_dev_save() and rte_eth_dev_get_changed_port().
rte_eth_dev_save() is used for saving current rte_eth_dev structures.
rte_eth_dev_get_changed_port() receives the rte_eth_dev structures, then
compare these with current values to know which port is actually
attached or detached.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 21 +++++++++++++++++++++
 lib/librte_ether/rte_ethdev.h | 21 +++++++++++++++++++++
 2 files changed, 42 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 51697e1..6a3700e 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -416,6 +416,27 @@ rte_eth_dev_count(void)
 	return (nb_ports);
 }
 
+void
+rte_eth_dev_save(struct rte_eth_dev *devs)
+{
+	if (devs == NULL)
+		return;
+
+	/* save current rte_eth_devices */
+	memcpy(devs, rte_eth_devices,
+			sizeof(struct rte_eth_dev) * RTE_MAX_ETHPORTS);
+}
+
+int
+rte_eth_dev_get_changed_port(struct rte_eth_dev *devs, uint8_t *port_id)
+{
+	/* check which port was attached or detached */
+	for (*port_id = 0; *port_id < RTE_MAX_ETHPORTS; (*port_id)++, devs++)
+		if (rte_eth_devices[*port_id].attached ^ devs->attached)
+			return 0;
+	return 1;
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index b329e11..03c8850 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1642,6 +1642,27 @@ extern struct rte_eth_dev rte_eth_devices[];
 extern uint8_t rte_eth_dev_count(void);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Copies current ethdev structures to the specified pointer.
+ *
+ * @param	devs	The pointer to the ethdev structures
+ */
+extern void rte_eth_dev_save(struct rte_eth_dev *devs);
+
+/**
+ * Function for internal use by port hotplug functions.
+ * Compare the specified ethdev structures with currents. Then
+ * if there is a port which status is changed, fill the specified pointer
+ * with the port id of that port.
+ * @param	devs	The pointer to the ethdev structures
+ * @param	port_id	The pointer to the port id
+ * @return
+ *   - 0 on success, negative on error
+ */
+extern int rte_eth_dev_get_changed_port(
+		struct rte_eth_dev *devs, uint8_t *port_id);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 08/28] ethdev: Add rte_eth_dev_get_addr_by_port
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (6 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 07/28] ethdev: Add functions to know which port is attached or detached Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 09/28] ethdev: Add rte_eth_dev_get_port_by_addr Tetsuya Mukawa
                       ` (19 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The function returns a pci address of a ethdev specified by port
identifier.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 17 +++++++++++++++++
 lib/librte_ether/rte_ethdev.h | 13 +++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 6a3700e..ddaf14a 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -437,6 +437,23 @@ rte_eth_dev_get_changed_port(struct rte_eth_dev *devs, uint8_t *port_id)
 	return 1;
 }
 
+int
+rte_eth_dev_get_addr_by_port(uint8_t port_id, struct rte_pci_addr *addr)
+{
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -EINVAL;
+	}
+
+	if (addr == NULL) {
+		PMD_DEBUG_TRACE("Null pointer is specified\n");
+		return -EINVAL;
+	}
+
+	*addr = rte_eth_devices[port_id].pci_dev->addr;
+	return 0;
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 03c8850..30277a2 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1663,6 +1663,19 @@ extern int rte_eth_dev_get_changed_port(
 		struct rte_eth_dev *devs, uint8_t *port_id);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Returns a pci address of a ethdev specified by port identifier.
+ * @param	port_id
+ *   The port identifier of the Ethernet device
+ * @param	addr
+ *   The pointer to the pci address
+ * @return
+ *   - 0 on success, negative on error
+ */
+extern int rte_eth_dev_get_addr_by_port(
+		uint8_t port_id, struct rte_pci_addr *addr);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 09/28] ethdev: Add rte_eth_dev_get_port_by_addr
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (7 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 08/28] ethdev: Add rte_eth_dev_get_addr_by_port Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 10/28] ethdev: Add rte_eth_dev_get_name_by_port Tetsuya Mukawa
                       ` (18 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The function returns a port identifier of a ethdev specified by pci
address.

v3:
- Fix if-condition bug while comparing pci addresses.
- Add error checking codes.
Reported-by: Mark Enright <menrigh@brocade.com>

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 22 ++++++++++++++++++++++
 lib/librte_ether/rte_ethdev.h | 13 +++++++++++++
 2 files changed, 35 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index ddaf14a..4e9f0f7 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -454,6 +454,28 @@ rte_eth_dev_get_addr_by_port(uint8_t port_id, struct rte_pci_addr *addr)
 	return 0;
 }
 
+int
+rte_eth_dev_get_port_by_addr(struct rte_pci_addr *addr, uint8_t *port_id)
+{
+	struct rte_pci_addr *tmp;
+
+	if ((addr == NULL) || (port_id == NULL)) {
+		PMD_DEBUG_TRACE("Null pointer is specified\n");
+		return -1;
+	}
+
+	for (*port_id = 0; *port_id < RTE_MAX_ETHPORTS; (*port_id)++) {
+		if (!rte_eth_devices[*port_id].attached)
+			continue;
+		if (!rte_eth_devices[*port_id].pci_dev)
+			continue;
+		tmp = &rte_eth_devices[*port_id].pci_dev->addr;
+		if (eal_compare_pci_addr(tmp, addr) == 0)
+			return 0;
+	}
+	return -1;
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 30277a2..8c55c56 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1676,6 +1676,19 @@ extern int rte_eth_dev_get_addr_by_port(
 		uint8_t port_id, struct rte_pci_addr *addr);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Returns a port identifier of a ethdev specified by pci address.
+ * @param	addr
+ *   The pointer to the pci address of the Ethernet device.
+ * @param	port_id
+ *   The pointer to the port identifier
+ * @return
+ *   - 0 on success, negative on error
+ */
+extern int rte_eth_dev_get_port_by_addr(
+		struct rte_pci_addr *addr, uint8_t *port_id);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 10/28] ethdev: Add rte_eth_dev_get_name_by_port
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (8 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 09/28] ethdev: Add rte_eth_dev_get_port_by_addr Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 11/28] ethdev: Add rte_eth_dev_check_detachable Tetsuya Mukawa
                       ` (17 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The function returns a unique identifier name of a ethdev specified by
port identifier.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 22 ++++++++++++++++++++++
 lib/librte_ether/rte_ethdev.h | 12 ++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 4e9f0f7..1d82f69 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -476,6 +476,28 @@ rte_eth_dev_get_port_by_addr(struct rte_pci_addr *addr, uint8_t *port_id)
 	return -1;
 }
 
+int
+rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
+{
+	char *tmp;
+
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -EINVAL;
+	}
+
+	if (name == NULL) {
+		PMD_DEBUG_TRACE("Null pointer is specified\n");
+		return -EINVAL;
+	}
+
+	/* shouldn't check 'rte_eth_devices[i].data',
+	 * because it might be overwritten by VDEV PMD */
+	tmp = rte_eth_dev_data[port_id].name;
+	strncpy(name, tmp, strlen(tmp) + 1);
+	return 0;
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 8c55c56..bd921d0 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1689,6 +1689,18 @@ extern int rte_eth_dev_get_port_by_addr(
 		struct rte_pci_addr *addr, uint8_t *port_id);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Returns a unique identifier name of a ethdev specified by port identifier.
+ * @param	port_id
+ *   The port identifier.
+ * @param	name
+ *  The pointer to the Unique identifier name for each Ethernet device
+ * @return
+ *   - 0 on success, negative on error
+ */
+extern int rte_eth_dev_get_name_by_port(uint8_t port_id, char *name);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 11/28] ethdev: Add rte_eth_dev_check_detachable
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (9 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 10/28] ethdev: Add rte_eth_dev_get_name_by_port Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 12/28] ethdev: Change scope of rte_eth_dev_allocated to global Tetsuya Mukawa
                       ` (16 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The function returns whether a PMD supports detach function, or not.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c |  9 +++++++++
 lib/librte_ether/rte_ethdev.h | 11 +++++++++++
 2 files changed, 20 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 1d82f69..ed53e66 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -498,6 +498,15 @@ rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
 	return 0;
 }
 
+int
+rte_eth_dev_check_detachable(uint8_t port_id)
+{
+	uint32_t drv_flags;
+
+	drv_flags = rte_eth_devices[port_id].driver->pci_drv.drv_flags;
+	return !(drv_flags & RTE_PCI_DRV_DETACHABLE);
+}
+
 static int
 rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index bd921d0..404c41f 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1701,6 +1701,17 @@ extern int rte_eth_dev_get_port_by_addr(
 extern int rte_eth_dev_get_name_by_port(uint8_t port_id, char *name);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Check whether or not, a PMD that is handling the ethdev specified by port
+ * identifier can support detach function.
+ * @param	port_id
+ *   The port identifier
+ * @return
+ *   - 0 on supporting detach function, negative on not supporting
+ */
+extern int rte_eth_dev_check_detachable(uint8_t port_id);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 12/28] ethdev: Change scope of rte_eth_dev_allocated to global
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (10 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 11/28] ethdev: Add rte_eth_dev_check_detachable Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 13/28] eal/pci: Prevent double registration for devargs_list Tetsuya Mukawa
                       ` (15 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

This function is used by virtual PMDs to support port hotplug framework.
So change scope of the function to global.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c |  2 +-
 lib/librte_ether/rte_ethdev.h | 10 ++++++++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index ed53e66..86200e0 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -206,7 +206,7 @@ rte_eth_dev_data_alloc(void)
 				RTE_MAX_ETHPORTS * sizeof(*rte_eth_dev_data));
 }
 
-static struct rte_eth_dev *
+struct rte_eth_dev *
 rte_eth_dev_allocated(const char *name)
 {
 	unsigned i;
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 404c41f..47622a2 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1712,6 +1712,16 @@ extern int rte_eth_dev_get_name_by_port(uint8_t port_id, char *name);
 extern int rte_eth_dev_check_detachable(uint8_t port_id);
 
 /**
+ * Function for internal use by port hotplug functions.
+ * Returns a ethdev slot specified by the unique identifier name.
+ * @param	name
+ *  The pointer to the Unique identifier name for each Ethernet device
+ * @return
+ *   - The pointer to the ethdev slot, on success. NULL on error
+ */
+extern struct rte_eth_dev *rte_eth_dev_allocated(const char *name);
+
+/**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
  * driver.
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 13/28] eal/pci: Prevent double registration for devargs_list
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (11 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 12/28] ethdev: Change scope of rte_eth_dev_allocated to global Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 14/28] eal/pci: Add rte_eal_devargs_remove Tetsuya Mukawa
                       ` (14 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch fixes rte_eal_devargs_add() not to register same device twice.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_devargs.c | 35 ++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index 4c7d11a..f95a12d 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -44,6 +44,35 @@
 struct rte_devargs_list devargs_list =
 	TAILQ_HEAD_INITIALIZER(devargs_list);
 
+
+/* find a entry specified by pci address or device name */
+static struct rte_devargs *
+rte_eal_devargs_find(enum rte_devtype devtype, void *args)
+{
+	struct rte_devargs *devargs;
+
+	if (args == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(devargs, &devargs_list, next) {
+		switch (devtype) {
+		case RTE_DEVTYPE_WHITELISTED_PCI:
+		case RTE_DEVTYPE_BLACKLISTED_PCI:
+			if (eal_compare_pci_addr(&devargs->pci.addr, args) == 0)
+				goto found;
+			break;
+		case RTE_DEVTYPE_VIRTUAL:
+			if (memcmp(&devargs->virtual.drv_name, args,
+					strlen((char *)args)) == 0)
+				goto found;
+			break;
+		}
+	}
+	return NULL;
+found:
+	return devargs;
+}
+
 /* store a whitelist parameter for later parsing */
 int
 rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str)
@@ -101,6 +130,12 @@ rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str)
 		break;
 	}
 
+	/* make sure there is no same entry */
+	if (rte_eal_devargs_find(devtype, &devargs->pci.addr)) {
+		RTE_LOG(ERR, EAL, "device already registered: <%s>\n", buf);
+		return -1;
+	}
+
 	TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
 	return 0;
 }
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 14/28] eal/pci: Add rte_eal_devargs_remove
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (12 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 13/28] eal/pci: Prevent double registration for devargs_list Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 15/28] eal/pci: Add probe and close function for virtual drivers Tetsuya Mukawa
                       ` (13 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The function removes a specified devargs from devargs_list.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_devargs.c  | 16 ++++++++++++++++
 lib/librte_eal/common/include/rte_devargs.h | 18 ++++++++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index f95a12d..5fd2a2c 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -140,6 +140,22 @@ rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str)
 	return 0;
 }
 
+/* remove it from the devargs_list */
+void
+rte_eal_devargs_remove(enum rte_devtype devtype, void *args)
+{
+	struct rte_devargs *devargs;
+
+	if (args == NULL)
+		return;
+
+	devargs = rte_eal_devargs_find(devtype, args);
+	if (devargs == NULL)
+		return;
+
+	TAILQ_REMOVE(&devargs_list, devargs, next);
+}
+
 /* count the number of devices of a specified type */
 unsigned int
 rte_eal_devargs_type_count(enum rte_devtype devtype)
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
index 9f9c98f..1066efd 100644
--- a/lib/librte_eal/common/include/rte_devargs.h
+++ b/lib/librte_eal/common/include/rte_devargs.h
@@ -123,6 +123,24 @@ extern struct rte_devargs_list devargs_list;
 int rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str);
 
 /**
+ * Remove a device from the user device list
+ *
+ * For PCI devices, the format of arguments string is "PCI_ADDR". It shouldn't
+ * involves parameters for the device. Example: "08:00.1".
+ *
+ * For virtual devices, the format of arguments string is "DRIVER_NAME*". It
+ * shouldn't involves parameters for the device. Example: "eth_ring". The
+ * validity of the driver name is not checked by this function, it is done
+ * when closing the drivers.
+ *
+ * @param devtype
+ *   The type of the device.
+ * @param name
+ *   The name of the device.
+ */
+void rte_eal_devargs_remove(enum rte_devtype devtype, void *args);
+
+/**
  * Count the number of user devices of a specified type
  *
  * @param devtype
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 15/28] eal/pci: Add probe and close function for virtual drivers
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (13 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 14/28] eal/pci: Add rte_eal_devargs_remove Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 16/28] eal/pci: Add port hotplug functions for virtual devices Tetsuya Mukawa
                       ` (12 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch adds rte_eal_dev_init_one() and rte_eal_dev_close_one().
These are used for attaching and detaching virtual devices.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_dev.c  | 66 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h |  6 +++
 lib/librte_eal/linuxapp/eal/Makefile    |  1 +
 3 files changed, 73 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index eae5656..f573a54 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -32,10 +32,13 @@
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <stdio.h>
+#include <limits.h>
 #include <string.h>
 #include <inttypes.h>
 #include <sys/queue.h>
 
+#include <rte_ethdev.h>
 #include <rte_dev.h>
 #include <rte_devargs.h>
 #include <rte_debug.h>
@@ -107,3 +110,66 @@ rte_eal_dev_init(void)
 	}
 	return 0;
 }
+
+/* So far, linux only supports DPDK hotplug function. */
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+
+#define INVOKE_PROBE	(0)
+#define INVOKE_CLOSE	(1)
+
+static void
+rte_eal_dev_invoke(struct rte_driver *driver,
+		struct rte_devargs *devargs, int type)
+{
+	if ((driver == NULL) || (devargs == NULL))
+		return;
+
+	switch (type) {
+	case INVOKE_PROBE:
+		driver->init(devargs->virtual.drv_name, devargs->args);
+		break;
+	case INVOKE_CLOSE:
+		driver->close(devargs->virtual.drv_name, devargs->args);
+		break;
+	}
+}
+
+static int
+rte_eal_dev_find_and_invoke(const char *name, int type)
+{
+	struct rte_devargs *devargs;
+	struct rte_driver *driver;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	/* call the init function for each virtual device */
+	TAILQ_FOREACH(devargs, &devargs_list, next) {
+
+		if (devargs->type != RTE_DEVTYPE_VIRTUAL)
+			continue;
+
+		if (strncmp(name, devargs->virtual.drv_name, strlen(name)))
+			continue;
+
+		TAILQ_FOREACH(driver, &dev_driver_list, next) {
+			if (driver->type != PMD_VDEV)
+				continue;
+
+			/* search a driver prefix in virtual device name */
+			if (!strncmp(driver->name, devargs->virtual.drv_name,
+					strlen(driver->name))) {
+				rte_eal_dev_invoke(driver, devargs, type);
+				break;
+			}
+		}
+
+		if (driver == NULL) {
+			RTE_LOG(WARNING, EAL, "no driver found for %s\n",
+				  devargs->virtual.drv_name);
+		}
+		return 0;
+	}
+	return 1;
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index f7e3a10..71d40c3 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -57,6 +57,11 @@ TAILQ_HEAD(rte_driver_list, rte_driver);
 typedef int (rte_dev_init_t)(const char *name, const char *args);
 
 /**
+ * Close function called for each device driver once.
+ */
+typedef int (rte_dev_close_t)(const char *name, const char *args);
+
+/**
  * Driver type enumeration
  */
 enum pmd_type {
@@ -72,6 +77,7 @@ struct rte_driver {
 	enum pmd_type type;		   /**< PMD Driver type */
 	const char *name;                   /**< Driver name. */
 	rte_dev_init_t *init;              /**< Device init. function. */
+	rte_dev_close_t *close;            /**< Device close. function. */
 };
 
 /**
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 72ecf3a..0ec83b5 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -41,6 +41,7 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
 CFLAGS += -I$(RTE_SDK)/lib/librte_ring
 CFLAGS += -I$(RTE_SDK)/lib/librte_mempool
 CFLAGS += -I$(RTE_SDK)/lib/librte_malloc
+CFLAGS += -I$(RTE_SDK)/lib/librte_mbuf
 CFLAGS += -I$(RTE_SDK)/lib/librte_ether
 CFLAGS += -I$(RTE_SDK)/lib/librte_ivshmem
 CFLAGS += -I$(RTE_SDK)/lib/librte_pmd_ring
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 16/28] eal/pci: Add port hotplug functions for virtual devices.
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (14 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 15/28] eal/pci: Add probe and close function for virtual drivers Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 17/28] eal/linux/pci: Add functions for unmapping igb_uio resources Tetsuya Mukawa
                       ` (11 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch adds rte_eal_dev_attach_vdev() and rte_eal_dev_detach_vdev().

rte_eal_dev_attach_vdev() receives virtual device name and parameters,
and returns an attached port number.
rte_eal_dev_detach_vdev() receives a port number, and returns device
name actually detached.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_dev.c  | 86 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h | 29 +++++++++++
 2 files changed, 115 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index f573a54..4ea3502 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -172,4 +172,90 @@ rte_eal_dev_find_and_invoke(const char *name, int type)
 	}
 	return 1;
 }
+
+static void
+get_vdev_name(char *vdevargs)
+{
+	char *sep;
+
+	if (vdevargs == NULL)
+		return;
+
+	/* set the first ',' to '\0' to split name and arguments */
+	sep = strchr(vdevargs, ',');
+	if (sep != NULL)
+		sep[0] = '\0';
+}
+
+/* attach the new virtual device, then store port_id of the device */
+int
+rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id)
+{
+	char *args;
+	uint8_t new_port_id;
+	struct rte_eth_dev devs[RTE_MAX_ETHPORTS];
+
+	if ((vdevargs == NULL) || (port_id == NULL))
+		goto err0;
+
+	args = strdup(vdevargs);
+	if (args == NULL)
+		goto err0;
+
+	/* save current port status */
+	rte_eth_dev_save(devs);
+	/* add the vdevargs to devargs_list */
+	if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, args))
+		goto err1;
+	/* parse vdevargs, then retrieve device name */
+	get_vdev_name(args);
+	/* walk around dev_driver_list to find the driver of the device,
+	 * then invoke probe function o the driver */
+	if (rte_eal_dev_find_and_invoke(args, INVOKE_PROBE))
+		goto err2;
+	/* get port_id enabled by above procedures */
+	if (rte_eth_dev_get_changed_port(devs, &new_port_id))
+		goto err2;
+
+	free(args);
+	*port_id = new_port_id;
+	return 0;
+err2:
+	rte_eal_devargs_remove(RTE_DEVTYPE_VIRTUAL, args);
+err1:
+	free(args);
+err0:
+	RTE_LOG(ERR, EAL, "Drver, cannot detach the device\n");
+	return -1;
+}
+
+/* detach the new virtual device, then store the name of the device */
+int
+rte_eal_dev_detach_vdev(uint8_t port_id, char *vdevname)
+{
+	char name[RTE_ETH_NAME_MAX_LEN];
+
+	if (vdevname == NULL)
+		goto err;
+
+	/* check whether the driver supports detach feature, or not */
+	if (rte_eth_dev_check_detachable(port_id))
+		goto err;
+
+	/* get device name by port id */
+	if (rte_eth_dev_get_name_by_port(port_id, name))
+		goto err;
+	/* walk around dev_driver_list to find the driver of the device,
+	 * then invoke close function o the driver */
+	if (rte_eal_dev_find_and_invoke(name, INVOKE_CLOSE))
+		goto err;
+	/* remove the vdevname from devargs_list */
+	rte_eal_devargs_remove(RTE_DEVTYPE_VIRTUAL, name);
+
+	strncpy(vdevname, name, sizeof(name));
+	return 0;
+err:
+	RTE_LOG(ERR, EAL, "Drver, cannot detach the device\n");
+	return -1;
+}
 #endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 71d40c3..159d5a5 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -98,6 +98,35 @@ void rte_eal_driver_register(struct rte_driver *driver);
  */
 void rte_eal_driver_unregister(struct rte_driver *driver);
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+
+/**
+ * Attach a new virtual device.
+ *
+ * @param vdevargs
+ *   A pointer to a strings array describing the new device
+ *   to be attached.
+ * @param port_id
+ *  A pointer to a port identifier actually attached.
+ * @return
+ *  0 on success and port_id is filled, negative on error
+ */
+int rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id);
+
+/**
+ * Detach a virtual device.
+ *
+ * @param port_id
+ *   The port identifier of the virtual device to detach.
+ * @param addr
+ *  A pointer to a virtual device name actually detached.
+ * @return
+ *  0 on success and vdevname is filled, negative on error
+ */
+int rte_eal_dev_detach_vdev(uint8_t port_id, char *vdevname);
+
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /**
  * Initalize all the registered drivers in this process
  */
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 17/28] eal/linux/pci: Add functions for unmapping igb_uio resources
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (15 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 16/28] eal/pci: Add port hotplug functions for virtual devices Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 18/28] eal/pci: Prevent double registrations for pci_device_list Tetsuya Mukawa
                       ` (10 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch adds functions for unmapping igb_uio resources. The patch is only
for Linux and igb_uio environment. VFIO and BSD are not supported.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/linuxapp/eal/eal_pci.c      | 35 ++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci_init.h |  7 ++++
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c  | 65 ++++++++++++++++++++++++++++++
 3 files changed, 107 insertions(+)

diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 23a69e9..fe212d1 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -137,6 +137,22 @@ pci_map_resource(void *requested_addr, int fd, off_t offset, size_t size)
 	return mapaddr;
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+/* unmap a particular resource */
+void
+pci_unmap_resource(void *requested_addr, size_t size)
+{
+	/* Unmap the PCI memory resource of device */
+	if (munmap(requested_addr, size)) {
+		RTE_LOG(ERR, EAL, "%s(): cannot munmap(%p, 0x%lx): %s\n",
+			__func__, requested_addr, (unsigned long)size,
+			strerror(errno));
+	} else
+		RTE_LOG(DEBUG, EAL, "  PCI memory mapped at %p\n",
+				requested_addr);
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /* parse the "resource" sysfs file */
 #define IORESOURCE_MEM  0x00000200
 
@@ -507,6 +523,25 @@ pci_map_device(struct rte_pci_device *dev)
 	return 0;
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+static void
+pci_unmap_device(struct rte_pci_device *dev)
+{
+	if (dev == NULL)
+		return;
+
+	/* try unmapping the NIC resources using VFIO if it exists */
+#ifdef VFIO_PRESENT
+	if (pci_vfio_is_enabled()) {
+		RTE_LOG(ERR, EAL, "%s() doesn't support vfio yet.\n",
+				__func__);
+		return;
+	}
+#endif
+	pci_uio_unmap_resource(dev);
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /*
  * If vendor/device ID match, call the devinit() function of the
  * driver.
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_init.h b/lib/librte_eal/linuxapp/eal/eal_pci_init.h
index 1070eb8..c733ac3 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_init.h
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_init.h
@@ -71,6 +71,13 @@ void *pci_map_resource(void *requested_addr, int fd, off_t offset,
 /* map IGB_UIO resource prototype */
 int pci_uio_map_resource(struct rte_pci_device *dev);
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+void pci_unmap_resource(void *requested_addr, size_t size);
+
+/* unmap IGB_UIO resource prototype */
+void pci_uio_unmap_resource(struct rte_pci_device *dev);
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 #ifdef VFIO_PRESENT
 
 #define VFIO_MAX_GROUPS 64
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
index 1da3507..77e7389 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
@@ -404,6 +404,71 @@ pci_uio_map_resource(struct rte_pci_device *dev)
 	return 0;
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+static void
+pci_uio_unmap(struct mapped_pci_resource *uio_res)
+{
+	int i;
+
+	if (uio_res == NULL)
+		return;
+
+	for (i = 0; i != uio_res->nb_maps; i++)
+		pci_unmap_resource(uio_res->maps[i].addr,
+				(size_t)uio_res->maps[i].size);
+}
+
+static struct mapped_pci_resource *
+pci_uio_find_resource(struct rte_pci_device *dev)
+{
+	struct mapped_pci_resource *uio_res;
+
+	if (dev == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(uio_res, pci_res_list, next) {
+
+		/* skip this element if it doesn't match our PCI address */
+		if (!eal_compare_pci_addr(&uio_res->pci_addr, &dev->addr))
+			return uio_res;
+	}
+	return NULL;
+}
+
+/* unmap the PCI resource of a PCI device in virtual memory */
+void
+pci_uio_unmap_resource(struct rte_pci_device *dev)
+{
+	struct mapped_pci_resource *uio_res;
+
+	if (dev == NULL)
+		return;
+
+	/* find an entry for the device */
+	uio_res = pci_uio_find_resource(dev);
+	if (uio_res == NULL)
+		return;
+
+	/* secondary processes - just free maps */
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return pci_uio_unmap(uio_res);
+
+	TAILQ_REMOVE(pci_res_list, uio_res, next);
+
+	/* unmap all resources */
+	pci_uio_unmap(uio_res);
+
+	/* free uio resource */
+	rte_free(uio_res);
+
+	/* close fd if in primary process */
+	close(dev->intr_handle.fd);
+
+	dev->intr_handle.fd = -1;
+	dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /*
  * parse a sysfs file containing one integer value
  * different to the eal version, as it needs to work with 64-bit values
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 18/28] eal/pci: Prevent double registrations for pci_device_list
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (16 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 17/28] eal/linux/pci: Add functions for unmapping igb_uio resources Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 19/28] eal/pci: Change scope of rte_eal_pci_scan to global Tetsuya Mukawa
                       ` (9 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch fixes pci_scan_one() not to register same pci devices twice.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/linuxapp/eal/eal_pci.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index fe212d1..355c858 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -306,14 +306,17 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
 	}
 	else {
 		struct rte_pci_device *dev2 = NULL;
+		int ret;
 
 		TAILQ_FOREACH(dev2, &pci_device_list, next) {
-			if (eal_compare_pci_addr(&dev->addr, &dev2->addr) != 0)
+			ret = eal_compare_pci_addr(&dev->addr, &dev2->addr);
+			if (ret > 0)
 				continue;
-			else {
+			else if (ret < 0) {
 				TAILQ_INSERT_BEFORE(dev2, dev, next);
 				return 0;
-			}
+			} else	/* already registered */
+				return 0;
 		}
 		TAILQ_INSERT_TAIL(&pci_device_list, dev, next);
 	}
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 19/28] eal/pci: Change scope of rte_eal_pci_scan to global
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (17 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 18/28] eal/pci: Prevent double registrations for pci_device_list Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 20/28] eal/pci: Add rte_eal_pci_close_one_driver Tetsuya Mukawa
                       ` (8 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The function is called by port hotplug framework, so change scope of the
function to global.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_private.h   | 11 +++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c |  6 +++---
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index 232fcec..a1127ab 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -154,6 +154,17 @@ struct rte_pci_driver;
 struct rte_pci_device;
 
 /**
+ * Scan the content of the PCI bus, and the devices in the devices
+ * list
+ *
+ * This function is private to EAL.
+ *
+ * @return
+ *  0 on success, negative on error
+ */
+int rte_eal_pci_scan(void);
+
+/**
  * Mmap memory for single PCI device
  *
  * This function is private to EAL.
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 355c858..8d683f5 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -375,8 +375,8 @@ error:
  * Scan the content of the PCI bus, and the devices in the devices
  * list
  */
-static int
-pci_scan(void)
+int
+rte_eal_pci_scan(void)
 {
 	struct dirent *e;
 	DIR *dir;
@@ -629,7 +629,7 @@ rte_eal_pci_init(void)
 	if (internal_config.no_pci)
 		return 0;
 
-	if (pci_scan() < 0) {
+	if (rte_eal_pci_scan() < 0) {
 		RTE_LOG(ERR, EAL, "%s(): Cannot scan PCI bus\n", __func__);
 		return -1;
 	}
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 20/28] eal/pci: Add rte_eal_pci_close_one_driver
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (18 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 19/28] eal/pci: Change scope of rte_eal_pci_scan to global Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 21/28] eal/pci: Fix pci_probe_all_drivers to share code with closing function Tetsuya Mukawa
                       ` (7 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The function is used for closing the specified driver and device.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_private.h   | 15 +++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c | 61 +++++++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+)

diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index a1127ab..f892ac4 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -176,6 +176,21 @@ int rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr,
 		struct rte_pci_device *dev);
 
 /**
+ * Munmap memory for single PCI device
+ *
+ * This function is private to EAL.
+ *
+ * @param	dr
+ *  The pointer to the pci driver structure
+ * @param	dev
+ *  The pointer to the pci device structure
+ * @return
+ *   0 on success, negative on error
+ */
+int rte_eal_pci_close_one_driver(struct rte_pci_driver *dr,
+		struct rte_pci_device *dev);
+
+/**
  * Init tail queues for non-EAL library structures. This is to allow
  * the rings, mempools, etc. lists to be shared among multiple processes
  *
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 8d683f5..93456f3 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -616,6 +616,67 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d
 	return 1;
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+/*
+ * If vendor/device ID match, call the devshutdown() function of the
+ * driver.
+ */
+int
+rte_eal_pci_close_one_driver(struct rte_pci_driver *dr,
+		struct rte_pci_device *dev)
+{
+	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_addr *loc = &dev->addr;
+
+		RTE_LOG(DEBUG, EAL,
+				"PCI device "PCI_PRI_FMT" on NUMA socket %i\n",
+				loc->domain, loc->bus, loc->devid,
+				loc->function, dev->numa_node);
+
+		RTE_LOG(DEBUG, EAL, "  remove driver: %x:%x %s\n",
+				dev->id.vendor_id, dev->id.device_id,
+				dr->name);
+
+		/* call the driver devshutdown() function */
+		if (dr->devshutdown && (dr->devshutdown(dr, dev) < 0))
+			return -1;	/* negative value is an error */
+
+		/* clear driver structure */
+		dev->driver = NULL;
+
+		if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
+			/* unmap resources for devices that use igb_uio */
+			pci_unmap_device(dev);
+
+		return 0;
+	}
+	/* return positive value if driver is not found */
+	return 1;
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /* Init the PCI EAL subsystem */
 int
 rte_eal_pci_init(void)
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 21/28] eal/pci: Fix pci_probe_all_drivers to share code with closing function
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (19 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 20/28] eal/pci: Add rte_eal_pci_close_one_driver Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 22/28] eal/pci: Add pci_close_all_drivers Tetsuya Mukawa
                       ` (6 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

pci_close_all_drivers() will be implemented after the patch.
To share a part of code between thses 2 functions, The patch fixes
pci_probe_all_drivers() first.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_pci.c | 28 ++++++++++++++++++++--------
 1 file changed, 20 insertions(+), 8 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index f01f258..1e3efea 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -99,19 +99,20 @@ static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
 	return NULL;
 }
 
-/*
- * If vendor/device ID match, call the devinit() function of all
- * registered driver for the given device. Return -1 if initialization
- * failed, return 1 if no driver is found for this device.
- */
+#define INVOKE_PROBE	(0)
+
 static int
-pci_probe_all_drivers(struct rte_pci_device *dev)
+pci_invoke_all_drivers(struct rte_pci_device *dev, int type)
 {
 	struct rte_pci_driver *dr = NULL;
-	int rc;
+	int rc = 0;
 
 	TAILQ_FOREACH(dr, &pci_driver_list, next) {
-		rc = rte_eal_pci_probe_one_driver(dr, dev);
+		switch (type) {
+		case INVOKE_PROBE:
+			rc = rte_eal_pci_probe_one_driver(dr, dev);
+			break;
+		}
 		if (rc < 0)
 			/* negative value is an error */
 			return -1;
@@ -124,6 +125,17 @@ pci_probe_all_drivers(struct rte_pci_device *dev)
 }
 
 /*
+ * If vendor/device ID match, call the devinit() 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_probe_all_drivers(struct rte_pci_device *dev)
+{
+	return pci_invoke_all_drivers(dev, INVOKE_PROBE);
+}
+
+/*
  * Scan the content of the PCI bus, and call the devinit() function for
  * all registered drivers that have a matching entry in its id_table
  * for discovered devices.
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 22/28] eal/pci: Add pci_close_all_drivers
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (20 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 21/28] eal/pci: Fix pci_probe_all_drivers to share code with closing function Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 23/28] eal/pci: Add rte_eal_pci_probe_one and rte_eal_pci_close_one Tetsuya Mukawa
                       ` (5 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The function tries to find a driver for the specified device, and then
close the driver.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_pci.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index 1e3efea..b404ee0 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -100,6 +100,7 @@ static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
 }
 
 #define INVOKE_PROBE	(0)
+#define INVOKE_CLOSE	(1)
 
 static int
 pci_invoke_all_drivers(struct rte_pci_device *dev, int type)
@@ -112,6 +113,11 @@ pci_invoke_all_drivers(struct rte_pci_device *dev, int type)
 		case INVOKE_PROBE:
 			rc = rte_eal_pci_probe_one_driver(dr, dev);
 			break;
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+		case INVOKE_CLOSE:
+			rc = rte_eal_pci_close_one_driver(dr, dev);
+			break;
+#endif
 		}
 		if (rc < 0)
 			/* negative value is an error */
@@ -135,6 +141,19 @@ pci_probe_all_drivers(struct rte_pci_device *dev)
 	return pci_invoke_all_drivers(dev, INVOKE_PROBE);
 }
 
+#if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
+/*
+ * If vendor/device ID match, call the devclose() 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_close_all_drivers(struct rte_pci_device *dev)
+{
+	return pci_invoke_all_drivers(dev, INVOKE_CLOSE);
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
+
 /*
  * Scan the content of the PCI bus, and call the devinit() function for
  * all registered drivers that have a matching entry in its id_table
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 23/28] eal/pci: Add rte_eal_pci_probe_one and rte_eal_pci_close_one
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (21 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 22/28] eal/pci: Add pci_close_all_drivers Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 24/28] eal/pci: Add port hotplug functions for physical devices Tetsuya Mukawa
                       ` (4 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The functions are used for probe and close a device.
First the function tries to find a device that has the specfied PCI address.
Then, probe or close the device.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_pci.c  | 58 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_pci.h | 26 +++++++++++++++
 2 files changed, 84 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index b404ee0..5ff7b49 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -152,6 +152,64 @@ pci_close_all_drivers(struct rte_pci_device *dev)
 {
 	return pci_invoke_all_drivers(dev, INVOKE_CLOSE);
 }
+
+static int
+rte_eal_pci_invoke_one(struct rte_pci_addr *addr, int type)
+{
+	struct rte_pci_device *dev = NULL;
+	int ret = 0;
+
+	TAILQ_FOREACH(dev, &pci_device_list, next) {
+		if (eal_compare_pci_addr(&dev->addr, addr))
+			continue;
+
+		switch (type) {
+		case INVOKE_PROBE:
+			ret = pci_probe_all_drivers(dev);
+			break;
+		case INVOKE_CLOSE:
+			ret = pci_close_all_drivers(dev);
+			break;
+		}
+		if (ret < 0)
+			goto invoke_err_return;
+		if (type == INVOKE_CLOSE)
+			goto remove_dev;
+		return 0;
+	}
+
+	return -1;
+
+invoke_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);
+	return -1;
+
+remove_dev:
+	TAILQ_REMOVE(&pci_device_list, dev, next);
+	return 0;
+}
+
+/*
+ * Find the pci device specified by pci address, then invoke probe function of
+ * the driver of the devive.
+ */
+int
+rte_eal_pci_probe_one(struct rte_pci_addr *addr)
+{
+	return rte_eal_pci_invoke_one(addr, INVOKE_PROBE);
+}
+
+/*
+ * Find the pci device specified by pci address, then invoke close function of
+ * the driver of the devive.
+ */
+int
+rte_eal_pci_close_one(struct rte_pci_addr *addr)
+{
+	return rte_eal_pci_invoke_one(addr, INVOKE_CLOSE);
+}
 #endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
 
 /*
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 74720d1..5a7e06f 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -311,6 +311,32 @@ eal_compare_pci_addr(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
 int rte_eal_pci_probe(void);
 
 /**
+ * Probe the single PCI device.
+ *
+ * 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.
+ *
+ * @return
+ *   - 0 on success.
+ *   - Negative on error.
+ */
+int rte_eal_pci_probe_one(struct rte_pci_addr *addr);
+
+/**
+ * Close the single PCI device.
+ *
+ * Scan the content of the PCI bus, and find the pci device specified by pci
+ * address, then call the close() function for registered driver that has a
+ * matching entry in its id_table for discovered device.
+ *
+ * @return
+ *   - 0 on success.
+ *   - Negative on error.
+ */
+int rte_eal_pci_close_one(struct rte_pci_addr *addr);
+
+/**
  * Dump the content of the PCI bus.
  *
  * @param f
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 24/28] eal/pci: Add port hotplug functions for physical devices.
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (22 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 23/28] eal/pci: Add rte_eal_pci_probe_one and rte_eal_pci_close_one Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 25/28] eal/pci: Remove pci_probe/close_all_drivers() Tetsuya Mukawa
                       ` (3 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch adds rte_eal_dev_attach_pdev() and rte_eal_dev_detach_pdev().

rte_eal_dev_attach_pdev() receives a PCI address of the device and
returns an attached port number.
rte_eal_dev_detach_pdev() receives a port number, and returns a PCI
address actually detached.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_dev.c  | 64 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h | 26 ++++++++++++++
 2 files changed, 90 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 4ea3502..9ff03ed 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -173,6 +173,70 @@ rte_eal_dev_find_and_invoke(const char *name, int type)
 	return 1;
 }
 
+/* attach the new physical device, then store port_id of the device */
+int
+rte_eal_dev_attach_pdev(struct rte_pci_addr *addr, uint8_t *port_id)
+{
+	uint8_t new_port_id;
+	struct rte_eth_dev devs[RTE_MAX_ETHPORTS];
+
+	if ((addr == NULL) || (port_id == NULL))
+		goto err;
+
+	/* save current port status */
+	rte_eth_dev_save(devs);
+	/* re-construct pci_device_list */
+	if (rte_eal_pci_scan())
+		goto err;
+	/* invoke probe func of the driver can handle the new device */
+	if (rte_eal_pci_probe_one(addr))
+		goto err;
+	/* get port_id enabled by above procedures */
+	if (rte_eth_dev_get_changed_port(devs, &new_port_id))
+		goto err;
+
+	*port_id = new_port_id;
+	return 0;
+err:
+	RTE_LOG(ERR, EAL, "Drver, cannot attach the device\n");
+	return -1;
+}
+
+/* detach the new physical device, then store pci_addr of the device */
+int
+rte_eal_dev_detach_pdev(uint8_t port_id, struct rte_pci_addr *addr)
+{
+	struct rte_pci_addr freed_addr;
+	struct rte_pci_addr vp;
+
+	if (addr == NULL)
+		goto err;
+
+	/* check whether the driver supports detach feature, or not */
+	if (rte_eth_dev_check_detachable(port_id))
+		goto err;
+
+	/* get pci address by port id */
+	if (rte_eth_dev_get_addr_by_port(port_id, &freed_addr))
+		goto err;
+
+	/* Zerod pci addr means the port comes from virtual device */
+	vp.domain = vp.bus = vp.devid = vp.function = 0;
+	if (eal_compare_pci_addr(&vp, &freed_addr) == 0)
+		goto err;
+
+	/* invoke close func of the driver,
+	 * also remove the device from pci_device_list */
+	if (rte_eal_pci_close_one(&freed_addr))
+		goto err;
+
+	*addr = freed_addr;
+	return 0;
+err:
+	RTE_LOG(ERR, EAL, "Drver, cannot detach the device\n");
+	return -1;
+}
+
 static void
 get_vdev_name(char *vdevargs)
 {
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 159d5a5..f0677cb 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -47,6 +47,7 @@ extern "C" {
 #endif
 
 #include <sys/queue.h>
+#include <rte_pci.h>
 
 /** Double linked list of device drivers. */
 TAILQ_HEAD(rte_driver_list, rte_driver);
@@ -101,6 +102,19 @@ void rte_eal_driver_unregister(struct rte_driver *driver);
 #if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
 
 /**
+ * Attach a new physical device.
+ *
+ * @param addr
+ *   A pointer to a pci address structure describing the new
+ *   device to be attached.
+ * @param port_id
+ *  A pointer to a port identifier actually attached.
+ * @return
+ *  0 on success and port_id is filled, negative on error
+ */
+int rte_eal_dev_attach_pdev(struct rte_pci_addr *addr, uint8_t *port_id);
+
+/**
  * Attach a new virtual device.
  *
  * @param vdevargs
@@ -114,6 +128,18 @@ void rte_eal_driver_unregister(struct rte_driver *driver);
 int rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id);
 
 /**
+ * Detach a physical device.
+ *
+ * @param port_id
+ *   The port identifier of the physical device to detach.
+ * @param addr
+ *  A pointer to a pci address structure actually detached.
+ * @return
+ *  0 on success and addr is filled, negative on error
+ */
+int rte_eal_dev_detach_pdev(uint8_t port_id, struct rte_pci_addr *addr);
+
+/**
  * Detach a virtual device.
  *
  * @param port_id
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 25/28] eal/pci: Remove pci_probe/close_all_drivers()
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (23 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 24/28] eal/pci: Add port hotplug functions for physical devices Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 26/28] eal/pci: Add rte_eal_dev_attach/detach() functions Tetsuya Mukawa
                       ` (2 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

These functions are actually wrappers of pci_invoke_all_drivers().
Just call it directly.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_pci.c | 30 ++++--------------------------
 1 file changed, 4 insertions(+), 26 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index 5ff7b49..5044d8e 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -130,29 +130,7 @@ pci_invoke_all_drivers(struct rte_pci_device *dev, int type)
 	return 1;
 }
 
-/*
- * If vendor/device ID match, call the devinit() 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_probe_all_drivers(struct rte_pci_device *dev)
-{
-	return pci_invoke_all_drivers(dev, INVOKE_PROBE);
-}
-
 #if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
-/*
- * If vendor/device ID match, call the devclose() 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_close_all_drivers(struct rte_pci_device *dev)
-{
-	return pci_invoke_all_drivers(dev, INVOKE_CLOSE);
-}
-
 static int
 rte_eal_pci_invoke_one(struct rte_pci_addr *addr, int type)
 {
@@ -165,10 +143,10 @@ rte_eal_pci_invoke_one(struct rte_pci_addr *addr, int type)
 
 		switch (type) {
 		case INVOKE_PROBE:
-			ret = pci_probe_all_drivers(dev);
+			ret = pci_invoke_all_drivers(dev, INVOKE_PROBE);
 			break;
 		case INVOKE_CLOSE:
-			ret = pci_close_all_drivers(dev);
+			ret = pci_invoke_all_drivers(dev, INVOKE_CLOSE);
 			break;
 		}
 		if (ret < 0)
@@ -237,10 +215,10 @@ rte_eal_pci_probe(void)
 
 		/* probe all or only whitelisted devices */
 		if (probe_all)
-			ret = pci_probe_all_drivers(dev);
+			ret = pci_invoke_all_drivers(dev, INVOKE_PROBE);
 		else if (devargs != NULL &&
 			devargs->type == RTE_DEVTYPE_WHITELISTED_PCI)
-			ret = pci_probe_all_drivers(dev);
+			ret = pci_invoke_all_drivers(dev, INVOKE_PROBE);
 		if (ret < 0)
 			rte_exit(EXIT_FAILURE, "Requested device " PCI_PRI_FMT
 				 " cannot be used\n", dev->addr.domain, dev->addr.bus,
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 26/28] eal/pci: Add rte_eal_dev_attach/detach() functions
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (24 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 25/28] eal/pci: Remove pci_probe/close_all_drivers() Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 27/28] eal/pci: Remove rte_eal_dev_attach/detach_pdev() and rte_eal_dev_attach/detach_vdev() Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 28/28] eal: Enable port hotplug framework in Linux Tetsuya Mukawa
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

This functions wraps attaching and detaching functions for physical and virtual
device.
When rte_eal_dev_attach() is called, the function tries to
realize the device name as pci address. If this is done successfully,
rte_eal_dev_attach() will call rte_eal_dev_attach_pdev(). If not, calls
rte_eal_dev_attach_vdev().
When rte_eal_dev_detach() is called, the function gets the device type of
this port to know whether the port is came from physical or virtual. And
then rte_eal_dev_detach_pdev() or rte_eal_dev_detach_vdev() will be called.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 app/test/virtual_pmd.c                       |  2 +-
 lib/librte_eal/common/eal_common_dev.c       | 34 ++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h      | 25 ++++++++++++++++++++
 lib/librte_ether/rte_ethdev.c                | 14 ++++++++++--
 lib/librte_ether/rte_ethdev.h                | 24 +++++++++++++++++++-
 lib/librte_pmd_af_packet/rte_eth_af_packet.c |  2 +-
 lib/librte_pmd_bond/rte_eth_bond_api.c       |  2 +-
 lib/librte_pmd_pcap/rte_eth_pcap.c           |  2 +-
 lib/librte_pmd_ring/rte_eth_ring.c           |  2 +-
 lib/librte_pmd_xenvirt/rte_eth_xenvirt.c     |  2 +-
 10 files changed, 100 insertions(+), 9 deletions(-)

diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c
index ade6cb0..ff8f747 100644
--- a/app/test/virtual_pmd.c
+++ b/app/test/virtual_pmd.c
@@ -556,7 +556,7 @@ virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
 		goto err;
 
 	/* reserve an ethdev entry */
-	eth_dev = rte_eth_dev_allocate(name);
+	eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_PHYSICAL);
 	if (eth_dev == NULL)
 		goto err;
 
diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 9ff03ed..c9d4894 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -322,4 +322,38 @@ err:
 	RTE_LOG(ERR, EAL, "Drver, cannot detach the device\n");
 	return -1;
 }
+
+/* attach the new device, then store port_id of the device */
+int
+rte_eal_dev_attach(const char *devargs, uint8_t *port_id)
+{
+	struct rte_pci_addr addr;
+
+	if (eal_parse_pci_DomBDF(devargs, &addr) == 0)
+		return rte_eal_dev_attach_pdev(&addr, port_id);
+	else
+		return rte_eal_dev_attach_vdev(devargs, port_id);
+}
+
+/* detach the device, then store the name of the device */
+int
+rte_eal_dev_detach(uint8_t port_id, char *name)
+{
+	struct rte_pci_addr addr;
+	int ret;
+
+	if (rte_eth_dev_get_device_type(port_id) == RTE_ETH_DEV_PHYSICAL) {
+		ret = rte_eth_dev_get_addr_by_port(port_id, &addr);
+		if (ret < 0)
+			return ret;
+
+		ret = rte_eal_dev_detach_pdev(port_id, &addr);
+		if (ret == 0)
+			snprintf(name, RTE_ETH_NAME_MAX_LEN, "%04x.%02x.%02x.%d",
+				addr.domain, addr.bus, addr.devid, addr.function);
+
+		return ret;
+	} else
+		return rte_eal_dev_detach_vdev(port_id, name);
+}
 #endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index f0677cb..1f8f24a 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -151,6 +151,31 @@ int rte_eal_dev_detach_pdev(uint8_t port_id, struct rte_pci_addr *addr);
  */
 int rte_eal_dev_detach_vdev(uint8_t port_id, char *vdevname);
 
+/**
+ * Attach a new device.
+ *
+ * @param devargs
+ *   A pointer to a strings array describing the new device
+ *   to be attached.
+ * @param port_id
+ *  A pointer to a port identifier actually attached.
+ * @return
+ *  0 on success and port_id is filled, negative on error
+ */
+int rte_eal_dev_attach(const char *devargs, uint8_t *port_id);
+
+/**
+ * Detach a device.
+ *
+ * @param port_id
+ *   The port identifier of the device to detach.
+ * @param addr
+ *  A pointer to a device name actually detached.
+ * @return
+ *  0 on success and devname is filled, negative on error
+ */
+int rte_eal_dev_detach(uint8_t port_id, char *devname);
+
 #endif /* RTE_LIBRTE_EAL_HOTPLUG & RTE_LIBRTE_EAL_LINUXAPP */
 
 /**
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 86200e0..cd5ef67 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -232,7 +232,7 @@ rte_eth_dev_allocate_new_port(void)
 }
 
 struct rte_eth_dev *
-rte_eth_dev_allocate(const char *name)
+rte_eth_dev_allocate(const char *name, enum rte_eth_dev_type type)
 {
 	uint8_t port_id;
 	struct rte_eth_dev *eth_dev;
@@ -256,6 +256,7 @@ rte_eth_dev_allocate(const char *name)
 	snprintf(eth_dev->data->name, sizeof(eth_dev->data->name), "%s", name);
 	eth_dev->data->port_id = port_id;
 	eth_dev->attached = DEV_CONNECTED;
+	eth_dev->dev_type = type;
 	nb_ports++;
 	return eth_dev;
 }
@@ -273,6 +274,7 @@ rte_eth_dev_free(const char *name)
 	}
 
 	eth_dev->attached = 0;
+	eth_dev->dev_type = RTE_ETH_DEV_UNKNOWN;
 	nb_ports--;
 	return eth_dev;
 }
@@ -293,7 +295,7 @@ rte_eth_dev_init(struct rte_pci_driver *pci_drv,
 	snprintf(ethdev_name, RTE_ETH_NAME_MAX_LEN, "%d:%d.%d",
 			pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function);
 
-	eth_dev = rte_eth_dev_allocate(ethdev_name);
+	eth_dev = rte_eth_dev_allocate(ethdev_name, RTE_ETH_DEV_PHYSICAL);
 	if (eth_dev == NULL)
 		return -ENOMEM;
 
@@ -416,6 +418,14 @@ rte_eth_dev_count(void)
 	return (nb_ports);
 }
 
+enum rte_eth_dev_type
+rte_eth_dev_get_device_type(uint8_t port_id)
+{
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID)
+		return -1;
+	return rte_eth_devices[port_id].dev_type;
+}
+
 void
 rte_eth_dev_save(struct rte_eth_dev *devs)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 47622a2..0d500eb 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1548,6 +1548,16 @@ struct eth_dev_ops {
 };
 
 /**
+ * The eth device type
+ */
+enum rte_eth_dev_type {
+	RTE_ETH_DEV_UNKNOWN,	/**< unknown device type */
+	RTE_ETH_DEV_PHYSICAL,	/**< physical device type */
+	RTE_ETH_DEV_VIRTUAL,	/**< virtual device type */
+	RTE_ETH_DEV_MAX		/**< max value of this enum */
+};
+
+/**
  * @internal
  * The generic data structure associated with each ethernet device.
  *
@@ -1566,6 +1576,7 @@ struct rte_eth_dev {
 	struct rte_pci_device *pci_dev; /**< PCI info. supplied by probing */
 	struct rte_eth_dev_cb_list callbacks; /**< User application callbacks */
 	uint8_t attached; /**< Flag indicating the port is attached */
+	enum rte_eth_dev_type dev_type; /**< Flag indicating the device type */
 };
 
 struct rte_eth_dev_sriov {
@@ -1643,6 +1654,15 @@ extern uint8_t rte_eth_dev_count(void);
 
 /**
  * Function for internal use by port hotplug functions.
+ * Get the device type to know whether the device is physical or virtual.
+ *
+ * @return
+ *   - Device type.
+ */
+extern enum rte_eth_dev_type rte_eth_dev_get_device_type(uint8_t port_id);
+
+/**
+ * Function for internal use by port hotplug functions.
  * Copies current ethdev structures to the specified pointer.
  *
  * @param	devs	The pointer to the ethdev structures
@@ -1728,10 +1748,12 @@ extern struct rte_eth_dev *rte_eth_dev_allocated(const char *name);
  * to that slot for the driver to use.
  *
  * @param	name	Unique identifier name for each Ethernet device
+ * @param	type	Device type of this Ethernet device
  * @return
  *   - Slot in the rte_dev_devices array for a new device;
  */
-struct rte_eth_dev *rte_eth_dev_allocate(const char *name);
+struct rte_eth_dev *rte_eth_dev_allocate(const char *name,
+		enum rte_eth_dev_type type);
 
 /**
  * Function for internal use by dummy drivers primarily, e.g. ring-based
diff --git a/lib/librte_pmd_af_packet/rte_eth_af_packet.c b/lib/librte_pmd_af_packet/rte_eth_af_packet.c
index d0fb3eb..1237903 100644
--- a/lib/librte_pmd_af_packet/rte_eth_af_packet.c
+++ b/lib/librte_pmd_af_packet/rte_eth_af_packet.c
@@ -642,7 +642,7 @@ rte_pmd_init_internals(const char *name,
 	}
 
 	/* reserve an ethdev entry */
-	*eth_dev = rte_eth_dev_allocate(name);
+	*eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL);
 	if (*eth_dev == NULL)
 		goto error;
 
diff --git a/lib/librte_pmd_bond/rte_eth_bond_api.c b/lib/librte_pmd_bond/rte_eth_bond_api.c
index ef5ddf4..a6986e3 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_api.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_api.c
@@ -231,7 +231,7 @@ rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id)
 	}
 
 	/* reserve an ethdev entry */
-	eth_dev = rte_eth_dev_allocate(name);
+	eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL);
 	if (eth_dev == NULL) {
 		RTE_BOND_LOG(ERR, "Unable to allocate rte_eth_dev");
 		goto err;
diff --git a/lib/librte_pmd_pcap/rte_eth_pcap.c b/lib/librte_pmd_pcap/rte_eth_pcap.c
index f12d1e7..0f34f73 100644
--- a/lib/librte_pmd_pcap/rte_eth_pcap.c
+++ b/lib/librte_pmd_pcap/rte_eth_pcap.c
@@ -710,7 +710,7 @@ rte_pmd_init_internals(const char *name, const unsigned nb_rx_queues,
 		goto error;
 
 	/* reserve an ethdev entry */
-	*eth_dev = rte_eth_dev_allocate(name);
+	*eth_dev = rte_eth_dev_allocate(name, VIRTUAL);
 	if (*eth_dev == NULL)
 		goto error;
 
diff --git a/lib/librte_pmd_ring/rte_eth_ring.c b/lib/librte_pmd_ring/rte_eth_ring.c
index 4f1b6ed..d901053 100644
--- a/lib/librte_pmd_ring/rte_eth_ring.c
+++ b/lib/librte_pmd_ring/rte_eth_ring.c
@@ -256,7 +256,7 @@ rte_eth_from_rings(const char *name, struct rte_ring *const rx_queues[],
 		goto error;
 
 	/* reserve an ethdev entry */
-	eth_dev = rte_eth_dev_allocate(name);
+	eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL);
 	if (eth_dev == NULL)
 		goto error;
 
diff --git a/lib/librte_pmd_xenvirt/rte_eth_xenvirt.c b/lib/librte_pmd_xenvirt/rte_eth_xenvirt.c
index 6555ec5..4f0eda5 100644
--- a/lib/librte_pmd_xenvirt/rte_eth_xenvirt.c
+++ b/lib/librte_pmd_xenvirt/rte_eth_xenvirt.c
@@ -647,7 +647,7 @@ eth_dev_xenvirt_create(const char *name, const char *params,
 		goto err;
 
 	/* reserve an ethdev entry */
-	eth_dev = rte_eth_dev_allocate(name);
+	eth_dev = rte_eth_dev_allocate(name, VIRTUAL);
 	if (eth_dev == NULL)
 		goto err;
 
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 27/28] eal/pci: Remove rte_eal_dev_attach/detach_pdev() and rte_eal_dev_attach/detach_vdev()
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (25 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 26/28] eal/pci: Add rte_eal_dev_attach/detach() functions Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 28/28] eal: Enable port hotplug framework in Linux Tetsuya Mukawa
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

These functions are wrapped by rte_eal_dev_attach/detach(). So delete
these.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/eal_common_dev.c  |  8 +++---
 lib/librte_eal/common/include/rte_dev.h | 50 ---------------------------------
 2 files changed, 4 insertions(+), 54 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index c9d4894..7481fb7 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -174,7 +174,7 @@ rte_eal_dev_find_and_invoke(const char *name, int type)
 }
 
 /* attach the new physical device, then store port_id of the device */
-int
+static int
 rte_eal_dev_attach_pdev(struct rte_pci_addr *addr, uint8_t *port_id)
 {
 	uint8_t new_port_id;
@@ -203,7 +203,7 @@ err:
 }
 
 /* detach the new physical device, then store pci_addr of the device */
-int
+static int
 rte_eal_dev_detach_pdev(uint8_t port_id, struct rte_pci_addr *addr)
 {
 	struct rte_pci_addr freed_addr;
@@ -252,7 +252,7 @@ get_vdev_name(char *vdevargs)
 }
 
 /* attach the new virtual device, then store port_id of the device */
-int
+static int
 rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id)
 {
 	char *args;
@@ -294,7 +294,7 @@ err0:
 }
 
 /* detach the new virtual device, then store the name of the device */
-int
+static int
 rte_eal_dev_detach_vdev(uint8_t port_id, char *vdevname)
 {
 	char name[RTE_ETH_NAME_MAX_LEN];
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 1f8f24a..9da518d 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -102,56 +102,6 @@ void rte_eal_driver_unregister(struct rte_driver *driver);
 #if defined(RTE_LIBRTE_EAL_HOTPLUG) && defined(RTE_LIBRTE_EAL_LINUXAPP)
 
 /**
- * Attach a new physical device.
- *
- * @param addr
- *   A pointer to a pci address structure describing the new
- *   device to be attached.
- * @param port_id
- *  A pointer to a port identifier actually attached.
- * @return
- *  0 on success and port_id is filled, negative on error
- */
-int rte_eal_dev_attach_pdev(struct rte_pci_addr *addr, uint8_t *port_id);
-
-/**
- * Attach a new virtual device.
- *
- * @param vdevargs
- *   A pointer to a strings array describing the new device
- *   to be attached.
- * @param port_id
- *  A pointer to a port identifier actually attached.
- * @return
- *  0 on success and port_id is filled, negative on error
- */
-int rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id);
-
-/**
- * Detach a physical device.
- *
- * @param port_id
- *   The port identifier of the physical device to detach.
- * @param addr
- *  A pointer to a pci address structure actually detached.
- * @return
- *  0 on success and addr is filled, negative on error
- */
-int rte_eal_dev_detach_pdev(uint8_t port_id, struct rte_pci_addr *addr);
-
-/**
- * Detach a virtual device.
- *
- * @param port_id
- *   The port identifier of the virtual device to detach.
- * @param addr
- *  A pointer to a virtual device name actually detached.
- * @return
- *  0 on success and vdevname is filled, negative on error
- */
-int rte_eal_dev_detach_vdev(uint8_t port_id, char *vdevname);
-
-/**
  * Attach a new device.
  *
  * @param devargs
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2 28/28] eal: Enable port hotplug framework in Linux
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (26 preceding siblings ...)
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 27/28] eal/pci: Remove rte_eal_dev_attach/detach_pdev() and rte_eal_dev_attach/detach_vdev() Tetsuya Mukawa
@ 2014-12-09  3:42     ` Tetsuya Mukawa
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:42 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch enables CONFIG_RTE_LIBRTE_EAL_HOTPLUG in Linux configuration.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 config/common_linuxapp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/config/common_linuxapp b/config/common_linuxapp
index 2f9643b..27d05be 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -114,6 +114,11 @@ CONFIG_RTE_PCI_MAX_READ_REQUEST_SIZE=0
 CONFIG_RTE_LIBRTE_EAL_LINUXAPP=y
 
 #
+# Compile Environment Abstraction Layer to support hotplug
+#
+CONFIG_RTE_LIBRTE_EAL_HOTPLUG=y
+
+#
 # Compile Environment Abstraction Layer to support Vmware TSC map
 #
 CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=y
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2] librte_pmd_pcap: Add port hotplug support
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (25 preceding siblings ...)
  2014-12-09  3:42   ` [dpdk-dev] [PATCH v2 00/28] Port Hotplug Framework Tetsuya Mukawa
@ 2014-12-09  3:44   ` Tetsuya Mukawa
  2014-12-09  3:45   ` [dpdk-dev] [PATCH v2] testpmd: " Tetsuya Mukawa
                     ` (3 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:44 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

This patch adds finalization code to free resources allocated by the
PMD.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_pmd_pcap/rte_eth_pcap.c | 40 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/lib/librte_pmd_pcap/rte_eth_pcap.c b/lib/librte_pmd_pcap/rte_eth_pcap.c
index 0f34f73..c92ebb7 100644
--- a/lib/librte_pmd_pcap/rte_eth_pcap.c
+++ b/lib/librte_pmd_pcap/rte_eth_pcap.c
@@ -499,6 +499,13 @@ static struct eth_dev_ops ops = {
 		.stats_reset = eth_stats_reset,
 };
 
+static struct eth_driver rte_pcap_pmd = {
+	.pci_drv = {
+		.name = "rte_pcap_pmd",
+		.drv_flags = RTE_PCI_DRV_DETACHABLE,
+	},
+};
+
 /*
  * Function handler that opens the pcap file for reading a stores a
  * reference of it for use it later on.
@@ -714,6 +721,10 @@ rte_pmd_init_internals(const char *name, const unsigned nb_rx_queues,
 	if (*eth_dev == NULL)
 		goto error;
 
+	/* check length of device name */
+	if ((strlen((*eth_dev)->data->name) + 1) > sizeof(data->name))
+		goto error;
+
 	/* now put it all together
 	 * - store queue data in internals,
 	 * - store numa_node info in pci_driver
@@ -739,10 +750,13 @@ rte_pmd_init_internals(const char *name, const unsigned nb_rx_queues,
 	data->nb_tx_queues = (uint16_t)nb_tx_queues;
 	data->dev_link = pmd_link;
 	data->mac_addrs = &eth_addr;
+	strncpy(data->name,
+		(*eth_dev)->data->name, strlen((*eth_dev)->data->name));
 
 	(*eth_dev)->data = data;
 	(*eth_dev)->dev_ops = &ops;
 	(*eth_dev)->pci_dev = pci_dev;
+	(*eth_dev)->driver = &rte_pcap_pmd;
 
 	return 0;
 
@@ -927,10 +941,36 @@ rte_pmd_pcap_devinit(const char *name, const char *params)
 
 }
 
+static int
+rte_pmd_pcap_devclose(const char *name, const char *params __rte_unused)
+{
+	struct rte_eth_dev *eth_dev = NULL;
+
+	RTE_LOG(INFO, PMD, "Closing pcap ethdev on numa socket %u\n",
+			rte_socket_id());
+
+	if (name == NULL)
+		return -1;
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocated(name);
+	if (eth_dev == NULL)
+		return -1;
+
+	rte_free(eth_dev->data->dev_private);
+	rte_free(eth_dev->data);
+	rte_free(eth_dev->pci_dev);
+
+	rte_eth_dev_free(name);
+
+	return 0;
+}
+
 static struct rte_driver pmd_pcap_drv = {
 	.name = "eth_pcap",
 	.type = PMD_VDEV,
 	.init = rte_pmd_pcap_devinit,
+	.close = rte_pmd_pcap_devclose,
 };
 
 PMD_REGISTER_DRIVER(pmd_pcap_drv);
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v2] testpmd: Add port hotplug support
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (26 preceding siblings ...)
  2014-12-09  3:44   ` [dpdk-dev] [PATCH v2] librte_pmd_pcap: Add port hotplug support Tetsuya Mukawa
@ 2014-12-09  3:45   ` Tetsuya Mukawa
  2014-12-09  6:30   ` [dpdk-dev] [PATCH v3 00/28] Port Hotplug Framework Tetsuya Mukawa
                     ` (2 subsequent siblings)
  30 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  3:45 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch introduces following commands.
- port attach [ident]
- port detach [port_id]
 - attach: attaching a port
 - detach: detaching a port
 - ident: pci address of physical device.
          Or device name and paramerters of virtual device.
         (ex. 0000:02:00.0, eth_pcap0,iface=eth0)
 - port_id: port identifier

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 app/test-pmd/cmdline.c    | 133 +++++++++++++++++++++++++------
 app/test-pmd/config.c     | 116 +++++++++++++++------------
 app/test-pmd/parameters.c |  21 +++--
 app/test-pmd/testpmd.c    | 199 +++++++++++++++++++++++++++++++++++-----------
 app/test-pmd/testpmd.h    |  18 ++++-
 5 files changed, 357 insertions(+), 130 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index f79ea3e..40c2db7 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -572,6 +572,12 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"port close (port_id|all)\n"
 			"    Close all ports or port_id.\n\n"
 
+			"port add (p|a) (ident)\n"
+			"    Add physical or virtual dev by pci address or virtual device name\n\n"
+
+			"port del (p|a) (port_id)\n"
+			"    Del physical or virtual dev by port_id\n\n"
+
 			"port config (port_id|all)"
 			" speed (10|100|1000|10000|40000|auto)"
 			" duplex (half|full|auto)\n"
@@ -853,6 +859,89 @@ cmdline_parse_inst_t cmd_operate_specific_port = {
 	},
 };
 
+/* *** attach a specificied port *** */
+struct cmd_operate_attach_port_result {
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t keyword;
+	cmdline_fixed_string_t identifier;
+};
+
+static void cmd_operate_attach_port_parsed(void *parsed_result,
+				__attribute__((unused)) struct cmdline *cl,
+				__attribute__((unused)) void *data)
+{
+	struct cmd_operate_attach_port_result *res = parsed_result;
+
+	if (!strcmp(res->keyword, "attach"))
+		attach_port(res->identifier);
+	else
+		printf("Unknown parameter\n");
+}
+
+cmdline_parse_token_string_t cmd_operate_attach_port_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_operate_attach_port_keyword =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,
+			keyword, "attach");
+cmdline_parse_token_string_t cmd_operate_attach_port_identifier =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,
+			identifier, NULL);
+
+cmdline_parse_inst_t cmd_operate_attach_port = {
+	.f = cmd_operate_attach_port_parsed,
+	.data = NULL,
+	.help_str = "port attach identifier, "
+		"identifier: pci address or virtual dev name",
+	.tokens = {
+		(void *)&cmd_operate_attach_port_port,
+		(void *)&cmd_operate_attach_port_keyword,
+		(void *)&cmd_operate_attach_port_identifier,
+		NULL,
+	},
+};
+
+/* *** detach a specificied port *** */
+struct cmd_operate_detach_port_result {
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t keyword;
+	uint8_t port_id;
+};
+
+static void cmd_operate_detach_port_parsed(void *parsed_result,
+				__attribute__((unused)) struct cmdline *cl,
+				__attribute__((unused)) void *data)
+{
+	struct cmd_operate_detach_port_result *res = parsed_result;
+
+	if (!strcmp(res->keyword, "detach"))
+		detach_port(res->port_id);
+	else
+		printf("Unknown parameter\n");
+}
+
+cmdline_parse_token_string_t cmd_operate_detach_port_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_port_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_operate_detach_port_keyword =
+	TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_port_result,
+			keyword, "detach");
+cmdline_parse_token_num_t cmd_operate_detach_port_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_operate_detach_port_result,
+			port_id, UINT8);
+
+cmdline_parse_inst_t cmd_operate_detach_port = {
+	.f = cmd_operate_detach_port_parsed,
+	.data = NULL,
+	.help_str = "port detach port_id",
+	.tokens = {
+		(void *)&cmd_operate_detach_port_port,
+		(void *)&cmd_operate_detach_port_keyword,
+		(void *)&cmd_operate_detach_port_port_id,
+		NULL,
+	},
+};
+
 /* *** configure speed for all ports *** */
 struct cmd_config_speed_all {
 	cmdline_fixed_string_t port;
@@ -907,7 +996,7 @@ cmd_config_speed_all_parsed(void *parsed_result,
 		return;
 	}
 
-	for (pid = 0; pid < nb_ports; pid++) {
+	FOREACH_PORT(pid, ports) {
 		ports[pid].dev_conf.link_speed = link_speed;
 		ports[pid].dev_conf.link_duplex = link_duplex;
 	}
@@ -975,10 +1064,8 @@ cmd_config_speed_specific_parsed(void *parsed_result,
 		return;
 	}
 
-	if (res->id >= nb_ports) {
-		printf("Port id %d must be less than %d\n", res->id, nb_ports);
+	if (port_id_is_invalid(res->id, ENABLED_WARN))
 		return;
-	}
 
 	if (!strcmp(res->value1, "10"))
 		link_speed = ETH_LINK_SPEED_10;
@@ -1538,7 +1625,7 @@ cmd_config_rxtx_queue_parsed(void *parsed_result,
 		return;
 	}
 
-	if (port_id_is_invalid(res->portid))
+	if (port_id_is_invalid(res->portid, ENABLED_WARN))
 		return;
 
 	if (port_is_started(res->portid) != 1) {
@@ -2881,7 +2968,7 @@ cmd_tx_cksum_parsed(void *parsed_result,
 	uint16_t ol_flags, mask = 0;
 	struct rte_eth_dev_info dev_info;
 
-	if (port_id_is_invalid(res->port_id)) {
+	if (port_id_is_invalid(res->port_id, ENABLED_WARN)) {
 		printf("invalid port %d\n", res->port_id);
 		return;
 	}
@@ -3008,7 +3095,7 @@ cmd_tso_set_parsed(void *parsed_result,
 	struct cmd_tso_set_result *res = parsed_result;
 	struct rte_eth_dev_info dev_info;
 
-	if (port_id_is_invalid(res->port_id))
+	if (port_id_is_invalid(res->port_id, ENABLED_WARN))
 		return;
 
 	if (!strcmp(res->mode, "set"))
@@ -3984,10 +4071,8 @@ static void cmd_set_bond_mac_addr_parsed(void *parsed_result,
 	struct cmd_set_bond_mac_addr_result *res = parsed_result;
 	int ret;
 
-	if (res->port_num >= nb_ports) {
-		printf("Port id %d must be less than %d\n", res->port_num, nb_ports);
+	if (port_id_is_invalid(res->port_num, ENABLED_WARN))
 		return;
-	}
 
 	ret = rte_eth_bond_mac_address_set(res->port_num, &res->address);
 
@@ -4224,7 +4309,7 @@ static void cmd_set_promisc_mode_parsed(void *parsed_result,
 
 	/* all ports */
 	if (allports) {
-		for (i = 0; i < nb_ports; i++) {
+		FOREACH_PORT(i, ports) {
 			if (enable)
 				rte_eth_promiscuous_enable(i);
 			else
@@ -4304,7 +4389,7 @@ static void cmd_set_allmulti_mode_parsed(void *parsed_result,
 
 	/* all ports */
 	if (allports) {
-		for (i = 0; i < nb_ports; i++) {
+		FOREACH_PORT(i, ports) {
 			if (enable)
 				rte_eth_allmulticast_enable(i);
 			else
@@ -5489,25 +5574,25 @@ static void cmd_showportall_parsed(void *parsed_result,
 	struct cmd_showportall_result *res = parsed_result;
 	if (!strcmp(res->show, "clear")) {
 		if (!strcmp(res->what, "stats"))
-			for (i = 0; i < nb_ports; i++)
+			FOREACH_PORT(i, ports)
 				nic_stats_clear(i);
 		else if (!strcmp(res->what, "xstats"))
-			for (i = 0; i < nb_ports; i++)
+			FOREACH_PORT(i, ports)
 				nic_xstats_clear(i);
 	} else if (!strcmp(res->what, "info"))
-		for (i = 0; i < nb_ports; i++)
+		FOREACH_PORT(i, ports)
 			port_infos_display(i);
 	else if (!strcmp(res->what, "stats"))
-		for (i = 0; i < nb_ports; i++)
+		FOREACH_PORT(i, ports)
 			nic_stats_display(i);
 	else if (!strcmp(res->what, "xstats"))
-		for (i = 0; i < nb_ports; i++)
+		FOREACH_PORT(i, ports)
 			nic_xstats_display(i);
 	else if (!strcmp(res->what, "fdir"))
-		for (i = 0; i < nb_ports; i++)
+		FOREACH_PORT(i, ports)
 			fdir_get_infos(i);
 	else if (!strcmp(res->what, "stat_qmap"))
-		for (i = 0; i < nb_ports; i++)
+		FOREACH_PORT(i, ports)
 			nic_stats_mapping_display(i);
 }
 
@@ -8783,6 +8868,8 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_set_qmap,
 	(cmdline_parse_inst_t *)&cmd_operate_port,
 	(cmdline_parse_inst_t *)&cmd_operate_specific_port,
+	(cmdline_parse_inst_t *)&cmd_operate_attach_port,
+	(cmdline_parse_inst_t *)&cmd_operate_detach_port,
 	(cmdline_parse_inst_t *)&cmd_config_speed_all,
 	(cmdline_parse_inst_t *)&cmd_config_speed_specific,
 	(cmdline_parse_inst_t *)&cmd_config_rx_tx,
@@ -8859,7 +8946,7 @@ prompt(void)
 static void
 cmd_reconfig_device_queue(portid_t id, uint8_t dev, uint8_t queue)
 {
-	if (id < nb_ports) {
+	if (!port_id_is_invalid(id, DISABLED_WARN)) {
 		/* check if need_reconfig has been set to 1 */
 		if (ports[id].need_reconfig == 0)
 			ports[id].need_reconfig = dev;
@@ -8869,7 +8956,7 @@ cmd_reconfig_device_queue(portid_t id, uint8_t dev, uint8_t queue)
 	} else {
 		portid_t pid;
 
-		for (pid = 0; pid < nb_ports; pid++) {
+		FOREACH_PORT(pid, ports) {
 			/* check if need_reconfig has been set to 1 */
 			if (ports[pid].need_reconfig == 0)
 				ports[pid].need_reconfig = dev;
@@ -8887,10 +8974,8 @@ bypass_is_supported(portid_t port_id)
 	struct rte_port   *port;
 	struct rte_pci_id *pci_id;
 
-	if (port_id >= nb_ports) {
-		printf("\tPort id must be less than %d.\n", nb_ports);
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return 0;
-	}
 
 	/* Get the device id. */
 	port    = &ports[port_id];
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index 69a83c2..c68cc18 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -124,11 +124,15 @@ nic_stats_display(portid_t port_id)
 	struct rte_eth_stats stats;
 	struct rte_port *port = &ports[port_id];
 	uint8_t i;
+	portid_t pid;
 
 	static const char *nic_stats_border = "########################";
 
-	if (port_id >= nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+	if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+		printf("Valid port range is [0");
+		FOREACH_PORT(pid, ports)
+			printf(", %d", pid);
+		printf("]\n");
 		return;
 	}
 	rte_eth_stats_get(port_id, &stats);
@@ -201,8 +205,13 @@ nic_stats_display(portid_t port_id)
 void
 nic_stats_clear(portid_t port_id)
 {
-	if (port_id >= nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+	portid_t pid;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+		printf("Valid port range is [0");
+		FOREACH_PORT(pid, ports)
+			printf(", %d", pid);
+		printf("]\n");
 		return;
 	}
 	rte_eth_stats_reset(port_id);
@@ -249,11 +258,15 @@ nic_stats_mapping_display(portid_t port_id)
 {
 	struct rte_port *port = &ports[port_id];
 	uint16_t i;
+	portid_t pid;
 
 	static const char *nic_stats_mapping_border = "########################";
 
-	if (port_id >= nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+	if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+		printf("Valid port range is [0");
+		FOREACH_PORT(pid, ports)
+			printf(", %d", pid);
+		printf("]\n");
 		return;
 	}
 
@@ -302,9 +315,13 @@ port_infos_display(portid_t port_id)
 	int vlan_offload;
 	struct rte_mempool * mp;
 	static const char *info_border = "*********************";
+	portid_t pid;
 
-	if (port_id >= nb_ports) {
-		printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+	if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+		printf("Valid port range is [0");
+		FOREACH_PORT(pid, ports)
+			printf(", %d", pid);
+		printf("]\n");
 		return;
 	}
 	port = &ports[port_id];
@@ -362,11 +379,14 @@ port_infos_display(portid_t port_id)
 }
 
 int
-port_id_is_invalid(portid_t port_id)
+port_id_is_invalid(portid_t port_id, enum print_warning warning)
 {
-	if (port_id < nb_ports)
+	if (ports[port_id].enabled)
 		return 0;
-	printf("Invalid port %d (must be < nb_ports=%d)\n", port_id, nb_ports);
+
+	if (warning == ENABLED_WARN)
+		printf("Invalid port %d\n", port_id);
+
 	return 1;
 }
 
@@ -425,7 +445,7 @@ port_reg_bit_display(portid_t port_id, uint32_t reg_off, uint8_t bit_x)
 	uint32_t reg_v;
 
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 	if (port_reg_off_is_invalid(port_id, reg_off))
 		return;
@@ -444,7 +464,7 @@ port_reg_bit_field_display(portid_t port_id, uint32_t reg_off,
 	uint8_t  l_bit;
 	uint8_t  h_bit;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 	if (port_reg_off_is_invalid(port_id, reg_off))
 		return;
@@ -471,7 +491,7 @@ port_reg_display(portid_t port_id, uint32_t reg_off)
 {
 	uint32_t reg_v;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 	if (port_reg_off_is_invalid(port_id, reg_off))
 		return;
@@ -485,7 +505,7 @@ port_reg_bit_set(portid_t port_id, uint32_t reg_off, uint8_t bit_pos,
 {
 	uint32_t reg_v;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 	if (port_reg_off_is_invalid(port_id, reg_off))
 		return;
@@ -513,7 +533,7 @@ port_reg_bit_field_set(portid_t port_id, uint32_t reg_off,
 	uint8_t  l_bit;
 	uint8_t  h_bit;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 	if (port_reg_off_is_invalid(port_id, reg_off))
 		return;
@@ -547,7 +567,7 @@ port_reg_bit_field_set(portid_t port_id, uint32_t reg_off,
 void
 port_reg_set(portid_t port_id, uint32_t reg_off, uint32_t reg_v)
 {
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 	if (port_reg_off_is_invalid(port_id, reg_off))
 		return;
@@ -560,7 +580,7 @@ port_mtu_set(portid_t port_id, uint16_t mtu)
 {
 	int diag;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 	diag = rte_eth_dev_set_mtu(port_id, mtu);
 	if (diag == 0)
@@ -723,7 +743,7 @@ rx_ring_desc_display(portid_t port_id, queueid_t rxq_id, uint16_t rxd_id)
 {
 	const struct rte_memzone *rx_mz;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 	if (rx_queue_id_is_invalid(rxq_id))
 		return;
@@ -740,7 +760,7 @@ tx_ring_desc_display(portid_t port_id, queueid_t txq_id, uint16_t txd_id)
 {
 	const struct rte_memzone *tx_mz;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 	if (tx_queue_id_is_invalid(txq_id))
 		return;
@@ -796,7 +816,7 @@ port_rss_reta_info(portid_t port_id,
 	uint16_t i, idx, shift;
 	int ret;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 
 	ret = rte_eth_dev_rss_reta_query(port_id, reta_conf, nb_entries);
@@ -828,7 +848,7 @@ port_rss_hash_conf_show(portid_t port_id, int show_rss_key)
 	uint8_t i;
 	int diag;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 	/* Get RSS hash key if asked to display it */
 	rss_conf.rss_key = (show_rss_key) ? rss_key : NULL;
@@ -1406,12 +1426,8 @@ set_fwd_ports_list(unsigned int *portlist, unsigned int nb_pt)
  again:
 	for (i = 0; i < nb_pt; i++) {
 		port_id = (portid_t) portlist[i];
-		if (port_id >= nb_ports) {
-			printf("Invalid port id %u >= %u\n",
-			       (unsigned int) port_id,
-			       (unsigned int) nb_ports);
+		if (port_id_is_invalid(port_id, ENABLED_WARN))
 			return;
-		}
 		if (record_now)
 			fwd_ports_ids[i] = port_id;
 	}
@@ -1569,7 +1585,7 @@ vlan_extend_set(portid_t port_id, int on)
 	int diag;
 	int vlan_offload;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 
 	vlan_offload = rte_eth_dev_get_vlan_offload(port_id);
@@ -1591,7 +1607,7 @@ rx_vlan_strip_set(portid_t port_id, int on)
 	int diag;
 	int vlan_offload;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 
 	vlan_offload = rte_eth_dev_get_vlan_offload(port_id);
@@ -1612,7 +1628,7 @@ rx_vlan_strip_set_on_queue(portid_t port_id, uint16_t queue_id, int on)
 {
 	int diag;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 
 	diag = rte_eth_dev_set_vlan_strip_on_queue(port_id, queue_id, on);
@@ -1627,7 +1643,7 @@ rx_vlan_filter_set(portid_t port_id, int on)
 	int diag;
 	int vlan_offload;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 
 	vlan_offload = rte_eth_dev_get_vlan_offload(port_id);
@@ -1648,7 +1664,7 @@ rx_vft_set(portid_t port_id, uint16_t vlan_id, int on)
 {
 	int diag;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 	if (vlan_id_is_invalid(vlan_id))
 		return;
@@ -1665,7 +1681,7 @@ rx_vlan_all_filter_set(portid_t port_id, int on)
 {
 	uint16_t vlan_id;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 	for (vlan_id = 0; vlan_id < 4096; vlan_id++)
 		rx_vft_set(port_id, vlan_id, on);
@@ -1675,7 +1691,7 @@ void
 vlan_tpid_set(portid_t port_id, uint16_t tp_id)
 {
 	int diag;
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 
 	diag = rte_eth_dev_set_vlan_ether_type(port_id, tp_id);
@@ -1690,7 +1706,7 @@ vlan_tpid_set(portid_t port_id, uint16_t tp_id)
 void
 tx_vlan_set(portid_t port_id, uint16_t vlan_id)
 {
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 	if (vlan_id_is_invalid(vlan_id))
 		return;
@@ -1701,7 +1717,7 @@ tx_vlan_set(portid_t port_id, uint16_t vlan_id)
 void
 tx_vlan_reset(portid_t port_id)
 {
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 	ports[port_id].tx_ol_flags &= ~TESTPMD_TX_OFFLOAD_INSERT_VLAN;
 }
@@ -1709,7 +1725,7 @@ tx_vlan_reset(portid_t port_id)
 void
 tx_vlan_pvid_set(portid_t port_id, uint16_t vlan_id, int on)
 {
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 
 	rte_eth_dev_set_vlan_pvid(port_id, vlan_id, on);
@@ -1721,7 +1737,7 @@ set_qmap(portid_t port_id, uint8_t is_rx, uint16_t queue_id, uint8_t map_value)
 	uint16_t i;
 	uint8_t existing_mapping_found = 0;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 
 	if (is_rx ? (rx_queue_id_is_invalid(queue_id)) : (tx_queue_id_is_invalid(queue_id)))
@@ -1773,7 +1789,7 @@ fdir_add_signature_filter(portid_t port_id, uint8_t queue_id,
 {
 	int diag;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 
 	diag = rte_eth_dev_fdir_add_signature_filter(port_id, fdir_filter,
@@ -1791,7 +1807,7 @@ fdir_update_signature_filter(portid_t port_id, uint8_t queue_id,
 {
 	int diag;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 
 	diag = rte_eth_dev_fdir_update_signature_filter(port_id, fdir_filter,
@@ -1809,7 +1825,7 @@ fdir_remove_signature_filter(portid_t port_id,
 {
 	int diag;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 
 	diag = rte_eth_dev_fdir_remove_signature_filter(port_id, fdir_filter);
@@ -1881,7 +1897,7 @@ fdir_get_infos(portid_t port_id)
 
 	static const char *fdir_stats_border = "########################";
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 	ret = rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_FDIR);
 	if (ret < 0) {
@@ -1955,7 +1971,7 @@ fdir_add_perfect_filter(portid_t port_id, uint16_t soft_id, uint8_t queue_id,
 {
 	int diag;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 
 	diag = rte_eth_dev_fdir_add_perfect_filter(port_id, fdir_filter,
@@ -1973,7 +1989,7 @@ fdir_update_perfect_filter(portid_t port_id, uint16_t soft_id, uint8_t queue_id,
 {
 	int diag;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 
 	diag = rte_eth_dev_fdir_update_perfect_filter(port_id, fdir_filter,
@@ -1991,7 +2007,7 @@ fdir_remove_perfect_filter(portid_t port_id, uint16_t soft_id,
 {
 	int diag;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 
 	diag = rte_eth_dev_fdir_remove_perfect_filter(port_id, fdir_filter,
@@ -2008,7 +2024,7 @@ fdir_set_masks(portid_t port_id, struct rte_fdir_masks *fdir_masks)
 {
 	int diag;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 
 	diag = rte_eth_dev_fdir_set_masks(port_id, fdir_masks);
@@ -2085,7 +2101,7 @@ set_vf_traffic(portid_t port_id, uint8_t is_rx, uint16_t vf, uint8_t on)
 {
 	int diag;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 	if (is_rx)
 		diag = rte_eth_dev_set_vf_rx(port_id,vf,on);
@@ -2107,7 +2123,7 @@ set_vf_rx_vlan(portid_t port_id, uint16_t vlan_id, uint64_t vf_mask, uint8_t on)
 {
 	int diag;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 	if (vlan_id_is_invalid(vlan_id))
 		return;
@@ -2124,7 +2140,7 @@ set_queue_rate_limit(portid_t port_id, uint16_t queue_idx, uint16_t rate)
 	int diag;
 	struct rte_eth_link link;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return 1;
 	rte_eth_link_get_nowait(port_id, &link);
 	if (rate > link.link_speed) {
@@ -2149,7 +2165,7 @@ set_vf_rate_limit(portid_t port_id, uint16_t vf, uint16_t rate, uint64_t q_msk)
 	if (q_msk == 0)
 		return 0;
 
-	if (port_id_is_invalid(port_id))
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return 1;
 	rte_eth_link_get_nowait(port_id, &link);
 	if (rate > link.link_speed) {
diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
index fcb2c99..8175635 100644
--- a/app/test-pmd/parameters.c
+++ b/app/test-pmd/parameters.c
@@ -376,6 +376,7 @@ parse_portnuma_config(const char *q_arg)
 	};
 	unsigned long int_fld[_NUM_FLD];
 	char *str_fld[_NUM_FLD];
+	portid_t pid;
 
 	/* reset from value set at definition */
 	while ((p = strchr(p0,'(')) != NULL) {
@@ -397,8 +398,11 @@ parse_portnuma_config(const char *q_arg)
 				return -1;
 		}
 		port_id = (uint8_t)int_fld[FLD_PORT];
-		if (port_id >= nb_ports) {
-			printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+		if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+			printf("Valid port range is [0");
+			FOREACH_PORT(pid, ports)
+				printf(", %d", pid);
+			printf("]\n");
 			return -1;
 		}
 		socket_id = (uint8_t)int_fld[FLD_SOCKET];
@@ -429,6 +433,7 @@ parse_ringnuma_config(const char *q_arg)
 	};
 	unsigned long int_fld[_NUM_FLD];
 	char *str_fld[_NUM_FLD];
+	portid_t pid;
 	#define RX_RING_ONLY 0x1
 	#define TX_RING_ONLY 0x2
 	#define RXTX_RING    0x3
@@ -453,8 +458,11 @@ parse_ringnuma_config(const char *q_arg)
 				return -1;
 		}
 		port_id = (uint8_t)int_fld[FLD_PORT];
-		if (port_id >= nb_ports) {
-			printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+		if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+			printf("Valid port range is [0");
+			FOREACH_PORT(pid, ports)
+				printf(", %d", pid);
+			printf("]\n");
 			return -1;
 		}
 		socket_id = (uint8_t)int_fld[FLD_SOCKET];
@@ -672,12 +680,11 @@ launch_args_parse(int argc, char** argv)
 #endif
 			if (!strcmp(lgopts[opt_idx].name, "nb-ports")) {
 				n = atoi(optarg);
-				if (n > 0 && n <= nb_ports)
+				if (n > 0 && !port_id_is_invalid(n, DISABLED_WARN))
 					nb_fwd_ports = (uint8_t) n;
 				else
 					rte_exit(EXIT_FAILURE,
-						 "nb-ports should be > 0 and <= %d\n",
-						 nb_ports);
+						 "Invalid port %d\n", n);
 			}
 			if (!strcmp(lgopts[opt_idx].name, "nb-cores")) {
 				n = atoi(optarg);
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 8c69756..00d2292 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -71,6 +71,7 @@
 #include <rte_pci.h>
 #include <rte_ether.h>
 #include <rte_ethdev.h>
+#include <rte_dev.h>
 #include <rte_string_fns.h>
 #ifdef RTE_LIBRTE_PMD_XENVIRT
 #include <rte_eth_xenvirt.h>
@@ -315,7 +316,7 @@ uint16_t nb_rx_queue_stats_mappings = 0;
 
 /* Forward function declarations */
 static void map_port_queue_stats_mapping_registers(uint8_t pi, struct rte_port *port);
-static void check_all_ports_link_status(uint8_t port_num, uint32_t port_mask);
+static void check_all_ports_link_status(uint32_t port_mask);
 
 /*
  * Check if all the ports are started.
@@ -324,6 +325,20 @@ static void check_all_ports_link_status(uint8_t port_num, uint32_t port_mask);
 static int all_ports_started(void);
 
 /*
+ * Find next enabled port
+ */
+portid_t
+find_next_port(portid_t p, struct rte_port *ports, int size)
+{
+	if (ports == NULL)
+		rte_exit(-EINVAL, "failed to find a next port id\n");
+
+	while ((ports[p].enabled == 0) && (p < size))
+		p++;
+	return p;
+}
+
+/*
  * Setup default configuration.
  */
 static void
@@ -552,7 +567,8 @@ init_config(void)
 				+ RTE_TEST_TX_DESC_MAX + MAX_PKT_BURST;
 
 		if (!numa_support)
-			nb_mbuf_per_pool = (nb_mbuf_per_pool * nb_ports);
+			nb_mbuf_per_pool =
+				(nb_mbuf_per_pool * RTE_MAX_ETHPORTS);
 	}
 
 	if (!numa_support) {
@@ -565,14 +581,19 @@ init_config(void)
 
 	/* Configuration of Ethernet ports. */
 	ports = rte_zmalloc("testpmd: ports",
-			    sizeof(struct rte_port) * nb_ports,
+			    sizeof(struct rte_port) * RTE_MAX_ETHPORTS,
 			    RTE_CACHE_LINE_SIZE);
 	if (ports == NULL) {
-		rte_exit(EXIT_FAILURE, "rte_zmalloc(%d struct rte_port) "
-							"failed\n", nb_ports);
+		rte_exit(EXIT_FAILURE,
+				"rte_zmalloc(%d struct rte_port) failed\n",
+				RTE_MAX_ETHPORTS);
 	}
 
-	for (pid = 0; pid < nb_ports; pid++) {
+	/* enabled allocated ports */
+	for (pid = 0; pid < nb_ports; pid++)
+		ports[pid].enabled = 1;
+
+	FOREACH_PORT(pid, ports) {
 		port = &ports[pid];
 		rte_eth_dev_info_get(pid, &port->dev_info);
 
@@ -602,8 +623,7 @@ init_config(void)
 			nb_mbuf_per_pool = nb_mbuf_per_pool/nb_ports;
 
 		for (i = 0; i < MAX_SOCKET; i++) {
-			nb_mbuf = (nb_mbuf_per_pool *
-						port_per_socket[i]);
+			nb_mbuf = (nb_mbuf_per_pool * RTE_MAX_ETHPORTS);
 			if (nb_mbuf)
 				mbuf_pool_create(mbuf_data_size,
 						nb_mbuf,i);
@@ -635,14 +655,6 @@ reconfig(portid_t new_port_id, unsigned socket_id)
 	struct rte_port *port;
 
 	/* Reconfiguration of Ethernet ports. */
-	ports = rte_realloc(ports,
-			    sizeof(struct rte_port) * nb_ports,
-			    RTE_CACHE_LINE_SIZE);
-	if (ports == NULL) {
-		rte_exit(EXIT_FAILURE, "rte_realloc(%d struct rte_port) failed\n",
-				nb_ports);
-	}
-
 	port = &ports[new_port_id];
 	rte_eth_dev_info_get(new_port_id, &port->dev_info);
 
@@ -663,7 +675,7 @@ init_fwd_streams(void)
 	streamid_t sm_id, nb_fwd_streams_new;
 
 	/* set socket id according to numa or not */
-	for (pid = 0; pid < nb_ports; pid++) {
+	FOREACH_PORT(pid, ports) {
 		port = &ports[pid];
 		if (nb_rxq > port->dev_info.max_rx_queues) {
 			printf("Fail: nb_rxq(%d) is greater than "
@@ -1264,7 +1276,7 @@ all_ports_started(void)
 	portid_t pi;
 	struct rte_port *port;
 
-	for (pi = 0; pi < nb_ports; pi++) {
+	FOREACH_PORT(pi, ports) {
 		port = &ports[pi];
 		/* Check if there is a port which is not started */
 		if (port->port_status != RTE_PORT_STARTED)
@@ -1276,6 +1288,45 @@ all_ports_started(void)
 }
 
 int
+all_ports_stopped(void)
+{
+	portid_t pi;
+	struct rte_port *port;
+
+	FOREACH_PORT(pi, ports) {
+		port = &ports[pi];
+		if (port->port_status != RTE_PORT_STOPPED)
+			return 0;
+	}
+
+	return 1;
+}
+
+int
+port_is_started(portid_t port_id)
+{
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return 0;
+
+	if (ports[port_id].port_status != RTE_PORT_STARTED)
+		return 0;
+
+	return 1;
+}
+
+static int
+port_is_closed(portid_t port_id)
+{
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return 0;
+
+	if (ports[port_id].port_status != RTE_PORT_CLOSED)
+		return 0;
+
+	return 1;
+}
+
+int
 start_port(portid_t pid)
 {
 	int diag, need_check_link_status = 0;
@@ -1296,8 +1347,8 @@ start_port(portid_t pid)
 
 	if(dcb_config)
 		dcb_test = 1;
-	for (pi = 0; pi < nb_ports; pi++) {
-		if (pid < nb_ports && pid != pi)
+	FOREACH_PORT(pi, ports) {
+		if (!port_id_is_invalid(pid, DISABLED_WARN) && pid != pi)
 			continue;
 
 		port = &ports[pi];
@@ -1421,7 +1472,7 @@ start_port(portid_t pid)
 	}
 
 	if (need_check_link_status && !no_link_check)
-		check_all_ports_link_status(nb_ports, RTE_PORT_ALL);
+		check_all_ports_link_status(RTE_PORT_ALL);
 	else
 		printf("Please stop the ports first\n");
 
@@ -1446,8 +1497,8 @@ stop_port(portid_t pid)
 	}
 	printf("Stopping ports...\n");
 
-	for (pi = 0; pi < nb_ports; pi++) {
-		if (pid < nb_ports && pid != pi)
+	FOREACH_PORT(pi, ports) {
+		if (!port_id_is_invalid(pid, DISABLED_WARN) && pid != pi)
 			continue;
 
 		port = &ports[pi];
@@ -1463,7 +1514,7 @@ stop_port(portid_t pid)
 		need_check_link_status = 1;
 	}
 	if (need_check_link_status && !no_link_check)
-		check_all_ports_link_status(nb_ports, RTE_PORT_ALL);
+		check_all_ports_link_status(RTE_PORT_ALL);
 
 	printf("Done\n");
 }
@@ -1481,8 +1532,8 @@ close_port(portid_t pid)
 
 	printf("Closing ports...\n");
 
-	for (pi = 0; pi < nb_ports; pi++) {
-		if (pid < nb_ports && pid != pi)
+	FOREACH_PORT(pi, ports) {
+		if (!port_id_is_invalid(pid, DISABLED_WARN) && pid != pi)
 			continue;
 
 		port = &ports[pi];
@@ -1502,31 +1553,83 @@ close_port(portid_t pid)
 	printf("Done\n");
 }
 
-int
-all_ports_stopped(void)
+void
+attach_port(char *identifier)
 {
-	portid_t pi;
-	struct rte_port *port;
+	portid_t i, j, pi = 0;
 
-	for (pi = 0; pi < nb_ports; pi++) {
-		port = &ports[pi];
-		if (port->port_status != RTE_PORT_STOPPED)
-			return 0;
+	printf("Attaching a new port...\n");
+
+	if (identifier == NULL) {
+		printf("Invalid parameters are speficied\n");
+		return;
 	}
 
-	return 1;
+	if (test_done == 0) {
+		printf("Please stop forwarding first\n");
+		return;
+	}
+
+	if (rte_eal_dev_attach(identifier, &pi))
+		return;
+
+	ports[pi].enabled = 1;
+	reconfig(pi, rte_eth_dev_socket_id(pi));
+	rte_eth_promiscuous_enable(pi);
+
+	nb_ports = rte_eth_dev_count();
+
+	/* set_default_fwd_ports_config(); */
+	bzero(fwd_ports_ids, sizeof(fwd_ports_ids));
+	i = 0;
+	FOREACH_PORT(j, ports) {
+		fwd_ports_ids[i] = j;
+		i++;
+	}
+	nb_cfg_ports = nb_ports;
+	nb_fwd_ports++;
+
+	ports[pi].port_status = RTE_PORT_STOPPED;
+
+	printf("Port %d is attached. Now total ports is %d\n", pi, nb_ports);
+	printf("Done\n");
 }
 
-int
-port_is_started(portid_t port_id)
+void
+detach_port(uint8_t port_id)
 {
-	if (port_id_is_invalid(port_id))
-		return -1;
+	portid_t i, pi = 0;
+	char name[RTE_ETH_NAME_MAX_LEN];
 
-	if (ports[port_id].port_status != RTE_PORT_STARTED)
-		return 0;
+	printf("Detaching a port...\n");
 
-	return 1;
+	if (!port_is_closed(port_id)) {
+		printf("Please close port first\n");
+		return;
+	}
+
+	rte_eth_promiscuous_disable(port_id);
+
+	if (rte_eal_dev_detach(port_id, name))
+		return;
+
+	ports[port_id].enabled = 0;
+	nb_ports = rte_eth_dev_count();
+
+	/* set_default_fwd_ports_config(); */
+	bzero(fwd_ports_ids, sizeof(fwd_ports_ids));
+	i = 0;
+	FOREACH_PORT(pi, ports) {
+		fwd_ports_ids[i] = pi;
+		i++;
+	}
+	nb_cfg_ports = nb_ports;
+	nb_fwd_ports--;
+
+	printf("Port '%s' is detached. Now total ports is %d\n",
+			name, nb_ports);
+	printf("Done\n");
+	return;
 }
 
 void
@@ -1534,7 +1637,7 @@ pmd_test_exit(void)
 {
 	portid_t pt_id;
 
-	for (pt_id = 0; pt_id < nb_ports; pt_id++) {
+	FOREACH_PORT(pt_id, ports) {
 		printf("Stopping port %d...", pt_id);
 		fflush(stdout);
 		rte_eth_dev_close(pt_id);
@@ -1553,7 +1656,7 @@ struct pmd_test_command {
 
 /* Check the link status of all ports in up to 9s, and print them finally */
 static void
-check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+check_all_ports_link_status(uint32_t port_mask)
 {
 #define CHECK_INTERVAL 100 /* 100ms */
 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
@@ -1564,7 +1667,7 @@ check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
 	fflush(stdout);
 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
 		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
+		FOREACH_PORT(portid, ports) {
 			if ((port_mask & (1 << portid)) == 0)
 				continue;
 			memset(&link, 0, sizeof(link));
@@ -1688,7 +1791,7 @@ init_port_config(void)
 	portid_t pid;
 	struct rte_port *port;
 
-	for (pid = 0; pid < nb_ports; pid++) {
+	FOREACH_PORT(pid, ports) {
 		port = &ports[pid];
 		port->dev_conf.rxmode = rx_mode;
 		port->dev_conf.fdir_conf = fdir_conf;
@@ -1867,7 +1970,7 @@ main(int argc, char** argv)
 
 	nb_ports = (portid_t) rte_eth_dev_count();
 	if (nb_ports == 0)
-		rte_exit(EXIT_FAILURE, "No probed ethernet device\n");
+		RTE_LOG(WARNING, EAL, "No probed ethernet devices\n");
 
 	set_def_fwd_config();
 	if (nb_lcores == 0)
@@ -1889,7 +1992,7 @@ main(int argc, char** argv)
 		rte_exit(EXIT_FAILURE, "Start ports failed\n");
 
 	/* set all ports to promiscuous mode by default */
-	for (port_id = 0; port_id < nb_ports; port_id++)
+	FOREACH_PORT(port_id, ports)
 		rte_eth_promiscuous_enable(port_id);
 
 #ifdef RTE_LIBRTE_CMDLINE
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index f8b0740..50ab134 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -134,6 +134,7 @@ struct fwd_stream {
  * The data structure associated with each port.
  */
 struct rte_port {
+	uint8_t                 enabled;    /**< Port enabled or not */
 	struct rte_eth_dev_info dev_info;   /**< PCI info + driver name */
 	struct rte_eth_conf     dev_conf;   /**< Port configuration. */
 	struct ether_addr       eth_addr;   /**< Port ethernet address */
@@ -159,6 +160,14 @@ struct rte_port {
 	struct rte_eth_txconf   tx_conf;    /**< tx configuration */
 };
 
+extern portid_t __rte_unused
+find_next_port(portid_t p, struct rte_port *ports, int size);
+
+#define FOREACH_PORT(p, ports) \
+	for (p = find_next_port(0, ports, RTE_MAX_ETHPORTS); \
+	    p < RTE_MAX_ETHPORTS; \
+	    p = find_next_port(p + 1, ports, RTE_MAX_ETHPORTS))
+
 /**
  * The data structure associated with each forwarding logical core.
  * The logical cores are internally numbered by a core index from 0 to
@@ -512,6 +521,8 @@ int init_port_dcb_config(portid_t pid,struct dcb_config *dcb_conf);
 int start_port(portid_t pid);
 void stop_port(portid_t pid);
 void close_port(portid_t pid);
+void attach_port(char *identifier);
+void detach_port(uint8_t port_id);
 int all_ports_stopped(void);
 int port_is_started(portid_t port_id);
 void pmd_test_exit(void);
@@ -555,10 +566,15 @@ void get_ethertype_filter(uint8_t port_id, uint16_t index);
 void get_2tuple_filter(uint8_t port_id, uint16_t index);
 void get_5tuple_filter(uint8_t port_id, uint16_t index);
 void get_flex_filter(uint8_t port_id, uint16_t index);
-int port_id_is_invalid(portid_t port_id);
 int rx_queue_id_is_invalid(queueid_t rxq_id);
 int tx_queue_id_is_invalid(queueid_t txq_id);
 
+enum print_warning {
+	ENABLED_WARN = 0,
+	DISABLED_WARN
+};
+int port_id_is_invalid(portid_t port_id, enum print_warning warning);
+
 /*
  * Work-around of a compilation error with ICC on invocations of the
  * rte_be_to_cpu_16() function.
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [dpdk-dev] [PATCH v2 02/28] ethdev: Remove assumption that port will not be detached
  2014-12-09  3:42     ` [dpdk-dev] [PATCH v2 02/28] ethdev: Remove assumption that port will not be detached Tetsuya Mukawa
@ 2014-12-09  5:07       ` Zhang, Helin
  2014-12-09  6:06         ` Tetsuya Mukawa
  0 siblings, 1 reply; 176+ messages in thread
From: Zhang, Helin @ 2014-12-09  5:07 UTC (permalink / raw)
  To: Tetsuya Mukawa, dev; +Cc: nakajima.yoshihiro, masutani.hitoshi, menrigh



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tetsuya Mukawa
> Sent: Tuesday, December 9, 2014 11:42 AM
> To: dev@dpdk.org
> Cc: nakajima.yoshihiro@lab.ntt.co.jp; menrigh@brocade.com;
> masutani.hitoshi@lab.ntt.co.jp
> Subject: [dpdk-dev] [PATCH v2 02/28] ethdev: Remove assumption that port will
> not be detached
> 
> To remove assumption, do like followings.
> 
> - Add 'attached' member to rte_eth_dev structure.
>   This member is used for indicating the port is attached, or not.
> - Add rte_eth_dev_allocate_new_port().
>   This function is used for allocating new port.
> 
> Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
> ---
>  lib/librte_ether/rte_ethdev.c | 248 ++++++++++++++++++++++++------------------
>  lib/librte_ether/rte_ethdev.h |   5 +
>  2 files changed, 149 insertions(+), 104 deletions(-)
> 
> diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c index
> 95f2ceb..9f713ae 100644
> --- a/lib/librte_ether/rte_ethdev.c
> +++ b/lib/librte_ether/rte_ethdev.c
> @@ -175,6 +175,16 @@ enum {
>  	STAT_QMAP_RX
>  };
> 
> +enum {
> +	DEV_VALID = 0,
> +	DEV_INVALID
> +};
Would it be safer to define DEV_INVALID = 0, then DEV_VALID after it?
Or even as below?
Enum {
	DEV_UNKNOWN = 0,
	DEV_VALID,
	DEV_INVALID
};

Regards,
Helin

> +
> +enum {
> +	DEV_DISCONNECTED = 0,
> +	DEV_CONNECTED
> +};
> +
>  static inline void
>  rte_eth_dev_data_alloc(void)
>  {
> @@ -201,19 +211,34 @@ rte_eth_dev_allocated(const char *name)  {
>  	unsigned i;
> 
> -	for (i = 0; i < nb_ports; i++) {
> -		if (strcmp(rte_eth_devices[i].data->name, name) == 0)
> +	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
> +		if ((rte_eth_devices[i].attached == DEV_CONNECTED)
> +				&& strcmp(rte_eth_devices[i].data->name,
> +					name) == 0)
>  			return &rte_eth_devices[i];
>  	}
>  	return NULL;
>  }
> 
> +static uint8_t
> +rte_eth_dev_allocate_new_port(void)
> +{
> +	unsigned i;
> +
> +	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
> +		if (rte_eth_devices[i].attached == DEV_DISCONNECTED)
> +			return i;
> +	return RTE_MAX_ETHPORTS;
> +}
> +
>  struct rte_eth_dev *
>  rte_eth_dev_allocate(const char *name)
>  {
> +	uint8_t port_id;
>  	struct rte_eth_dev *eth_dev;
> 
> -	if (nb_ports == RTE_MAX_ETHPORTS) {
> +	port_id = rte_eth_dev_allocate_new_port();
> +	if (port_id == RTE_MAX_ETHPORTS) {
>  		PMD_DEBUG_TRACE("Reached maximum number of Ethernet
> ports\n");
>  		return NULL;
>  	}
> @@ -226,10 +251,12 @@ rte_eth_dev_allocate(const char *name)
>  		return NULL;
>  	}
> 
> -	eth_dev = &rte_eth_devices[nb_ports];
> -	eth_dev->data = &rte_eth_dev_data[nb_ports];
> +	eth_dev = &rte_eth_devices[port_id];
> +	eth_dev->data = &rte_eth_dev_data[port_id];
>  	snprintf(eth_dev->data->name, sizeof(eth_dev->data->name), "%s",
> name);
> -	eth_dev->data->port_id = nb_ports++;
> +	eth_dev->data->port_id = port_id;
> +	eth_dev->attached = DEV_CONNECTED;
> +	nb_ports++;
>  	return eth_dev;
>  }
> 
> @@ -283,6 +310,7 @@ rte_eth_dev_init(struct rte_pci_driver *pci_drv,
>  			(unsigned) pci_dev->id.device_id);
>  	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
>  		rte_free(eth_dev->data->dev_private);
> +	eth_dev->attached = DEV_DISCONNECTED;
>  	nb_ports--;
>  	return diag;
>  }
> @@ -308,10 +336,22 @@ rte_eth_driver_register(struct eth_driver *eth_drv)
>  	rte_eal_pci_register(&eth_drv->pci_drv);
>  }
> 
> +static int
> +rte_eth_dev_validate_port(uint8_t port_id) {
> +	if (port_id >= RTE_MAX_ETHPORTS)
> +		return DEV_INVALID;
> +
> +	if (rte_eth_devices[port_id].attached == DEV_CONNECTED)
> +		return DEV_VALID;
> +	else
> +		return DEV_INVALID;
> +}
> +
>  int
>  rte_eth_dev_socket_id(uint8_t port_id)
>  {
> -	if (port_id >= nb_ports)
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID)
>  		return -1;
>  	return rte_eth_devices[port_id].pci_dev->numa_node;
>  }
> @@ -369,7 +409,7 @@ rte_eth_dev_rx_queue_start(uint8_t port_id, uint16_t
> rx_queue_id)
>  	 * in a multi-process setup*/
>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -EINVAL;
>  	}
> @@ -395,7 +435,7 @@ rte_eth_dev_rx_queue_stop(uint8_t port_id, uint16_t
> rx_queue_id)
>  	 * in a multi-process setup*/
>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -EINVAL;
>  	}
> @@ -421,7 +461,7 @@ rte_eth_dev_tx_queue_start(uint8_t port_id, uint16_t
> tx_queue_id)
>  	 * in a multi-process setup*/
>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -EINVAL;
>  	}
> @@ -447,7 +487,7 @@ rte_eth_dev_tx_queue_stop(uint8_t port_id, uint16_t
> tx_queue_id)
>  	 * in a multi-process setup*/
>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -EINVAL;
>  	}
> @@ -662,7 +702,7 @@ rte_eth_dev_configure(uint8_t port_id, uint16_t
> nb_rx_q, uint16_t nb_tx_q,
>  	 * in a multi-process setup*/
>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
> 
> -	if (port_id >= nb_ports || port_id >= RTE_MAX_ETHPORTS) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-EINVAL);
>  	}
> @@ -847,7 +887,7 @@ rte_eth_dev_start(uint8_t port_id)
>  	 * in a multi-process setup*/
>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%" PRIu8 "\n", port_id);
>  		return (-EINVAL);
>  	}
> @@ -882,7 +922,7 @@ rte_eth_dev_stop(uint8_t port_id)
>  	 * in a multi-process setup*/
>  	PROC_PRIMARY_OR_RET();
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%" PRIu8 "\n", port_id);
>  		return;
>  	}
> @@ -910,7 +950,7 @@ rte_eth_dev_set_link_up(uint8_t port_id)
>  	 * in a multi-process setup*/
>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -EINVAL;
>  	}
> @@ -929,7 +969,7 @@ rte_eth_dev_set_link_down(uint8_t port_id)
>  	 * in a multi-process setup*/
>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -EINVAL;
>  	}
> @@ -948,7 +988,7 @@ rte_eth_dev_close(uint8_t port_id)
>  	 * in a multi-process setup*/
>  	PROC_PRIMARY_OR_RET();
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return;
>  	}
> @@ -976,7 +1016,7 @@ rte_eth_rx_queue_setup(uint8_t port_id, uint16_t
> rx_queue_id,
>  	 * in a multi-process setup*/
>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-EINVAL);
>  	}
> @@ -1049,7 +1089,7 @@ rte_eth_tx_queue_setup(uint8_t port_id, uint16_t
> tx_queue_id,
>  	 * in a multi-process setup*/
>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
> 
> -	if (port_id >= RTE_MAX_ETHPORTS || port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-EINVAL);
>  	}
> @@ -1082,7 +1122,7 @@ rte_eth_promiscuous_enable(uint8_t port_id)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return;
>  	}
> @@ -1098,7 +1138,7 @@ rte_eth_promiscuous_disable(uint8_t port_id)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return;
>  	}
> @@ -1114,7 +1154,7 @@ rte_eth_promiscuous_get(uint8_t port_id)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -1;
>  	}
> @@ -1128,7 +1168,7 @@ rte_eth_allmulticast_enable(uint8_t port_id)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return;
>  	}
> @@ -1144,7 +1184,7 @@ rte_eth_allmulticast_disable(uint8_t port_id)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return;
>  	}
> @@ -1160,7 +1200,7 @@ rte_eth_allmulticast_get(uint8_t port_id)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -1;
>  	}
> @@ -1188,7 +1228,7 @@ rte_eth_link_get(uint8_t port_id, struct
> rte_eth_link *eth_link)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return;
>  	}
> @@ -1208,7 +1248,7 @@ rte_eth_link_get_nowait(uint8_t port_id, struct
> rte_eth_link *eth_link)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return;
>  	}
> @@ -1228,7 +1268,7 @@ rte_eth_stats_get(uint8_t port_id, struct
> rte_eth_stats *stats)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return;
>  	}
> @@ -1245,7 +1285,7 @@ rte_eth_stats_reset(uint8_t port_id)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return;
>  	}
> @@ -1266,7 +1306,7 @@ rte_eth_xstats_get(uint8_t port_id, struct
> rte_eth_xstats *xstats,
>  	uint64_t val;
>  	char *stats_ptr;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -1;
>  	}
> @@ -1335,7 +1375,7 @@ rte_eth_xstats_reset(uint8_t port_id)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return;
>  	}
> @@ -1357,7 +1397,7 @@ set_queue_stats_mapping(uint8_t port_id, uint16_t
> queue_id, uint8_t stat_idx,  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -1392,7 +1432,7 @@ rte_eth_dev_info_get(uint8_t port_id, struct
> rte_eth_dev_info *dev_info)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return;
>  	}
> @@ -1412,7 +1452,7 @@ rte_eth_macaddr_get(uint8_t port_id, struct
> ether_addr *mac_addr)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return;
>  	}
> @@ -1426,7 +1466,7 @@ rte_eth_dev_get_mtu(uint8_t port_id, uint16_t
> *mtu)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -1442,7 +1482,7 @@ rte_eth_dev_set_mtu(uint8_t port_id, uint16_t
> mtu)
>  	int ret;
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -1462,7 +1502,7 @@ rte_eth_dev_vlan_filter(uint8_t port_id, uint16_t
> vlan_id, int on)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -1487,7 +1527,7 @@ rte_eth_dev_set_vlan_strip_on_queue(uint8_t
> port_id, uint16_t rx_queue_id, int o  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -1509,7 +1549,7 @@ rte_eth_dev_set_vlan_ether_type(uint8_t port_id,
> uint16_t tpid)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -1529,7 +1569,7 @@ rte_eth_dev_set_vlan_offload(uint8_t port_id, int
> offload_mask)
>  	int mask = 0;
>  	int cur, org = 0;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -1574,7 +1614,7 @@ rte_eth_dev_get_vlan_offload(uint8_t port_id)
>  	struct rte_eth_dev *dev;
>  	int ret = 0;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -1598,7 +1638,7 @@ rte_eth_dev_set_vlan_pvid(uint8_t port_id,
> uint16_t pvid, int on)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -1616,7 +1656,7 @@ rte_eth_dev_fdir_add_signature_filter(uint8_t
> port_id,  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -1650,7 +1690,7 @@ rte_eth_dev_fdir_update_signature_filter(uint8_t
> port_id,  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -1684,7 +1724,7 @@ rte_eth_dev_fdir_remove_signature_filter(uint8_t
> port_id,  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -1715,7 +1755,7 @@ rte_eth_dev_fdir_get_infos(uint8_t port_id, struct
> rte_eth_fdir *fdir)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -1740,7 +1780,7 @@ rte_eth_dev_fdir_add_perfect_filter(uint8_t port_id,
> {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -1780,7 +1820,7 @@ rte_eth_dev_fdir_update_perfect_filter(uint8_t
> port_id,  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -1818,7 +1858,7 @@ rte_eth_dev_fdir_remove_perfect_filter(uint8_t
> port_id,  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -1854,7 +1894,7 @@ rte_eth_dev_fdir_set_masks(uint8_t port_id, struct
> rte_fdir_masks *fdir_mask)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -1874,7 +1914,7 @@ rte_eth_dev_flow_ctrl_get(uint8_t port_id, struct
> rte_eth_fc_conf *fc_conf)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -1890,7 +1930,7 @@ rte_eth_dev_flow_ctrl_set(uint8_t port_id, struct
> rte_eth_fc_conf *fc_conf)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -1910,7 +1950,7 @@ rte_eth_dev_priority_flow_ctrl_set(uint8_t port_id,
> struct rte_eth_pfc_conf *pfc  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2019,7 +2059,7 @@ rte_eth_dev_rss_reta_query(uint8_t port_id,
>  	struct rte_eth_dev *dev;
>  	int ret;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -2040,7 +2080,7 @@ rte_eth_dev_rss_hash_update(uint8_t port_id,
> struct rte_eth_rss_conf *rss_conf)
>  	struct rte_eth_dev *dev;
>  	uint16_t rss_hash_protos;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2062,7 +2102,7 @@ rte_eth_dev_rss_hash_conf_get(uint8_t port_id,  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2077,7 +2117,7 @@ rte_eth_dev_udp_tunnel_add(uint8_t port_id,  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -2103,7 +2143,7 @@ rte_eth_dev_udp_tunnel_delete(uint8_t port_id,  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -2128,7 +2168,7 @@ rte_eth_led_on(uint8_t port_id)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2143,7 +2183,7 @@ rte_eth_led_off(uint8_t port_id)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2183,7 +2223,7 @@ rte_eth_dev_mac_addr_add(uint8_t port_id, struct
> ether_addr *addr,
>  	int index;
>  	uint64_t pool_mask;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2234,7 +2274,7 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id,
> struct ether_addr *addr)
>  	struct rte_eth_dev *dev;
>  	int index;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2268,7 +2308,7 @@ rte_eth_dev_set_vf_rxmode(uint8_t port_id,
> uint16_t vf,
>  	struct rte_eth_dev *dev;
>  	struct rte_eth_dev_info dev_info;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("set VF RX mode:Invalid port_id=%d\n",
>  				port_id);
>  		return (-ENODEV);
> @@ -2323,7 +2363,7 @@ rte_eth_dev_uc_hash_table_set(uint8_t port_id,
> struct ether_addr *addr,
>  	int ret;
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("unicast hash setting:Invalid port_id=%d\n",
>  			port_id);
>  		return (-ENODEV);
> @@ -2376,7 +2416,7 @@ rte_eth_dev_uc_all_hash_table_set(uint8_t port_id,
> uint8_t on)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("unicast hash setting:Invalid port_id=%d\n",
>  			port_id);
>  		return (-ENODEV);
> @@ -2395,7 +2435,7 @@ rte_eth_dev_set_vf_rx(uint8_t port_id,uint16_t vf,
> uint8_t on)
>  	struct rte_eth_dev *dev;
>  	struct rte_eth_dev_info dev_info;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2421,7 +2461,7 @@ rte_eth_dev_set_vf_tx(uint8_t port_id,uint16_t vf,
> uint8_t on)
>  	struct rte_eth_dev *dev;
>  	struct rte_eth_dev_info dev_info;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("set pool tx:Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2446,7 +2486,7 @@ rte_eth_dev_set_vf_vlan_filter(uint8_t port_id,
> uint16_t vlan_id,  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("VF VLAN filter:invalid port id=%d\n",
>  				port_id);
>  		return (-ENODEV);
> @@ -2477,7 +2517,7 @@ int rte_eth_set_queue_rate_limit(uint8_t port_id,
> uint16_t queue_idx,
>  	struct rte_eth_dev_info dev_info;
>  	struct rte_eth_link link;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("set queue rate limit:invalid port id=%d\n",
>  				port_id);
>  		return -ENODEV;
> @@ -2514,7 +2554,7 @@ int rte_eth_set_vf_rate_limit(uint8_t port_id,
> uint16_t vf, uint16_t tx_rate,
>  	if (q_msk == 0)
>  		return 0;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("set VF rate limit:invalid port id=%d\n",
>  				port_id);
>  		return -ENODEV;
> @@ -2548,7 +2588,7 @@ rte_eth_mirror_rule_set(uint8_t port_id,  {
>  	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2589,7 +2629,7 @@ rte_eth_mirror_rule_reset(uint8_t port_id, uint8_t
> rule_id)  {
>  	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2614,7 +2654,7 @@ rte_eth_rx_burst(uint8_t port_id, uint16_t
> queue_id,  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return 0;
>  	}
> @@ -2634,7 +2674,7 @@ rte_eth_tx_burst(uint8_t port_id, uint16_t
> queue_id,  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return 0;
>  	}
> @@ -2654,7 +2694,7 @@ rte_eth_rx_queue_count(uint8_t port_id, uint16_t
> queue_id)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return 0;
>  	}
> @@ -2668,7 +2708,7 @@ rte_eth_rx_descriptor_done(uint8_t port_id,
> uint16_t queue_id, uint16_t offset)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2689,7 +2729,7 @@ rte_eth_dev_callback_register(uint8_t port_id,
> 
>  	if (!cb_fn)
>  		return (-EINVAL);
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-EINVAL);
>  	}
> @@ -2729,7 +2769,7 @@ rte_eth_dev_callback_unregister(uint8_t port_id,
> 
>  	if (!cb_fn)
>  		return (-EINVAL);
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-EINVAL);
>  	}
> @@ -2789,7 +2829,7 @@ int rte_eth_dev_bypass_init(uint8_t port_id)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2809,7 +2849,7 @@ rte_eth_dev_bypass_state_show(uint8_t port_id,
> uint32_t *state)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2828,7 +2868,7 @@ rte_eth_dev_bypass_state_set(uint8_t port_id,
> uint32_t *new_state)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2848,7 +2888,7 @@ rte_eth_dev_bypass_event_show(uint8_t port_id,
> uint32_t event, uint32_t *state)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2868,7 +2908,7 @@ rte_eth_dev_bypass_event_store(uint8_t port_id,
> uint32_t event, uint32_t state)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2888,7 +2928,7 @@ rte_eth_dev_wd_timeout_store(uint8_t port_id,
> uint32_t timeout)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2908,7 +2948,7 @@ rte_eth_dev_bypass_ver_show(uint8_t port_id,
> uint32_t *ver)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2928,7 +2968,7 @@ rte_eth_dev_bypass_wd_timeout_show(uint8_t
> port_id, uint32_t *wd_timeout)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2948,7 +2988,7 @@ rte_eth_dev_bypass_wd_reset(uint8_t port_id)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return (-ENODEV);
>  	}
> @@ -2970,7 +3010,7 @@ rte_eth_dev_add_syn_filter(uint8_t port_id,  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -2985,7 +3025,7 @@ rte_eth_dev_remove_syn_filter(uint8_t port_id)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -3004,7 +3044,7 @@ rte_eth_dev_get_syn_filter(uint8_t port_id,
>  	if (filter == NULL || rx_queue == NULL)
>  		return -EINVAL;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -3020,7 +3060,7 @@ rte_eth_dev_add_ethertype_filter(uint8_t port_id,
> uint16_t index,  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -3041,7 +3081,7 @@ rte_eth_dev_remove_ethertype_filter(uint8_t
> port_id,  uint16_t index)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -3060,7 +3100,7 @@ rte_eth_dev_get_ethertype_filter(uint8_t port_id,
> uint16_t index,
>  	if (filter == NULL || rx_queue == NULL)
>  		return -EINVAL;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -3077,7 +3117,7 @@ rte_eth_dev_add_2tuple_filter(uint8_t port_id,
> uint16_t index,  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -3099,7 +3139,7 @@ rte_eth_dev_remove_2tuple_filter(uint8_t port_id,
> uint16_t index)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -3118,7 +3158,7 @@ rte_eth_dev_get_2tuple_filter(uint8_t port_id,
> uint16_t index,
>  	if (filter == NULL || rx_queue == NULL)
>  		return -EINVAL;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -3134,7 +3174,7 @@ rte_eth_dev_add_5tuple_filter(uint8_t port_id,
> uint16_t index,  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -3157,7 +3197,7 @@ rte_eth_dev_remove_5tuple_filter(uint8_t port_id,
> uint16_t index)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -3176,7 +3216,7 @@ rte_eth_dev_get_5tuple_filter(uint8_t port_id,
> uint16_t index,
>  	if (filter == NULL || rx_queue == NULL)
>  		return -EINVAL;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -3193,7 +3233,7 @@ rte_eth_dev_add_flex_filter(uint8_t port_id,
> uint16_t index,  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -3208,7 +3248,7 @@ rte_eth_dev_remove_flex_filter(uint8_t port_id,
> uint16_t index)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -3227,7 +3267,7 @@ rte_eth_dev_get_flex_filter(uint8_t port_id,
> uint16_t index,
>  	if (filter == NULL || rx_queue == NULL)
>  		return -EINVAL;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -3243,7 +3283,7 @@ rte_eth_dev_filter_supported(uint8_t port_id,
> enum rte_filter_type filter_type)  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> @@ -3260,7 +3300,7 @@ rte_eth_dev_filter_ctrl(uint8_t port_id, enum
> rte_filter_type filter_type,  {
>  	struct rte_eth_dev *dev;
> 
> -	if (port_id >= nb_ports) {
> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>  		return -ENODEV;
>  	}
> diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h index
> f66805d..257de86 100644
> --- a/lib/librte_ether/rte_ethdev.h
> +++ b/lib/librte_ether/rte_ethdev.h
> @@ -1565,6 +1565,7 @@ struct rte_eth_dev {
>  	struct eth_dev_ops *dev_ops;    /**< Functions exported by PMD */
>  	struct rte_pci_device *pci_dev; /**< PCI info. supplied by probing */
>  	struct rte_eth_dev_cb_list callbacks; /**< User application callbacks */
> +	uint8_t attached; /**< Flag indicating the port is attached */
>  };
> 
>  struct rte_eth_dev_sriov {
> @@ -1630,6 +1631,10 @@ extern struct rte_eth_dev rte_eth_devices[];
>   * initialized by the [matching] Ethernet driver during the PCI probing phase.
>   * All devices whose port identifier is in the range
>   * [0,  rte_eth_dev_count() - 1] can be operated on by network applications.
> + * immediately after invoking rte_eal_init().
> + * If the application unplugs a port using hotplug function, The
> + enabled port
> + * numbers may be noncontiguous. In the case, the applications need to
> + manage
> + * enabled port by themselves.
>   *
>   * @return
>   *   - The total number of usable Ethernet devices.
> --
> 1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* Re: [dpdk-dev] [PATCH v2 02/28] ethdev: Remove assumption that port will not be detached
  2014-12-09  5:07       ` Zhang, Helin
@ 2014-12-09  6:06         ` Tetsuya Mukawa
  0 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  6:06 UTC (permalink / raw)
  To: Zhang, Helin, dev; +Cc: nakajima.yoshihiro, masutani.hitoshi, menrigh

Hi Zhang,

Thanks to your comment.
I will submit again soon.

Thanks,
Tetsuya

(2014/12/09 14:07), Zhang, Helin wrote:
>
>> -----Original Message-----
>> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tetsuya Mukawa
>> Sent: Tuesday, December 9, 2014 11:42 AM
>> To: dev@dpdk.org
>> Cc: nakajima.yoshihiro@lab.ntt.co.jp; menrigh@brocade.com;
>> masutani.hitoshi@lab.ntt.co.jp
>> Subject: [dpdk-dev] [PATCH v2 02/28] ethdev: Remove assumption that port will
>> not be detached
>>
>> To remove assumption, do like followings.
>>
>> - Add 'attached' member to rte_eth_dev structure.
>>   This member is used for indicating the port is attached, or not.
>> - Add rte_eth_dev_allocate_new_port().
>>   This function is used for allocating new port.
>>
>> Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
>> ---
>>  lib/librte_ether/rte_ethdev.c | 248 ++++++++++++++++++++++++------------------
>>  lib/librte_ether/rte_ethdev.h |   5 +
>>  2 files changed, 149 insertions(+), 104 deletions(-)
>>
>> diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c index
>> 95f2ceb..9f713ae 100644
>> --- a/lib/librte_ether/rte_ethdev.c
>> +++ b/lib/librte_ether/rte_ethdev.c
>> @@ -175,6 +175,16 @@ enum {
>>  	STAT_QMAP_RX
>>  };
>>
>> +enum {
>> +	DEV_VALID = 0,
>> +	DEV_INVALID
>> +};
> Would it be safer to define DEV_INVALID = 0, then DEV_VALID after it?
> Or even as below?
> Enum {
> 	DEV_UNKNOWN = 0,
> 	DEV_VALID,
> 	DEV_INVALID
> };
>
> Regards,
> Helin
>
>> +
>> +enum {
>> +	DEV_DISCONNECTED = 0,
>> +	DEV_CONNECTED
>> +};
>> +
>>  static inline void
>>  rte_eth_dev_data_alloc(void)
>>  {
>> @@ -201,19 +211,34 @@ rte_eth_dev_allocated(const char *name)  {
>>  	unsigned i;
>>
>> -	for (i = 0; i < nb_ports; i++) {
>> -		if (strcmp(rte_eth_devices[i].data->name, name) == 0)
>> +	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
>> +		if ((rte_eth_devices[i].attached == DEV_CONNECTED)
>> +				&& strcmp(rte_eth_devices[i].data->name,
>> +					name) == 0)
>>  			return &rte_eth_devices[i];
>>  	}
>>  	return NULL;
>>  }
>>
>> +static uint8_t
>> +rte_eth_dev_allocate_new_port(void)
>> +{
>> +	unsigned i;
>> +
>> +	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
>> +		if (rte_eth_devices[i].attached == DEV_DISCONNECTED)
>> +			return i;
>> +	return RTE_MAX_ETHPORTS;
>> +}
>> +
>>  struct rte_eth_dev *
>>  rte_eth_dev_allocate(const char *name)
>>  {
>> +	uint8_t port_id;
>>  	struct rte_eth_dev *eth_dev;
>>
>> -	if (nb_ports == RTE_MAX_ETHPORTS) {
>> +	port_id = rte_eth_dev_allocate_new_port();
>> +	if (port_id == RTE_MAX_ETHPORTS) {
>>  		PMD_DEBUG_TRACE("Reached maximum number of Ethernet
>> ports\n");
>>  		return NULL;
>>  	}
>> @@ -226,10 +251,12 @@ rte_eth_dev_allocate(const char *name)
>>  		return NULL;
>>  	}
>>
>> -	eth_dev = &rte_eth_devices[nb_ports];
>> -	eth_dev->data = &rte_eth_dev_data[nb_ports];
>> +	eth_dev = &rte_eth_devices[port_id];
>> +	eth_dev->data = &rte_eth_dev_data[port_id];
>>  	snprintf(eth_dev->data->name, sizeof(eth_dev->data->name), "%s",
>> name);
>> -	eth_dev->data->port_id = nb_ports++;
>> +	eth_dev->data->port_id = port_id;
>> +	eth_dev->attached = DEV_CONNECTED;
>> +	nb_ports++;
>>  	return eth_dev;
>>  }
>>
>> @@ -283,6 +310,7 @@ rte_eth_dev_init(struct rte_pci_driver *pci_drv,
>>  			(unsigned) pci_dev->id.device_id);
>>  	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
>>  		rte_free(eth_dev->data->dev_private);
>> +	eth_dev->attached = DEV_DISCONNECTED;
>>  	nb_ports--;
>>  	return diag;
>>  }
>> @@ -308,10 +336,22 @@ rte_eth_driver_register(struct eth_driver *eth_drv)
>>  	rte_eal_pci_register(&eth_drv->pci_drv);
>>  }
>>
>> +static int
>> +rte_eth_dev_validate_port(uint8_t port_id) {
>> +	if (port_id >= RTE_MAX_ETHPORTS)
>> +		return DEV_INVALID;
>> +
>> +	if (rte_eth_devices[port_id].attached == DEV_CONNECTED)
>> +		return DEV_VALID;
>> +	else
>> +		return DEV_INVALID;
>> +}
>> +
>>  int
>>  rte_eth_dev_socket_id(uint8_t port_id)
>>  {
>> -	if (port_id >= nb_ports)
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID)
>>  		return -1;
>>  	return rte_eth_devices[port_id].pci_dev->numa_node;
>>  }
>> @@ -369,7 +409,7 @@ rte_eth_dev_rx_queue_start(uint8_t port_id, uint16_t
>> rx_queue_id)
>>  	 * in a multi-process setup*/
>>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -EINVAL;
>>  	}
>> @@ -395,7 +435,7 @@ rte_eth_dev_rx_queue_stop(uint8_t port_id, uint16_t
>> rx_queue_id)
>>  	 * in a multi-process setup*/
>>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -EINVAL;
>>  	}
>> @@ -421,7 +461,7 @@ rte_eth_dev_tx_queue_start(uint8_t port_id, uint16_t
>> tx_queue_id)
>>  	 * in a multi-process setup*/
>>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -EINVAL;
>>  	}
>> @@ -447,7 +487,7 @@ rte_eth_dev_tx_queue_stop(uint8_t port_id, uint16_t
>> tx_queue_id)
>>  	 * in a multi-process setup*/
>>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -EINVAL;
>>  	}
>> @@ -662,7 +702,7 @@ rte_eth_dev_configure(uint8_t port_id, uint16_t
>> nb_rx_q, uint16_t nb_tx_q,
>>  	 * in a multi-process setup*/
>>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
>>
>> -	if (port_id >= nb_ports || port_id >= RTE_MAX_ETHPORTS) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-EINVAL);
>>  	}
>> @@ -847,7 +887,7 @@ rte_eth_dev_start(uint8_t port_id)
>>  	 * in a multi-process setup*/
>>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%" PRIu8 "\n", port_id);
>>  		return (-EINVAL);
>>  	}
>> @@ -882,7 +922,7 @@ rte_eth_dev_stop(uint8_t port_id)
>>  	 * in a multi-process setup*/
>>  	PROC_PRIMARY_OR_RET();
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%" PRIu8 "\n", port_id);
>>  		return;
>>  	}
>> @@ -910,7 +950,7 @@ rte_eth_dev_set_link_up(uint8_t port_id)
>>  	 * in a multi-process setup*/
>>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -EINVAL;
>>  	}
>> @@ -929,7 +969,7 @@ rte_eth_dev_set_link_down(uint8_t port_id)
>>  	 * in a multi-process setup*/
>>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -EINVAL;
>>  	}
>> @@ -948,7 +988,7 @@ rte_eth_dev_close(uint8_t port_id)
>>  	 * in a multi-process setup*/
>>  	PROC_PRIMARY_OR_RET();
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return;
>>  	}
>> @@ -976,7 +1016,7 @@ rte_eth_rx_queue_setup(uint8_t port_id, uint16_t
>> rx_queue_id,
>>  	 * in a multi-process setup*/
>>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-EINVAL);
>>  	}
>> @@ -1049,7 +1089,7 @@ rte_eth_tx_queue_setup(uint8_t port_id, uint16_t
>> tx_queue_id,
>>  	 * in a multi-process setup*/
>>  	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
>>
>> -	if (port_id >= RTE_MAX_ETHPORTS || port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-EINVAL);
>>  	}
>> @@ -1082,7 +1122,7 @@ rte_eth_promiscuous_enable(uint8_t port_id)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return;
>>  	}
>> @@ -1098,7 +1138,7 @@ rte_eth_promiscuous_disable(uint8_t port_id)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return;
>>  	}
>> @@ -1114,7 +1154,7 @@ rte_eth_promiscuous_get(uint8_t port_id)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -1;
>>  	}
>> @@ -1128,7 +1168,7 @@ rte_eth_allmulticast_enable(uint8_t port_id)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return;
>>  	}
>> @@ -1144,7 +1184,7 @@ rte_eth_allmulticast_disable(uint8_t port_id)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return;
>>  	}
>> @@ -1160,7 +1200,7 @@ rte_eth_allmulticast_get(uint8_t port_id)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -1;
>>  	}
>> @@ -1188,7 +1228,7 @@ rte_eth_link_get(uint8_t port_id, struct
>> rte_eth_link *eth_link)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return;
>>  	}
>> @@ -1208,7 +1248,7 @@ rte_eth_link_get_nowait(uint8_t port_id, struct
>> rte_eth_link *eth_link)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return;
>>  	}
>> @@ -1228,7 +1268,7 @@ rte_eth_stats_get(uint8_t port_id, struct
>> rte_eth_stats *stats)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return;
>>  	}
>> @@ -1245,7 +1285,7 @@ rte_eth_stats_reset(uint8_t port_id)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return;
>>  	}
>> @@ -1266,7 +1306,7 @@ rte_eth_xstats_get(uint8_t port_id, struct
>> rte_eth_xstats *xstats,
>>  	uint64_t val;
>>  	char *stats_ptr;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -1;
>>  	}
>> @@ -1335,7 +1375,7 @@ rte_eth_xstats_reset(uint8_t port_id)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return;
>>  	}
>> @@ -1357,7 +1397,7 @@ set_queue_stats_mapping(uint8_t port_id, uint16_t
>> queue_id, uint8_t stat_idx,  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -1392,7 +1432,7 @@ rte_eth_dev_info_get(uint8_t port_id, struct
>> rte_eth_dev_info *dev_info)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return;
>>  	}
>> @@ -1412,7 +1452,7 @@ rte_eth_macaddr_get(uint8_t port_id, struct
>> ether_addr *mac_addr)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return;
>>  	}
>> @@ -1426,7 +1466,7 @@ rte_eth_dev_get_mtu(uint8_t port_id, uint16_t
>> *mtu)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -1442,7 +1482,7 @@ rte_eth_dev_set_mtu(uint8_t port_id, uint16_t
>> mtu)
>>  	int ret;
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -1462,7 +1502,7 @@ rte_eth_dev_vlan_filter(uint8_t port_id, uint16_t
>> vlan_id, int on)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -1487,7 +1527,7 @@ rte_eth_dev_set_vlan_strip_on_queue(uint8_t
>> port_id, uint16_t rx_queue_id, int o  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -1509,7 +1549,7 @@ rte_eth_dev_set_vlan_ether_type(uint8_t port_id,
>> uint16_t tpid)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -1529,7 +1569,7 @@ rte_eth_dev_set_vlan_offload(uint8_t port_id, int
>> offload_mask)
>>  	int mask = 0;
>>  	int cur, org = 0;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -1574,7 +1614,7 @@ rte_eth_dev_get_vlan_offload(uint8_t port_id)
>>  	struct rte_eth_dev *dev;
>>  	int ret = 0;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -1598,7 +1638,7 @@ rte_eth_dev_set_vlan_pvid(uint8_t port_id,
>> uint16_t pvid, int on)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -1616,7 +1656,7 @@ rte_eth_dev_fdir_add_signature_filter(uint8_t
>> port_id,  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -1650,7 +1690,7 @@ rte_eth_dev_fdir_update_signature_filter(uint8_t
>> port_id,  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -1684,7 +1724,7 @@ rte_eth_dev_fdir_remove_signature_filter(uint8_t
>> port_id,  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -1715,7 +1755,7 @@ rte_eth_dev_fdir_get_infos(uint8_t port_id, struct
>> rte_eth_fdir *fdir)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -1740,7 +1780,7 @@ rte_eth_dev_fdir_add_perfect_filter(uint8_t port_id,
>> {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -1780,7 +1820,7 @@ rte_eth_dev_fdir_update_perfect_filter(uint8_t
>> port_id,  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -1818,7 +1858,7 @@ rte_eth_dev_fdir_remove_perfect_filter(uint8_t
>> port_id,  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -1854,7 +1894,7 @@ rte_eth_dev_fdir_set_masks(uint8_t port_id, struct
>> rte_fdir_masks *fdir_mask)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -1874,7 +1914,7 @@ rte_eth_dev_flow_ctrl_get(uint8_t port_id, struct
>> rte_eth_fc_conf *fc_conf)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -1890,7 +1930,7 @@ rte_eth_dev_flow_ctrl_set(uint8_t port_id, struct
>> rte_eth_fc_conf *fc_conf)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -1910,7 +1950,7 @@ rte_eth_dev_priority_flow_ctrl_set(uint8_t port_id,
>> struct rte_eth_pfc_conf *pfc  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2019,7 +2059,7 @@ rte_eth_dev_rss_reta_query(uint8_t port_id,
>>  	struct rte_eth_dev *dev;
>>  	int ret;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -2040,7 +2080,7 @@ rte_eth_dev_rss_hash_update(uint8_t port_id,
>> struct rte_eth_rss_conf *rss_conf)
>>  	struct rte_eth_dev *dev;
>>  	uint16_t rss_hash_protos;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2062,7 +2102,7 @@ rte_eth_dev_rss_hash_conf_get(uint8_t port_id,  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2077,7 +2117,7 @@ rte_eth_dev_udp_tunnel_add(uint8_t port_id,  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -2103,7 +2143,7 @@ rte_eth_dev_udp_tunnel_delete(uint8_t port_id,  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -2128,7 +2168,7 @@ rte_eth_led_on(uint8_t port_id)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2143,7 +2183,7 @@ rte_eth_led_off(uint8_t port_id)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2183,7 +2223,7 @@ rte_eth_dev_mac_addr_add(uint8_t port_id, struct
>> ether_addr *addr,
>>  	int index;
>>  	uint64_t pool_mask;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2234,7 +2274,7 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id,
>> struct ether_addr *addr)
>>  	struct rte_eth_dev *dev;
>>  	int index;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2268,7 +2308,7 @@ rte_eth_dev_set_vf_rxmode(uint8_t port_id,
>> uint16_t vf,
>>  	struct rte_eth_dev *dev;
>>  	struct rte_eth_dev_info dev_info;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("set VF RX mode:Invalid port_id=%d\n",
>>  				port_id);
>>  		return (-ENODEV);
>> @@ -2323,7 +2363,7 @@ rte_eth_dev_uc_hash_table_set(uint8_t port_id,
>> struct ether_addr *addr,
>>  	int ret;
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("unicast hash setting:Invalid port_id=%d\n",
>>  			port_id);
>>  		return (-ENODEV);
>> @@ -2376,7 +2416,7 @@ rte_eth_dev_uc_all_hash_table_set(uint8_t port_id,
>> uint8_t on)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("unicast hash setting:Invalid port_id=%d\n",
>>  			port_id);
>>  		return (-ENODEV);
>> @@ -2395,7 +2435,7 @@ rte_eth_dev_set_vf_rx(uint8_t port_id,uint16_t vf,
>> uint8_t on)
>>  	struct rte_eth_dev *dev;
>>  	struct rte_eth_dev_info dev_info;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2421,7 +2461,7 @@ rte_eth_dev_set_vf_tx(uint8_t port_id,uint16_t vf,
>> uint8_t on)
>>  	struct rte_eth_dev *dev;
>>  	struct rte_eth_dev_info dev_info;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("set pool tx:Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2446,7 +2486,7 @@ rte_eth_dev_set_vf_vlan_filter(uint8_t port_id,
>> uint16_t vlan_id,  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("VF VLAN filter:invalid port id=%d\n",
>>  				port_id);
>>  		return (-ENODEV);
>> @@ -2477,7 +2517,7 @@ int rte_eth_set_queue_rate_limit(uint8_t port_id,
>> uint16_t queue_idx,
>>  	struct rte_eth_dev_info dev_info;
>>  	struct rte_eth_link link;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("set queue rate limit:invalid port id=%d\n",
>>  				port_id);
>>  		return -ENODEV;
>> @@ -2514,7 +2554,7 @@ int rte_eth_set_vf_rate_limit(uint8_t port_id,
>> uint16_t vf, uint16_t tx_rate,
>>  	if (q_msk == 0)
>>  		return 0;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("set VF rate limit:invalid port id=%d\n",
>>  				port_id);
>>  		return -ENODEV;
>> @@ -2548,7 +2588,7 @@ rte_eth_mirror_rule_set(uint8_t port_id,  {
>>  	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2589,7 +2629,7 @@ rte_eth_mirror_rule_reset(uint8_t port_id, uint8_t
>> rule_id)  {
>>  	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2614,7 +2654,7 @@ rte_eth_rx_burst(uint8_t port_id, uint16_t
>> queue_id,  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return 0;
>>  	}
>> @@ -2634,7 +2674,7 @@ rte_eth_tx_burst(uint8_t port_id, uint16_t
>> queue_id,  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return 0;
>>  	}
>> @@ -2654,7 +2694,7 @@ rte_eth_rx_queue_count(uint8_t port_id, uint16_t
>> queue_id)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return 0;
>>  	}
>> @@ -2668,7 +2708,7 @@ rte_eth_rx_descriptor_done(uint8_t port_id,
>> uint16_t queue_id, uint16_t offset)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2689,7 +2729,7 @@ rte_eth_dev_callback_register(uint8_t port_id,
>>
>>  	if (!cb_fn)
>>  		return (-EINVAL);
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-EINVAL);
>>  	}
>> @@ -2729,7 +2769,7 @@ rte_eth_dev_callback_unregister(uint8_t port_id,
>>
>>  	if (!cb_fn)
>>  		return (-EINVAL);
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-EINVAL);
>>  	}
>> @@ -2789,7 +2829,7 @@ int rte_eth_dev_bypass_init(uint8_t port_id)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2809,7 +2849,7 @@ rte_eth_dev_bypass_state_show(uint8_t port_id,
>> uint32_t *state)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2828,7 +2868,7 @@ rte_eth_dev_bypass_state_set(uint8_t port_id,
>> uint32_t *new_state)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2848,7 +2888,7 @@ rte_eth_dev_bypass_event_show(uint8_t port_id,
>> uint32_t event, uint32_t *state)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2868,7 +2908,7 @@ rte_eth_dev_bypass_event_store(uint8_t port_id,
>> uint32_t event, uint32_t state)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2888,7 +2928,7 @@ rte_eth_dev_wd_timeout_store(uint8_t port_id,
>> uint32_t timeout)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2908,7 +2948,7 @@ rte_eth_dev_bypass_ver_show(uint8_t port_id,
>> uint32_t *ver)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2928,7 +2968,7 @@ rte_eth_dev_bypass_wd_timeout_show(uint8_t
>> port_id, uint32_t *wd_timeout)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2948,7 +2988,7 @@ rte_eth_dev_bypass_wd_reset(uint8_t port_id)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return (-ENODEV);
>>  	}
>> @@ -2970,7 +3010,7 @@ rte_eth_dev_add_syn_filter(uint8_t port_id,  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -2985,7 +3025,7 @@ rte_eth_dev_remove_syn_filter(uint8_t port_id)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -3004,7 +3044,7 @@ rte_eth_dev_get_syn_filter(uint8_t port_id,
>>  	if (filter == NULL || rx_queue == NULL)
>>  		return -EINVAL;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -3020,7 +3060,7 @@ rte_eth_dev_add_ethertype_filter(uint8_t port_id,
>> uint16_t index,  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -3041,7 +3081,7 @@ rte_eth_dev_remove_ethertype_filter(uint8_t
>> port_id,  uint16_t index)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -3060,7 +3100,7 @@ rte_eth_dev_get_ethertype_filter(uint8_t port_id,
>> uint16_t index,
>>  	if (filter == NULL || rx_queue == NULL)
>>  		return -EINVAL;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -3077,7 +3117,7 @@ rte_eth_dev_add_2tuple_filter(uint8_t port_id,
>> uint16_t index,  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -3099,7 +3139,7 @@ rte_eth_dev_remove_2tuple_filter(uint8_t port_id,
>> uint16_t index)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -3118,7 +3158,7 @@ rte_eth_dev_get_2tuple_filter(uint8_t port_id,
>> uint16_t index,
>>  	if (filter == NULL || rx_queue == NULL)
>>  		return -EINVAL;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -3134,7 +3174,7 @@ rte_eth_dev_add_5tuple_filter(uint8_t port_id,
>> uint16_t index,  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -3157,7 +3197,7 @@ rte_eth_dev_remove_5tuple_filter(uint8_t port_id,
>> uint16_t index)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -3176,7 +3216,7 @@ rte_eth_dev_get_5tuple_filter(uint8_t port_id,
>> uint16_t index,
>>  	if (filter == NULL || rx_queue == NULL)
>>  		return -EINVAL;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -3193,7 +3233,7 @@ rte_eth_dev_add_flex_filter(uint8_t port_id,
>> uint16_t index,  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -3208,7 +3248,7 @@ rte_eth_dev_remove_flex_filter(uint8_t port_id,
>> uint16_t index)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -3227,7 +3267,7 @@ rte_eth_dev_get_flex_filter(uint8_t port_id,
>> uint16_t index,
>>  	if (filter == NULL || rx_queue == NULL)
>>  		return -EINVAL;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -3243,7 +3283,7 @@ rte_eth_dev_filter_supported(uint8_t port_id,
>> enum rte_filter_type filter_type)  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> @@ -3260,7 +3300,7 @@ rte_eth_dev_filter_ctrl(uint8_t port_id, enum
>> rte_filter_type filter_type,  {
>>  	struct rte_eth_dev *dev;
>>
>> -	if (port_id >= nb_ports) {
>> +	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
>>  		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>>  		return -ENODEV;
>>  	}
>> diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h index
>> f66805d..257de86 100644
>> --- a/lib/librte_ether/rte_ethdev.h
>> +++ b/lib/librte_ether/rte_ethdev.h
>> @@ -1565,6 +1565,7 @@ struct rte_eth_dev {
>>  	struct eth_dev_ops *dev_ops;    /**< Functions exported by PMD */
>>  	struct rte_pci_device *pci_dev; /**< PCI info. supplied by probing */
>>  	struct rte_eth_dev_cb_list callbacks; /**< User application callbacks */
>> +	uint8_t attached; /**< Flag indicating the port is attached */
>>  };
>>
>>  struct rte_eth_dev_sriov {
>> @@ -1630,6 +1631,10 @@ extern struct rte_eth_dev rte_eth_devices[];
>>   * initialized by the [matching] Ethernet driver during the PCI probing phase.
>>   * All devices whose port identifier is in the range
>>   * [0,  rte_eth_dev_count() - 1] can be operated on by network applications.
>> + * immediately after invoking rte_eal_init().
>> + * If the application unplugs a port using hotplug function, The
>> + enabled port
>> + * numbers may be noncontiguous. In the case, the applications need to
>> + manage
>> + * enabled port by themselves.
>>   *
>>   * @return
>>   *   - The total number of usable Ethernet devices.
>> --
>> 1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v3 00/28] Port Hotplug Framework
  2014-11-20  9:06 ` [dpdk-dev] [PATCH " Tetsuya Mukawa
                     ` (27 preceding siblings ...)
  2014-12-09  3:45   ` [dpdk-dev] [PATCH v2] testpmd: " Tetsuya Mukawa
@ 2014-12-09  6:30   ` Tetsuya Mukawa
  2014-12-09  6:30     ` [dpdk-dev] [PATCH v3 01/28] eal/pci: Add a new flag indicating a driver can detach devices at runtime Tetsuya Mukawa
                       ` (27 more replies)
  2014-12-09  6:32   ` [dpdk-dev] [PATCH v3] librte_pmd_pcap: Add port hotplug support Tetsuya Mukawa
  2014-12-09  6:33   ` [dpdk-dev] [PATCH v3] testpmd: " Tetsuya Mukawa
  30 siblings, 28 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  6:30 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

This patch series adds a dynamic port hotplug framework to DPDK.
With the patches, DPDK apps can attach or detach ports at runtime.

The basic concept of the port hotplug is like followings.
- DPDK apps must have responsibility to manage ports.
  DPDK apps only know which ports are attached or detached at the moment.
  The port hotplug framework is implemented to allow DPDK apps to manage ports.
  For example, when DPDK apps call port attach function, attached port number
  will be returned. Also DPDK apps can detach port by port number.
- Kernel support is needed for attaching or detaching physical device ports.
  To attach new device, the device will be recognized by kernel at first and
  controlled by kernel driver. Then user can bind the device to igb_uio
  by 'dpdk_nic_bind.py'. Finally, DPDK apps can call the port hotplug
  functions to attach ports.
  For detaching, steps are vice versa.
- Before detach ports, ports must be stopped and closed.
  DPDK application must call rte_eth_dev_stop() and rte_eth_dev_close() before
  detaching ports. These function will call finalization codes of PMDs.
  But so far, no PMD frees all resources allocated by initialization.
  It means PMDs are needed to be fixed to support the port hotplug.
  'RTE_PCI_DRV_DETACHABLE' is a new flag indicating a PMD supports detaching.
  Without this flag, detaching will be failed.
- Mustn't affect legacy DPDK apps.
  No DPDK EAL behavior is changed, if the port hotplug functions are't called.
  So all legacy DPDK apps can still work without modifications.

And a few limitations.
- The port hotplug functions are not thread safe.
  DPDK apps should handle it.
- Only support Linux and igb_uio so far.
  BSD and VFIO is not supported. I will send VFIO patches at least, but I don't
  have a plan to submit BSD patch so far.


Here is port hotplug APIs.
-------------------------------------------------------------------------------
/**
 * Attach a new device.
 *
 * @param devargs
 *   A pointer to a strings array describing the new device
 *   to be attached. The strings should be a pci address like
 *   '0000:01:00.0' or virtual device name like 'eth_pcap0'.
 * @param port_id
 *  A pointer to a port identifier actually attached.
 * @return
 *  0 on success and port_id is filled, negative on error
 */
int rte_eal_dev_attach(const char *devargs, uint8_t *port_id);

/**
 * Detach a device.
 *
 * @param port_id
 *   The port identifier of the device to detach.
 * @param addr
 *  A pointer to a device name actually detached.
 * @return
 *  0 on success and devname is filled, negative on error
 */
int rte_eal_dev_detach(uint8_t port_id, char *devname);
-------------------------------------------------------------------------------

This patch series are for DPDK EAL. To use port hotplug function by DPDK apps,
each PMD should be fixed to support 'RTE_PCI_DRV_DETACHABLE' flag. Please check
a patch for pcap PMD.

Also please check testpmd patch. It will show you how to fix your legacy
applications to support port hotplug feature.


PATCH v3 chages:
 - Fix enum definition used in rte_ethdev.c.
   (Thanks to Zhang, Helin)

PATCH v2 chages:
 - Replace rte_eal_dev_attach_pdev(), rte_eal_dev_detach_pdev,
   rte_eal_dev_attach_vdev() and rte_eal_dev_detach_vdev() to
   rte_eal_dev_attach() and rte_eal_dev_detach().
 - Add parameter values checking.
 - Refashion a few functions.
   (Thanks to Iremonger, Bernard)

PATCH v1 Chages:
 - Fix error checking code of librte_eth APIs.
 - Fix issue that port from pcap PMD cannot be detached correctly.
 - Fix issue that testpmd could hang after forwarding, if attaching and detaching
   is repeatedly.
 - Fix if-condition of rte_eth_dev_get_port_by_addr().
   (Thanks to Mark Enright)

RFC PATCH v2 Changes:
- remove 'rte_eth_dev_validate_port()', and cleanup codes.


Tetsuya Mukawa (28):
  eal/pci: Add a new flag indicating a driver can detach devices at
    runtime.
  ethdev: Remove assumption that port will not be detached
  eal/pci: Replace pci address comparison code by eal_compare_pci_addr
  ethdev: Add rte_eth_dev_free to free specified device
  eal,ethdev: Add function pointer for closing a device
  ethdev: Add rte_eth_dev_shutdown for closing PCI devices.
  ethdev: Add functions to know which port is attached or detached
  ethdev: Add rte_eth_dev_get_addr_by_port
  ethdev: Add rte_eth_dev_get_port_by_addr
  ethdev: Add rte_eth_dev_get_name_by_port
  ethdev: Add rte_eth_dev_check_detachable
  ethdev: Change scope of rte_eth_dev_allocated to global
  eal/pci: Prevent double registration for devargs_list
  eal/pci: Add rte_eal_devargs_remove
  eal/pci: Add probe and close function for virtual drivers
  eal/pci: Add port hotplug functions for virtual devices.
  eal/linux/pci: Add functions for unmapping igb_uio resources
  eal/pci: Prevent double registrations for pci_device_list
  eal/pci: Change scope of rte_eal_pci_scan to global
  eal/pci: Add rte_eal_pci_close_one_driver
  eal/pci: Fix pci_probe_all_drivers to share code with closing function
  eal/pci: Add pci_close_all_drivers
  eal/pci: Add rte_eal_pci_probe_one and rte_eal_pci_close_one
  eal/pci: Add port hotplug functions for physical devices.
  eal/pci: Remove pci_probe/close_all_drivers()
  eal/pci: Add rte_eal_dev_attach/detach() functions
  eal/pci: Remove rte_eal_dev_attach/detach_pdev() and
    rte_eal_dev_attach/detach_vdev()
  eal: Enable port hotplug framework in Linux

 app/test/virtual_pmd.c                       |   2 +-
 config/common_linuxapp                       |   5 +
 lib/librte_eal/bsdapp/eal/eal_pci.c          |  16 +-
 lib/librte_eal/common/eal_common_dev.c       | 250 ++++++++++++++++
 lib/librte_eal/common/eal_common_devargs.c   |  51 ++++
 lib/librte_eal/common/eal_common_pci.c       |  89 +++++-
 lib/librte_eal/common/eal_private.h          |  26 ++
 lib/librte_eal/common/include/rte_dev.h      |  36 +++
 lib/librte_eal/common/include/rte_devargs.h  |  18 ++
 lib/librte_eal/common/include/rte_pci.h      |  64 +++++
 lib/librte_eal/linuxapp/eal/Makefile         |   1 +
 lib/librte_eal/linuxapp/eal/eal_pci.c        | 125 ++++++--
 lib/librte_eal/linuxapp/eal/eal_pci_init.h   |   7 +
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c    |  67 ++++-
 lib/librte_ether/rte_ethdev.c                | 409 ++++++++++++++++++++-------
 lib/librte_ether/rte_ethdev.h                | 144 +++++++++-
 lib/librte_pmd_af_packet/rte_eth_af_packet.c |   2 +-
 lib/librte_pmd_bond/rte_eth_bond_api.c       |   2 +-
 lib/librte_pmd_pcap/rte_eth_pcap.c           |   2 +-
 lib/librte_pmd_ring/rte_eth_ring.c           |   2 +-
 lib/librte_pmd_xenvirt/rte_eth_xenvirt.c     |   2 +-
 21 files changed, 1159 insertions(+), 161 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v3 01/28] eal/pci: Add a new flag indicating a driver can detach devices at runtime.
  2014-12-09  6:30   ` [dpdk-dev] [PATCH v3 00/28] Port Hotplug Framework Tetsuya Mukawa
@ 2014-12-09  6:30     ` Tetsuya Mukawa
  2014-12-09  6:30     ` [dpdk-dev] [PATCH v3 02/28] ethdev: Remove assumption that port will not be detached Tetsuya Mukawa
                       ` (26 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  6:30 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

This patch adds "RTE_PCI_DRV_DETACHABLE" to drv_flags of rte_pci_driver
structure. The flags indicates the driver can detach devices at runtime.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/include/rte_pci.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 66ed793..b819539 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -199,6 +199,8 @@ 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 capablity */
+#define RTE_PCI_DRV_DETACHABLE	0x0010
 
 /**< Internal use only - Macro used by pci addr parsing functions **/
 #define GET_PCIADDR_FIELD(in, fd, lim, dlm)                   \
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v3 02/28] ethdev: Remove assumption that port will not be detached
  2014-12-09  6:30   ` [dpdk-dev] [PATCH v3 00/28] Port Hotplug Framework Tetsuya Mukawa
  2014-12-09  6:30     ` [dpdk-dev] [PATCH v3 01/28] eal/pci: Add a new flag indicating a driver can detach devices at runtime Tetsuya Mukawa
@ 2014-12-09  6:30     ` Tetsuya Mukawa
  2014-12-09  6:30     ` [dpdk-dev] [PATCH v3 03/28] eal/pci: Replace pci address comparison code by eal_compare_pci_addr Tetsuya Mukawa
                       ` (25 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  6:30 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

To remove assumption, do like followings.

- Add 'attached' member to rte_eth_dev structure.
  This member is used for indicating the port is attached, or not.
- Add rte_eth_dev_allocate_new_port().
  This function is used for allocating new port.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 248 ++++++++++++++++++++++++------------------
 lib/librte_ether/rte_ethdev.h |   5 +
 2 files changed, 149 insertions(+), 104 deletions(-)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 95f2ceb..9f713ae 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -175,6 +175,16 @@ enum {
 	STAT_QMAP_RX
 };
 
+enum {
+	DEV_VALID = 0,
+	DEV_INVALID
+};
+
+enum {
+	DEV_DISCONNECTED = 0,
+	DEV_CONNECTED
+};
+
 static inline void
 rte_eth_dev_data_alloc(void)
 {
@@ -201,19 +211,34 @@ rte_eth_dev_allocated(const char *name)
 {
 	unsigned i;
 
-	for (i = 0; i < nb_ports; i++) {
-		if (strcmp(rte_eth_devices[i].data->name, name) == 0)
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if ((rte_eth_devices[i].attached == DEV_CONNECTED)
+				&& strcmp(rte_eth_devices[i].data->name,
+					name) == 0)
 			return &rte_eth_devices[i];
 	}
 	return NULL;
 }
 
+static uint8_t
+rte_eth_dev_allocate_new_port(void)
+{
+	unsigned i;
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++)
+		if (rte_eth_devices[i].attached == DEV_DISCONNECTED)
+			return i;
+	return RTE_MAX_ETHPORTS;
+}
+
 struct rte_eth_dev *
 rte_eth_dev_allocate(const char *name)
 {
+	uint8_t port_id;
 	struct rte_eth_dev *eth_dev;
 
-	if (nb_ports == RTE_MAX_ETHPORTS) {
+	port_id = rte_eth_dev_allocate_new_port();
+	if (port_id == RTE_MAX_ETHPORTS) {
 		PMD_DEBUG_TRACE("Reached maximum number of Ethernet ports\n");
 		return NULL;
 	}
@@ -226,10 +251,12 @@ rte_eth_dev_allocate(const char *name)
 		return NULL;
 	}
 
-	eth_dev = &rte_eth_devices[nb_ports];
-	eth_dev->data = &rte_eth_dev_data[nb_ports];
+	eth_dev = &rte_eth_devices[port_id];
+	eth_dev->data = &rte_eth_dev_data[port_id];
 	snprintf(eth_dev->data->name, sizeof(eth_dev->data->name), "%s", name);
-	eth_dev->data->port_id = nb_ports++;
+	eth_dev->data->port_id = port_id;
+	eth_dev->attached = DEV_CONNECTED;
+	nb_ports++;
 	return eth_dev;
 }
 
@@ -283,6 +310,7 @@ rte_eth_dev_init(struct rte_pci_driver *pci_drv,
 			(unsigned) pci_dev->id.device_id);
 	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
 		rte_free(eth_dev->data->dev_private);
+	eth_dev->attached = DEV_DISCONNECTED;
 	nb_ports--;
 	return diag;
 }
@@ -308,10 +336,22 @@ rte_eth_driver_register(struct eth_driver *eth_drv)
 	rte_eal_pci_register(&eth_drv->pci_drv);
 }
 
+static int
+rte_eth_dev_validate_port(uint8_t port_id)
+{
+	if (port_id >= RTE_MAX_ETHPORTS)
+		return DEV_INVALID;
+
+	if (rte_eth_devices[port_id].attached == DEV_CONNECTED)
+		return DEV_VALID;
+	else
+		return DEV_INVALID;
+}
+
 int
 rte_eth_dev_socket_id(uint8_t port_id)
 {
-	if (port_id >= nb_ports)
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID)
 		return -1;
 	return rte_eth_devices[port_id].pci_dev->numa_node;
 }
@@ -369,7 +409,7 @@ rte_eth_dev_rx_queue_start(uint8_t port_id, uint16_t rx_queue_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -395,7 +435,7 @@ rte_eth_dev_rx_queue_stop(uint8_t port_id, uint16_t rx_queue_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -421,7 +461,7 @@ rte_eth_dev_tx_queue_start(uint8_t port_id, uint16_t tx_queue_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -447,7 +487,7 @@ rte_eth_dev_tx_queue_stop(uint8_t port_id, uint16_t tx_queue_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -662,7 +702,7 @@ rte_eth_dev_configure(uint8_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports || port_id >= RTE_MAX_ETHPORTS) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -847,7 +887,7 @@ rte_eth_dev_start(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%" PRIu8 "\n", port_id);
 		return (-EINVAL);
 	}
@@ -882,7 +922,7 @@ rte_eth_dev_stop(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_RET();
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%" PRIu8 "\n", port_id);
 		return;
 	}
@@ -910,7 +950,7 @@ rte_eth_dev_set_link_up(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -929,7 +969,7 @@ rte_eth_dev_set_link_down(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -EINVAL;
 	}
@@ -948,7 +988,7 @@ rte_eth_dev_close(uint8_t port_id)
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_RET();
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -976,7 +1016,7 @@ rte_eth_rx_queue_setup(uint8_t port_id, uint16_t rx_queue_id,
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -1049,7 +1089,7 @@ rte_eth_tx_queue_setup(uint8_t port_id, uint16_t tx_queue_id,
 	 * in a multi-process setup*/
 	PROC_PRIMARY_OR_ERR_RET(-E_RTE_SECONDARY);
 
-	if (port_id >= RTE_MAX_ETHPORTS || port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -1082,7 +1122,7 @@ rte_eth_promiscuous_enable(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1098,7 +1138,7 @@ rte_eth_promiscuous_disable(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1114,7 +1154,7 @@ rte_eth_promiscuous_get(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -1;
 	}
@@ -1128,7 +1168,7 @@ rte_eth_allmulticast_enable(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1144,7 +1184,7 @@ rte_eth_allmulticast_disable(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1160,7 +1200,7 @@ rte_eth_allmulticast_get(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -1;
 	}
@@ -1188,7 +1228,7 @@ rte_eth_link_get(uint8_t port_id, struct rte_eth_link *eth_link)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1208,7 +1248,7 @@ rte_eth_link_get_nowait(uint8_t port_id, struct rte_eth_link *eth_link)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1228,7 +1268,7 @@ rte_eth_stats_get(uint8_t port_id, struct rte_eth_stats *stats)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1245,7 +1285,7 @@ rte_eth_stats_reset(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1266,7 +1306,7 @@ rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstats *xstats,
 	uint64_t val;
 	char *stats_ptr;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -1;
 	}
@@ -1335,7 +1375,7 @@ rte_eth_xstats_reset(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1357,7 +1397,7 @@ set_queue_stats_mapping(uint8_t port_id, uint16_t queue_id, uint8_t stat_idx,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -1392,7 +1432,7 @@ rte_eth_dev_info_get(uint8_t port_id, struct rte_eth_dev_info *dev_info)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1412,7 +1452,7 @@ rte_eth_macaddr_get(uint8_t port_id, struct ether_addr *mac_addr)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return;
 	}
@@ -1426,7 +1466,7 @@ rte_eth_dev_get_mtu(uint8_t port_id, uint16_t *mtu)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1442,7 +1482,7 @@ rte_eth_dev_set_mtu(uint8_t port_id, uint16_t mtu)
 	int ret;
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1462,7 +1502,7 @@ rte_eth_dev_vlan_filter(uint8_t port_id, uint16_t vlan_id, int on)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1487,7 +1527,7 @@ rte_eth_dev_set_vlan_strip_on_queue(uint8_t port_id, uint16_t rx_queue_id, int o
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1509,7 +1549,7 @@ rte_eth_dev_set_vlan_ether_type(uint8_t port_id, uint16_t tpid)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1529,7 +1569,7 @@ rte_eth_dev_set_vlan_offload(uint8_t port_id, int offload_mask)
 	int mask = 0;
 	int cur, org = 0;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1574,7 +1614,7 @@ rte_eth_dev_get_vlan_offload(uint8_t port_id)
 	struct rte_eth_dev *dev;
 	int ret = 0;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1598,7 +1638,7 @@ rte_eth_dev_set_vlan_pvid(uint8_t port_id, uint16_t pvid, int on)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1616,7 +1656,7 @@ rte_eth_dev_fdir_add_signature_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1650,7 +1690,7 @@ rte_eth_dev_fdir_update_signature_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1684,7 +1724,7 @@ rte_eth_dev_fdir_remove_signature_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1715,7 +1755,7 @@ rte_eth_dev_fdir_get_infos(uint8_t port_id, struct rte_eth_fdir *fdir)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1740,7 +1780,7 @@ rte_eth_dev_fdir_add_perfect_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1780,7 +1820,7 @@ rte_eth_dev_fdir_update_perfect_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1818,7 +1858,7 @@ rte_eth_dev_fdir_remove_perfect_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1854,7 +1894,7 @@ rte_eth_dev_fdir_set_masks(uint8_t port_id, struct rte_fdir_masks *fdir_mask)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1874,7 +1914,7 @@ rte_eth_dev_flow_ctrl_get(uint8_t port_id, struct rte_eth_fc_conf *fc_conf)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1890,7 +1930,7 @@ rte_eth_dev_flow_ctrl_set(uint8_t port_id, struct rte_eth_fc_conf *fc_conf)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -1910,7 +1950,7 @@ rte_eth_dev_priority_flow_ctrl_set(uint8_t port_id, struct rte_eth_pfc_conf *pfc
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2019,7 +2059,7 @@ rte_eth_dev_rss_reta_query(uint8_t port_id,
 	struct rte_eth_dev *dev;
 	int ret;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -2040,7 +2080,7 @@ rte_eth_dev_rss_hash_update(uint8_t port_id, struct rte_eth_rss_conf *rss_conf)
 	struct rte_eth_dev *dev;
 	uint16_t rss_hash_protos;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2062,7 +2102,7 @@ rte_eth_dev_rss_hash_conf_get(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2077,7 +2117,7 @@ rte_eth_dev_udp_tunnel_add(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -2103,7 +2143,7 @@ rte_eth_dev_udp_tunnel_delete(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -2128,7 +2168,7 @@ rte_eth_led_on(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2143,7 +2183,7 @@ rte_eth_led_off(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2183,7 +2223,7 @@ rte_eth_dev_mac_addr_add(uint8_t port_id, struct ether_addr *addr,
 	int index;
 	uint64_t pool_mask;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2234,7 +2274,7 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 	struct rte_eth_dev *dev;
 	int index;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2268,7 +2308,7 @@ rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 	struct rte_eth_dev *dev;
 	struct rte_eth_dev_info dev_info;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("set VF RX mode:Invalid port_id=%d\n",
 				port_id);
 		return (-ENODEV);
@@ -2323,7 +2363,7 @@ rte_eth_dev_uc_hash_table_set(uint8_t port_id, struct ether_addr *addr,
 	int ret;
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("unicast hash setting:Invalid port_id=%d\n",
 			port_id);
 		return (-ENODEV);
@@ -2376,7 +2416,7 @@ rte_eth_dev_uc_all_hash_table_set(uint8_t port_id, uint8_t on)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("unicast hash setting:Invalid port_id=%d\n",
 			port_id);
 		return (-ENODEV);
@@ -2395,7 +2435,7 @@ rte_eth_dev_set_vf_rx(uint8_t port_id,uint16_t vf, uint8_t on)
 	struct rte_eth_dev *dev;
 	struct rte_eth_dev_info dev_info;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2421,7 +2461,7 @@ rte_eth_dev_set_vf_tx(uint8_t port_id,uint16_t vf, uint8_t on)
 	struct rte_eth_dev *dev;
 	struct rte_eth_dev_info dev_info;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("set pool tx:Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2446,7 +2486,7 @@ rte_eth_dev_set_vf_vlan_filter(uint8_t port_id, uint16_t vlan_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("VF VLAN filter:invalid port id=%d\n",
 				port_id);
 		return (-ENODEV);
@@ -2477,7 +2517,7 @@ int rte_eth_set_queue_rate_limit(uint8_t port_id, uint16_t queue_idx,
 	struct rte_eth_dev_info dev_info;
 	struct rte_eth_link link;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("set queue rate limit:invalid port id=%d\n",
 				port_id);
 		return -ENODEV;
@@ -2514,7 +2554,7 @@ int rte_eth_set_vf_rate_limit(uint8_t port_id, uint16_t vf, uint16_t tx_rate,
 	if (q_msk == 0)
 		return 0;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("set VF rate limit:invalid port id=%d\n",
 				port_id);
 		return -ENODEV;
@@ -2548,7 +2588,7 @@ rte_eth_mirror_rule_set(uint8_t port_id,
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2589,7 +2629,7 @@ rte_eth_mirror_rule_reset(uint8_t port_id, uint8_t rule_id)
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2614,7 +2654,7 @@ rte_eth_rx_burst(uint8_t port_id, uint16_t queue_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return 0;
 	}
@@ -2634,7 +2674,7 @@ rte_eth_tx_burst(uint8_t port_id, uint16_t queue_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return 0;
 	}
@@ -2654,7 +2694,7 @@ rte_eth_rx_queue_count(uint8_t port_id, uint16_t queue_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return 0;
 	}
@@ -2668,7 +2708,7 @@ rte_eth_rx_descriptor_done(uint8_t port_id, uint16_t queue_id, uint16_t offset)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2689,7 +2729,7 @@ rte_eth_dev_callback_register(uint8_t port_id,
 
 	if (!cb_fn)
 		return (-EINVAL);
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -2729,7 +2769,7 @@ rte_eth_dev_callback_unregister(uint8_t port_id,
 
 	if (!cb_fn)
 		return (-EINVAL);
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-EINVAL);
 	}
@@ -2789,7 +2829,7 @@ int rte_eth_dev_bypass_init(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2809,7 +2849,7 @@ rte_eth_dev_bypass_state_show(uint8_t port_id, uint32_t *state)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2828,7 +2868,7 @@ rte_eth_dev_bypass_state_set(uint8_t port_id, uint32_t *new_state)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2848,7 +2888,7 @@ rte_eth_dev_bypass_event_show(uint8_t port_id, uint32_t event, uint32_t *state)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2868,7 +2908,7 @@ rte_eth_dev_bypass_event_store(uint8_t port_id, uint32_t event, uint32_t state)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2888,7 +2928,7 @@ rte_eth_dev_wd_timeout_store(uint8_t port_id, uint32_t timeout)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2908,7 +2948,7 @@ rte_eth_dev_bypass_ver_show(uint8_t port_id, uint32_t *ver)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2928,7 +2968,7 @@ rte_eth_dev_bypass_wd_timeout_show(uint8_t port_id, uint32_t *wd_timeout)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2948,7 +2988,7 @@ rte_eth_dev_bypass_wd_reset(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return (-ENODEV);
 	}
@@ -2970,7 +3010,7 @@ rte_eth_dev_add_syn_filter(uint8_t port_id,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -2985,7 +3025,7 @@ rte_eth_dev_remove_syn_filter(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3004,7 +3044,7 @@ rte_eth_dev_get_syn_filter(uint8_t port_id,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3020,7 +3060,7 @@ rte_eth_dev_add_ethertype_filter(uint8_t port_id, uint16_t index,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3041,7 +3081,7 @@ rte_eth_dev_remove_ethertype_filter(uint8_t port_id,  uint16_t index)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3060,7 +3100,7 @@ rte_eth_dev_get_ethertype_filter(uint8_t port_id, uint16_t index,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3077,7 +3117,7 @@ rte_eth_dev_add_2tuple_filter(uint8_t port_id, uint16_t index,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3099,7 +3139,7 @@ rte_eth_dev_remove_2tuple_filter(uint8_t port_id, uint16_t index)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3118,7 +3158,7 @@ rte_eth_dev_get_2tuple_filter(uint8_t port_id, uint16_t index,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3134,7 +3174,7 @@ rte_eth_dev_add_5tuple_filter(uint8_t port_id, uint16_t index,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3157,7 +3197,7 @@ rte_eth_dev_remove_5tuple_filter(uint8_t port_id, uint16_t index)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3176,7 +3216,7 @@ rte_eth_dev_get_5tuple_filter(uint8_t port_id, uint16_t index,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3193,7 +3233,7 @@ rte_eth_dev_add_flex_filter(uint8_t port_id, uint16_t index,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3208,7 +3248,7 @@ rte_eth_dev_remove_flex_filter(uint8_t port_id, uint16_t index)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3227,7 +3267,7 @@ rte_eth_dev_get_flex_filter(uint8_t port_id, uint16_t index,
 	if (filter == NULL || rx_queue == NULL)
 		return -EINVAL;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3243,7 +3283,7 @@ rte_eth_dev_filter_supported(uint8_t port_id, enum rte_filter_type filter_type)
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
@@ -3260,7 +3300,7 @@ rte_eth_dev_filter_ctrl(uint8_t port_id, enum rte_filter_type filter_type,
 {
 	struct rte_eth_dev *dev;
 
-	if (port_id >= nb_ports) {
+	if (rte_eth_dev_validate_port(port_id) == DEV_INVALID) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
 		return -ENODEV;
 	}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index f66805d..257de86 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1565,6 +1565,7 @@ struct rte_eth_dev {
 	struct eth_dev_ops *dev_ops;    /**< Functions exported by PMD */
 	struct rte_pci_device *pci_dev; /**< PCI info. supplied by probing */
 	struct rte_eth_dev_cb_list callbacks; /**< User application callbacks */
+	uint8_t attached; /**< Flag indicating the port is attached */
 };
 
 struct rte_eth_dev_sriov {
@@ -1630,6 +1631,10 @@ extern struct rte_eth_dev rte_eth_devices[];
  * initialized by the [matching] Ethernet driver during the PCI probing phase.
  * All devices whose port identifier is in the range
  * [0,  rte_eth_dev_count() - 1] can be operated on by network applications.
+ * immediately after invoking rte_eal_init().
+ * If the application unplugs a port using hotplug function, The enabled port
+ * numbers may be noncontiguous. In the case, the applications need to manage
+ * enabled port by themselves.
  *
  * @return
  *   - The total number of usable Ethernet devices.
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v3 03/28] eal/pci: Replace pci address comparison code by eal_compare_pci_addr
  2014-12-09  6:30   ` [dpdk-dev] [PATCH v3 00/28] Port Hotplug Framework Tetsuya Mukawa
  2014-12-09  6:30     ` [dpdk-dev] [PATCH v3 01/28] eal/pci: Add a new flag indicating a driver can detach devices at runtime Tetsuya Mukawa
  2014-12-09  6:30     ` [dpdk-dev] [PATCH v3 02/28] ethdev: Remove assumption that port will not be detached Tetsuya Mukawa
@ 2014-12-09  6:30     ` Tetsuya Mukawa
  2014-12-09 14:22       ` Qiu, Michael
  2014-12-09  6:30     ` [dpdk-dev] [PATCH v3 04/28] ethdev: Add rte_eth_dev_free to free specified device Tetsuya Mukawa
                       ` (24 subsequent siblings)
  27 siblings, 1 reply; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  6:30 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

This patch replaces pci_addr_comparison() and memcmp() of pci addresses by
eal_compare_pci_addr().

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/bsdapp/eal/eal_pci.c       | 16 +---------------
 lib/librte_eal/common/eal_common_pci.c    |  2 +-
 lib/librte_eal/common/include/rte_pci.h   | 29 +++++++++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c     | 16 +---------------
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c |  2 +-
 5 files changed, 33 insertions(+), 32 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 74ecce7..7eda513 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -270,20 +270,6 @@ pci_uio_map_resource(struct rte_pci_device *dev)
 	return (0);
 }
 
-/* Compare two PCI device addresses. */
-static int
-pci_addr_comparison(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
-{
-	uint64_t dev_addr = (addr->domain << 24) + (addr->bus << 16) + (addr->devid << 8) + addr->function;
-	uint64_t dev_addr2 = (addr2->domain << 24) + (addr2->bus << 16) + (addr2->devid << 8) + addr2->function;
-
-	if (dev_addr > dev_addr2)
-		return 1;
-	else
-		return 0;
-}
-
-
 /* Scan one pci sysfs entry, and fill the devices list from it. */
 static int
 pci_scan_one(int dev_pci_fd, struct pci_conf *conf)
@@ -358,7 +344,7 @@ pci_scan_one(int dev_pci_fd, struct pci_conf *conf)
 		struct rte_pci_device *dev2 = NULL;
 
 		TAILQ_FOREACH(dev2, &pci_device_list, next) {
-			if (pci_addr_comparison(&dev->addr, &dev2->addr))
+			if (eal_compare_pci_addr(&dev->addr, &dev2->addr))
 				continue;
 			else {
 				TAILQ_INSERT_BEFORE(dev2, dev, next);
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index f3c7f71..f01f258 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -93,7 +93,7 @@ static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
 		if (devargs->type != RTE_DEVTYPE_BLACKLISTED_PCI &&
 			devargs->type != RTE_DEVTYPE_WHITELISTED_PCI)
 			continue;
-		if (!memcmp(&dev->addr, &devargs->pci.addr, sizeof(dev->addr)))
+		if (eal_compare_pci_addr(&dev->addr, &devargs->pci.addr))
 			return devargs;
 	}
 	return NULL;
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index b819539..fe374a8 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -261,6 +261,35 @@ eal_parse_pci_DomBDF(const char *input, struct rte_pci_addr *dev_addr)
 }
 #undef GET_PCIADDR_FIELD
 
+/* Compare two PCI device addresses. */
+/**
+ * Utility function to compare two PCI device addresses.
+ *
+ * @param addr
+ *	The PCI Bus-Device-Function address to compare
+ * @param addr2
+ *	The PCI Bus-Device-Function address to compare
+ * @return
+ *  0 on equal PCI address.
+ *  Positive on addr is greater than addr2.
+ *  Negative on addr is less than addr2.
+ */
+static inline int
+eal_compare_pci_addr(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
+{
+	uint64_t dev_addr = (addr->domain << 24) + (addr->bus << 16) +
+					(addr->devid << 8) + addr->function;
+	uint64_t dev_addr2 = (addr2->domain << 24) + (addr2->bus << 16) +
+					(addr2->devid << 8) + addr2->function;
+
+	if (dev_addr > dev_addr2)
+		return 1;
+	else if (dev_addr < dev_addr2)
+		return -1;
+	else
+		return 0;
+}
+
 /**
  * Probe the PCI bus for registered drivers.
  *
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index b5f5410..23a69e9 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -200,20 +200,6 @@ error:
 	return -1;
 }
 
-/* Compare two PCI device addresses. */
-static int
-pci_addr_comparison(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
-{
-	uint64_t dev_addr = (addr->domain << 24) + (addr->bus << 16) + (addr->devid << 8) + addr->function;
-	uint64_t dev_addr2 = (addr2->domain << 24) + (addr2->bus << 16) + (addr2->devid << 8) + addr2->function;
-
-	if (dev_addr > dev_addr2)
-		return 1;
-	else
-		return 0;
-}
-
-
 /* 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,
@@ -306,7 +292,7 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
 		struct rte_pci_device *dev2 = NULL;
 
 		TAILQ_FOREACH(dev2, &pci_device_list, next) {
-			if (pci_addr_comparison(&dev->addr, &dev2->addr))
+			if (eal_compare_pci_addr(&dev->addr, &dev2->addr) != 0)
 				continue;
 			else {
 				TAILQ_INSERT_BEFORE(dev2, dev, next);
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
index e53f06b..1da3507 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
@@ -123,7 +123,7 @@ pci_uio_map_secondary(struct rte_pci_device *dev)
 	TAILQ_FOREACH(uio_res, pci_res_list, next) {
 
 		/* skip this element if it doesn't match our PCI address */
-		if (memcmp(&uio_res->pci_addr, &dev->addr, sizeof(dev->addr)))
+		if (eal_compare_pci_addr(&uio_res->pci_addr, &dev->addr))
 			continue;
 
 		for (i = 0; i != uio_res->nb_maps; i++) {
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v3 04/28] ethdev: Add rte_eth_dev_free to free specified device
  2014-12-09  6:30   ` [dpdk-dev] [PATCH v3 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (2 preceding siblings ...)
  2014-12-09  6:30     ` [dpdk-dev] [PATCH v3 03/28] eal/pci: Replace pci address comparison code by eal_compare_pci_addr Tetsuya Mukawa
@ 2014-12-09  6:30     ` Tetsuya Mukawa
  2014-12-09  6:30     ` [dpdk-dev] [PATCH v3 05/28] eal, ethdev: Add function pointer for closing a device Tetsuya Mukawa
                       ` (23 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  6:30 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

This patch adds rte_eth_dev_free(). The function is used for changing a
attached status of the device that has specified name.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 17 +++++++++++++++++
 lib/librte_ether/rte_ethdev.h | 11 +++++++++++
 2 files changed, 28 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 9f713ae..d5fdb03 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -260,6 +260,23 @@ rte_eth_dev_allocate(const char *name)
 	return eth_dev;
 }
 
+struct rte_eth_dev *
+rte_eth_dev_free(const char *name)
+{
+	struct rte_eth_dev *eth_dev;
+
+	eth_dev = rte_eth_dev_allocated(name);
+	if (eth_dev == NULL) {
+		PMD_DEBUG_TRACE("Ethernet Device with name %s doesn't exist!\n",
+				name);
+		return NULL;
+	}
+
+	eth_dev->attached = 0;
+	nb_ports--;
+	return eth_dev;
+}
+
 static int
 rte_eth_dev_init(struct rte_pci_driver *pci_drv,
 		 struct rte_pci_device *pci_dev)
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 257de86..fb1caea 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1653,6 +1653,17 @@ extern uint8_t rte_eth_dev_count(void);
  */
 struct rte_eth_dev *rte_eth_dev_allocate(const char *name);
 
+/**
+ * Function for internal use by dummy drivers primarily, e.g. ring-based
+ * driver.
+ * Free the specified ethdev and returns the pointer to that slot.
+ *
+ * @param	name	Unique identifier name for each Ethernet device
+ * @return
+ *   - Slot in the rte_dev_devices array for the freed device;
+ */
+struct rte_eth_dev *rte_eth_dev_free(const char *name);
+
 struct eth_driver;
 /**
  * @internal
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v3 05/28] eal, ethdev: Add function pointer for closing a device
  2014-12-09  6:30   ` [dpdk-dev] [PATCH v3 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (3 preceding siblings ...)
  2014-12-09  6:30     ` [dpdk-dev] [PATCH v3 04/28] ethdev: Add rte_eth_dev_free to free specified device Tetsuya Mukawa
@ 2014-12-09  6:30     ` Tetsuya Mukawa
  2014-12-09  6:30     ` [dpdk-dev] [PATCH v3 06/28] ethdev: Add rte_eth_dev_shutdown for closing PCI devices Tetsuya Mukawa
                       ` (22 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  6:30 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

The patch adds function pointer to rte_pci_driver and eth_driver
structure. These function pointers are used when ports are detached.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/common/include/rte_pci.h |  7 +++++++
 lib/librte_ether/rte_ethdev.h           | 24 ++++++++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index fe374a8..74720d1 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -181,12 +181,19 @@ struct rte_pci_driver;
 typedef int (pci_devinit_t)(struct rte_pci_driver *, struct rte_pci_device *);
 
 /**
+ * Shutdown function for the driver called during hotplugging.
+ */
+typedef int (pci_devshutdown_t)(
+		struct rte_pci_driver *, struct rte_pci_device *);
+
+/**
  * A structure describing a PCI driver.
  */
 struct rte_pci_driver {
 	TAILQ_ENTRY(rte_pci_driver) next;       /**< Next in list. */
 	const char *name;                       /**< Driver name. */
 	pci_devinit_t *devinit;                 /**< Device init. function. */
+	pci_devshutdown_t *devshutdown;         /**< Device shutdown function. */
 	struct rte_pci_id *id_table;            /**< ID table, NULL terminated. */
 	uint32_t drv_flags;                     /**< Flags contolling handling of device. */
 };
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index fb1caea..b329e11 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1702,6 +1702,27 @@ typedef int (*eth_dev_init_t)(struct eth_driver  *eth_drv,
 
 /**
  * @internal
+ * Finalization function of an Ethernet driver invoked for each matching
+ * Ethernet PCI device detected during the PCI closing phase.
+ *
+ * @param eth_drv
+ *   The pointer to the [matching] Ethernet driver structure supplied by
+ *   the PMD when it registered itself.
+ * @param eth_dev
+ *   The *eth_dev* pointer is the address of the *rte_eth_dev* structure
+ *   associated with the matching device and which have been [automatically]
+ *   allocated in the *rte_eth_devices* array.
+ * @return
+ *   - 0: Success, the device is properly finalized by the driver.
+ *        In particular, the driver MUST free the *dev_ops* pointer
+ *        of the *eth_dev* structure.
+ *   - <0: Error code of the device initialization failure.
+ */
+typedef int (*eth_dev_shutdown_t)(struct eth_driver  *eth_drv,
+				  struct rte_eth_dev *eth_dev);
+
+/**
+ * @internal
  * The structure associated with a PMD Ethernet driver.
  *
  * Each Ethernet driver acts as a PCI driver and is represented by a generic
@@ -1711,11 +1732,14 @@ typedef int (*eth_dev_init_t)(struct eth_driver  *eth_drv,
  *
  * - The *eth_dev_init* function invoked for each matching PCI device.
  *
+ * - The *eth_dev_shutdown* function invoked for each matching PCI device.
+ *
  * - The size of the private data to allocate for each matching device.
  */
 struct eth_driver {
 	struct rte_pci_driver pci_drv;    /**< The PMD is also a PCI driver. */
 	eth_dev_init_t eth_dev_init;      /**< Device init function. */
+	eth_dev_shutdown_t eth_dev_shutdown;/**< Device shutdown function. */
 	unsigned int dev_private_size;    /**< Size of device private data. */
 };
 
-- 
1.9.1

^ permalink raw reply	[flat|nested] 176+ messages in thread

* [dpdk-dev] [PATCH v3 06/28] ethdev: Add rte_eth_dev_shutdown for closing PCI devices.
  2014-12-09  6:30   ` [dpdk-dev] [PATCH v3 00/28] Port Hotplug Framework Tetsuya Mukawa
                       ` (4 preceding siblings ...)
  2014-12-09  6:30     ` [dpdk-dev] [PATCH v3 05/28] eal, ethdev: Add function pointer for closing a device Tetsuya Mukawa
@ 2014-12-09  6:30     ` Tetsuya Mukawa
  2014-12-09  6:30     ` [dpdk-dev] [PATCH v3 07/28] ethdev: Add functions to know which port is attached or detached Tetsuya Mukawa
                       ` (21 subsequent siblings)
  27 siblings, 0 replies; 176+ messages in thread
From: Tetsuya Mukawa @ 2014-12-09  6:30 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, menrigh, masutani.hitoshi

rte_eth_dev_shutdown() is called when PCI device is closed.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_ether/rte_ethdev.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index d5fdb03..51697e1 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -332,6 +332,42 @@ rte_eth_dev_init(struct rte_pci_driver *pci_drv,
 	return diag;
 }
 
+static int
+rte_eth_dev_shutdown(struct rte_pci_driver *pci_drv,
+		 struct rte_pci_device *pci_dev)
+{
+	struct eth_driver *eth_drv;
+	struct rte_eth_dev *eth_dev;
+	char ethdev_name[RTE_ETH_NAME_MAX_LEN];
+
+	/* Create unique Ethernet device name using PCI address */
+	snprintf(ethdev_name, RTE_ETH_NAME_MAX_LEN, "%d:%d.%d",
+			pci_dev->addr.bus, pci_dev->addr.devid,
+			pci_dev->addr.function);
+
+	eth_dev = rte_eth_dev_free(ethdev_name);
+	if (eth_dev == NULL)
+		return -ENODEV;
+
+	eth_drv = (struct eth_driver *)pci_drv;
+
+	/* Invoke PMD device shutdown function */
+	if (*eth_drv->eth_dev_shutdown)
+		(*eth_drv->eth_dev_shutdown)(eth_drv, eth_de