Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
3 : : */
4 : :
5 : : /**
6 : : * @file
7 : : * CDX probing using Linux VFIO.
8 : : *
9 : : * This code tries to determine if the CDX device is bound to VFIO driver,
10 : : * and initialize it (map MMIO regions, set up interrupts) if that's the case.
11 : : *
12 : : */
13 : :
14 : : #include <uapi/linux/vfio.h>
15 : :
16 : : #include <fcntl.h>
17 : : #include <unistd.h>
18 : : #include <sys/eventfd.h>
19 : : #include <sys/socket.h>
20 : : #include <sys/ioctl.h>
21 : : #include <sys/mman.h>
22 : :
23 : : #include <eal_export.h>
24 : : #include <rte_eal_paging.h>
25 : : #include <rte_malloc.h>
26 : : #include <rte_vfio.h>
27 : :
28 : : #include "bus_cdx_driver.h"
29 : : #include "cdx_logs.h"
30 : : #include "private.h"
31 : :
32 : : /**
33 : : * A structure describing a CDX mapping.
34 : : */
35 : : struct cdx_map {
36 : : void *addr;
37 : : char *path;
38 : : uint64_t offset;
39 : : uint64_t size;
40 : : };
41 : :
42 : : /**
43 : : * A structure describing a mapped CDX resource.
44 : : * For multi-process we need to reproduce all CDX mappings in secondary
45 : : * processes, so save them in a tailq.
46 : : */
47 : : struct mapped_cdx_resource {
48 : : TAILQ_ENTRY(mapped_cdx_resource) next;
49 : : char name[RTE_DEV_NAME_MAX_LEN]; /**< CDX device name */
50 : : char path[PATH_MAX];
51 : : int nb_maps;
52 : : struct cdx_map maps[RTE_CDX_MAX_RESOURCE];
53 : : };
54 : :
55 : : /** mapped cdx device list */
56 : : TAILQ_HEAD(mapped_cdx_res_list, mapped_cdx_resource);
57 : :
58 : : /* IRQ set buffer length for MSI interrupts */
59 : : #define MSI_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \
60 : : sizeof(int) * (RTE_MAX_RXTX_INTR_VEC_ID + 1))
61 : :
62 : : static struct rte_tailq_elem cdx_vfio_tailq = {
63 : : .name = "VFIO_CDX_RESOURCE_LIST",
64 : : };
65 [ - + ]: 253 : EAL_REGISTER_TAILQ(cdx_vfio_tailq)
66 : :
67 : : static struct mapped_cdx_resource *
68 : 0 : cdx_vfio_find_and_unmap_resource(struct mapped_cdx_res_list *vfio_res_list,
69 : : struct rte_cdx_device *dev)
70 : : {
71 : : struct mapped_cdx_resource *vfio_res = NULL;
72 : 0 : const char *dev_name = dev->device.name;
73 : : struct cdx_map *maps;
74 : : int i;
75 : :
76 : : /* Get vfio_res */
77 [ # # ]: 0 : TAILQ_FOREACH(vfio_res, vfio_res_list, next) {
78 [ # # ]: 0 : if (strcmp(vfio_res->name, dev_name))
79 : : continue;
80 : : break;
81 : : }
82 : :
83 [ # # ]: 0 : if (vfio_res == NULL)
84 : : return vfio_res;
85 : :
86 : 0 : CDX_BUS_INFO("Releasing CDX mapped resource for %s", dev_name);
87 : :
88 : 0 : maps = vfio_res->maps;
89 [ # # ]: 0 : for (i = 0; i < vfio_res->nb_maps; i++) {
90 [ # # ]: 0 : if (maps[i].addr) {
91 : 0 : CDX_BUS_DEBUG("Calling cdx_unmap_resource for %s at %p",
92 : : dev_name, maps[i].addr);
93 : 0 : cdx_unmap_resource(maps[i].addr, maps[i].size);
94 : : }
95 : : }
96 : :
97 : : return vfio_res;
98 : : }
99 : :
100 : : static int
101 : 0 : cdx_vfio_unmap_resource_primary(struct rte_cdx_device *dev)
102 : : {
103 : 0 : char cdx_addr[PATH_MAX] = {0};
104 : : struct mapped_cdx_resource *vfio_res = NULL;
105 : : struct mapped_cdx_res_list *vfio_res_list;
106 : : int ret, vfio_dev_fd;
107 : :
108 [ # # ]: 0 : if (rte_intr_fd_get(dev->intr_handle) >= 0) {
109 [ # # ]: 0 : if (rte_cdx_vfio_bm_disable(dev) < 0)
110 : 0 : CDX_BUS_ERR("Error when disabling bus master for %s",
111 : : dev->device.name);
112 : :
113 [ # # ]: 0 : if (close(rte_intr_fd_get(dev->intr_handle)) < 0) {
114 : 0 : CDX_BUS_ERR("Error when closing eventfd file descriptor for %s",
115 : : dev->device.name);
116 : 0 : return -1;
117 : : }
118 : : }
119 : :
120 : 0 : vfio_dev_fd = rte_intr_dev_fd_get(dev->intr_handle);
121 [ # # ]: 0 : if (vfio_dev_fd < 0)
122 : : return -1;
123 : :
124 : 0 : ret = rte_vfio_release_device(RTE_CDX_BUS_DEVICES_PATH, dev->device.name,
125 : : vfio_dev_fd);
126 [ # # ]: 0 : if (ret < 0) {
127 : 0 : CDX_BUS_ERR("Cannot release VFIO device");
128 : 0 : return ret;
129 : : }
130 : :
131 : 0 : vfio_res_list =
132 : 0 : RTE_TAILQ_CAST(cdx_vfio_tailq.head, mapped_cdx_res_list);
133 : 0 : vfio_res = cdx_vfio_find_and_unmap_resource(vfio_res_list, dev);
134 : :
135 : : /* if we haven't found our tailq entry, something's wrong */
136 [ # # ]: 0 : if (vfio_res == NULL) {
137 : 0 : CDX_BUS_ERR("%s cannot find TAILQ entry for cdx device!",
138 : : cdx_addr);
139 : 0 : return -1;
140 : : }
141 : :
142 [ # # ]: 0 : TAILQ_REMOVE(vfio_res_list, vfio_res, next);
143 : 0 : rte_free(vfio_res);
144 : 0 : return 0;
145 : : }
146 : :
147 : : static int
148 : 0 : cdx_vfio_unmap_resource_secondary(struct rte_cdx_device *dev)
149 : : {
150 : : struct mapped_cdx_resource *vfio_res = NULL;
151 : : struct mapped_cdx_res_list *vfio_res_list;
152 : : int ret, vfio_dev_fd;
153 : :
154 : 0 : vfio_dev_fd = rte_intr_dev_fd_get(dev->intr_handle);
155 [ # # ]: 0 : if (vfio_dev_fd < 0)
156 : : return -1;
157 : :
158 : 0 : ret = rte_vfio_release_device(RTE_CDX_BUS_DEVICES_PATH, dev->device.name,
159 : : vfio_dev_fd);
160 [ # # ]: 0 : if (ret < 0) {
161 : 0 : CDX_BUS_ERR("Cannot release VFIO device");
162 : 0 : return ret;
163 : : }
164 : :
165 : 0 : vfio_res_list =
166 : 0 : RTE_TAILQ_CAST(cdx_vfio_tailq.head, mapped_cdx_res_list);
167 : 0 : vfio_res = cdx_vfio_find_and_unmap_resource(vfio_res_list, dev);
168 : :
169 : : /* if we haven't found our tailq entry, something's wrong */
170 [ # # ]: 0 : if (vfio_res == NULL) {
171 : 0 : CDX_BUS_ERR("%s cannot find TAILQ entry for CDX device!",
172 : : dev->device.name);
173 : 0 : return -1;
174 : : }
175 : :
176 : : return 0;
177 : : }
178 : :
179 : : int
180 : 0 : cdx_vfio_unmap_resource(struct rte_cdx_device *dev)
181 : : {
182 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY)
183 : 0 : return cdx_vfio_unmap_resource_primary(dev);
184 : : else
185 : 0 : return cdx_vfio_unmap_resource_secondary(dev);
186 : : }
187 : :
188 : : /* set up interrupt support (but not enable interrupts) */
189 : : static int
190 : 0 : cdx_vfio_setup_interrupts(struct rte_cdx_device *dev, int vfio_dev_fd,
191 : : int num_irqs)
192 : : {
193 : : int i, ret;
194 : :
195 [ # # ]: 0 : if (rte_intr_dev_fd_set(dev->intr_handle, vfio_dev_fd))
196 : : return -1;
197 : :
198 [ # # ]: 0 : if (num_irqs == 0)
199 : : return 0;
200 : :
201 : : /* start from MSI interrupt type */
202 [ # # ]: 0 : for (i = 0; i < num_irqs; i++) {
203 : 0 : struct vfio_irq_info irq = { .argsz = sizeof(irq) };
204 : : int fd = -1;
205 : :
206 : 0 : irq.index = i;
207 : :
208 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_IRQ_INFO, &irq);
209 [ # # ]: 0 : if (ret < 0) {
210 : 0 : CDX_BUS_ERR("Cannot get VFIO IRQ info, error %i (%s)",
211 : : errno, strerror(errno));
212 : 0 : return -1;
213 : : }
214 : :
215 : : /* if this vector cannot be used with eventfd, fail if we explicitly
216 : : * specified interrupt type, otherwise continue
217 : : */
218 [ # # ]: 0 : if ((irq.flags & VFIO_IRQ_INFO_EVENTFD) == 0)
219 : 0 : continue;
220 : :
221 : : /* Set nb_intr to the total number of interrupts */
222 [ # # ]: 0 : if (rte_intr_event_list_update(dev->intr_handle, irq.count))
223 : : return -1;
224 : :
225 : : /* set up an eventfd for interrupts */
226 : 0 : fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
227 [ # # ]: 0 : if (fd < 0) {
228 : 0 : CDX_BUS_ERR("Cannot set up eventfd, error %i (%s)",
229 : : errno, strerror(errno));
230 : 0 : return -1;
231 : : }
232 : :
233 [ # # ]: 0 : if (rte_intr_fd_set(dev->intr_handle, fd))
234 : : return -1;
235 : :
236 : : /* DPDK CDX bus currently supports only MSI-X */
237 [ # # ]: 0 : if (rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_VFIO_MSIX))
238 : 0 : return -1;
239 : :
240 : : return 0;
241 : : }
242 : :
243 : : /* if we're here, we haven't found a suitable interrupt vector */
244 : : return -1;
245 : : }
246 : :
247 : : static int
248 : 0 : cdx_vfio_setup_device(struct rte_cdx_device *dev, int vfio_dev_fd,
249 : : int num_irqs)
250 : : {
251 [ # # ]: 0 : if (cdx_vfio_setup_interrupts(dev, vfio_dev_fd, num_irqs) != 0) {
252 : 0 : CDX_BUS_ERR("Error setting up interrupts!");
253 : 0 : return -1;
254 : : }
255 : :
256 : : /*
257 : : * Reset the device. If the device is not capable of resetting,
258 : : * then it updates errno as EINVAL.
259 : : */
260 [ # # # # ]: 0 : if (ioctl(vfio_dev_fd, VFIO_DEVICE_RESET) && errno != EINVAL) {
261 : 0 : CDX_BUS_ERR("Unable to reset device! Error: %d (%s)", errno,
262 : : strerror(errno));
263 : 0 : return -1;
264 : : }
265 : :
266 : : /*
267 : : * Enable Bus mastering for the device. errno is set as ENOTTY if
268 : : * device does not support configuring bus master.
269 : : */
270 [ # # # # ]: 0 : if (rte_cdx_vfio_bm_enable(dev) && (errno != -ENOTTY)) {
271 : 0 : CDX_BUS_ERR("Bus master enable failure! Error: %d (%s)", errno,
272 : : strerror(errno));
273 : 0 : return -1;
274 : : }
275 : :
276 : : return 0;
277 : : }
278 : :
279 : : static int
280 : 0 : cdx_vfio_mmap_resource(int vfio_dev_fd, struct mapped_cdx_resource *vfio_res,
281 : : int index, int additional_flags)
282 : : {
283 : : struct cdx_map *map = &vfio_res->maps[index];
284 : : void *vaddr;
285 : :
286 [ # # ]: 0 : if (map->size == 0) {
287 : 0 : CDX_BUS_DEBUG("map size is 0, skip region %d", index);
288 : 0 : return 0;
289 : : }
290 : :
291 : : /* reserve the address using an inaccessible mapping */
292 : 0 : vaddr = mmap(map->addr, map->size, 0, MAP_PRIVATE |
293 : : MAP_ANONYMOUS | additional_flags, -1, 0);
294 [ # # ]: 0 : if (vaddr != MAP_FAILED) {
295 : : void *map_addr = NULL;
296 : :
297 [ # # ]: 0 : if (map->size) {
298 : : /* actual map of first part */
299 : 0 : map_addr = cdx_map_resource(vaddr, vfio_dev_fd,
300 : : map->offset, map->size,
301 : : RTE_MAP_FORCE_ADDRESS);
302 : : }
303 : :
304 [ # # ]: 0 : if (map_addr == NULL) {
305 : 0 : munmap(vaddr, map->size);
306 : : vaddr = MAP_FAILED;
307 : 0 : CDX_BUS_ERR("Failed to map cdx MMIO region %d", index);
308 : 0 : return -1;
309 : : }
310 : : } else {
311 : 0 : CDX_BUS_ERR("Failed to create inaccessible mapping for MMIO region %d",
312 : : index);
313 : 0 : return -1;
314 : : }
315 : :
316 : 0 : map->addr = vaddr;
317 : 0 : return 0;
318 : : }
319 : :
320 : : /*
321 : : * region info may contain capability headers, so we need to keep reallocating
322 : : * the memory until we match allocated memory size with argsz.
323 : : */
324 : : static int
325 : 0 : cdx_vfio_get_region_info(int vfio_dev_fd, struct vfio_region_info **info,
326 : : int region)
327 : : {
328 : : struct vfio_region_info *ri;
329 : : size_t argsz = sizeof(*ri);
330 : : int ret;
331 : :
332 : 0 : ri = malloc(sizeof(*ri));
333 [ # # ]: 0 : if (ri == NULL) {
334 : 0 : CDX_BUS_ERR("Cannot allocate memory for VFIO region info");
335 : 0 : return -1;
336 : : }
337 : 0 : again:
338 : : memset(ri, 0, argsz);
339 : 0 : ri->argsz = argsz;
340 : 0 : ri->index = region;
341 : :
342 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_REGION_INFO, ri);
343 [ # # ]: 0 : if (ret < 0) {
344 : 0 : free(ri);
345 : 0 : return ret;
346 : : }
347 [ # # ]: 0 : if (ri->argsz != argsz) {
348 : : struct vfio_region_info *tmp;
349 : :
350 : : argsz = ri->argsz;
351 : 0 : tmp = realloc(ri, argsz);
352 : :
353 [ # # ]: 0 : if (tmp == NULL) {
354 : : /* realloc failed but the ri is still there */
355 : 0 : free(ri);
356 : 0 : CDX_BUS_ERR("Cannot reallocate memory for VFIO region info");
357 : 0 : return -1;
358 : : }
359 : : ri = tmp;
360 : 0 : goto again;
361 : : }
362 : 0 : *info = ri;
363 : :
364 : 0 : return 0;
365 : : }
366 : :
367 : : static int
368 : 0 : find_max_end_va(const struct rte_memseg_list *msl, void *arg)
369 : : {
370 : 0 : size_t sz = msl->len;
371 : 0 : void *end_va = RTE_PTR_ADD(msl->base_va, sz);
372 : : void **max_va = arg;
373 : :
374 [ # # ]: 0 : if (*max_va < end_va)
375 : 0 : *max_va = end_va;
376 : 0 : return 0;
377 : : }
378 : :
379 : : static void *
380 : : cdx_find_max_end_va(void)
381 : : {
382 : 0 : void *va = NULL;
383 : :
384 : 0 : rte_memseg_list_walk(find_max_end_va, &va);
385 : 0 : return va;
386 : : }
387 : :
388 : : static int
389 : 0 : cdx_vfio_map_resource_primary(struct rte_cdx_device *dev)
390 : : {
391 : 0 : struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
392 : 0 : char cdx_addr[PATH_MAX] = {0};
393 : : static void *cdx_map_addr;
394 : : struct mapped_cdx_resource *vfio_res = NULL;
395 : 0 : struct mapped_cdx_res_list *vfio_res_list =
396 : 0 : RTE_TAILQ_CAST(cdx_vfio_tailq.head, mapped_cdx_res_list);
397 : 0 : const char *dev_name = dev->device.name;
398 : : struct cdx_map *maps;
399 : : int vfio_dev_fd, i, ret;
400 : :
401 [ # # ]: 0 : if (rte_intr_fd_set(dev->intr_handle, -1))
402 : : return -1;
403 : :
404 : 0 : ret = rte_vfio_setup_device(RTE_CDX_BUS_DEVICES_PATH, dev_name,
405 : : &vfio_dev_fd, &device_info);
406 [ # # ]: 0 : if (ret)
407 : : return ret;
408 : :
409 : : /* allocate vfio_res and get region info */
410 : 0 : vfio_res = rte_zmalloc("VFIO_RES", sizeof(*vfio_res), 0);
411 [ # # ]: 0 : if (vfio_res == NULL) {
412 : 0 : CDX_BUS_ERR("Cannot store VFIO mmap details");
413 : 0 : goto err_vfio_dev_fd;
414 : : }
415 : 0 : memcpy(vfio_res->name, dev_name, RTE_DEV_NAME_MAX_LEN);
416 : :
417 : : /* get number of registers */
418 : 0 : vfio_res->nb_maps = device_info.num_regions;
419 : :
420 : : /* map memory regions */
421 : 0 : maps = vfio_res->maps;
422 : :
423 [ # # ]: 0 : for (i = 0; i < vfio_res->nb_maps; i++) {
424 : 0 : struct vfio_region_info *reg = NULL;
425 : : void *vaddr;
426 : :
427 : 0 : ret = cdx_vfio_get_region_info(vfio_dev_fd, ®, i);
428 [ # # ]: 0 : if (ret < 0) {
429 : 0 : CDX_BUS_ERR("%s cannot get device region info error %i (%s)",
430 : : dev_name, errno, strerror(errno));
431 : 0 : goto err_vfio_res;
432 : : }
433 : :
434 : : /* skip non-mmappable regions */
435 [ # # ]: 0 : if ((reg->flags & VFIO_REGION_INFO_FLAG_MMAP) == 0) {
436 : 0 : free(reg);
437 : 0 : continue;
438 : : }
439 : :
440 : : /* try mapping somewhere close to the end of hugepages */
441 [ # # ]: 0 : if (cdx_map_addr == NULL)
442 : 0 : cdx_map_addr = cdx_find_max_end_va();
443 : :
444 : 0 : vaddr = cdx_map_addr;
445 : 0 : cdx_map_addr = RTE_PTR_ADD(vaddr, (size_t)reg->size);
446 : :
447 : 0 : cdx_map_addr = RTE_PTR_ALIGN(cdx_map_addr,
448 : : sysconf(_SC_PAGE_SIZE));
449 : :
450 : 0 : maps[i].addr = vaddr;
451 : 0 : maps[i].offset = reg->offset;
452 : 0 : maps[i].size = reg->size;
453 : 0 : maps[i].path = NULL; /* vfio doesn't have per-resource paths */
454 : :
455 : 0 : ret = cdx_vfio_mmap_resource(vfio_dev_fd, vfio_res, i, 0);
456 [ # # ]: 0 : if (ret < 0) {
457 : 0 : CDX_BUS_ERR("%s mapping region %i failed: %s",
458 : : cdx_addr, i, strerror(errno));
459 : 0 : free(reg);
460 : 0 : goto err_vfio_res;
461 : : }
462 : :
463 : 0 : dev->mem_resource[i].addr = maps[i].addr;
464 : 0 : dev->mem_resource[i].len = maps[i].size;
465 : :
466 : 0 : free(reg);
467 : : }
468 : :
469 [ # # ]: 0 : if (cdx_vfio_setup_device(dev, vfio_dev_fd, device_info.num_irqs) < 0) {
470 : 0 : CDX_BUS_ERR("%s setup device failed", dev_name);
471 : 0 : goto err_vfio_res;
472 : : }
473 : :
474 : 0 : TAILQ_INSERT_TAIL(vfio_res_list, vfio_res, next);
475 : :
476 : 0 : return 0;
477 : 0 : err_vfio_res:
478 : 0 : cdx_vfio_find_and_unmap_resource(vfio_res_list, dev);
479 : 0 : rte_free(vfio_res);
480 : 0 : err_vfio_dev_fd:
481 : 0 : rte_vfio_release_device(RTE_CDX_BUS_DEVICES_PATH, dev_name, vfio_dev_fd);
482 : 0 : return -1;
483 : : }
484 : :
485 : : static int
486 : 0 : cdx_vfio_map_resource_secondary(struct rte_cdx_device *dev)
487 : : {
488 : 0 : struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
489 : 0 : char cdx_addr[PATH_MAX] = {0};
490 : : int vfio_dev_fd;
491 : : int i, ret;
492 : : struct mapped_cdx_resource *vfio_res = NULL;
493 : : struct mapped_cdx_res_list *vfio_res_list =
494 : 0 : RTE_TAILQ_CAST(cdx_vfio_tailq.head, mapped_cdx_res_list);
495 : 0 : const char *dev_name = dev->device.name;
496 : : struct cdx_map *maps;
497 : :
498 [ # # ]: 0 : if (rte_intr_fd_set(dev->intr_handle, -1))
499 : : return -1;
500 : :
501 : : /* if we're in a secondary process, just find our tailq entry */
502 [ # # ]: 0 : TAILQ_FOREACH(vfio_res, vfio_res_list, next) {
503 [ # # ]: 0 : if (strcmp(vfio_res->name, dev_name))
504 : : continue;
505 : : break;
506 : : }
507 : : /* if we haven't found our tailq entry, something's wrong */
508 [ # # ]: 0 : if (vfio_res == NULL) {
509 : 0 : CDX_BUS_ERR("%s cannot find TAILQ entry for cdx device!",
510 : : dev_name);
511 : 0 : return -1;
512 : : }
513 : :
514 : 0 : ret = rte_vfio_setup_device(RTE_CDX_BUS_DEVICES_PATH, dev_name,
515 : : &vfio_dev_fd, &device_info);
516 [ # # ]: 0 : if (ret)
517 : : return ret;
518 : :
519 : : /* map MMIO regions */
520 : 0 : maps = vfio_res->maps;
521 : :
522 [ # # ]: 0 : for (i = 0; i < vfio_res->nb_maps; i++) {
523 : 0 : ret = cdx_vfio_mmap_resource(vfio_dev_fd, vfio_res, i, MAP_FIXED);
524 [ # # ]: 0 : if (ret < 0) {
525 : 0 : CDX_BUS_ERR("%s mapping MMIO region %i failed: %s",
526 : : dev_name, i, strerror(errno));
527 : 0 : goto err_vfio_dev_fd;
528 : : }
529 : :
530 : 0 : dev->mem_resource[i].addr = maps[i].addr;
531 : 0 : dev->mem_resource[i].len = maps[i].size;
532 : : }
533 : :
534 : : /* we need save vfio_dev_fd, so it can be used during release */
535 [ # # ]: 0 : if (rte_intr_dev_fd_set(dev->intr_handle, vfio_dev_fd))
536 : 0 : goto err_vfio_dev_fd;
537 : :
538 : : return 0;
539 : 0 : err_vfio_dev_fd:
540 : 0 : rte_vfio_release_device(RTE_CDX_BUS_DEVICES_PATH, cdx_addr, vfio_dev_fd);
541 : 0 : return -1;
542 : : }
543 : :
544 : : /*
545 : : * map the CDX resources of a CDX device in virtual memory (VFIO version).
546 : : * primary and secondary processes follow almost exactly the same path
547 : : */
548 : : int
549 : 0 : cdx_vfio_map_resource(struct rte_cdx_device *dev)
550 : : {
551 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY)
552 : 0 : return cdx_vfio_map_resource_primary(dev);
553 : : else
554 : 0 : return cdx_vfio_map_resource_secondary(dev);
555 : : }
556 : :
557 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_cdx_vfio_intr_enable)
558 : : int
559 : 0 : rte_cdx_vfio_intr_enable(const struct rte_intr_handle *intr_handle)
560 : : {
561 : : char irq_set_buf[MSI_IRQ_SET_BUF_LEN];
562 : : struct vfio_irq_set *irq_set;
563 : : int *fd_ptr, vfio_dev_fd, i;
564 : : int ret;
565 : :
566 : : irq_set = (struct vfio_irq_set *) irq_set_buf;
567 : 0 : irq_set->count = rte_intr_nb_intr_get(intr_handle);
568 : 0 : irq_set->argsz = sizeof(struct vfio_irq_set) +
569 : : (sizeof(int) * irq_set->count);
570 : :
571 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
572 : 0 : irq_set->index = 0;
573 : 0 : irq_set->start = 0;
574 : : fd_ptr = (int *) &irq_set->data;
575 : :
576 [ # # ]: 0 : for (i = 0; i < rte_intr_nb_efd_get(intr_handle); i++)
577 : 0 : fd_ptr[i] = rte_intr_efds_index_get(intr_handle, i);
578 : :
579 : 0 : vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
580 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
581 : :
582 [ # # ]: 0 : if (ret) {
583 : 0 : CDX_BUS_ERR("Error enabling MSI interrupts for fd %d",
584 : : rte_intr_fd_get(intr_handle));
585 : 0 : return -1;
586 : : }
587 : :
588 : : return 0;
589 : : }
590 : :
591 : : /* disable MSI interrupts */
592 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_cdx_vfio_intr_disable)
593 : : int
594 : 0 : rte_cdx_vfio_intr_disable(const struct rte_intr_handle *intr_handle)
595 : : {
596 : : struct vfio_irq_set *irq_set;
597 : : char irq_set_buf[MSI_IRQ_SET_BUF_LEN];
598 : : int len, ret, vfio_dev_fd;
599 : :
600 : : len = sizeof(struct vfio_irq_set);
601 : :
602 : : irq_set = (struct vfio_irq_set *) irq_set_buf;
603 : 0 : irq_set->argsz = len;
604 : 0 : irq_set->count = 0;
605 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
606 : 0 : irq_set->index = 0;
607 : 0 : irq_set->start = 0;
608 : :
609 : 0 : vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
610 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
611 : :
612 [ # # ]: 0 : if (ret)
613 : 0 : CDX_BUS_ERR("Error disabling MSI interrupts for fd %d",
614 : : rte_intr_fd_get(intr_handle));
615 : :
616 : 0 : return ret;
617 : : }
618 : :
619 : : /* Enable Bus Mastering */
620 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_cdx_vfio_bm_enable)
621 : : int
622 : 0 : rte_cdx_vfio_bm_enable(struct rte_cdx_device *dev)
623 : : {
624 : : struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
625 : : struct vfio_device_feature_bus_master *vfio_bm_feature;
626 : : struct vfio_device_feature *feature;
627 : : int vfio_dev_fd, ret;
628 : : size_t argsz;
629 : :
630 : 0 : vfio_dev_fd = rte_intr_dev_fd_get(dev->intr_handle);
631 [ # # ]: 0 : if (vfio_dev_fd < 0)
632 : : return -1;
633 : :
634 : : argsz = sizeof(struct vfio_device_feature) + sizeof(struct vfio_device_feature_bus_master);
635 : :
636 : 0 : feature = (struct vfio_device_feature *)malloc(argsz);
637 [ # # ]: 0 : if (!feature)
638 : : return -ENOMEM;
639 : :
640 : : vfio_bm_feature = (struct vfio_device_feature_bus_master *) feature->data;
641 : :
642 : 0 : feature->argsz = argsz;
643 : :
644 : : feature->flags = VFIO_DEVICE_FEATURE_BUS_MASTER | VFIO_DEVICE_FEATURE_PROBE;
645 : 0 : feature->flags |= VFIO_DEVICE_FEATURE_SET;
646 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_FEATURE, feature);
647 [ # # ]: 0 : if (ret) {
648 : 0 : CDX_BUS_ERR("Bus Master configuring not supported for device: %s, error: %d (%s)",
649 : : dev->name, errno, strerror(errno));
650 : 0 : free(feature);
651 : 0 : return ret;
652 : : }
653 : :
654 : 0 : feature->flags = VFIO_DEVICE_FEATURE_BUS_MASTER | VFIO_DEVICE_FEATURE_SET;
655 : 0 : vfio_bm_feature->op = VFIO_DEVICE_FEATURE_SET_MASTER;
656 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_FEATURE, feature);
657 [ # # ]: 0 : if (ret < 0)
658 : 0 : CDX_BUS_ERR("BM Enable Error for device: %s, Error: %d (%s)",
659 : : dev->name, errno, strerror(errno));
660 : :
661 : 0 : free(feature);
662 : 0 : return ret;
663 : : }
664 : :
665 : : /* Disable Bus Mastering */
666 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_cdx_vfio_bm_disable)
667 : : int
668 : 0 : rte_cdx_vfio_bm_disable(struct rte_cdx_device *dev)
669 : : {
670 : : struct vfio_device_feature_bus_master *vfio_bm_feature;
671 : : struct vfio_device_feature *feature;
672 : : int vfio_dev_fd, ret;
673 : : size_t argsz;
674 : :
675 : 0 : vfio_dev_fd = rte_intr_dev_fd_get(dev->intr_handle);
676 [ # # ]: 0 : if (vfio_dev_fd < 0)
677 : : return -1;
678 : :
679 : : argsz = sizeof(struct vfio_device_feature) + sizeof(struct vfio_device_feature_bus_master);
680 : :
681 : 0 : feature = (struct vfio_device_feature *)malloc(argsz);
682 [ # # ]: 0 : if (!feature)
683 : : return -ENOMEM;
684 : :
685 : : vfio_bm_feature = (struct vfio_device_feature_bus_master *) feature->data;
686 : :
687 : 0 : feature->argsz = argsz;
688 : :
689 : : feature->flags = VFIO_DEVICE_FEATURE_BUS_MASTER | VFIO_DEVICE_FEATURE_PROBE;
690 : 0 : feature->flags |= VFIO_DEVICE_FEATURE_SET;
691 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_FEATURE, feature);
692 [ # # ]: 0 : if (ret) {
693 : 0 : CDX_BUS_ERR("Bus Master configuring not supported for device: %s, Error: %d (%s)",
694 : : dev->name, errno, strerror(errno));
695 : 0 : free(feature);
696 : 0 : return ret;
697 : : }
698 : :
699 : 0 : feature->flags = VFIO_DEVICE_FEATURE_BUS_MASTER | VFIO_DEVICE_FEATURE_SET;
700 : 0 : vfio_bm_feature->op = VFIO_DEVICE_FEATURE_CLEAR_MASTER;
701 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_FEATURE, feature);
702 [ # # ]: 0 : if (ret < 0)
703 : 0 : CDX_BUS_ERR("BM Disable Error for device: %s, Error: %d (%s)",
704 : : dev->name, errno, strerror(errno));
705 : :
706 : 0 : free(feature);
707 : 0 : return ret;
708 : : }
|