[dpdk-dev] [PATCH v6 12/13] eal/pci: Add rte_eal_dev_attach/detach() functions

Qiu, Michael michael.qiu at intel.com
Mon Feb 2 06:42:38 CET 2015


On 2/1/2015 12:02 PM, Tetsuya Mukawa wrote:
> These functions are used for attaching or detaching a port.
> 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 attach physical device port. If not, attaches
> virtual devive port.
> 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 specific detaching function will be called.
>
> v5:
> - Change function names like below.
>   rte_eal_dev_find_and_invoke() to rte_eal_vdev_find_and_invoke().
>   rte_eal_dev_invoke() to rte_eal_vdev_invoke().
> - Add code to handle a return value of rte_eal_devargs_remove().
> - Fix pci address format in rte_eal_dev_detach().
> v4:
> - Fix comment.
> - Add error checking.
> - Fix indent of 'if' statement.
> - Change function name.
>
> Signed-off-by: Tetsuya Mukawa <mukawa at igel.co.jp>
> ---
>  lib/librte_eal/common/eal_common_dev.c  | 274 ++++++++++++++++++++++++++++++++
>  lib/librte_eal/common/eal_private.h     |  11 ++
>  lib/librte_eal/common/include/rte_dev.h |  33 ++++
>  lib/librte_eal/linuxapp/eal/Makefile    |   1 +
>  lib/librte_eal/linuxapp/eal/eal_pci.c   |   6 +-
>  5 files changed, 322 insertions(+), 3 deletions(-)
>
> diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
> index eae5656..e3a3f54 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,274 @@ rte_eal_dev_init(void)
>  	}
>  	return 0;
>  }
> +
> +/* So far, DPDK hotplug function only supports linux */
> +#ifdef ENABLE_HOTPLUG
> +static void
> +rte_eal_vdev_invoke(struct rte_driver *driver,
> +		struct rte_devargs *devargs, enum rte_eal_invoke_type type)
> +{
> +	if ((driver == NULL) || (devargs == NULL))
> +		return;
> +
> +	switch (type) {
> +	case RTE_EAL_INVOKE_TYPE_PROBE:
> +		driver->init(devargs->virtual.drv_name, devargs->args);
> +		break;
> +	case RTE_EAL_INVOKE_TYPE_CLOSE:
> +		driver->uninit(devargs->virtual.drv_name, devargs->args);
> +		break;
> +	default:
> +		break;
> +	}
> +}
> +
> +static int
> +rte_eal_vdev_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_vdev_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;
> +}
> +
> +/* attach the new physical device, then store port_id of the device */
> +static 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");

Sorry, what does "Drver" means?

My English is bad, also I haven't gotten this work in google

Thanks,
Michael
> +	return -1;
> +}
> +
> +/* detach the new physical device, then store pci_addr of the device */
> +static 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");

Here, "Drver"
> +	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 */
> +static 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_vdev_find_and_invoke(args, RTE_EAL_INVOKE_TYPE_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");

Here also "Drver",


Thanks,
Michael
> +	return -1;
> +}
> +
> +/* detach the new virtual device, then store the name of the device */
> +static 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_vdev_find_and_invoke(name, RTE_EAL_INVOKE_TYPE_CLOSE))
> +		goto err;
> +	/* remove the vdevname from devargs_list */
> +	if (rte_eal_devargs_remove(RTE_DEVTYPE_VIRTUAL, name))
> +		goto err;
> +
> +	strncpy(vdevname, name, sizeof(name));
> +	return 0;
> +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 ((devargs == NULL) || (port_id == NULL))
> +		return -EINVAL;
> +
> +	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 (name == NULL)
> +		return -EINVAL;
> +
> +	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);
> +}
> +#else /* ENABLE_HOTPLUG */
> +int
> +rte_eal_dev_attach(const char *devargs __rte_unused,
> +			uint8_t *port_id __rte_unused)
> +{
> +	RTE_LOG(ERR, EAL, "Hotplug support isn't enabled\n");
> +	return -1;
> +}
> +
> +/* detach the device, then store the name of the device */
> +int
> +rte_eal_dev_detach(uint8_t port_id __rte_unused,
> +			char *name __rte_unused)
> +{
> +	RTE_LOG(ERR, EAL, "Hotplug support isn't enabled\n");
> +	return -1;
> +}
> +#endif /* ENABLE_HOTPLUG */
> diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
> index 1a362ab..8168a7a 100644
> --- a/lib/librte_eal/common/eal_private.h
> +++ b/lib/librte_eal/common/eal_private.h
> @@ -163,6 +163,17 @@ enum rte_eal_invoke_type {
>  };
>  
>  /**
> + * 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/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
> index f7e3a10..e63dd1c 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);
> @@ -57,6 +58,11 @@ TAILQ_HEAD(rte_driver_list, rte_driver);
>  typedef int (rte_dev_init_t)(const char *name, const char *args);
>  
>  /**
> + * Uninitilization function called for each device driver once.
> + */
> +typedef int (rte_dev_uninit_t)(const char *name, const char *args);
> +
> +/**
>   * Driver type enumeration
>   */
>  enum pmd_type {
> @@ -72,6 +78,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_uninit_t *uninit;          /**< Device uninit. function. */
>  };
>  
>  /**
> @@ -93,6 +100,32 @@ void rte_eal_driver_register(struct rte_driver *driver);
>  void rte_eal_driver_unregister(struct rte_driver *driver);
>  
>  /**
> + * 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);
> +
> +/**
>   * Initalize all the registered drivers in this process
>   */
>  int rte_eal_dev_init(void);
> 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
> diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
> index 831422e..1f43688 100644
> --- a/lib/librte_eal/linuxapp/eal/eal_pci.c
> +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
> @@ -431,8 +431,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;
> @@ -764,7 +764,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;
>  	}



More information about the dev mailing list