common/cnxk: add null authentication with IPsec
[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_eal.h>
13 #include <rte_log.h>
14 #include <rte_dmadev_pmd.h>
15 #include <rte_string_fns.h>
16
17 #include "idxd_internal.h"
18
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"
22
23 static unsigned int devcount;
24
25 /** unique identifier for a DSA device/WQ instance */
26 struct dsa_wq_addr {
27         uint16_t device_id;
28         uint16_t wq_id;
29 };
30
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 */
35
36         char wq_name[32];                   /**< the workqueue name/number e.g. wq0.1 */
37         struct dsa_wq_addr addr;            /**< Identifies the specific WQ */
38 };
39
40 /* forward prototypes */
41 struct dsa_bus;
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);
48
49 /** List of devices */
50 TAILQ_HEAD(dsa_device_list, rte_dsa_device);
51
52 /**
53  * Structure describing the DSA bus
54  */
55 struct 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 */
59 };
60
61 struct dsa_bus dsa_bus = {
62         .bus = {
63                 .scan = dsa_scan,
64                 .probe = dsa_probe,
65                 .find_device = dsa_find_device,
66                 .get_iommu_class = dsa_get_iommu_class,
67                 .parse = dsa_addr_parse,
68         },
69         .driver = {
70                 .name = "dmadev_idxd"
71         },
72         .device_list = TAILQ_HEAD_INITIALIZER(dsa_bus.device_list),
73 };
74
75 static inline const char *
76 dsa_get_dev_path(void)
77 {
78         const char *path = getenv("DSA_DEV_PATH");
79         return path ? path : DSA_DEV_PATH;
80 }
81
82 static inline const char *
83 dsa_get_sysfs_path(void)
84 {
85         const char *path = getenv("DSA_SYSFS_PATH");
86         return path ? path : DSA_SYSFS_PATH;
87 }
88
89 static int
90 idxd_dev_close(struct rte_dma_dev *dev)
91 {
92         struct idxd_dmadev *idxd = dev->data->dev_private;
93         munmap(idxd->portal, 0x1000);
94         return 0;
95 }
96
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,
106 };
107
108 static void *
109 idxd_bus_mmap_wq(struct rte_dsa_device *dev)
110 {
111         void *addr;
112         char path[PATH_MAX];
113         int fd;
114
115         snprintf(path, sizeof(path), "%s/%s", dsa_get_dev_path(), dev->wq_name);
116         fd = open(path, O_RDWR);
117         if (fd < 0) {
118                 IDXD_PMD_ERR("Failed to open device path: %s", path);
119                 return NULL;
120         }
121
122         addr = mmap(NULL, 0x1000, PROT_WRITE, MAP_SHARED, fd, 0);
123         close(fd);
124         if (addr == MAP_FAILED) {
125                 IDXD_PMD_ERR("Failed to mmap device %s", path);
126                 return NULL;
127         }
128
129         return addr;
130 }
131
132 static int
133 read_wq_string(struct rte_dsa_device *dev, const char *filename,
134                 char *value, size_t valuelen)
135 {
136         char sysfs_node[PATH_MAX];
137         int len;
138         int fd;
139
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);
143         if (fd < 0) {
144                 IDXD_PMD_ERR("%s(): opening file '%s' failed: %s",
145                                 __func__, sysfs_node, strerror(errno));
146                 return -1;
147         }
148
149         len = read(fd, value, valuelen - 1);
150         close(fd);
151         if (len < 0) {
152                 IDXD_PMD_ERR("%s(): error reading file '%s': %s",
153                                 __func__, sysfs_node, strerror(errno));
154                 return -1;
155         }
156         value[len] = '\0';
157         return 0;
158 }
159
160 static int
161 read_wq_int(struct rte_dsa_device *dev, const char *filename,
162                 int *value)
163 {
164         char sysfs_node[PATH_MAX];
165         FILE *f;
166         int ret = 0;
167
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");
171         if (f == NULL) {
172                 IDXD_PMD_ERR("%s(): opening file '%s' failed: %s",
173                                 __func__, sysfs_node, strerror(errno));
174                 return -1;
175         }
176
177         if (fscanf(f, "%d", value) != 1) {
178                 IDXD_PMD_ERR("%s(): error reading file '%s': %s",
179                                 __func__, sysfs_node, strerror(errno));
180                 ret = -1;
181         }
182
183         fclose(f);
184         return ret;
185 }
186
187 static int
188 read_device_int(struct rte_dsa_device *dev, const char *filename,
189                 int *value)
190 {
191         char sysfs_node[PATH_MAX];
192         FILE *f;
193         int ret = 0;
194
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");
198         if (f == NULL) {
199                 IDXD_PMD_ERR("%s(): opening file '%s' failed: %s",
200                                 __func__, sysfs_node, strerror(errno));
201                 return -1;
202         }
203
204         if (fscanf(f, "%d", value) != 1) {
205                 IDXD_PMD_ERR("%s(): error reading file '%s': %s",
206                                 __func__, sysfs_node, strerror(errno));
207                 ret = -1;
208         }
209
210         fclose(f);
211         return ret;
212 }
213
214 static int
215 idxd_probe_dsa(struct rte_dsa_device *dev)
216 {
217         struct idxd_dmadev idxd = {0};
218         int ret = 0;
219
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)
223                 return -1;
224         idxd.max_batches = ret;
225         if (read_wq_int(dev, "max_batch_size", &ret) < 0)
226                 return -1;
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;
231
232         idxd.portal = idxd_bus_mmap_wq(dev);
233         if (idxd.portal == NULL) {
234                 IDXD_PMD_ERR("WQ mmap failed");
235                 return -ENOENT;
236         }
237
238         ret = idxd_dmadev_create(dev->wq_name, &dev->device, &idxd, &idxd_bus_ops);
239         if (ret) {
240                 IDXD_PMD_ERR("Failed to create dmadev %s", dev->wq_name);
241                 return ret;
242         }
243
244         return 0;
245 }
246
247 static int
248 is_for_this_process_use(const char *name)
249 {
250         char *runtime_dir = strdup(rte_eal_get_runtime_dir());
251         char *prefix = basename(runtime_dir);
252         int prefixlen = strlen(prefix);
253         int retval = 0;
254
255         if (strncmp(name, "dpdk_", 5) == 0)
256                 retval = 1;
257         if (strncmp(name, prefix, prefixlen) == 0 && name[prefixlen] == '_')
258                 retval = 1;
259
260         free(runtime_dir);
261         return retval;
262 }
263
264 static int
265 dsa_probe(void)
266 {
267         struct rte_dsa_device *dev;
268
269         TAILQ_FOREACH(dev, &dsa_bus.device_list, next) {
270                 char type[64], name[64];
271
272                 if (read_wq_string(dev, "type", type, sizeof(type)) < 0 ||
273                                 read_wq_string(dev, "name", name, sizeof(name)) < 0)
274                         continue;
275
276                 if (strncmp(type, "user", 4) == 0 && is_for_this_process_use(name)) {
277                         dev->device.driver = &dsa_bus.driver;
278                         idxd_probe_dsa(dev);
279                         continue;
280                 }
281                 IDXD_PMD_DEBUG("WQ '%s', not allocated to DPDK", dev->wq_name);
282         }
283
284         return 0;
285 }
286
287 static int
288 dsa_scan(void)
289 {
290         const char *path = dsa_get_dev_path();
291         struct dirent *wq;
292         DIR *dev_dir;
293
294         dev_dir = opendir(path);
295         if (dev_dir == NULL) {
296                 if (errno == ENOENT)
297                         return 0; /* no bus, return without error */
298                 IDXD_PMD_ERR("%s(): opendir '%s' failed: %s",
299                                 __func__, path, strerror(errno));
300                 return -1;
301         }
302
303         while ((wq = readdir(dev_dir)) != NULL) {
304                 struct rte_dsa_device *dev;
305                 int numa_node = -1;
306
307                 if (strncmp(wq->d_name, "wq", 2) != 0)
308                         continue;
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);
312                         continue;
313                 }
314                 IDXD_PMD_DEBUG("%s(): found %s/%s", __func__, path, wq->d_name);
315
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);
319                         free(dev);
320                         continue;
321                 }
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);
325                 devcount++;
326
327                 read_device_int(dev, "numa_node", &numa_node);
328                 dev->device.numa_node = numa_node;
329                 dev->device.name = dev->wq_name;
330         }
331
332         closedir(dev_dir);
333         return 0;
334 }
335
336 static struct rte_device *
337 dsa_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
338                          const void *data)
339 {
340         struct rte_dsa_device *dev = TAILQ_FIRST(&dsa_bus.device_list);
341
342         /* the rte_device struct must be at start of dsa structure */
343         RTE_BUILD_BUG_ON(offsetof(struct rte_dsa_device, device) != 0);
344
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)
349                         return &dev->device;
350                 dev = TAILQ_NEXT(dev, next);
351         }
352         return NULL;
353 }
354
355 static enum rte_iova_mode
356 dsa_get_iommu_class(void)
357 {
358         /* if there are no devices, report don't care, otherwise VA mode */
359         return devcount > 0 ? RTE_IOVA_VA : RTE_IOVA_DC;
360 }
361
362 static int
363 dsa_addr_parse(const char *name, void *addr)
364 {
365         struct dsa_wq_addr *wq = addr;
366         unsigned int device_id, wq_id;
367
368         if (sscanf(name, "wq%u.%u", &device_id, &wq_id) != 2) {
369                 IDXD_PMD_DEBUG("Parsing WQ name failed: %s", name);
370                 return -1;
371         }
372
373         wq->device_id = device_id;
374         wq->wq_id = wq_id;
375         return 0;
376 }
377
378 RTE_REGISTER_BUS(dsa, dsa_bus.bus);