911462eb4a
All information about a device to probe can be grouped in a common string, which is what we usually call devargs. An application should not have to parse this string before calling the EAL probe function. And the syntax could evolve to be more complex and support matching multiple devices in one string. That's why the bus name and device name should be removed from rte_eal_hotplug_add(). Instead of changing this function, a simpler one is added and used in the old one, which may be deprecated later. When removing a device, we already know its rte_device handle which can be directly passed as parameter of rte_eal_hotplug_remove(). If the rte_device is not known, it can be retrieved with the devargs, by iterating in the device list (future RTE_DEV_FOREACH()). Similarly to the probing case, a new function is added and used in the old one, which may be deprecated later. The new function is used in failsafe, because the replacement is easy. Signed-off-by: Thomas Monjalon <thomas@monjalon.net> Reviewed-by: Andrew Rybchenko <arybchenko@solarflare.com> Acked-by: Gaetan Rivet <gaetan.rivet@6wind.com> Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
167 lines
3.9 KiB
C
167 lines
3.9 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright 2017 6WIND S.A.
|
|
* Copyright 2017 Mellanox Technologies, Ltd
|
|
*/
|
|
|
|
#include <rte_malloc.h>
|
|
|
|
#include "failsafe_private.h"
|
|
|
|
static int
|
|
fs_ethdev_portid_get(const char *name, uint16_t *port_id)
|
|
{
|
|
uint16_t pid;
|
|
size_t len;
|
|
|
|
if (name == NULL) {
|
|
DEBUG("Null pointer is specified\n");
|
|
return -EINVAL;
|
|
}
|
|
len = strlen(name);
|
|
for (pid = 0; pid < RTE_MAX_ETHPORTS; pid++) {
|
|
if (rte_eth_dev_is_valid_port(pid) &&
|
|
!strncmp(name, rte_eth_devices[pid].device->name, len)) {
|
|
*port_id = pid;
|
|
return 0;
|
|
}
|
|
}
|
|
return -ENODEV;
|
|
}
|
|
|
|
static int
|
|
fs_bus_init(struct rte_eth_dev *dev)
|
|
{
|
|
struct sub_device *sdev;
|
|
struct rte_devargs *da;
|
|
uint8_t i;
|
|
uint16_t pid;
|
|
int ret;
|
|
|
|
FOREACH_SUBDEV(sdev, i, dev) {
|
|
if (sdev->state != DEV_PARSED)
|
|
continue;
|
|
da = &sdev->devargs;
|
|
if (fs_ethdev_portid_get(da->name, &pid) != 0) {
|
|
struct rte_eth_dev_owner pid_owner;
|
|
|
|
ret = rte_eal_hotplug_add(da->bus->name,
|
|
da->name,
|
|
da->args);
|
|
if (ret) {
|
|
ERROR("sub_device %d probe failed %s%s%s", i,
|
|
rte_errno ? "(" : "",
|
|
rte_errno ? strerror(rte_errno) : "",
|
|
rte_errno ? ")" : "");
|
|
continue;
|
|
}
|
|
if (fs_ethdev_portid_get(da->name, &pid) != 0) {
|
|
ERROR("sub_device %d init went wrong", i);
|
|
return -ENODEV;
|
|
}
|
|
/*
|
|
* The NEW callback tried to take ownership, check
|
|
* whether it succeed or didn't.
|
|
*/
|
|
rte_eth_dev_owner_get(pid, &pid_owner);
|
|
if (pid_owner.id != PRIV(dev)->my_owner.id) {
|
|
INFO("sub_device %d owner(%s_%016"PRIX64") is not my,"
|
|
" owner(%s_%016"PRIX64"), will try again later",
|
|
i, pid_owner.name, pid_owner.id,
|
|
PRIV(dev)->my_owner.name,
|
|
PRIV(dev)->my_owner.id);
|
|
continue;
|
|
}
|
|
} else {
|
|
/* The sub-device port was found. */
|
|
char devstr[DEVARGS_MAXLEN] = "";
|
|
struct rte_devargs *probed_da =
|
|
rte_eth_devices[pid].device->devargs;
|
|
|
|
/* Take control of probed device. */
|
|
free(da->args);
|
|
memset(da, 0, sizeof(*da));
|
|
if (probed_da != NULL)
|
|
snprintf(devstr, sizeof(devstr), "%s,%s",
|
|
probed_da->name, probed_da->args);
|
|
else
|
|
snprintf(devstr, sizeof(devstr), "%s",
|
|
rte_eth_devices[pid].device->name);
|
|
ret = rte_devargs_parse(da, devstr);
|
|
if (ret) {
|
|
ERROR("Probed devargs parsing failed with code"
|
|
" %d", ret);
|
|
return ret;
|
|
}
|
|
INFO("Taking control of a probed sub device"
|
|
" %d named %s", i, da->name);
|
|
ret = rte_eth_dev_owner_set(pid, &PRIV(dev)->my_owner);
|
|
if (ret < 0) {
|
|
INFO("sub_device %d owner set failed (%s), "
|
|
"will try again later", i, strerror(-ret));
|
|
continue;
|
|
} else if (strncmp(rte_eth_devices[pid].device->name,
|
|
da->name, strlen(da->name)) != 0) {
|
|
/*
|
|
* The device probably was removed and its port
|
|
* id was reallocated before ownership set.
|
|
*/
|
|
rte_eth_dev_owner_unset(pid,
|
|
PRIV(dev)->my_owner.id);
|
|
INFO("sub_device %d was removed before taking"
|
|
" ownership, will try again later", i);
|
|
continue;
|
|
}
|
|
}
|
|
ETH(sdev) = &rte_eth_devices[pid];
|
|
SUB_ID(sdev) = i;
|
|
sdev->fs_dev = dev;
|
|
sdev->dev = ETH(sdev)->device;
|
|
sdev->state = DEV_PROBED;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
failsafe_eal_init(struct rte_eth_dev *dev)
|
|
{
|
|
int ret;
|
|
|
|
ret = fs_bus_init(dev);
|
|
if (ret)
|
|
return ret;
|
|
if (PRIV(dev)->state < DEV_PROBED)
|
|
PRIV(dev)->state = DEV_PROBED;
|
|
fs_switch_dev(dev, NULL);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
fs_bus_uninit(struct rte_eth_dev *dev)
|
|
{
|
|
struct sub_device *sdev = NULL;
|
|
uint8_t i;
|
|
int sdev_ret;
|
|
int ret = 0;
|
|
|
|
FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) {
|
|
sdev_ret = rte_dev_remove(sdev->dev);
|
|
if (sdev_ret) {
|
|
ERROR("Failed to remove requested device %s (err: %d)",
|
|
sdev->dev->name, sdev_ret);
|
|
continue;
|
|
}
|
|
sdev->state = DEV_PROBED - 1;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
failsafe_eal_uninit(struct rte_eth_dev *dev)
|
|
{
|
|
int ret;
|
|
|
|
ret = fs_bus_uninit(dev);
|
|
PRIV(dev)->state = DEV_PROBED - 1;
|
|
return ret;
|
|
}
|