numam-dpdk/drivers/raw/ioat/idxd_bus.c
Kevin Laatz acbedb58fa raw/ioat: fix missing device name in idxd bus scan
The device name is not being initialized during the idxd bus scan which
will cause segmentation faults when an appliation tries to access this
information.

This patch adds the required initialization of the device name so that it
can be read without issues.

Fixes: b7aaf417f936 ("raw/ioat: add bus driver for device scanning automatically")
Cc: stable@dpdk.org

Reported-by: Sunil Pai G <sunil.pai.g@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
Tested-by: Sunil Pai G <sunil.pai.g@intel.com>
2021-06-17 09:37:12 +02:00

366 lines
8.6 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2021 Intel Corporation
*/
#include <dirent.h>
#include <libgen.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <rte_bus.h>
#include <rte_log.h>
#include <rte_string_fns.h>
#include "ioat_private.h"
/* default value for DSA paths, but allow override in environment for testing */
#define DSA_DEV_PATH "/dev/dsa"
#define DSA_SYSFS_PATH "/sys/bus/dsa/devices"
static unsigned int devcount;
/** unique identifier for a DSA device/WQ instance */
struct dsa_wq_addr {
uint16_t device_id;
uint16_t wq_id;
};
/** a DSA device instance */
struct rte_dsa_device {
struct rte_device device; /**< Inherit core device */
TAILQ_ENTRY(rte_dsa_device) next; /**< next dev in list */
char wq_name[32]; /**< the workqueue name/number e.g. wq0.1 */
struct dsa_wq_addr addr; /**< Identifies the specific WQ */
};
/* forward prototypes */
struct dsa_bus;
static int dsa_scan(void);
static int dsa_probe(void);
static struct rte_device *dsa_find_device(const struct rte_device *start,
rte_dev_cmp_t cmp, const void *data);
static enum rte_iova_mode dsa_get_iommu_class(void);
static int dsa_addr_parse(const char *name, void *addr);
/** List of devices */
TAILQ_HEAD(dsa_device_list, rte_dsa_device);
/**
* Structure describing the DSA bus
*/
struct dsa_bus {
struct rte_bus bus; /**< Inherit the generic class */
struct rte_driver driver; /**< Driver struct for devices to point to */
struct dsa_device_list device_list; /**< List of PCI devices */
};
struct dsa_bus dsa_bus = {
.bus = {
.scan = dsa_scan,
.probe = dsa_probe,
.find_device = dsa_find_device,
.get_iommu_class = dsa_get_iommu_class,
.parse = dsa_addr_parse,
},
.driver = {
.name = "rawdev_idxd"
},
.device_list = TAILQ_HEAD_INITIALIZER(dsa_bus.device_list),
};
static inline const char *
dsa_get_dev_path(void)
{
const char *path = getenv("DSA_DEV_PATH");
return path ? path : DSA_DEV_PATH;
}
static inline const char *
dsa_get_sysfs_path(void)
{
const char *path = getenv("DSA_SYSFS_PATH");
return path ? path : DSA_SYSFS_PATH;
}
static const struct rte_rawdev_ops idxd_vdev_ops = {
.dev_close = idxd_rawdev_close,
.dev_selftest = ioat_rawdev_test,
.dump = idxd_dev_dump,
.dev_configure = idxd_dev_configure,
.dev_info_get = idxd_dev_info_get,
.xstats_get = ioat_xstats_get,
.xstats_get_names = ioat_xstats_get_names,
.xstats_reset = ioat_xstats_reset,
};
static void *
idxd_vdev_mmap_wq(struct rte_dsa_device *dev)
{
void *addr;
char path[PATH_MAX];
int fd;
snprintf(path, sizeof(path), "%s/%s", dsa_get_dev_path(), dev->wq_name);
fd = open(path, O_RDWR);
if (fd < 0) {
IOAT_PMD_ERR("Failed to open device path: %s", path);
return NULL;
}
addr = mmap(NULL, 0x1000, PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
if (addr == MAP_FAILED) {
IOAT_PMD_ERR("Failed to mmap device %s", path);
return NULL;
}
return addr;
}
static int
read_wq_string(struct rte_dsa_device *dev, const char *filename,
char *value, size_t valuelen)
{
char sysfs_node[PATH_MAX];
int len;
int fd;
snprintf(sysfs_node, sizeof(sysfs_node), "%s/%s/%s",
dsa_get_sysfs_path(), dev->wq_name, filename);
fd = open(sysfs_node, O_RDONLY);
if (fd < 0) {
IOAT_PMD_ERR("%s(): opening file '%s' failed: %s",
__func__, sysfs_node, strerror(errno));
return -1;
}
len = read(fd, value, valuelen - 1);
close(fd);
if (len < 0) {
IOAT_PMD_ERR("%s(): error reading file '%s': %s",
__func__, sysfs_node, strerror(errno));
return -1;
}
value[len] = '\0';
return 0;
}
static int
read_wq_int(struct rte_dsa_device *dev, const char *filename,
int *value)
{
char sysfs_node[PATH_MAX];
FILE *f;
int ret = 0;
snprintf(sysfs_node, sizeof(sysfs_node), "%s/%s/%s",
dsa_get_sysfs_path(), dev->wq_name, filename);
f = fopen(sysfs_node, "r");
if (f == NULL) {
IOAT_PMD_ERR("%s(): opening file '%s' failed: %s",
__func__, sysfs_node, strerror(errno));
return -1;
}
if (fscanf(f, "%d", value) != 1) {
IOAT_PMD_ERR("%s(): error reading file '%s': %s",
__func__, sysfs_node, strerror(errno));
ret = -1;
}
fclose(f);
return ret;
}
static int
read_device_int(struct rte_dsa_device *dev, const char *filename,
int *value)
{
char sysfs_node[PATH_MAX];
FILE *f;
int ret = 0;
snprintf(sysfs_node, sizeof(sysfs_node), "%s/dsa%d/%s",
dsa_get_sysfs_path(), dev->addr.device_id, filename);
f = fopen(sysfs_node, "r");
if (f == NULL) {
IOAT_PMD_ERR("%s(): opening file '%s' failed: %s",
__func__, sysfs_node, strerror(errno));
return -1;
}
if (fscanf(f, "%d", value) != 1) {
IOAT_PMD_ERR("%s(): error reading file '%s': %s",
__func__, sysfs_node, strerror(errno));
ret = -1;
}
fclose(f);
return ret;
}
static int
idxd_rawdev_probe_dsa(struct rte_dsa_device *dev)
{
struct idxd_rawdev idxd = {{0}}; /* double {} to avoid error on BSD12 */
int ret = 0;
IOAT_PMD_INFO("Probing device %s on numa node %d",
dev->wq_name, dev->device.numa_node);
if (read_wq_int(dev, "size", &ret) < 0)
return -1;
idxd.max_batches = ret;
idxd.qid = dev->addr.wq_id;
idxd.u.vdev.dsa_id = dev->addr.device_id;
idxd.public.portal = idxd_vdev_mmap_wq(dev);
if (idxd.public.portal == NULL) {
IOAT_PMD_ERR("WQ mmap failed");
return -ENOENT;
}
ret = idxd_rawdev_create(dev->wq_name, &dev->device, &idxd, &idxd_vdev_ops);
if (ret) {
IOAT_PMD_ERR("Failed to create rawdev %s", dev->wq_name);
return ret;
}
return 0;
}
static int
is_for_this_process_use(const char *name)
{
char *runtime_dir = strdup(rte_eal_get_runtime_dir());
char *prefix = basename(runtime_dir);
int prefixlen = strlen(prefix);
int retval = 0;
if (strncmp(name, "dpdk_", 5) == 0)
retval = 1;
if (strncmp(name, prefix, prefixlen) == 0 && name[prefixlen] == '_')
retval = 1;
free(runtime_dir);
return retval;
}
static int
dsa_probe(void)
{
struct rte_dsa_device *dev;
TAILQ_FOREACH(dev, &dsa_bus.device_list, next) {
char type[64], name[64];
if (read_wq_string(dev, "type", type, sizeof(type)) < 0 ||
read_wq_string(dev, "name", name, sizeof(name)) < 0)
continue;
if (strncmp(type, "user", 4) == 0 && is_for_this_process_use(name)) {
dev->device.driver = &dsa_bus.driver;
idxd_rawdev_probe_dsa(dev);
continue;
}
IOAT_PMD_DEBUG("WQ '%s', not allocated to DPDK", dev->wq_name);
}
return 0;
}
static int
dsa_scan(void)
{
const char *path = dsa_get_dev_path();
struct dirent *wq;
DIR *dev_dir;
dev_dir = opendir(path);
if (dev_dir == NULL) {
if (errno == ENOENT)
return 0; /* no bus, return without error */
IOAT_PMD_ERR("%s(): opendir '%s' failed: %s",
__func__, path, strerror(errno));
return -1;
}
while ((wq = readdir(dev_dir)) != NULL) {
struct rte_dsa_device *dev;
int numa_node = -1;
if (strncmp(wq->d_name, "wq", 2) != 0)
continue;
if (strnlen(wq->d_name, sizeof(dev->wq_name)) == sizeof(dev->wq_name)) {
IOAT_PMD_ERR("%s(): wq name too long: '%s', skipping",
__func__, wq->d_name);
continue;
}
IOAT_PMD_DEBUG("%s(): found %s/%s", __func__, path, wq->d_name);
dev = malloc(sizeof(*dev));
if (dsa_addr_parse(wq->d_name, &dev->addr) < 0) {
IOAT_PMD_ERR("Error parsing WQ name: %s", wq->d_name);
free(dev);
continue;
}
dev->device.bus = &dsa_bus.bus;
strlcpy(dev->wq_name, wq->d_name, sizeof(dev->wq_name));
TAILQ_INSERT_TAIL(&dsa_bus.device_list, dev, next);
devcount++;
read_device_int(dev, "numa_node", &numa_node);
dev->device.numa_node = numa_node;
dev->device.name = dev->wq_name;
}
closedir(dev_dir);
return 0;
}
static struct rte_device *
dsa_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
const void *data)
{
struct rte_dsa_device *dev = TAILQ_FIRST(&dsa_bus.device_list);
/* the rte_device struct must be at start of dsa structure */
RTE_BUILD_BUG_ON(offsetof(struct rte_dsa_device, device) != 0);
if (start != NULL) /* jump to start point if given */
dev = TAILQ_NEXT((const struct rte_dsa_device *)start, next);
while (dev != NULL) {
if (cmp(&dev->device, data) == 0)
return &dev->device;
dev = TAILQ_NEXT(dev, next);
}
return NULL;
}
static enum rte_iova_mode
dsa_get_iommu_class(void)
{
/* if there are no devices, report don't care, otherwise VA mode */
return devcount > 0 ? RTE_IOVA_VA : RTE_IOVA_DC;
}
static int
dsa_addr_parse(const char *name, void *addr)
{
struct dsa_wq_addr *wq = addr;
unsigned int device_id, wq_id;
if (sscanf(name, "wq%u.%u", &device_id, &wq_id) != 2) {
IOAT_PMD_DEBUG("Parsing WQ name failed: %s", name);
return -1;
}
wq->device_id = device_id;
wq->wq_id = wq_id;
return 0;
}
RTE_REGISTER_BUS(dsa, dsa_bus.bus);