xref: /dpdk/drivers/bus/uacce/uacce.c (revision fd51012de5369679e807be1d6a81d63ef15015ce)
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