ethdev: attach or detach port
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. Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
This commit is contained in:
parent
9f1653e7b7
commit
92d94d3744
@ -312,6 +312,15 @@ rte_eal_compare_pci_addr(struct rte_pci_addr *addr, struct rte_pci_addr *addr2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -440,8 +440,8 @@ parse_pci_addr_format(const char *buf, int bufsize, uint16_t *domain,
|
||||
* 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;
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ DPDK_2.0 {
|
||||
rte_eal_pci_probe;
|
||||
rte_eal_pci_probe_one;
|
||||
rte_eal_pci_register;
|
||||
rte_eal_pci_scan;
|
||||
rte_eal_pci_unregister;
|
||||
rte_eal_process_type;
|
||||
rte_eal_remote_launch;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -175,6 +175,8 @@ extern "C" {
|
||||
#include <rte_log.h>
|
||||
#include <rte_interrupts.h>
|
||||
#include <rte_pci.h>
|
||||
#include <rte_dev.h>
|
||||
#include <rte_devargs.h>
|
||||
#include <rte_mbuf.h>
|
||||
#include "rte_ether.h"
|
||||
#include "rte_eth_ctrl.h"
|
||||
@ -1539,6 +1541,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.
|
||||
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user