numam-dpdk/lib/librte_eal/common/eal_common_devargs.c
Gaetan Rivet b65ecf1993 devargs: rename legacy API
The previous symbols were deprecated for two releases.
They are now marked as such and cannot be used anymore.

They are replaced by ones respecting the new namespace that are marked
experimental.

As a result, eth_dev attach and detach are slightly reworked to follow
the changes.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
Acked-by: Thomas Monjalon <thomas@monjalon.net>
2018-04-25 04:00:37 +02:00

245 lines
5.3 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright 2014 6WIND S.A.
*/
/* This file manages the list of devices and their arguments, as given
* by the user at startup
*
* Code here should not call rte_log since the EAL environment
* may not be initialized.
*/
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <rte_compat.h>
#include <rte_dev.h>
#include <rte_devargs.h>
#include <rte_tailq.h>
#include "eal_private.h"
/** user device double-linked queue type definition */
TAILQ_HEAD(rte_devargs_list, rte_devargs);
/** Global list of user devices */
struct rte_devargs_list devargs_list =
TAILQ_HEAD_INITIALIZER(devargs_list);
int
rte_eal_parse_devargs_str(const char *devargs_str,
char **drvname, char **drvargs)
{
char *sep;
if ((devargs_str) == NULL || (drvname) == NULL || (drvargs == NULL))
return -1;
*drvname = strdup(devargs_str);
if (*drvname == NULL)
return -1;
/* set the first ',' to '\0' to split name and arguments */
sep = strchr(*drvname, ',');
if (sep != NULL) {
sep[0] = '\0';
*drvargs = strdup(sep + 1);
} else {
*drvargs = strdup("");
}
if (*drvargs == NULL) {
free(*drvname);
*drvname = NULL;
return -1;
}
return 0;
}
static int
bus_name_cmp(const struct rte_bus *bus, const void *name)
{
return strncmp(bus->name, name, strlen(bus->name));
}
int __rte_experimental
rte_devargs_parse(struct rte_devargs *da, const char *format, ...)
{
struct rte_bus *bus = NULL;
va_list ap;
va_start(ap, format);
char dev[vsnprintf(NULL, 0, format, ap) + 1];
const char *devname;
const size_t maxlen = sizeof(da->name);
size_t i;
va_end(ap);
if (da == NULL)
return -EINVAL;
va_start(ap, format);
vsnprintf(dev, sizeof(dev), format, ap);
va_end(ap);
/* Retrieve eventual bus info */
do {
devname = dev;
bus = rte_bus_find(bus, bus_name_cmp, dev);
if (bus == NULL)
break;
devname = dev + strlen(bus->name) + 1;
if (rte_bus_find_by_device_name(devname) == bus)
break;
} while (1);
/* Store device name */
i = 0;
while (devname[i] != '\0' && devname[i] != ',') {
da->name[i] = devname[i];
i++;
if (i == maxlen) {
fprintf(stderr, "WARNING: Parsing \"%s\": device name should be shorter than %zu\n",
dev, maxlen);
da->name[i - 1] = '\0';
return -EINVAL;
}
}
da->name[i] = '\0';
if (bus == NULL) {
bus = rte_bus_find_by_device_name(da->name);
if (bus == NULL) {
fprintf(stderr, "ERROR: failed to parse device \"%s\"\n",
da->name);
return -EFAULT;
}
}
da->bus = bus;
/* Parse eventual device arguments */
if (devname[i] == ',')
da->args = strdup(&devname[i + 1]);
else
da->args = strdup("");
if (da->args == NULL) {
fprintf(stderr, "ERROR: not enough memory to parse arguments\n");
return -ENOMEM;
}
return 0;
}
int __rte_experimental
rte_devargs_insert(struct rte_devargs *da)
{
int ret;
ret = rte_devargs_remove(da->bus->name, da->name);
if (ret < 0)
return ret;
TAILQ_INSERT_TAIL(&devargs_list, da, next);
return 0;
}
/* store a whitelist parameter for later parsing */
__rte_experimental
int
rte_devargs_add(enum rte_devtype devtype, const char *devargs_str)
{
struct rte_devargs *devargs = NULL;
struct rte_bus *bus = NULL;
const char *dev = devargs_str;
/* use calloc instead of rte_zmalloc as it's called early at init */
devargs = calloc(1, sizeof(*devargs));
if (devargs == NULL)
goto fail;
if (rte_devargs_parse(devargs, "%s", dev))
goto fail;
devargs->type = devtype;
bus = devargs->bus;
if (devargs->type == RTE_DEVTYPE_BLACKLISTED_PCI)
devargs->policy = RTE_DEV_BLACKLISTED;
if (bus->conf.scan_mode == RTE_BUS_SCAN_UNDEFINED) {
if (devargs->policy == RTE_DEV_WHITELISTED)
bus->conf.scan_mode = RTE_BUS_SCAN_WHITELIST;
else if (devargs->policy == RTE_DEV_BLACKLISTED)
bus->conf.scan_mode = RTE_BUS_SCAN_BLACKLIST;
}
TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
return 0;
fail:
if (devargs) {
free(devargs->args);
free(devargs);
}
return -1;
}
int __rte_experimental
rte_devargs_remove(const char *busname, const char *devname)
{
struct rte_devargs *d;
void *tmp;
TAILQ_FOREACH_SAFE(d, &devargs_list, next, tmp) {
if (strcmp(d->bus->name, busname) == 0 &&
strcmp(d->name, devname) == 0) {
TAILQ_REMOVE(&devargs_list, d, next);
free(d->args);
free(d);
return 0;
}
}
return 1;
}
/* count the number of devices of a specified type */
__rte_experimental
unsigned int
rte_devargs_type_count(enum rte_devtype devtype)
{
struct rte_devargs *devargs;
unsigned int count = 0;
TAILQ_FOREACH(devargs, &devargs_list, next) {
if (devargs->type != devtype)
continue;
count++;
}
return count;
}
/* dump the user devices on the console */
__rte_experimental
void
rte_devargs_dump(FILE *f)
{
struct rte_devargs *devargs;
fprintf(f, "User device list:\n");
TAILQ_FOREACH(devargs, &devargs_list, next) {
fprintf(f, " [%s]: %s %s\n",
(devargs->bus ? devargs->bus->name : "??"),
devargs->name, devargs->args);
}
}
/* bus-aware rte_devargs iterator. */
__rte_experimental
struct rte_devargs *
rte_devargs_next(const char *busname, const struct rte_devargs *start)
{
struct rte_devargs *da;
if (start != NULL)
da = TAILQ_NEXT(start, next);
else
da = TAILQ_FIRST(&devargs_list);
while (da != NULL) {
if (busname == NULL ||
(strcmp(busname, da->bus->name) == 0))
return da;
da = TAILQ_NEXT(da, next);
}
return NULL;
}