From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pd0-f176.google.com (mail-pd0-f176.google.com [209.85.192.176]) by dpdk.org (Postfix) with ESMTP id ADEFCB411 for ; Mon, 23 Feb 2015 06:10:17 +0100 (CET) Received: by pdjg10 with SMTP id g10so22811651pdj.1 for ; Sun, 22 Feb 2015 21:10:17 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=h3MOSYf90FA7gpzxAHAf6bfm15+7608svbLAdQlsZUI=; b=I1UxcXFGRzsEjlZKx9eLz8UMOzF7VR3F/GvF5G2cbufbEGpIcTclcKFPGPTvC/PZUo rEbucm2yewZmyfzjVVo9qGklobxQYqIgCfOOYCqHmmbL0hePneZhyUE4Jl0+33e2JxM5 vN36+pY5hGStBW24pF5jTFuLZU9tbOTum83Zv8931StYX/qKjcgXTPP24PwhAcIOhY31 hUsHpVkGcMqfVm8Gj5H/8kuzqp2SWub5fk9nGLfK/9FBynbNi/kRL3/6u8x9OSrPAekr gTRLFtWpFME75uFjnIHH6lFj85D2YcmsL9yHnYXqrDWk0F5IE8CpqowewFt5n1hPrrCZ d05w== X-Gm-Message-State: ALoCoQleI7dKA8UI7E1HbbyWxMQIycsybSUR5sFC4fQ+qseT2HCEyG2tUfTiTLlOKFwwUIm0BGHP X-Received: by 10.66.217.198 with SMTP id pa6mr16193588pac.49.1424668217082; Sun, 22 Feb 2015 21:10:17 -0800 (PST) Received: from localhost.localdomain (napt.igel.co.jp. [219.106.231.132]) by mx.google.com with ESMTPSA id dc4sm12978066pbb.55.2015.02.22.21.10.14 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 22 Feb 2015 21:10:16 -0800 (PST) From: Tetsuya Mukawa To: dev@dpdk.org Date: Mon, 23 Feb 2015 14:09:28 +0900 Message-Id: <1424668171-8695-13-git-send-email-mukawa@igel.co.jp> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1424668171-8695-1-git-send-email-mukawa@igel.co.jp> References: <1424414390-18509-6-git-send-email-mukawa@igel.co.jp> <1424668171-8695-1-git-send-email-mukawa@igel.co.jp> Subject: [dpdk-dev] [PATCH v11 12/13] eal/pci: Add rte_eal_dev_attach/detach() functions X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Feb 2015 05:10:18 -0000 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 come from physical or virtual. And then specific detaching function will be called. v11: - Remove needless devargs handling codes. - Replace get_vdev_name() by rte_eal_parse_devargs_str(). - Replace rte_eal_vdev_find_and_init by rte_eal_vdev_init() - Replace rte_eal_vdev_find_and_uninit by rte_eal_vdev_uninit() - Fix rte_eal_dev_init() to use rte_eal_vdev_init(). (Thanks to Maxime Leroy) v10: - Add comments. - Change order of version.map. (Thanks to Thomas Monjalon) v9: - Fix comments. - Use strcmp() instead of strncmp(). - Remove RTE_EAL_INVOKE_TYPE_PROBE/CLOSE. - Change definition of rte_dev_uninit_t. (Thanks to Thomas Monjalon and Maxime Leroy) v8: - Add missing symbol in version map. (Thanks to Qiu, Michael and Iremonger, Bernard) v7: - Fix typo of warning messages. (Thanks to Qiu, Michael) 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 --- lib/librte_eal/common/eal_common_dev.c | 285 ++++++++++++++++++++++-- lib/librte_eal/common/eal_common_devargs.c | 46 ++-- lib/librte_eal/common/eal_private.h | 11 + lib/librte_eal/common/include/rte_dev.h | 33 +++ lib/librte_eal/common/include/rte_devargs.h | 28 +++ lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/linuxapp/eal/eal_pci.c | 6 +- lib/librte_eal/linuxapp/eal/rte_eal_version.map | 2 + 8 files changed, 378 insertions(+), 34 deletions(-) diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c index eae5656..7d4dce6 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 +#include #include #include #include +#include #include #include #include @@ -61,6 +64,37 @@ rte_eal_driver_unregister(struct rte_driver *driver) TAILQ_REMOVE(&dev_driver_list, driver, next); } +static int +rte_eal_vdev_init(const char *name, const char *args) +{ + struct rte_driver *driver; + + if (name == NULL) + return -EINVAL; + + TAILQ_FOREACH(driver, &dev_driver_list, next) { + if (driver->type != PMD_VDEV) + continue; + + /* + * search a driver prefix in virtual device name. + * For example, if the driver is pcap PMD, driver->name + * will be "eth_pcap", but "name" will be "eth_pcapN". + * So use strncmp to compare. + */ + if (!strncmp(driver->name, name, strlen(driver->name))) { + driver->init(name, args); + break; + } + } + + if (driver == NULL) { + RTE_LOG(WARNING, EAL, "no driver found for %s\n", name); + return -EINVAL; + } + return 0; +} + int rte_eal_dev_init(void) { @@ -79,23 +113,10 @@ rte_eal_dev_init(void) if (devargs->type != RTE_DEVTYPE_VIRTUAL) 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))) { - driver->init(devargs->virtual.drv_name, - devargs->args); - break; - } - } - - if (driver == NULL) { + if (rte_eal_vdev_init(devargs->virtual.drv_name, + devargs->args)) rte_panic("no driver found for %s\n", devargs->virtual.drv_name); - } } /* Once the vdevs are initalized, start calling all the pdev drivers */ @@ -107,3 +128,237 @@ rte_eal_dev_init(void) } return 0; } + +/* So far, DPDK hotplug function only supports linux */ +#ifdef RTE_LIBRTE_EAL_HOTPLUG +static int +rte_eal_vdev_uninit(const char *name) +{ + struct rte_driver *driver; + + if (name == NULL) + return -EINVAL; + + TAILQ_FOREACH(driver, &dev_driver_list, next) { + if (driver->type != PMD_VDEV) + continue; + + /* + * search a driver prefix in virtual device name. + * For example, if the driver is pcap PMD, driver->name + * will be "eth_pcap", but "name" will be "eth_pcapN". + * So use strncmp to compare. + */ + if (!strncmp(driver->name, name, strlen(driver->name))) { + driver->uninit(name); + break; + } + } + + if (driver == NULL) { + RTE_LOG(WARNING, EAL, "no driver found for %s\n", name); + return 1; + } + return 0; +} + +/* 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 */ + if (rte_eth_dev_save(devs, sizeof(devs))) + goto err; + /* re-construct pci_device_list */ + if (rte_eal_pci_scan()) + goto err; + /* invoke probe func of the driver can handle the new device. + * TODO: + * rte_eal_pci_probe_one() should return port_id. + * And rte_eth_dev_save() and rte_eth_dev_get_changed_port() + * should be removed. */ + 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, "Driver, 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_is_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 (rte_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, "Driver, cannot detach the device\n"); + return -1; +} + +/* 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 *name = NULL, *args = NULL; + uint8_t new_port_id; + struct rte_eth_dev devs[RTE_MAX_ETHPORTS]; + int ret = -1; + + if ((vdevargs == NULL) || (port_id == NULL)) + goto end; + + /* parse vdevargs, then retrieve device name and args */ + if (rte_eal_parse_devargs_str(vdevargs, &name, &args)) + goto end; + + /* save current port status */ + if (rte_eth_dev_save(devs, sizeof(devs))) + goto end; + /* walk around dev_driver_list to find the driver of the device, + * then invoke probe function o the driver. + * TODO: + * rte_eal_vdev_init() should return port_id, + * And rte_eth_dev_save() and rte_eth_dev_get_changed_port() + * should be removed. */ + if (rte_eal_vdev_init(name, args)) + goto end; + /* get port_id enabled by above procedures */ + if (rte_eth_dev_get_changed_port(devs, &new_port_id)) + goto end; + ret = 0; + +end: + if (name) + free(name); + if (args) + free(args); + + *port_id = new_port_id; + if (ret < 0) + RTE_LOG(ERR, EAL, "Driver, cannot attach the device\n"); + return ret; +} + +/* 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_is_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_uninit(name)) + goto err; + + strncpy(vdevname, name, sizeof(name)); + return 0; +err: + RTE_LOG(ERR, EAL, "Driver, 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_PCI) { + 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 /* RTE_LIBRTE_EAL_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 /* RTE_LIBRTE_EAL_HOTPLUG */ diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c index 3aace08..2988a70 100644 --- a/lib/librte_eal/common/eal_common_devargs.c +++ b/lib/librte_eal/common/eal_common_devargs.c @@ -44,13 +44,41 @@ struct rte_devargs_list devargs_list = TAILQ_HEAD_INITIALIZER(devargs_list); +int +rte_eal_parse_devargs_str(const char *devargs_str, + char **drvname, char **drvargs) +{ + char *sep; + + if ((devargs_str == NULL) || drvname == NULL || drvargs == NULL) + return -1; + + *drvname = strdup(devargs_str); + if (drvname == NULL) { + RTE_LOG(ERR, EAL, "cannot allocate temp memory for devargs\n"); + return -1; + } + + /* set the first ',' to '\0' to split name and arguments */ + sep = strchr(*drvname, ','); + if (sep != NULL) { + sep[0] = '\0'; + *drvargs = strdup(sep + 1); + if (*drvargs == NULL) { + RTE_LOG(ERR, EAL, "cannot allocate for devargs args\n"); + free(*drvname); + return -1; + } + } + return 0; +} + /* store a whitelist parameter for later parsing */ int rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str) { struct rte_devargs *devargs = NULL; char *buf = NULL; - char *sep; int ret; /* use malloc instead of rte_malloc as it's called early at init */ @@ -62,22 +90,8 @@ rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str) memset(devargs, 0, sizeof(*devargs)); devargs->type = devtype; - buf = strdup(devargs_str); - if (buf == NULL) { - RTE_LOG(ERR, EAL, "cannot allocate temp memory for devargs\n"); + if (rte_eal_parse_devargs_str(devargs_str, &buf, &devargs->args)) goto fail; - } - - /* set the first ',' to '\0' to split name and arguments */ - sep = strchr(buf, ','); - if (sep != NULL) { - sep[0] = '\0'; - devargs->args = strdup(sep + 1); - if (devargs->args == NULL) { - RTE_LOG(ERR, EAL, "cannot allocate for devargs args\n"); - goto fail; - } - } switch (devargs->type) { case RTE_DEVTYPE_WHITELISTED_PCI: diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h index 4acf5a0..98b286a 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/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h index f7e3a10..a5ac770 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 +#include /** 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); + +/** * 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/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h index 996e180..274a92c 100644 --- a/lib/librte_eal/common/include/rte_devargs.h +++ b/lib/librte_eal/common/include/rte_devargs.h @@ -99,6 +99,34 @@ TAILQ_HEAD(rte_devargs_list, rte_devargs); extern struct rte_devargs_list devargs_list; /** + * Parse a devargs string. + * + * For PCI devices, the format of arguments string is "PCI_ADDR" or + * "PCI_ADDR,key=val,key2=val2,...". Examples: "08:00.1", "0000:5:00.0", + * "04:00.0,arg=val". + * + * For virtual devices, the format of arguments string is "DRIVER_NAME*" + * or "DRIVER_NAME*,key=val,key2=val2,...". Examples: "eth_ring", + * "eth_ring0", "eth_pmdAnything,arg=0:arg2=1". + * + * The function parses the arguments string to get driver name and driver + * arguments. + * + * @param devargs_str + * The arguments as given by the user. + * @param drvname + * The pointer to the string to store parsed driver name. + * @param drvargs + * The pointer to the string to store parsed driver arguments. + * + * @return + * - 0 on success + * - A negative value on error + */ +int rte_eal_parse_devargs_str(const char *devargs_str, + char **drvname, char **drvargs); + +/** * Add a device to the user device list * * For PCI devices, the format of arguments string is "PCI_ADDR" or diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile index e117cec..b59b201 100644 --- a/lib/librte_eal/linuxapp/eal/Makefile +++ b/lib/librte_eal/linuxapp/eal/Makefile @@ -45,6 +45,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 85d9d09..ab77b68 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci.c +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c @@ -439,8 +439,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; @@ -772,7 +772,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; } diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map index 5ed6e4d..5d40e02 100644 --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map @@ -20,6 +20,8 @@ DPDK_2.0 { rte_dump_tailq; rte_eal_alarm_cancel; rte_eal_alarm_set; + rte_eal_dev_attach; + rte_eal_dev_detach; rte_eal_dev_init; rte_eal_devargs_add; rte_eal_devargs_dump; -- 1.9.1