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