1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2021 Intel Corporation
15 #include <rte_string_fns.h>
16 #include "ioat_private.h"
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"
22 /** unique identifier for a DSA device/WQ instance */
28 /** a DSA device instance */
29 struct rte_dsa_device {
30 struct rte_device device; /**< Inherit core device */
31 TAILQ_ENTRY(rte_dsa_device) next; /**< next dev in list */
33 char wq_name[32]; /**< the workqueue name/number e.g. wq0.1 */
34 struct dsa_wq_addr addr; /**< Identifies the specific WQ */
37 /* forward prototypes */
39 static int dsa_scan(void);
40 static int dsa_probe(void);
41 static struct rte_device *dsa_find_device(const struct rte_device *start,
42 rte_dev_cmp_t cmp, const void *data);
43 static enum rte_iova_mode dsa_get_iommu_class(void);
44 static int dsa_addr_parse(const char *name, void *addr);
46 /** List of devices */
47 TAILQ_HEAD(dsa_device_list, rte_dsa_device);
50 * Structure describing the DSA bus
53 struct rte_bus bus; /**< Inherit the generic class */
54 struct rte_driver driver; /**< Driver struct for devices to point to */
55 struct dsa_device_list device_list; /**< List of PCI devices */
58 struct dsa_bus dsa_bus = {
62 .find_device = dsa_find_device,
63 .get_iommu_class = dsa_get_iommu_class,
64 .parse = dsa_addr_parse,
69 .device_list = TAILQ_HEAD_INITIALIZER(dsa_bus.device_list),
72 static inline const char *
73 dsa_get_dev_path(void)
75 const char *path = getenv("DSA_DEV_PATH");
76 return path ? path : DSA_DEV_PATH;
79 static inline const char *
80 dsa_get_sysfs_path(void)
82 const char *path = getenv("DSA_SYSFS_PATH");
83 return path ? path : DSA_SYSFS_PATH;
86 static const struct rte_rawdev_ops idxd_vdev_ops = {
87 .dev_close = idxd_rawdev_close,
88 .dev_selftest = ioat_rawdev_test,
89 .dump = idxd_dev_dump,
90 .dev_configure = idxd_dev_configure,
91 .dev_info_get = idxd_dev_info_get,
92 .xstats_get = ioat_xstats_get,
93 .xstats_get_names = ioat_xstats_get_names,
94 .xstats_reset = ioat_xstats_reset,
98 idxd_vdev_mmap_wq(struct rte_dsa_device *dev)
104 snprintf(path, sizeof(path), "%s/%s", dsa_get_dev_path(), dev->wq_name);
105 fd = open(path, O_RDWR);
107 IOAT_PMD_ERR("Failed to open device path: %s", path);
111 addr = mmap(NULL, 0x1000, PROT_WRITE, MAP_SHARED, fd, 0);
113 if (addr == MAP_FAILED) {
114 IOAT_PMD_ERR("Failed to mmap device %s", path);
122 read_wq_string(struct rte_dsa_device *dev, const char *filename,
123 char *value, size_t valuelen)
125 char sysfs_node[PATH_MAX];
129 snprintf(sysfs_node, sizeof(sysfs_node), "%s/%s/%s",
130 dsa_get_sysfs_path(), dev->wq_name, filename);
131 fd = open(sysfs_node, O_RDONLY);
133 IOAT_PMD_ERR("%s(): opening file '%s' failed: %s",
134 __func__, sysfs_node, strerror(errno));
138 len = read(fd, value, valuelen - 1);
141 IOAT_PMD_ERR("%s(): error reading file '%s': %s",
142 __func__, sysfs_node, strerror(errno));
150 read_wq_int(struct rte_dsa_device *dev, const char *filename,
153 char sysfs_node[PATH_MAX];
157 snprintf(sysfs_node, sizeof(sysfs_node), "%s/%s/%s",
158 dsa_get_sysfs_path(), dev->wq_name, filename);
159 f = fopen(sysfs_node, "r");
161 IOAT_PMD_ERR("%s(): opening file '%s' failed: %s",
162 __func__, sysfs_node, strerror(errno));
166 if (fscanf(f, "%d", value) != 1) {
167 IOAT_PMD_ERR("%s(): error reading file '%s': %s",
168 __func__, sysfs_node, strerror(errno));
177 read_device_int(struct rte_dsa_device *dev, const char *filename,
180 char sysfs_node[PATH_MAX];
184 snprintf(sysfs_node, sizeof(sysfs_node), "%s/dsa%d/%s",
185 dsa_get_sysfs_path(), dev->addr.device_id, filename);
186 f = fopen(sysfs_node, "r");
188 IOAT_PMD_ERR("%s(): opening file '%s' failed: %s",
189 __func__, sysfs_node, strerror(errno));
193 if (fscanf(f, "%d", value) != 1) {
194 IOAT_PMD_ERR("%s(): error reading file '%s': %s",
195 __func__, sysfs_node, strerror(errno));
204 idxd_rawdev_probe_dsa(struct rte_dsa_device *dev)
206 struct idxd_rawdev idxd = {{0}}; /* double {} to avoid error on BSD12 */
209 IOAT_PMD_INFO("Probing device %s on numa node %d",
210 dev->wq_name, dev->device.numa_node);
211 if (read_wq_int(dev, "size", &ret) < 0)
213 idxd.max_batches = ret;
214 idxd.qid = dev->addr.wq_id;
215 idxd.u.vdev.dsa_id = dev->addr.device_id;
217 idxd.public.portal = idxd_vdev_mmap_wq(dev);
218 if (idxd.public.portal == NULL) {
219 IOAT_PMD_ERR("WQ mmap failed");
223 ret = idxd_rawdev_create(dev->wq_name, &dev->device, &idxd, &idxd_vdev_ops);
225 IOAT_PMD_ERR("Failed to create rawdev %s", dev->wq_name);
233 is_for_this_process_use(const char *name)
235 char *runtime_dir = strdup(rte_eal_get_runtime_dir());
236 char *prefix = basename(runtime_dir);
237 int prefixlen = strlen(prefix);
240 if (strncmp(name, "dpdk_", 5) == 0)
242 if (strncmp(name, prefix, prefixlen) == 0 && name[prefixlen] == '_')
252 struct rte_dsa_device *dev;
254 TAILQ_FOREACH(dev, &dsa_bus.device_list, next) {
255 char type[64], name[64];
257 if (read_wq_string(dev, "type", type, sizeof(type)) < 0 ||
258 read_wq_string(dev, "name", name, sizeof(name)) < 0)
261 if (strncmp(type, "user", 4) == 0 && is_for_this_process_use(name)) {
262 dev->device.driver = &dsa_bus.driver;
263 idxd_rawdev_probe_dsa(dev);
266 IOAT_PMD_DEBUG("WQ '%s', not allocated to DPDK", dev->wq_name);
275 const char *path = dsa_get_dev_path();
279 dev_dir = opendir(path);
280 if (dev_dir == NULL) {
282 return 0; /* no bus, return without error */
283 IOAT_PMD_ERR("%s(): opendir '%s' failed: %s",
284 __func__, path, strerror(errno));
288 while ((wq = readdir(dev_dir)) != NULL) {
289 struct rte_dsa_device *dev;
292 if (strncmp(wq->d_name, "wq", 2) != 0)
294 if (strnlen(wq->d_name, sizeof(dev->wq_name)) == sizeof(dev->wq_name)) {
295 IOAT_PMD_ERR("%s(): wq name too long: '%s', skipping",
296 __func__, wq->d_name);
299 IOAT_PMD_DEBUG("%s(): found %s/%s", __func__, path, wq->d_name);
301 dev = malloc(sizeof(*dev));
302 if (dsa_addr_parse(wq->d_name, &dev->addr) < 0) {
303 IOAT_PMD_ERR("Error parsing WQ name: %s", wq->d_name);
307 dev->device.bus = &dsa_bus.bus;
308 strlcpy(dev->wq_name, wq->d_name, sizeof(dev->wq_name));
309 TAILQ_INSERT_TAIL(&dsa_bus.device_list, dev, next);
311 read_device_int(dev, "numa_node", &numa_node);
312 dev->device.numa_node = numa_node;
318 static struct rte_device *
319 dsa_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
322 struct rte_dsa_device *dev = TAILQ_FIRST(&dsa_bus.device_list);
324 /* the rte_device struct must be at start of dsa structure */
325 RTE_BUILD_BUG_ON(offsetof(struct rte_dsa_device, device) != 0);
327 if (start != NULL) /* jump to start point if given */
328 dev = TAILQ_NEXT((const struct rte_dsa_device *)start, next);
329 while (dev != NULL) {
330 if (cmp(&dev->device, data) == 0)
332 dev = TAILQ_NEXT(dev, next);
337 static enum rte_iova_mode
338 dsa_get_iommu_class(void)
344 dsa_addr_parse(const char *name, void *addr)
346 struct dsa_wq_addr *wq = addr;
347 unsigned int device_id, wq_id;
349 if (sscanf(name, "wq%u.%u", &device_id, &wq_id) != 2) {
350 IOAT_PMD_DEBUG("Parsing WQ name failed: %s", name);
354 wq->device_id = device_id;
359 RTE_REGISTER_BUS(dsa, dsa_bus.bus);