From patchwork Mon Jan 19 10:40:26 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tetsuya Mukawa X-Patchwork-Id: 2375 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id 78C235AD0; Mon, 19 Jan 2015 11:41:46 +0100 (CET) Received: from mail-pd0-f178.google.com (mail-pd0-f178.google.com [209.85.192.178]) by dpdk.org (Postfix) with ESMTP id 4A4845ABF for ; Mon, 19 Jan 2015 11:41:26 +0100 (CET) Received: by mail-pd0-f178.google.com with SMTP id r10so35817348pdi.9 for ; Mon, 19 Jan 2015 02:41:25 -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=LITgkhtdCaK7RQkGbd0/X/yzjUu1d8oaVe1IbOZHvGc=; b=MqGZ9UUGoYTxDJPDP5Q0yAtguxyeP2Al1QwVjqgdm8mFFC4QJDQ2GCWwv+UQvO3QFo Pp86BR20wXKZDqoQfr5eYS4bKK0T6jpDIT3Bio1dKAfLmWfBR2X0zFXNIn2MO3SVh8bQ eHiyBoQg/m/ycO/hW5FD57wMmGRHVTDBPL1+tlVQFZeIm/sfX01P91hMtP5Ssh2pHed7 VOUrVMc+P47dzSWALGSOni/XyJamqYB/3lDkPmdFfrmZWRye0HEY/3Z9qZdeyenkagFG r2HSXmgAXwWZFiBea4k+YXrywhKsmGAv5xjIzHIGfG/VK1kpXLkh+Iwn9y4jN5qsF3hr Wb3w== X-Gm-Message-State: ALoCoQmcj2ZkitWvaTkwVNzOgWsu45VS8eh1RiVQsgnPXybZad0JXra4yP0C/0VDw66aBAjmQLm9 X-Received: by 10.68.242.200 with SMTP id ws8mr43880016pbc.138.1421664085663; Mon, 19 Jan 2015 02:41:25 -0800 (PST) Received: from localhost.localdomain (napt.igel.co.jp. [219.106.231.132]) by mx.google.com with ESMTPSA id a13sm11337588pdm.44.2015.01.19.02.41.24 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 19 Jan 2015 02:41:24 -0800 (PST) From: Tetsuya Mukawa To: dev@dpdk.org Date: Mon, 19 Jan 2015 19:40:26 +0900 Message-Id: <1421664027-17971-11-git-send-email-mukawa@igel.co.jp> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1421664027-17971-1-git-send-email-mukawa@igel.co.jp> References: <1418106629-22227-2-git-send-email-mukawa@igel.co.j> <1421664027-17971-1-git-send-email-mukawa@igel.co.jp> Subject: [dpdk-dev] [PATCH v4 10/11] 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: , Errors-To: dev-bounces@dpdk.org Sender: "dev" 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 --- 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 +#include #include #include #include +#include #include #include #include @@ -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) +{ + 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 +#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, 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; }