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