From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pa0-f47.google.com (mail-pa0-f47.google.com [209.85.220.47]) by dpdk.org (Postfix) with ESMTP id 788AB7E6A for ; Wed, 25 Feb 2015 20:33:12 +0100 (CET) Received: by pablj1 with SMTP id lj1so5173389pab.9 for ; Wed, 25 Feb 2015 11:33:11 -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=WFRvGobCeWzSZRr+Qz1OVTcBf00WHcFvalFaE1e8SFo=; b=kZr1/+pd+aScJlNnvp54UukwqIoiVs0n2z5M4M61KvXFAtdbXGEF2f/Yd8IMtAgZN6 X9B/BNyf+EldtmZatE/izGGqG4CCngAxlCaJI2WUHKZKJEkDd7CMGkincEYDXnHrFgjF RJk+9T/fIRiw/8WzPw6Hov1XhTkGpzcBwXQXAExF75VpjAjcKy30pdXOyqHATEq3fWfc jiNvqrjBTkQ+RPM2tS9LCvYI/rUeDNIPoxhiE9Ql+pvvdkFP1QG2l7Unz7C9wLKLctPG IXIK8CCmwFzD9A9XZznusPEVsM1mXXAIPkivzeI/VSitNohmNuwEpYAMUF1Y7/nPckI9 0RuA== X-Gm-Message-State: ALoCoQnhxcd7JAUP5pO10yzLSTE6aV0fIO8Ik+YzJrWG/EbzKFmxZ8iBfEuEvEpHD9tD8jgzgtjL X-Received: by 10.66.147.169 with SMTP id tl9mr8023705pab.63.1424892791887; Wed, 25 Feb 2015 11:33:11 -0800 (PST) Received: from localhost.localdomain (napt.igel.co.jp. [219.106.231.132]) by mx.google.com with ESMTPSA id ux7sm39997444pab.19.2015.02.25.11.33.09 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 25 Feb 2015 11:33:11 -0800 (PST) From: Tetsuya Mukawa To: dev@dpdk.org Date: Thu, 26 Feb 2015 04:32:26 +0900 Message-Id: <1424892749-31862-13-git-send-email-mukawa@igel.co.jp> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1424892749-31862-1-git-send-email-mukawa@igel.co.jp> References: <1424837093-5661-13-git-send-email-mukawa@igel.co.jp> <1424892749-31862-1-git-send-email-mukawa@igel.co.jp> Subject: [dpdk-dev] [PATCH v15 12/13] ethdev: Add rte_eth_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: Wed, 25 Feb 2015 19:33:13 -0000 These functions are used for attaching or detaching a port. When rte_eth_dev_attach() is called, the function tries to realize the device name as pci address. If this is done successfully, rte_eth_dev_attach() will attach physical device port. If not, attaches virtual devive port. When rte_eth_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. v15: - Fix issue that eal calls ethedv library APIs. - Remove rte_eal_dev_attach(), and add rte_eth_dev_attach(). - Remove rte_eal_dev_detach(), and add rte_eth_dev_detach(). - Call rte_eal_vdev_init/uninit from ethdev library. (Thanks to Thomas Monjalon) - Fix version.map - Squash below patch to compile. - ethdev: Add functions that will be used by port hotplug functions v14: - Remove needless if statement. (Thanks to Maxime Leroy) v13: - Change log level when error occurs in rte_eal_vdev_init() and rte_eal_dev_init(). - Return value of driver init and uninit functions. - Replace rte_panic by RTE_LOG in rte_eal_dev_init() - Fix return value of rte_eal_vdev_uninit(). - Fix rte_eal_dev_attach_vdev to set port_id correctly. (Thanks to Maxime Leroy) 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/include/rte_pci.h | 9 + lib/librte_eal/linuxapp/eal/eal_pci.c | 6 +- lib/librte_eal/linuxapp/eal/rte_eal_version.map | 1 + lib/librte_ether/rte_ethdev.c | 303 +++++++++++++++++++++++- lib/librte_ether/rte_ethdev.h | 38 +++ lib/librte_ether/rte_ether_version.map | 3 + 6 files changed, 355 insertions(+), 5 deletions(-) diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h index ac30925..b9cdf8b 100644 --- a/lib/librte_eal/common/include/rte_pci.h +++ b/lib/librte_eal/common/include/rte_pci.h @@ -313,6 +313,15 @@ rte_eal_compare_pci_addr(struct rte_pci_addr *addr, struct rte_pci_addr *addr2) } /** + * Scan the content of the PCI bus, and the devices in the devices + * list + * + * @return + * 0 on success, negative on error + */ +int rte_eal_pci_scan(void); + +/** * Probe the PCI bus for registered drivers. * * Scan the content of the PCI bus, and call the probe() function for diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c index f880f90..6d4932d 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci.c +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c @@ -440,8 +440,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; @@ -773,7 +773,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 214643d..7c2aac3 100644 --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map @@ -45,6 +45,7 @@ DPDK_2.0 { rte_eal_pci_probe_one; rte_eal_pci_register; rte_eal_pci_unregister; + rte_eal_pci_scan; rte_eal_process_type; rte_eal_remote_launch; rte_eal_tailq_lookup; diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c index b07f2df..868289c 100644 --- a/lib/librte_ether/rte_ethdev.c +++ b/lib/librte_ether/rte_ethdev.c @@ -201,7 +201,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; @@ -270,7 +270,6 @@ rte_eth_dev_create_unique_device_name(char *name, size_t size, pci_dev->addr.function); if (ret < 0) return ret; - return 0; } @@ -427,6 +426,306 @@ rte_eth_dev_count(void) return (nb_ports); } +static enum rte_eth_dev_type +rte_eth_dev_get_device_type(uint8_t port_id) +{ + if (!rte_eth_dev_is_valid_port(port_id)) + return -1; + return rte_eth_devices[port_id].dev_type; +} + +static int +rte_eth_dev_save(struct rte_eth_dev *devs, size_t size) +{ + if ((devs == NULL) || + (size != sizeof(struct rte_eth_dev) * RTE_MAX_ETHPORTS)) + return -EINVAL; + + /* save current rte_eth_devices */ + memcpy(devs, rte_eth_devices, size); + return 0; +} + +static int +rte_eth_dev_get_changed_port(struct rte_eth_dev *devs, uint8_t *port_id) +{ + if ((devs == NULL) || (port_id == NULL)) + return -EINVAL; + + /* 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 -ENODEV; +} + +static int +rte_eth_dev_get_addr_by_port(uint8_t port_id, struct rte_pci_addr *addr) +{ + if (!rte_eth_dev_is_valid_port(port_id)) { + 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_get_name_by_port(uint8_t port_id, char *name) +{ + char *tmp; + + if (!rte_eth_dev_is_valid_port(port_id)) { + 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; + strcpy(name, tmp); + return 0; +} + +static int +rte_eth_dev_is_detachable(uint8_t port_id) +{ + uint32_t drv_flags; + + if (port_id >= RTE_MAX_ETHPORTS) { + PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); + return -EINVAL; + } + + if (rte_eth_devices[port_id].dev_type == RTE_ETH_DEV_PCI) { + switch (rte_eth_devices[port_id].pci_dev->pt_driver) { + case RTE_PT_IGB_UIO: + case RTE_PT_UIO_GENERIC: + break; + case RTE_PT_VFIO: + default: + return -ENOTSUP; + } + } + + drv_flags = rte_eth_devices[port_id].driver->pci_drv.drv_flags; + return !(drv_flags & RTE_PCI_DRV_DETACHABLE); +} + +/* So far, DPDK hotplug function only supports linux */ +#ifdef RTE_LIBRTE_EAL_HOTPLUG +/* attach the new physical device, then store port_id of the device */ +static int +rte_eth_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_eth_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_eth_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; + *port_id = new_port_id; +end: + if (name) + free(name); + if (args) + free(args); + + 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_eth_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_eth_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_eth_dev_attach_pdev(&addr, port_id); + else + return rte_eth_dev_attach_vdev(devargs, port_id); +} + +/* detach the device, then store the name of the device */ +int +rte_eth_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_eth_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_eth_dev_detach_vdev(port_id, name); +} +#else /* RTE_LIBRTE_EAL_HOTPLUG */ +int +rte_eth_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_eth_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 */ + 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 50c2dce..53d146c 100644 --- a/lib/librte_ether/rte_ethdev.h +++ b/lib/librte_ether/rte_ethdev.h @@ -175,6 +175,8 @@ extern "C" { #include #include #include +#include +#include #include #include "rte_ether.h" #include "rte_eth_ctrl.h" @@ -1540,6 +1542,16 @@ extern struct rte_eth_dev rte_eth_devices[]; extern uint8_t rte_eth_dev_count(void); /** + * 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 @@ -1565,6 +1577,32 @@ struct rte_eth_dev *rte_eth_dev_allocate(const char *name, */ int rte_eth_dev_release_port(struct rte_eth_dev *eth_dev); +/** + * Attach a new Ethernet device specified by aruguments. + * + * @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_eth_dev_attach(const char *devargs, uint8_t *port_id); + +/** + * Detach a Ethernet device specified by port identifier. + * + * @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_eth_dev_detach(uint8_t port_id, char *devname); + struct eth_driver; /** * @internal diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map index 94fd685..0d46578 100644 --- a/lib/librte_ether/rte_ether_version.map +++ b/lib/librte_ether/rte_ether_version.map @@ -8,6 +8,8 @@ DPDK_2.0 { rte_eth_allmulticast_enable; rte_eth_allmulticast_get; rte_eth_dev_allocate; + rte_eth_dev_allocated; + rte_eth_dev_attach; rte_eth_dev_bypass_event_show; rte_eth_dev_bypass_event_store; rte_eth_dev_bypass_init; @@ -22,6 +24,7 @@ DPDK_2.0 { rte_eth_dev_close; rte_eth_dev_configure; rte_eth_dev_count; + rte_eth_dev_detach; rte_eth_dev_fdir_add_perfect_filter; rte_eth_dev_fdir_add_signature_filter; rte_eth_dev_fdir_get_infos; -- 1.9.1