Message ID | 1421664027-17971-11-git-send-email-mukawa@igel.co.jp (mailing list archive) |
---|---|
State | Superseded, archived |
Headers | show |
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@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* > +{ > + 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; > }
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@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; >> }
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) +{ + 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; }
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@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(-)