[dpdk-dev] [PATCH v4 10/11] eal/pci: Add rte_eal_dev_attach/detach() functions
Tetsuya Mukawa
mukawa at igel.co.jp
Wed Jan 21 07:34:47 CET 2015
Hi Michael,
On 2015/01/21 12:49, Qiu, Michael wrote:
> On 1/19/2015 6:43 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.
>>
>> 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 | 273 ++++++++++++++++++++++++++++++++
>> 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, 321 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..828bd70 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,273 @@ rte_eal_dev_init(void)
>> }
>> return 0;
>> }
>> +
>> +/* So far, DPDK hotplug function only supports linux */
>> +#ifdef ENABLE_HOTPLUG
>> +static void
>> +rte_eal_dev_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_dev_find_and_invoke(const char *name, int type)
> This function is totally for vdev, so I would like it shows in name,
> like *rte_eal_vdev_find_and_invoke*
Sure, I will change like above. I appreciate your suggestion.
Thanks,
Tetsuya
>> +{
>> + 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;
>> +}
>> +
>> +/* 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");
>> + 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");
>> + 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_dev_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");
>> + 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_dev_find_and_invoke(name, RTE_EAL_INVOKE_TYPE_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;
>> +}
>> +
>> +/* 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 a97c5d8..453a1eb 100644
>> --- a/lib/librte_eal/common/eal_private.h
>> +++ b/lib/librte_eal/common/eal_private.h
>> @@ -164,6 +164,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 a23cc59..8e7e650 100644
>> --- a/lib/librte_eal/linuxapp/eal/eal_pci.c
>> +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
>> @@ -378,8 +378,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;
>> @@ -701,7 +701,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