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