dpdk/drivers/raw/ioat/idxd_bus.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2021 Intel Corporation
   3 */
   4
   5#include <dirent.h>
   6#include <libgen.h>
   7#include <string.h>
   8#include <errno.h>
   9#include <unistd.h>
  10#include <fcntl.h>
  11#include <sys/mman.h>
  12
  13#include <rte_bus.h>
  14#include <rte_log.h>
  15#include <rte_string_fns.h>
  16#include "ioat_private.h"
  17
  18/* default value for DSA paths, but allow override in environment for testing */
  19#define DSA_DEV_PATH "/dev/dsa"
  20#define DSA_SYSFS_PATH "/sys/bus/dsa/devices"
  21
  22static unsigned int devcount;
  23
  24/** unique identifier for a DSA device/WQ instance */
  25struct dsa_wq_addr {
  26        uint16_t device_id;
  27        uint16_t wq_id;
  28};
  29
  30/** a DSA device instance */
  31struct rte_dsa_device {
  32        struct rte_device device;           /**< Inherit core device */
  33        TAILQ_ENTRY(rte_dsa_device) next;   /**< next dev in list */
  34
  35        char wq_name[32];                   /**< the workqueue name/number e.g. wq0.1 */
  36        struct dsa_wq_addr addr;            /**< Identifies the specific WQ */
  37};
  38
  39/* forward prototypes */
  40struct dsa_bus;
  41static int dsa_scan(void);
  42static int dsa_probe(void);
  43static struct rte_device *dsa_find_device(const struct rte_device *start,
  44                rte_dev_cmp_t cmp,  const void *data);
  45static enum rte_iova_mode dsa_get_iommu_class(void);
  46static int dsa_addr_parse(const char *name, void *addr);
  47
  48/** List of devices */
  49TAILQ_HEAD(dsa_device_list, rte_dsa_device);
  50
  51/**
  52 * Structure describing the DSA bus
  53 */
  54struct dsa_bus {
  55        struct rte_bus bus;               /**< Inherit the generic class */
  56        struct rte_driver driver;         /**< Driver struct for devices to point to */
  57        struct dsa_device_list device_list;  /**< List of PCI devices */
  58};
  59
  60struct dsa_bus dsa_bus = {
  61        .bus = {
  62                .scan = dsa_scan,
  63                .probe = dsa_probe,
  64                .find_device = dsa_find_device,
  65                .get_iommu_class = dsa_get_iommu_class,
  66                .parse = dsa_addr_parse,
  67        },
  68        .driver = {
  69                .name = "rawdev_idxd"
  70        },
  71        .device_list = TAILQ_HEAD_INITIALIZER(dsa_bus.device_list),
  72};
  73
  74static inline const char *
  75dsa_get_dev_path(void)
  76{
  77        const char *path = getenv("DSA_DEV_PATH");
  78        return path ? path : DSA_DEV_PATH;
  79}
  80
  81static inline const char *
  82dsa_get_sysfs_path(void)
  83{
  84        const char *path = getenv("DSA_SYSFS_PATH");
  85        return path ? path : DSA_SYSFS_PATH;
  86}
  87
  88static const struct rte_rawdev_ops idxd_vdev_ops = {
  89                .dev_close = idxd_rawdev_close,
  90                .dev_selftest = ioat_rawdev_test,
  91                .dump = idxd_dev_dump,
  92                .dev_configure = idxd_dev_configure,
  93                .dev_info_get = idxd_dev_info_get,
  94                .xstats_get = ioat_xstats_get,
  95                .xstats_get_names = ioat_xstats_get_names,
  96                .xstats_reset = ioat_xstats_reset,
  97};
  98
  99static void *
 100idxd_vdev_mmap_wq(struct rte_dsa_device *dev)
 101{
 102        void *addr;
 103        char path[PATH_MAX];
 104        int fd;
 105
 106        snprintf(path, sizeof(path), "%s/%s", dsa_get_dev_path(), dev->wq_name);
 107        fd = open(path, O_RDWR);
 108        if (fd < 0) {
 109                IOAT_PMD_ERR("Failed to open device path: %s", path);
 110                return NULL;
 111        }
 112
 113        addr = mmap(NULL, 0x1000, PROT_WRITE, MAP_SHARED, fd, 0);
 114        close(fd);
 115        if (addr == MAP_FAILED) {
 116                IOAT_PMD_ERR("Failed to mmap device %s", path);
 117                return NULL;
 118        }
 119
 120        return addr;
 121}
 122
 123static int
 124read_wq_string(struct rte_dsa_device *dev, const char *filename,
 125                char *value, size_t valuelen)
 126{
 127        char sysfs_node[PATH_MAX];
 128        int len;
 129        int fd;
 130
 131        snprintf(sysfs_node, sizeof(sysfs_node), "%s/%s/%s",
 132                        dsa_get_sysfs_path(), dev->wq_name, filename);
 133        fd = open(sysfs_node, O_RDONLY);
 134        if (fd < 0) {
 135                IOAT_PMD_ERR("%s(): opening file '%s' failed: %s",
 136                                __func__, sysfs_node, strerror(errno));
 137                return -1;
 138        }
 139
 140        len = read(fd, value, valuelen - 1);
 141        close(fd);
 142        if (len < 0) {
 143                IOAT_PMD_ERR("%s(): error reading file '%s': %s",
 144                                __func__, sysfs_node, strerror(errno));
 145                return -1;
 146        }
 147        value[len] = '\0';
 148        return 0;
 149}
 150
 151static int
 152read_wq_int(struct rte_dsa_device *dev, const char *filename,
 153                int *value)
 154{
 155        char sysfs_node[PATH_MAX];
 156        FILE *f;
 157        int ret = 0;
 158
 159        snprintf(sysfs_node, sizeof(sysfs_node), "%s/%s/%s",
 160                        dsa_get_sysfs_path(), dev->wq_name, filename);
 161        f = fopen(sysfs_node, "r");
 162        if (f == NULL) {
 163                IOAT_PMD_ERR("%s(): opening file '%s' failed: %s",
 164                                __func__, sysfs_node, strerror(errno));
 165                return -1;
 166        }
 167
 168        if (fscanf(f, "%d", value) != 1) {
 169                IOAT_PMD_ERR("%s(): error reading file '%s': %s",
 170                                __func__, sysfs_node, strerror(errno));
 171                ret = -1;
 172        }
 173
 174        fclose(f);
 175        return ret;
 176}
 177
 178static int
 179read_device_int(struct rte_dsa_device *dev, const char *filename,
 180                int *value)
 181{
 182        char sysfs_node[PATH_MAX];
 183        FILE *f;
 184        int ret = 0;
 185
 186        snprintf(sysfs_node, sizeof(sysfs_node), "%s/dsa%d/%s",
 187                        dsa_get_sysfs_path(), dev->addr.device_id, filename);
 188        f = fopen(sysfs_node, "r");
 189        if (f == NULL) {
 190                IOAT_PMD_ERR("%s(): opening file '%s' failed: %s",
 191                                __func__, sysfs_node, strerror(errno));
 192                return -1;
 193        }
 194
 195        if (fscanf(f, "%d", value) != 1) {
 196                IOAT_PMD_ERR("%s(): error reading file '%s': %s",
 197                                __func__, sysfs_node, strerror(errno));
 198                ret = -1;
 199        }
 200
 201        fclose(f);
 202        return ret;
 203}
 204
 205static int
 206idxd_rawdev_probe_dsa(struct rte_dsa_device *dev)
 207{
 208        struct idxd_rawdev idxd = {{0}}; /* double {} to avoid error on BSD12 */
 209        int ret = 0;
 210
 211        IOAT_PMD_INFO("Probing device %s on numa node %d",
 212                        dev->wq_name, dev->device.numa_node);
 213        if (read_wq_int(dev, "size", &ret) < 0)
 214                return -1;
 215        idxd.max_batches = ret;
 216        idxd.qid = dev->addr.wq_id;
 217        idxd.u.vdev.dsa_id = dev->addr.device_id;
 218
 219        idxd.public.portal = idxd_vdev_mmap_wq(dev);
 220        if (idxd.public.portal == NULL) {
 221                IOAT_PMD_ERR("WQ mmap failed");
 222                return -ENOENT;
 223        }
 224
 225        ret = idxd_rawdev_create(dev->wq_name, &dev->device, &idxd, &idxd_vdev_ops);
 226        if (ret) {
 227                IOAT_PMD_ERR("Failed to create rawdev %s", dev->wq_name);
 228                return ret;
 229        }
 230
 231        return 0;
 232}
 233
 234static int
 235is_for_this_process_use(const char *name)
 236{
 237        char *runtime_dir = strdup(rte_eal_get_runtime_dir());
 238        char *prefix = basename(runtime_dir);
 239        int prefixlen = strlen(prefix);
 240        int retval = 0;
 241
 242        if (strncmp(name, "dpdk_", 5) == 0)
 243                retval = 1;
 244        if (strncmp(name, prefix, prefixlen) == 0 && name[prefixlen] == '_')
 245                retval = 1;
 246
 247        free(runtime_dir);
 248        return retval;
 249}
 250
 251static int
 252dsa_probe(void)
 253{
 254        struct rte_dsa_device *dev;
 255
 256        TAILQ_FOREACH(dev, &dsa_bus.device_list, next) {
 257                char type[64], name[64];
 258
 259                if (read_wq_string(dev, "type", type, sizeof(type)) < 0 ||
 260                                read_wq_string(dev, "name", name, sizeof(name)) < 0)
 261                        continue;
 262
 263                if (strncmp(type, "user", 4) == 0 && is_for_this_process_use(name)) {
 264                        dev->device.driver = &dsa_bus.driver;
 265                        idxd_rawdev_probe_dsa(dev);
 266                        continue;
 267                }
 268                IOAT_PMD_DEBUG("WQ '%s', not allocated to DPDK", dev->wq_name);
 269        }
 270
 271        return 0;
 272}
 273
 274static int
 275dsa_scan(void)
 276{
 277        const char *path = dsa_get_dev_path();
 278        struct dirent *wq;
 279        DIR *dev_dir;
 280
 281        dev_dir = opendir(path);
 282        if (dev_dir == NULL) {
 283                if (errno == ENOENT)
 284                        return 0; /* no bus, return without error */
 285                IOAT_PMD_ERR("%s(): opendir '%s' failed: %s",
 286                                __func__, path, strerror(errno));
 287                return -1;
 288        }
 289
 290        while ((wq = readdir(dev_dir)) != NULL) {
 291                struct rte_dsa_device *dev;
 292                int numa_node = -1;
 293
 294                if (strncmp(wq->d_name, "wq", 2) != 0)
 295                        continue;
 296                if (strnlen(wq->d_name, sizeof(dev->wq_name)) == sizeof(dev->wq_name)) {
 297                        IOAT_PMD_ERR("%s(): wq name too long: '%s', skipping",
 298                                        __func__, wq->d_name);
 299                        continue;
 300                }
 301                IOAT_PMD_DEBUG("%s(): found %s/%s", __func__, path, wq->d_name);
 302
 303                dev = malloc(sizeof(*dev));
 304                if (dsa_addr_parse(wq->d_name, &dev->addr) < 0) {
 305                        IOAT_PMD_ERR("Error parsing WQ name: %s", wq->d_name);
 306                        free(dev);
 307                        continue;
 308                }
 309                dev->device.bus = &dsa_bus.bus;
 310                strlcpy(dev->wq_name, wq->d_name, sizeof(dev->wq_name));
 311                TAILQ_INSERT_TAIL(&dsa_bus.device_list, dev, next);
 312                devcount++;
 313
 314                read_device_int(dev, "numa_node", &numa_node);
 315                dev->device.numa_node = numa_node;
 316                dev->device.name = dev->wq_name;
 317        }
 318
 319        closedir(dev_dir);
 320        return 0;
 321}
 322
 323static struct rte_device *
 324dsa_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
 325                         const void *data)
 326{
 327        struct rte_dsa_device *dev = TAILQ_FIRST(&dsa_bus.device_list);
 328
 329        /* the rte_device struct must be at start of dsa structure */
 330        RTE_BUILD_BUG_ON(offsetof(struct rte_dsa_device, device) != 0);
 331
 332        if (start != NULL) /* jump to start point if given */
 333                dev = TAILQ_NEXT((const struct rte_dsa_device *)start, next);
 334        while (dev != NULL) {
 335                if (cmp(&dev->device, data) == 0)
 336                        return &dev->device;
 337                dev = TAILQ_NEXT(dev, next);
 338        }
 339        return NULL;
 340}
 341
 342static enum rte_iova_mode
 343dsa_get_iommu_class(void)
 344{
 345        /* if there are no devices, report don't care, otherwise VA mode */
 346        return devcount > 0 ? RTE_IOVA_VA : RTE_IOVA_DC;
 347}
 348
 349static int
 350dsa_addr_parse(const char *name, void *addr)
 351{
 352        struct dsa_wq_addr *wq = addr;
 353        unsigned int device_id, wq_id;
 354
 355        if (sscanf(name, "wq%u.%u", &device_id, &wq_id) != 2) {
 356                IOAT_PMD_DEBUG("Parsing WQ name failed: %s", name);
 357                return -1;
 358        }
 359
 360        wq->device_id = device_id;
 361        wq->wq_id = wq_id;
 362        return 0;
 363}
 364
 365RTE_REGISTER_BUS(dsa, dsa_bus.bus);
 366