162b906cfSChengwen Feng /* SPDX-License-Identifier: BSD-3-Clause 262b906cfSChengwen Feng * Copyright(c) 2024 HiSilicon Limited 362b906cfSChengwen Feng */ 462b906cfSChengwen Feng 562b906cfSChengwen Feng #include <dirent.h> 662b906cfSChengwen Feng #include <errno.h> 762b906cfSChengwen Feng #include <fcntl.h> 862b906cfSChengwen Feng #include <unistd.h> 962b906cfSChengwen Feng #include <stdlib.h> 1062b906cfSChengwen Feng #include <string.h> 1162b906cfSChengwen Feng #include <sys/ioctl.h> 1262b906cfSChengwen Feng #include <sys/mman.h> 1362b906cfSChengwen Feng #include <sys/stat.h> 1462b906cfSChengwen Feng #include <sys/types.h> 1562b906cfSChengwen Feng 1662b906cfSChengwen Feng #include <rte_bitops.h> 1762b906cfSChengwen Feng #include <rte_common.h> 1862b906cfSChengwen Feng #include <rte_devargs.h> 1962b906cfSChengwen Feng #include <rte_eal_paging.h> 2062b906cfSChengwen Feng #include <rte_errno.h> 2162b906cfSChengwen Feng #include <rte_log.h> 2262b906cfSChengwen Feng #include <rte_kvargs.h> 2362b906cfSChengwen Feng #include <bus_driver.h> 2462b906cfSChengwen Feng 2562b906cfSChengwen Feng #include "bus_uacce_driver.h" 2662b906cfSChengwen Feng 2762b906cfSChengwen Feng #define UACCE_BUS_CLASS_PATH "/sys/class/uacce" 2862b906cfSChengwen Feng 2962b906cfSChengwen Feng /* UACCE device flag of SVA. */ 3062b906cfSChengwen Feng #define UACCE_DEV_FLGA_SVA RTE_BIT32(0) 3162b906cfSChengwen Feng 3262b906cfSChengwen Feng /* Support -a uacce:device-name when start DPDK application. */ 3362b906cfSChengwen Feng #define UACCE_DEV_PREFIX "uacce:" 3462b906cfSChengwen Feng 3562b906cfSChengwen Feng /* 3662b906cfSChengwen Feng * Structure describing the UACCE bus. 3762b906cfSChengwen Feng */ 3862b906cfSChengwen Feng struct rte_uacce_bus { 3962b906cfSChengwen Feng struct rte_bus bus; /* Inherit the generic class. */ 4062b906cfSChengwen Feng TAILQ_HEAD(, rte_uacce_device) device_list; /* List of devices. */ 4162b906cfSChengwen Feng TAILQ_HEAD(, rte_uacce_driver) driver_list; /* List of drivers. */ 4262b906cfSChengwen Feng }; 4362b906cfSChengwen Feng 4462b906cfSChengwen Feng /* Forward declaration of UACCE bus. */ 4562b906cfSChengwen Feng static struct rte_uacce_bus uacce_bus; 4662b906cfSChengwen Feng 4762b906cfSChengwen Feng enum uacce_params { 4862b906cfSChengwen Feng RTE_UACCE_PARAM_NAME, 4962b906cfSChengwen Feng }; 5062b906cfSChengwen Feng 5162b906cfSChengwen Feng static const char *const uacce_params_keys[] = { 5262b906cfSChengwen Feng [RTE_UACCE_PARAM_NAME] = "name", 5362b906cfSChengwen Feng NULL, 5462b906cfSChengwen Feng }; 5562b906cfSChengwen Feng 5662b906cfSChengwen Feng #define FOREACH_DEVICE_ON_UACCEBUS(p) \ 5762b906cfSChengwen Feng RTE_TAILQ_FOREACH(p, &uacce_bus.device_list, next) 5862b906cfSChengwen Feng #define FOREACH_DRIVER_ON_UACCEBUS(p) \ 5962b906cfSChengwen Feng RTE_TAILQ_FOREACH(p, &uacce_bus.driver_list, next) 6062b906cfSChengwen Feng 6162b906cfSChengwen Feng extern int uacce_bus_logtype; 622b843cacSDavid Marchand #define RTE_LOGTYPE_UACCE_BUS uacce_bus_logtype 632b843cacSDavid Marchand #define UACCE_BUS_LOG(level, ...) \ 642b843cacSDavid Marchand RTE_LOG_LINE(level, UACCE_BUS, __VA_ARGS__) 65*fd51012dSAndre Muezerie #define UACCE_BUS_ERR(fmt, ...) UACCE_BUS_LOG(ERR, fmt, ##__VA_ARGS__) 66*fd51012dSAndre Muezerie #define UACCE_BUS_WARN(fmt, ...) UACCE_BUS_LOG(WARNING, fmt, ##__VA_ARGS__) 67*fd51012dSAndre Muezerie #define UACCE_BUS_INFO(fmt, ...) UACCE_BUS_LOG(INFO, fmt, ##__VA_ARGS__) 68*fd51012dSAndre Muezerie #define UACCE_BUS_DEBUG(fmt, ...) UACCE_BUS_LOG(DEBUG, fmt, ##__VA_ARGS__) 6962b906cfSChengwen Feng 7062b906cfSChengwen Feng 7162b906cfSChengwen Feng static struct rte_devargs * 7262b906cfSChengwen Feng uacce_devargs_lookup(const char *dev_name) 7362b906cfSChengwen Feng { 7462b906cfSChengwen Feng char name[RTE_UACCE_DEV_PATH_SIZE] = {0}; 7562b906cfSChengwen Feng struct rte_devargs *devargs; 7662b906cfSChengwen Feng 7762b906cfSChengwen Feng snprintf(name, sizeof(name), "%s%s", UACCE_DEV_PREFIX, dev_name); 7862b906cfSChengwen Feng RTE_EAL_DEVARGS_FOREACH("uacce", devargs) { 7962b906cfSChengwen Feng if (strcmp(devargs->name, name) == 0) 8062b906cfSChengwen Feng return devargs; 8162b906cfSChengwen Feng } 8262b906cfSChengwen Feng 8362b906cfSChengwen Feng return NULL; 8462b906cfSChengwen Feng } 8562b906cfSChengwen Feng 8662b906cfSChengwen Feng static bool 8762b906cfSChengwen Feng uacce_ignore_device(const char *dev_name) 8862b906cfSChengwen Feng { 8962b906cfSChengwen Feng struct rte_devargs *devargs = uacce_devargs_lookup(dev_name); 9062b906cfSChengwen Feng 9162b906cfSChengwen Feng switch (uacce_bus.bus.conf.scan_mode) { 9262b906cfSChengwen Feng case RTE_BUS_SCAN_ALLOWLIST: 9362b906cfSChengwen Feng if (devargs && devargs->policy == RTE_DEV_ALLOWED) 9462b906cfSChengwen Feng return false; 9562b906cfSChengwen Feng break; 9662b906cfSChengwen Feng case RTE_BUS_SCAN_UNDEFINED: 9762b906cfSChengwen Feng case RTE_BUS_SCAN_BLOCKLIST: 9862b906cfSChengwen Feng if (devargs == NULL || devargs->policy != RTE_DEV_BLOCKED) 9962b906cfSChengwen Feng return false; 10062b906cfSChengwen Feng break; 10162b906cfSChengwen Feng } 10262b906cfSChengwen Feng 10362b906cfSChengwen Feng return true; 10462b906cfSChengwen Feng } 10562b906cfSChengwen Feng 10662b906cfSChengwen Feng /* 10762b906cfSChengwen Feng * Returns the number of bytes read (removed last newline) on success. 10862b906cfSChengwen Feng * Otherwise negative value is returned. 10962b906cfSChengwen Feng */ 11062b906cfSChengwen Feng static int 11162b906cfSChengwen Feng uacce_read_attr(const char *dev_root, const char *attr, char *buf, uint32_t sz) 11262b906cfSChengwen Feng { 11362b906cfSChengwen Feng char filename[PATH_MAX] = {0}; 11462b906cfSChengwen Feng int ret; 11562b906cfSChengwen Feng int fd; 11662b906cfSChengwen Feng 11762b906cfSChengwen Feng snprintf(filename, sizeof(filename), "%s/%s", dev_root, attr); 11862b906cfSChengwen Feng fd = open(filename, O_RDONLY, 0); 11962b906cfSChengwen Feng if (fd < 0) { 12062b906cfSChengwen Feng UACCE_BUS_ERR("failed to open %s", filename); 12162b906cfSChengwen Feng return -EIO; 12262b906cfSChengwen Feng } 12362b906cfSChengwen Feng 12462b906cfSChengwen Feng ret = read(fd, buf, sz); 12562b906cfSChengwen Feng if (ret > 0) { 12662b906cfSChengwen Feng /* Remove the last new line character. */ 12762b906cfSChengwen Feng if (buf[ret - 1] == '\n') { 12862b906cfSChengwen Feng buf[ret - 1] = '\0'; 12962b906cfSChengwen Feng ret--; 13062b906cfSChengwen Feng } 13162b906cfSChengwen Feng } 13262b906cfSChengwen Feng if (ret <= 0) { 13362b906cfSChengwen Feng UACCE_BUS_ERR("failed to read %s", filename); 13462b906cfSChengwen Feng ret = -EIO; 13562b906cfSChengwen Feng } 13662b906cfSChengwen Feng 13762b906cfSChengwen Feng close(fd); 13862b906cfSChengwen Feng 13962b906cfSChengwen Feng return ret; 14062b906cfSChengwen Feng } 14162b906cfSChengwen Feng 14262b906cfSChengwen Feng /* 0 on success. Otherwise negative value is returned. */ 14362b906cfSChengwen Feng static int 14462b906cfSChengwen Feng uacce_read_attr_int(const char *dev_root, const char *attr, int *val) 14562b906cfSChengwen Feng { 14662b906cfSChengwen Feng char buf[RTE_UACCE_ATTR_MAX_SIZE] = {0}; 14762b906cfSChengwen Feng char *s = NULL; 14862b906cfSChengwen Feng int ret; 14962b906cfSChengwen Feng 15062b906cfSChengwen Feng ret = uacce_read_attr(dev_root, attr, buf, sizeof(buf) - 1); 15162b906cfSChengwen Feng if (ret < 0) 15262b906cfSChengwen Feng return ret; 15362b906cfSChengwen Feng 15462b906cfSChengwen Feng *val = strtol(buf, &s, 0); 15562b906cfSChengwen Feng if (s[0] != '\0') { 15662b906cfSChengwen Feng UACCE_BUS_ERR("read attr %s/%s expect an integer value", dev_root, attr); 15762b906cfSChengwen Feng return -EINVAL; 15862b906cfSChengwen Feng } 15962b906cfSChengwen Feng 16062b906cfSChengwen Feng return 0; 16162b906cfSChengwen Feng } 16262b906cfSChengwen Feng 16362b906cfSChengwen Feng /* 0 on success. Otherwise negative value is returned. */ 16462b906cfSChengwen Feng static int 16562b906cfSChengwen Feng uacce_read_attr_u32(const char *dev_root, const char *attr, uint32_t *val) 16662b906cfSChengwen Feng { 16762b906cfSChengwen Feng char buf[RTE_UACCE_ATTR_MAX_SIZE] = {0}; 16862b906cfSChengwen Feng char *s = NULL; 16962b906cfSChengwen Feng int ret; 17062b906cfSChengwen Feng 17162b906cfSChengwen Feng ret = uacce_read_attr(dev_root, attr, buf, sizeof(buf) - 1); 17262b906cfSChengwen Feng if (ret < 0) 17362b906cfSChengwen Feng return ret; 17462b906cfSChengwen Feng 17562b906cfSChengwen Feng *val = strtoul(buf, &s, 0); 17662b906cfSChengwen Feng if (s[0] != '\0') { 17762b906cfSChengwen Feng UACCE_BUS_ERR("read attr %s/%s expect an uint32 value", dev_root, attr); 17862b906cfSChengwen Feng return -EINVAL; 17962b906cfSChengwen Feng } 18062b906cfSChengwen Feng 18162b906cfSChengwen Feng return 0; 18262b906cfSChengwen Feng } 18362b906cfSChengwen Feng 18462b906cfSChengwen Feng static int 18562b906cfSChengwen Feng uacce_read_api(struct rte_uacce_device *dev) 18662b906cfSChengwen Feng { 18762b906cfSChengwen Feng int ret = uacce_read_attr(dev->dev_root, "api", dev->api, sizeof(dev->api) - 1); 18862b906cfSChengwen Feng if (ret < 0) 18962b906cfSChengwen Feng return ret; 19062b906cfSChengwen Feng return 0; 19162b906cfSChengwen Feng } 19262b906cfSChengwen Feng 19362b906cfSChengwen Feng static int 19462b906cfSChengwen Feng uacce_read_algs(struct rte_uacce_device *dev) 19562b906cfSChengwen Feng { 19662b906cfSChengwen Feng int ret = uacce_read_attr(dev->dev_root, "algorithms", dev->algs, sizeof(dev->algs) - 1); 19762b906cfSChengwen Feng if (ret < 0) 19862b906cfSChengwen Feng return ret; 19962b906cfSChengwen Feng return 0; 20062b906cfSChengwen Feng } 20162b906cfSChengwen Feng 20262b906cfSChengwen Feng static int 20362b906cfSChengwen Feng uacce_read_flags(struct rte_uacce_device *dev) 20462b906cfSChengwen Feng { 20562b906cfSChengwen Feng return uacce_read_attr_u32(dev->dev_root, "flags", &dev->flags); 20662b906cfSChengwen Feng } 20762b906cfSChengwen Feng 20862b906cfSChengwen Feng static void 20962b906cfSChengwen Feng uacce_read_numa_node(struct rte_uacce_device *dev) 21062b906cfSChengwen Feng { 21162b906cfSChengwen Feng int ret = uacce_read_attr_int(dev->dev_root, "device/numa_node", &dev->numa_node); 21262b906cfSChengwen Feng if (ret != 0) { 21362b906cfSChengwen Feng UACCE_BUS_WARN("read attr numa_node failed! set to default"); 21462b906cfSChengwen Feng dev->numa_node = -1; 21562b906cfSChengwen Feng } 21662b906cfSChengwen Feng } 21762b906cfSChengwen Feng 21862b906cfSChengwen Feng static int 21962b906cfSChengwen Feng uacce_read_qfrt_sz(struct rte_uacce_device *dev) 22062b906cfSChengwen Feng { 22162b906cfSChengwen Feng int ret = uacce_read_attr_u32(dev->dev_root, "region_mmio_size", 22262b906cfSChengwen Feng &dev->qfrt_sz[RTE_UACCE_QFRT_MMIO]); 22362b906cfSChengwen Feng if (ret != 0) 22462b906cfSChengwen Feng return ret; 22562b906cfSChengwen Feng return uacce_read_attr_u32(dev->dev_root, "region_dus_size", 22662b906cfSChengwen Feng &dev->qfrt_sz[RTE_UACCE_QFRT_DUS]); 22762b906cfSChengwen Feng } 22862b906cfSChengwen Feng 22962b906cfSChengwen Feng static int 23062b906cfSChengwen Feng uacce_verify(struct rte_uacce_device *dev) 23162b906cfSChengwen Feng { 23262b906cfSChengwen Feng if (!(dev->flags & UACCE_DEV_FLGA_SVA)) { 23362b906cfSChengwen Feng UACCE_BUS_WARN("device %s don't support SVA, skip it!", dev->name); 23462b906cfSChengwen Feng return 1; /* >0 will skip this device. */ 23562b906cfSChengwen Feng } 23662b906cfSChengwen Feng 23762b906cfSChengwen Feng return 0; 23862b906cfSChengwen Feng } 23962b906cfSChengwen Feng 24062b906cfSChengwen Feng /* 24162b906cfSChengwen Feng * Scan one UACCE sysfs entry, and fill the devices list from it. 24262b906cfSChengwen Feng * It reads api/algs/flags/numa_node/region-size (please refer Linux kernel: 24362b906cfSChengwen Feng * Documentation/ABI/testing/sysfs-driver-uacce) and stores them for later 24462b906cfSChengwen Feng * device-driver matching, driver init... 24562b906cfSChengwen Feng */ 24662b906cfSChengwen Feng static int 24762b906cfSChengwen Feng uacce_scan_one(const char *dev_name) 24862b906cfSChengwen Feng { 24962b906cfSChengwen Feng struct rte_uacce_device *dev; 25062b906cfSChengwen Feng int ret; 25162b906cfSChengwen Feng 25262b906cfSChengwen Feng dev = calloc(1, sizeof(*dev)); 25362b906cfSChengwen Feng if (!dev) 25462b906cfSChengwen Feng return -ENOMEM; 25562b906cfSChengwen Feng 25662b906cfSChengwen Feng dev->device.bus = &uacce_bus.bus; 25762b906cfSChengwen Feng dev->device.name = dev->name; 25862b906cfSChengwen Feng dev->device.devargs = uacce_devargs_lookup(dev_name); 25962b906cfSChengwen Feng snprintf(dev->name, sizeof(dev->name), "%s", dev_name); 26062b906cfSChengwen Feng snprintf(dev->dev_root, sizeof(dev->dev_root), "%s/%s", 26162b906cfSChengwen Feng UACCE_BUS_CLASS_PATH, dev_name); 26262b906cfSChengwen Feng snprintf(dev->cdev_path, sizeof(dev->cdev_path), "/dev/%s", dev_name); 26362b906cfSChengwen Feng 26462b906cfSChengwen Feng ret = uacce_read_api(dev); 26562b906cfSChengwen Feng if (ret != 0) 26662b906cfSChengwen Feng goto err; 26762b906cfSChengwen Feng ret = uacce_read_algs(dev); 26862b906cfSChengwen Feng if (ret != 0) 26962b906cfSChengwen Feng goto err; 27062b906cfSChengwen Feng ret = uacce_read_flags(dev); 27162b906cfSChengwen Feng if (ret != 0) 27262b906cfSChengwen Feng goto err; 27362b906cfSChengwen Feng uacce_read_numa_node(dev); 27462b906cfSChengwen Feng ret = uacce_read_qfrt_sz(dev); 27562b906cfSChengwen Feng if (ret != 0) 27662b906cfSChengwen Feng goto err; 27762b906cfSChengwen Feng 27862b906cfSChengwen Feng ret = uacce_verify(dev); 27962b906cfSChengwen Feng if (ret != 0) 28062b906cfSChengwen Feng goto err; 28162b906cfSChengwen Feng 28262b906cfSChengwen Feng TAILQ_INSERT_TAIL(&uacce_bus.device_list, dev, next); 28362b906cfSChengwen Feng return 0; 28462b906cfSChengwen Feng 28562b906cfSChengwen Feng err: 28662b906cfSChengwen Feng free(dev); 28762b906cfSChengwen Feng return ret; 28862b906cfSChengwen Feng } 28962b906cfSChengwen Feng 29062b906cfSChengwen Feng static int 29162b906cfSChengwen Feng uacce_scan(void) 29262b906cfSChengwen Feng { 29362b906cfSChengwen Feng struct dirent *e; 29462b906cfSChengwen Feng DIR *dir; 29562b906cfSChengwen Feng 29662b906cfSChengwen Feng dir = opendir(UACCE_BUS_CLASS_PATH); 29762b906cfSChengwen Feng if (dir == NULL) { 29862b906cfSChengwen Feng UACCE_BUS_LOG(INFO, "open %s failed!", UACCE_BUS_CLASS_PATH); 29962b906cfSChengwen Feng return 0; 30062b906cfSChengwen Feng } 30162b906cfSChengwen Feng 30262b906cfSChengwen Feng while ((e = readdir(dir)) != NULL) { 30362b906cfSChengwen Feng if (e->d_name[0] == '.') 30462b906cfSChengwen Feng continue; 30562b906cfSChengwen Feng 30662b906cfSChengwen Feng if (strlen(e->d_name) >= RTE_DEV_NAME_MAX_LEN) { 30762b906cfSChengwen Feng UACCE_BUS_LOG(WARNING, "uacce device name %s too long, skip it!", 30862b906cfSChengwen Feng e->d_name); 30962b906cfSChengwen Feng continue; 31062b906cfSChengwen Feng } 31162b906cfSChengwen Feng 31262b906cfSChengwen Feng if (uacce_ignore_device(e->d_name)) 31362b906cfSChengwen Feng continue; 31462b906cfSChengwen Feng 31562b906cfSChengwen Feng if (uacce_scan_one(e->d_name) < 0) 31662b906cfSChengwen Feng goto error; 31762b906cfSChengwen Feng } 31862b906cfSChengwen Feng closedir(dir); 31962b906cfSChengwen Feng return 0; 32062b906cfSChengwen Feng 32162b906cfSChengwen Feng error: 32262b906cfSChengwen Feng closedir(dir); 32362b906cfSChengwen Feng return -1; 32462b906cfSChengwen Feng } 32562b906cfSChengwen Feng 32662b906cfSChengwen Feng static bool 32762b906cfSChengwen Feng uacce_match(const struct rte_uacce_driver *dr, const struct rte_uacce_device *dev) 32862b906cfSChengwen Feng { 32962b906cfSChengwen Feng const struct rte_uacce_id *id_table; 33062b906cfSChengwen Feng uint32_t len; 33162b906cfSChengwen Feng char *map; 33262b906cfSChengwen Feng 33362b906cfSChengwen Feng for (id_table = dr->id_table; id_table->dev_api != NULL; id_table++) { 33462b906cfSChengwen Feng if (strcmp(id_table->dev_api, dev->api) != 0) 33562b906cfSChengwen Feng continue; 33662b906cfSChengwen Feng 33762b906cfSChengwen Feng if (id_table->dev_alg == NULL) 33862b906cfSChengwen Feng return true; 33962b906cfSChengwen Feng 34062b906cfSChengwen Feng /* The dev->algs's algrothims is separated by new line, for 34162b906cfSChengwen Feng * example: dev->algs could be: aaa\nbbbb\ncc, which has three 34262b906cfSChengwen Feng * algorithms: aaa, bbbb and cc. 34362b906cfSChengwen Feng * The id_table->dev_alg should be a single algrithm, e.g. bbbb. 34462b906cfSChengwen Feng */ 34562b906cfSChengwen Feng map = strstr(dev->algs, id_table->dev_alg); 34662b906cfSChengwen Feng if (map == NULL) 34762b906cfSChengwen Feng continue; 34862b906cfSChengwen Feng if (map != dev->algs && map[-1] != '\n') 34962b906cfSChengwen Feng continue; 35062b906cfSChengwen Feng len = strlen(id_table->dev_alg); 35162b906cfSChengwen Feng if (map[len] != '\0' && map[len] != '\n') 35262b906cfSChengwen Feng continue; 35362b906cfSChengwen Feng 35462b906cfSChengwen Feng return true; 35562b906cfSChengwen Feng } 35662b906cfSChengwen Feng 35762b906cfSChengwen Feng return false; 35862b906cfSChengwen Feng } 35962b906cfSChengwen Feng 36062b906cfSChengwen Feng static int 36162b906cfSChengwen Feng uacce_probe_one_driver(struct rte_uacce_driver *dr, struct rte_uacce_device *dev) 36262b906cfSChengwen Feng { 36362b906cfSChengwen Feng const char *dev_name = dev->name; 36462b906cfSChengwen Feng bool already_probed; 36562b906cfSChengwen Feng int ret; 36662b906cfSChengwen Feng 36762b906cfSChengwen Feng if (!uacce_match(dr, dev)) 36862b906cfSChengwen Feng /* Match of device and driver failed */ 36962b906cfSChengwen Feng return 1; 37062b906cfSChengwen Feng 37162b906cfSChengwen Feng already_probed = rte_dev_is_probed(&dev->device); 37262b906cfSChengwen Feng if (already_probed) { 37362b906cfSChengwen Feng UACCE_BUS_INFO("device %s is already probed", dev_name); 37462b906cfSChengwen Feng return -EEXIST; 37562b906cfSChengwen Feng } 37662b906cfSChengwen Feng 37762b906cfSChengwen Feng UACCE_BUS_DEBUG("probe device %s using driver %s", dev_name, dr->driver.name); 37862b906cfSChengwen Feng 37962b906cfSChengwen Feng ret = dr->probe(dr, dev); 38062b906cfSChengwen Feng if (ret != 0) { 38162b906cfSChengwen Feng UACCE_BUS_ERR("probe device %s with driver %s failed %d", 38262b906cfSChengwen Feng dev_name, dr->driver.name, ret); 38362b906cfSChengwen Feng } else { 38462b906cfSChengwen Feng dev->device.driver = &dr->driver; 38562b906cfSChengwen Feng dev->driver = dr; 38662b906cfSChengwen Feng UACCE_BUS_DEBUG("probe device %s with driver %s success", 38762b906cfSChengwen Feng dev_name, dr->driver.name); 38862b906cfSChengwen Feng } 38962b906cfSChengwen Feng 39062b906cfSChengwen Feng return ret; 39162b906cfSChengwen Feng } 39262b906cfSChengwen Feng 39362b906cfSChengwen Feng static int 39462b906cfSChengwen Feng uacce_probe_all_drivers(struct rte_uacce_device *dev) 39562b906cfSChengwen Feng { 39662b906cfSChengwen Feng struct rte_uacce_driver *dr; 39762b906cfSChengwen Feng int rc; 39862b906cfSChengwen Feng 39962b906cfSChengwen Feng FOREACH_DRIVER_ON_UACCEBUS(dr) { 40062b906cfSChengwen Feng rc = uacce_probe_one_driver(dr, dev); 40162b906cfSChengwen Feng if (rc < 0) 40262b906cfSChengwen Feng /* negative value is an error */ 40362b906cfSChengwen Feng return rc; 40462b906cfSChengwen Feng if (rc > 0) 40562b906cfSChengwen Feng /* positive value means driver doesn't support it */ 40662b906cfSChengwen Feng continue; 40762b906cfSChengwen Feng return 0; 40862b906cfSChengwen Feng } 40962b906cfSChengwen Feng 41062b906cfSChengwen Feng return 1; 41162b906cfSChengwen Feng } 41262b906cfSChengwen Feng 41362b906cfSChengwen Feng static int 41462b906cfSChengwen Feng uacce_probe(void) 41562b906cfSChengwen Feng { 41662b906cfSChengwen Feng size_t probed = 0, failed = 0; 41762b906cfSChengwen Feng struct rte_uacce_device *dev; 41862b906cfSChengwen Feng int ret; 41962b906cfSChengwen Feng 42062b906cfSChengwen Feng FOREACH_DEVICE_ON_UACCEBUS(dev) { 42162b906cfSChengwen Feng probed++; 42262b906cfSChengwen Feng 42362b906cfSChengwen Feng ret = uacce_probe_all_drivers(dev); 42462b906cfSChengwen Feng if (ret < 0) { 42562b906cfSChengwen Feng UACCE_BUS_LOG(ERR, "Requested device %s cannot be used", 42662b906cfSChengwen Feng dev->name); 42762b906cfSChengwen Feng rte_errno = errno; 42862b906cfSChengwen Feng failed++; 42962b906cfSChengwen Feng } 43062b906cfSChengwen Feng } 43162b906cfSChengwen Feng 43262b906cfSChengwen Feng return (probed && probed == failed) ? -1 : 0; 43362b906cfSChengwen Feng } 43462b906cfSChengwen Feng 43562b906cfSChengwen Feng static int 43662b906cfSChengwen Feng uacce_cleanup(void) 43762b906cfSChengwen Feng { 43862b906cfSChengwen Feng struct rte_uacce_device *dev, *tmp_dev; 43962b906cfSChengwen Feng int error = 0; 44062b906cfSChengwen Feng 44162b906cfSChengwen Feng RTE_TAILQ_FOREACH_SAFE(dev, &uacce_bus.device_list, next, tmp_dev) { 44262b906cfSChengwen Feng struct rte_uacce_driver *dr = dev->driver; 44362b906cfSChengwen Feng int ret = 0; 44462b906cfSChengwen Feng 44562b906cfSChengwen Feng if (dr == NULL || dr->remove == NULL) 44662b906cfSChengwen Feng goto free; 44762b906cfSChengwen Feng 44862b906cfSChengwen Feng ret = dr->remove(dev); 44962b906cfSChengwen Feng if (ret < 0) { 45062b906cfSChengwen Feng rte_errno = errno; 45162b906cfSChengwen Feng error = -1; 45262b906cfSChengwen Feng } 45362b906cfSChengwen Feng dev->driver = NULL; 45462b906cfSChengwen Feng dev->device.driver = NULL; 45562b906cfSChengwen Feng 45662b906cfSChengwen Feng free: 45762b906cfSChengwen Feng memset(dev, 0, sizeof(*dev)); 45862b906cfSChengwen Feng free(dev); 45962b906cfSChengwen Feng } 46062b906cfSChengwen Feng 46162b906cfSChengwen Feng return error; 46262b906cfSChengwen Feng } 46362b906cfSChengwen Feng 46462b906cfSChengwen Feng static int 46562b906cfSChengwen Feng uacce_plug(struct rte_device *dev) 46662b906cfSChengwen Feng { 46762b906cfSChengwen Feng return uacce_probe_all_drivers(RTE_DEV_TO_UACCE_DEV(dev)); 46862b906cfSChengwen Feng } 46962b906cfSChengwen Feng 47062b906cfSChengwen Feng static int 47162b906cfSChengwen Feng uacce_detach_dev(struct rte_uacce_device *dev) 47262b906cfSChengwen Feng { 47362b906cfSChengwen Feng struct rte_uacce_driver *dr; 47462b906cfSChengwen Feng int ret = 0; 47562b906cfSChengwen Feng 47662b906cfSChengwen Feng dr = dev->driver; 47762b906cfSChengwen Feng 47862b906cfSChengwen Feng UACCE_BUS_DEBUG("detach device %s using driver: %s", dev->device.name, dr->driver.name); 47962b906cfSChengwen Feng 48062b906cfSChengwen Feng if (dr->remove) { 48162b906cfSChengwen Feng ret = dr->remove(dev); 48262b906cfSChengwen Feng if (ret < 0) 48362b906cfSChengwen Feng return ret; 48462b906cfSChengwen Feng } 48562b906cfSChengwen Feng 48662b906cfSChengwen Feng dev->driver = NULL; 48762b906cfSChengwen Feng dev->device.driver = NULL; 48862b906cfSChengwen Feng 48962b906cfSChengwen Feng return 0; 49062b906cfSChengwen Feng } 49162b906cfSChengwen Feng 49262b906cfSChengwen Feng static int 49362b906cfSChengwen Feng uacce_unplug(struct rte_device *dev) 49462b906cfSChengwen Feng { 49562b906cfSChengwen Feng struct rte_uacce_device *uacce_dev; 49662b906cfSChengwen Feng int ret; 49762b906cfSChengwen Feng 49862b906cfSChengwen Feng uacce_dev = RTE_DEV_TO_UACCE_DEV(dev); 49962b906cfSChengwen Feng ret = uacce_detach_dev(uacce_dev); 50062b906cfSChengwen Feng if (ret == 0) { 50162b906cfSChengwen Feng TAILQ_REMOVE(&uacce_bus.device_list, uacce_dev, next); 50262b906cfSChengwen Feng rte_devargs_remove(dev->devargs); 50362b906cfSChengwen Feng free(uacce_dev); 50462b906cfSChengwen Feng } 50562b906cfSChengwen Feng 50662b906cfSChengwen Feng return ret; 50762b906cfSChengwen Feng } 50862b906cfSChengwen Feng 50962b906cfSChengwen Feng static struct rte_device * 51062b906cfSChengwen Feng uacce_find_device(const struct rte_device *start, rte_dev_cmp_t cmp, const void *data) 51162b906cfSChengwen Feng { 51262b906cfSChengwen Feng const struct rte_uacce_device *uacce_start; 51362b906cfSChengwen Feng struct rte_uacce_device *uacce_dev; 51462b906cfSChengwen Feng 51562b906cfSChengwen Feng if (start != NULL) { 51662b906cfSChengwen Feng uacce_start = RTE_DEV_TO_UACCE_DEV_CONST(start); 51762b906cfSChengwen Feng uacce_dev = TAILQ_NEXT(uacce_start, next); 51862b906cfSChengwen Feng } else { 51962b906cfSChengwen Feng uacce_dev = TAILQ_FIRST(&uacce_bus.device_list); 52062b906cfSChengwen Feng } 52162b906cfSChengwen Feng 52262b906cfSChengwen Feng while (uacce_dev != NULL) { 52362b906cfSChengwen Feng if (cmp(&uacce_dev->device, data) == 0) 52462b906cfSChengwen Feng return &uacce_dev->device; 52562b906cfSChengwen Feng uacce_dev = TAILQ_NEXT(uacce_dev, next); 52662b906cfSChengwen Feng } 52762b906cfSChengwen Feng 52862b906cfSChengwen Feng return NULL; 52962b906cfSChengwen Feng } 53062b906cfSChengwen Feng 53162b906cfSChengwen Feng static int 53262b906cfSChengwen Feng uacce_parse(const char *name, void *addr) 53362b906cfSChengwen Feng { 53462b906cfSChengwen Feng const char **out = addr; 53562b906cfSChengwen Feng int ret; 53662b906cfSChengwen Feng 53762b906cfSChengwen Feng ret = strncmp(name, UACCE_DEV_PREFIX, strlen(UACCE_DEV_PREFIX)); 53862b906cfSChengwen Feng 53962b906cfSChengwen Feng if (ret == 0 && addr) 54062b906cfSChengwen Feng *out = name; 54162b906cfSChengwen Feng 54262b906cfSChengwen Feng return ret; 54362b906cfSChengwen Feng } 54462b906cfSChengwen Feng 54562b906cfSChengwen Feng static int 54662b906cfSChengwen Feng uacce_dev_match(const struct rte_device *dev, const void *_kvlist) 54762b906cfSChengwen Feng { 54862b906cfSChengwen Feng const char *key = uacce_params_keys[RTE_UACCE_PARAM_NAME]; 54962b906cfSChengwen Feng const struct rte_kvargs *kvlist = _kvlist; 55062b906cfSChengwen Feng const char *name; 55162b906cfSChengwen Feng 55262b906cfSChengwen Feng /* no kvlist arg, all devices match. */ 55362b906cfSChengwen Feng if (kvlist == NULL) 55462b906cfSChengwen Feng return 0; 55562b906cfSChengwen Feng 55662b906cfSChengwen Feng /* if key is present in kvlist and does not match, filter device. */ 55762b906cfSChengwen Feng name = rte_kvargs_get(kvlist, key); 55862b906cfSChengwen Feng if (name != NULL && strcmp(name, dev->name)) 55962b906cfSChengwen Feng return -1; 56062b906cfSChengwen Feng 56162b906cfSChengwen Feng return 0; 56262b906cfSChengwen Feng } 56362b906cfSChengwen Feng 56462b906cfSChengwen Feng static void * 56562b906cfSChengwen Feng uacce_dev_iterate(const void *start, const char *str, 56662b906cfSChengwen Feng const struct rte_dev_iterator *it __rte_unused) 56762b906cfSChengwen Feng { 56862b906cfSChengwen Feng rte_bus_find_device_t find_device; 56962b906cfSChengwen Feng struct rte_kvargs *kvargs = NULL; 57062b906cfSChengwen Feng struct rte_device *dev; 57162b906cfSChengwen Feng 57262b906cfSChengwen Feng if (str != NULL) { 57362b906cfSChengwen Feng kvargs = rte_kvargs_parse(str, uacce_params_keys); 57462b906cfSChengwen Feng if (kvargs == NULL) { 57562b906cfSChengwen Feng UACCE_BUS_ERR("cannot parse argument list %s", str); 57662b906cfSChengwen Feng return NULL; 57762b906cfSChengwen Feng } 57862b906cfSChengwen Feng } 57962b906cfSChengwen Feng find_device = uacce_bus.bus.find_device; 58062b906cfSChengwen Feng dev = find_device(start, uacce_dev_match, kvargs); 58162b906cfSChengwen Feng rte_kvargs_free(kvargs); 58262b906cfSChengwen Feng return dev; 58362b906cfSChengwen Feng } 58462b906cfSChengwen Feng 58562b906cfSChengwen Feng int 58662b906cfSChengwen Feng rte_uacce_avail_queues(struct rte_uacce_device *dev) 58762b906cfSChengwen Feng { 58862b906cfSChengwen Feng int avails = 0; 58962b906cfSChengwen Feng int ret; 59062b906cfSChengwen Feng 59162b906cfSChengwen Feng ret = uacce_read_attr_int(dev->dev_root, "available_instances", &avails); 59262b906cfSChengwen Feng if (ret == 0) 59362b906cfSChengwen Feng ret = avails; 59462b906cfSChengwen Feng 59562b906cfSChengwen Feng return ret; 59662b906cfSChengwen Feng } 59762b906cfSChengwen Feng 59862b906cfSChengwen Feng int 59962b906cfSChengwen Feng rte_uacce_queue_alloc(struct rte_uacce_device *dev, struct rte_uacce_qcontex *qctx) 60062b906cfSChengwen Feng { 60162b906cfSChengwen Feng memset(qctx, 0, sizeof(*qctx)); 60262b906cfSChengwen Feng 60362b906cfSChengwen Feng qctx->fd = open(dev->cdev_path, O_RDWR | O_CLOEXEC); 60462b906cfSChengwen Feng if (qctx->fd >= 0) { 60562b906cfSChengwen Feng qctx->dev = dev; 60662b906cfSChengwen Feng return 0; 60762b906cfSChengwen Feng } 60862b906cfSChengwen Feng 60962b906cfSChengwen Feng return -EIO; 61062b906cfSChengwen Feng } 61162b906cfSChengwen Feng 61262b906cfSChengwen Feng void 61362b906cfSChengwen Feng rte_uacce_queue_free(struct rte_uacce_qcontex *qctx) 61462b906cfSChengwen Feng { 61562b906cfSChengwen Feng if (qctx->fd >= 0) 61662b906cfSChengwen Feng close(qctx->fd); 61762b906cfSChengwen Feng memset(qctx, 0, sizeof(*qctx)); 61862b906cfSChengwen Feng qctx->fd = -1; 61962b906cfSChengwen Feng } 62062b906cfSChengwen Feng 62162b906cfSChengwen Feng int 62262b906cfSChengwen Feng rte_uacce_queue_start(struct rte_uacce_qcontex *qctx) 62362b906cfSChengwen Feng { 62462b906cfSChengwen Feng #define UACCE_CMD_START_Q _IO('W', 0) 62562b906cfSChengwen Feng return ioctl(qctx->fd, UACCE_CMD_START_Q); 62662b906cfSChengwen Feng } 62762b906cfSChengwen Feng 62862b906cfSChengwen Feng int 62962b906cfSChengwen Feng rte_uacce_queue_ioctl(struct rte_uacce_qcontex *qctx, unsigned long cmd, void *arg) 63062b906cfSChengwen Feng { 63162b906cfSChengwen Feng if (arg == NULL) 63262b906cfSChengwen Feng return ioctl(qctx->fd, cmd); 63362b906cfSChengwen Feng 63462b906cfSChengwen Feng return ioctl(qctx->fd, cmd, arg); 63562b906cfSChengwen Feng } 63662b906cfSChengwen Feng 63762b906cfSChengwen Feng void * 63862b906cfSChengwen Feng rte_uacce_queue_mmap(struct rte_uacce_qcontex *qctx, enum rte_uacce_qfrt qfrt) 63962b906cfSChengwen Feng { 64062b906cfSChengwen Feng size_t size = qctx->dev->qfrt_sz[qfrt]; 64162b906cfSChengwen Feng off_t off = qfrt * getpagesize(); 64262b906cfSChengwen Feng void *addr; 64362b906cfSChengwen Feng 64462b906cfSChengwen Feng if (size == 0 || qctx->qfrt_base[qfrt] != NULL) { 64562b906cfSChengwen Feng UACCE_BUS_ERR("failed to mmap for %s, size is zero or already mmapped!", 64662b906cfSChengwen Feng qctx->dev->name); 64762b906cfSChengwen Feng return NULL; 64862b906cfSChengwen Feng } 64962b906cfSChengwen Feng 65062b906cfSChengwen Feng addr = rte_mem_map(NULL, size, RTE_PROT_READ | RTE_PROT_WRITE, RTE_MAP_SHARED, 65162b906cfSChengwen Feng qctx->fd, off); 65262b906cfSChengwen Feng if (addr == NULL) { 65362b906cfSChengwen Feng UACCE_BUS_ERR("failed to mmap for %s, qfrt %d err %s!", 65462b906cfSChengwen Feng qctx->dev->name, qfrt, rte_strerror(rte_errno)); 65562b906cfSChengwen Feng return NULL; 65662b906cfSChengwen Feng } 65762b906cfSChengwen Feng qctx->qfrt_base[qfrt] = addr; 65862b906cfSChengwen Feng 65962b906cfSChengwen Feng return addr; 66062b906cfSChengwen Feng } 66162b906cfSChengwen Feng 66262b906cfSChengwen Feng void 66362b906cfSChengwen Feng rte_uacce_queue_unmap(struct rte_uacce_qcontex *qctx, enum rte_uacce_qfrt qfrt) 66462b906cfSChengwen Feng { 66562b906cfSChengwen Feng if (qctx->qfrt_base[qfrt] != NULL) { 66662b906cfSChengwen Feng rte_mem_unmap(qctx->qfrt_base[qfrt], qctx->dev->qfrt_sz[qfrt]); 66762b906cfSChengwen Feng qctx->qfrt_base[qfrt] = NULL; 66862b906cfSChengwen Feng } 66962b906cfSChengwen Feng } 67062b906cfSChengwen Feng 67162b906cfSChengwen Feng void 67262b906cfSChengwen Feng rte_uacce_register(struct rte_uacce_driver *driver) 67362b906cfSChengwen Feng { 67462b906cfSChengwen Feng TAILQ_INSERT_TAIL(&uacce_bus.driver_list, driver, next); 67562b906cfSChengwen Feng driver->bus = &uacce_bus; 67662b906cfSChengwen Feng } 67762b906cfSChengwen Feng 67862b906cfSChengwen Feng void 67962b906cfSChengwen Feng rte_uacce_unregister(struct rte_uacce_driver *driver) 68062b906cfSChengwen Feng { 68162b906cfSChengwen Feng TAILQ_REMOVE(&uacce_bus.driver_list, driver, next); 68262b906cfSChengwen Feng driver->bus = NULL; 68362b906cfSChengwen Feng } 68462b906cfSChengwen Feng 68562b906cfSChengwen Feng static struct rte_uacce_bus uacce_bus = { 68662b906cfSChengwen Feng .bus = { 68762b906cfSChengwen Feng .scan = uacce_scan, 68862b906cfSChengwen Feng .probe = uacce_probe, 68962b906cfSChengwen Feng .cleanup = uacce_cleanup, 69062b906cfSChengwen Feng .plug = uacce_plug, 69162b906cfSChengwen Feng .unplug = uacce_unplug, 69262b906cfSChengwen Feng .find_device = uacce_find_device, 69362b906cfSChengwen Feng .parse = uacce_parse, 69462b906cfSChengwen Feng .dev_iterate = uacce_dev_iterate, 69562b906cfSChengwen Feng }, 69662b906cfSChengwen Feng .device_list = TAILQ_HEAD_INITIALIZER(uacce_bus.device_list), 69762b906cfSChengwen Feng .driver_list = TAILQ_HEAD_INITIALIZER(uacce_bus.driver_list), 69862b906cfSChengwen Feng }; 69962b906cfSChengwen Feng 70062b906cfSChengwen Feng RTE_REGISTER_BUS(uacce, uacce_bus.bus); 70162b906cfSChengwen Feng RTE_LOG_REGISTER_DEFAULT(uacce_bus_logtype, NOTICE); 702