1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2021 Intel Corporation
14 #include <rte_dmadev_pmd.h>
15 #include <rte_string_fns.h>
17 #include "idxd_internal.h"
19 /* default value for DSA paths, but allow override in environment for testing */
20 #define DSA_DEV_PATH "/dev/dsa"
21 #define DSA_SYSFS_PATH "/sys/bus/dsa/devices"
23 static unsigned int devcount;
25 /** unique identifier for a DSA device/WQ instance */
31 /** a DSA device instance */
32 struct rte_dsa_device {
33 struct rte_device device; /**< Inherit core device */
34 TAILQ_ENTRY(rte_dsa_device) next; /**< next dev in list */
36 char wq_name[32]; /**< the workqueue name/number e.g. wq0.1 */
37 struct dsa_wq_addr addr; /**< Identifies the specific WQ */
40 /* forward prototypes */
42 static int dsa_scan(void);
43 static int dsa_probe(void);
44 static struct rte_device *dsa_find_device(const struct rte_device *start,
45 rte_dev_cmp_t cmp, const void *data);
46 static enum rte_iova_mode dsa_get_iommu_class(void);
47 static int dsa_addr_parse(const char *name, void *addr);
49 /** List of devices */
50 TAILQ_HEAD(dsa_device_list, rte_dsa_device);
53 * Structure describing the DSA bus
56 struct rte_bus bus; /**< Inherit the generic class */
57 struct rte_driver driver; /**< Driver struct for devices to point to */
58 struct dsa_device_list device_list; /**< List of PCI devices */
61 struct dsa_bus dsa_bus = {
65 .find_device = dsa_find_device,
66 .get_iommu_class = dsa_get_iommu_class,
67 .parse = dsa_addr_parse,
72 .device_list = TAILQ_HEAD_INITIALIZER(dsa_bus.device_list),
75 static inline const char *
76 dsa_get_dev_path(void)
78 const char *path = getenv("DSA_DEV_PATH");
79 return path ? path : DSA_DEV_PATH;
82 static inline const char *
83 dsa_get_sysfs_path(void)
85 const char *path = getenv("DSA_SYSFS_PATH");
86 return path ? path : DSA_SYSFS_PATH;
90 idxd_dev_close(struct rte_dma_dev *dev)
92 struct idxd_dmadev *idxd = dev->data->dev_private;
93 munmap(idxd->portal, 0x1000);
97 static const struct rte_dma_dev_ops idxd_bus_ops = {
98 .dev_close = idxd_dev_close,
99 .dev_dump = idxd_dump,
100 .dev_configure = idxd_configure,
101 .vchan_setup = idxd_vchan_setup,
102 .dev_info_get = idxd_info_get,
103 .stats_get = idxd_stats_get,
104 .stats_reset = idxd_stats_reset,
105 .vchan_status = idxd_vchan_status,
109 idxd_bus_mmap_wq(struct rte_dsa_device *dev)
115 snprintf(path, sizeof(path), "%s/%s", dsa_get_dev_path(), dev->wq_name);
116 fd = open(path, O_RDWR);
118 IDXD_PMD_ERR("Failed to open device path: %s", path);
122 addr = mmap(NULL, 0x1000, PROT_WRITE, MAP_SHARED, fd, 0);
124 if (addr == MAP_FAILED) {
125 IDXD_PMD_ERR("Failed to mmap device %s", path);
133 read_wq_string(struct rte_dsa_device *dev, const char *filename,
134 char *value, size_t valuelen)
136 char sysfs_node[PATH_MAX];
140 snprintf(sysfs_node, sizeof(sysfs_node), "%s/%s/%s",
141 dsa_get_sysfs_path(), dev->wq_name, filename);
142 fd = open(sysfs_node, O_RDONLY);
144 IDXD_PMD_ERR("%s(): opening file '%s' failed: %s",
145 __func__, sysfs_node, strerror(errno));
149 len = read(fd, value, valuelen - 1);
152 IDXD_PMD_ERR("%s(): error reading file '%s': %s",
153 __func__, sysfs_node, strerror(errno));
161 read_wq_int(struct rte_dsa_device *dev, const char *filename,
164 char sysfs_node[PATH_MAX];
168 snprintf(sysfs_node, sizeof(sysfs_node), "%s/%s/%s",
169 dsa_get_sysfs_path(), dev->wq_name, filename);
170 f = fopen(sysfs_node, "r");
172 IDXD_PMD_ERR("%s(): opening file '%s' failed: %s",
173 __func__, sysfs_node, strerror(errno));
177 if (fscanf(f, "%d", value) != 1) {
178 IDXD_PMD_ERR("%s(): error reading file '%s': %s",
179 __func__, sysfs_node, strerror(errno));
188 read_device_int(struct rte_dsa_device *dev, const char *filename,
191 char sysfs_node[PATH_MAX];
195 snprintf(sysfs_node, sizeof(sysfs_node), "%s/dsa%d/%s",
196 dsa_get_sysfs_path(), dev->addr.device_id, filename);
197 f = fopen(sysfs_node, "r");
199 IDXD_PMD_ERR("%s(): opening file '%s' failed: %s",
200 __func__, sysfs_node, strerror(errno));
204 if (fscanf(f, "%d", value) != 1) {
205 IDXD_PMD_ERR("%s(): error reading file '%s': %s",
206 __func__, sysfs_node, strerror(errno));
215 idxd_probe_dsa(struct rte_dsa_device *dev)
217 struct idxd_dmadev idxd = {0};
220 IDXD_PMD_INFO("Probing device %s on numa node %d",
221 dev->wq_name, dev->device.numa_node);
222 if (read_wq_int(dev, "size", &ret) < 0)
224 idxd.max_batches = ret;
225 if (read_wq_int(dev, "max_batch_size", &ret) < 0)
227 idxd.max_batch_size = ret;
228 idxd.qid = dev->addr.wq_id;
229 idxd.u.bus.dsa_id = dev->addr.device_id;
230 idxd.sva_support = 1;
232 idxd.portal = idxd_bus_mmap_wq(dev);
233 if (idxd.portal == NULL) {
234 IDXD_PMD_ERR("WQ mmap failed");
238 ret = idxd_dmadev_create(dev->wq_name, &dev->device, &idxd, &idxd_bus_ops);
240 IDXD_PMD_ERR("Failed to create dmadev %s", dev->wq_name);
248 is_for_this_process_use(const char *name)
250 char *runtime_dir = strdup(rte_eal_get_runtime_dir());
251 char *prefix = basename(runtime_dir);
252 int prefixlen = strlen(prefix);
255 if (strncmp(name, "dpdk_", 5) == 0)
257 if (strncmp(name, prefix, prefixlen) == 0 && name[prefixlen] == '_')
267 struct rte_dsa_device *dev;
269 TAILQ_FOREACH(dev, &dsa_bus.device_list, next) {
270 char type[64], name[64];
272 if (read_wq_string(dev, "type", type, sizeof(type)) < 0 ||
273 read_wq_string(dev, "name", name, sizeof(name)) < 0)
276 if (strncmp(type, "user", 4) == 0 && is_for_this_process_use(name)) {
277 dev->device.driver = &dsa_bus.driver;
281 IDXD_PMD_DEBUG("WQ '%s', not allocated to DPDK", dev->wq_name);
290 const char *path = dsa_get_dev_path();
294 dev_dir = opendir(path);
295 if (dev_dir == NULL) {
297 return 0; /* no bus, return without error */
298 IDXD_PMD_ERR("%s(): opendir '%s' failed: %s",
299 __func__, path, strerror(errno));
303 while ((wq = readdir(dev_dir)) != NULL) {
304 struct rte_dsa_device *dev;
307 if (strncmp(wq->d_name, "wq", 2) != 0)
309 if (strnlen(wq->d_name, sizeof(dev->wq_name)) == sizeof(dev->wq_name)) {
310 IDXD_PMD_ERR("%s(): wq name too long: '%s', skipping",
311 __func__, wq->d_name);
314 IDXD_PMD_DEBUG("%s(): found %s/%s", __func__, path, wq->d_name);
316 dev = malloc(sizeof(*dev));
317 if (dsa_addr_parse(wq->d_name, &dev->addr) < 0) {
318 IDXD_PMD_ERR("Error parsing WQ name: %s", wq->d_name);
322 dev->device.bus = &dsa_bus.bus;
323 strlcpy(dev->wq_name, wq->d_name, sizeof(dev->wq_name));
324 TAILQ_INSERT_TAIL(&dsa_bus.device_list, dev, next);
327 read_device_int(dev, "numa_node", &numa_node);
328 dev->device.numa_node = numa_node;
329 dev->device.name = dev->wq_name;
336 static struct rte_device *
337 dsa_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
340 struct rte_dsa_device *dev = TAILQ_FIRST(&dsa_bus.device_list);
342 /* the rte_device struct must be at start of dsa structure */
343 RTE_BUILD_BUG_ON(offsetof(struct rte_dsa_device, device) != 0);
345 if (start != NULL) /* jump to start point if given */
346 dev = TAILQ_NEXT((const struct rte_dsa_device *)start, next);
347 while (dev != NULL) {
348 if (cmp(&dev->device, data) == 0)
350 dev = TAILQ_NEXT(dev, next);
355 static enum rte_iova_mode
356 dsa_get_iommu_class(void)
358 /* if there are no devices, report don't care, otherwise VA mode */
359 return devcount > 0 ? RTE_IOVA_VA : RTE_IOVA_DC;
363 dsa_addr_parse(const char *name, void *addr)
365 struct dsa_wq_addr *wq = addr;
366 unsigned int device_id, wq_id;
368 if (sscanf(name, "wq%u.%u", &device_id, &wq_id) != 2) {
369 IDXD_PMD_DEBUG("Parsing WQ name failed: %s", name);
373 wq->device_id = device_id;
378 RTE_REGISTER_BUS(dsa, dsa_bus.bus);