Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation
3 : : */
4 : :
5 : : #include <unistd.h>
6 : : #include <string.h>
7 : : #include <fcntl.h>
8 : : #include <sys/eventfd.h>
9 : : #include <sys/socket.h>
10 : : #include <sys/ioctl.h>
11 : : #include <sys/mman.h>
12 : : #include <stdbool.h>
13 : :
14 : : #include <rte_log.h>
15 : : #include <rte_pci.h>
16 : : #include <rte_bus_pci.h>
17 : : #include <rte_eal_paging.h>
18 : : #include <rte_malloc.h>
19 : : #include <rte_vfio.h>
20 : : #include <rte_eal.h>
21 : : #include <bus_driver.h>
22 : : #include <rte_spinlock.h>
23 : : #include <rte_tailq.h>
24 : :
25 : : #include "eal_filesystem.h"
26 : :
27 : : #include "pci_init.h"
28 : : #include "private.h"
29 : :
30 : : /**
31 : : * @file
32 : : * PCI probing using Linux VFIO.
33 : : *
34 : : * This code tries to determine if the PCI device is bound to VFIO driver,
35 : : * and initialize it (map BARs, set up interrupts) if that's the case.
36 : : *
37 : : */
38 : :
39 : : #ifdef VFIO_PRESENT
40 : :
41 : : static struct rte_tailq_elem rte_vfio_tailq = {
42 : : .name = "VFIO_RESOURCE_LIST",
43 : : };
44 [ - + ]: 238 : EAL_REGISTER_TAILQ(rte_vfio_tailq)
45 : :
46 : : static int
47 : : pci_vfio_get_region(const struct rte_pci_device *dev, int index,
48 : : uint64_t *size, uint64_t *offset)
49 : : {
50 : : const struct rte_pci_device_internal *pdev =
51 : : RTE_PCI_DEVICE_INTERNAL_CONST(dev);
52 : :
53 [ # # # # ]: 0 : if (index >= VFIO_PCI_NUM_REGIONS || index >= RTE_MAX_PCI_REGIONS)
54 : : return -1;
55 : :
56 [ # # # # : 0 : if (pdev->region[index].size == 0 && pdev->region[index].offset == 0)
# # # # #
# # # # #
# # # # #
# # # #
# ]
57 : : return -1;
58 : :
59 : : *size = pdev->region[index].size;
60 : 0 : *offset = pdev->region[index].offset;
61 : :
62 : 0 : return 0;
63 : : }
64 : :
65 : : int
66 : 0 : pci_vfio_read_config(const struct rte_pci_device *dev,
67 : : void *buf, size_t len, off_t offs)
68 : : {
69 : : uint64_t size, offset;
70 : : int fd;
71 : :
72 : 0 : fd = rte_intr_dev_fd_get(dev->intr_handle);
73 [ # # ]: 0 : if (fd < 0)
74 : : return -1;
75 : :
76 [ # # ]: 0 : if (pci_vfio_get_region(dev, VFIO_PCI_CONFIG_REGION_INDEX,
77 : : &size, &offset) != 0)
78 : : return -1;
79 : :
80 [ # # ]: 0 : if ((uint64_t)len + offs > size)
81 : : return -1;
82 : :
83 [ # # ]: 0 : return pread64(fd, buf, len, offset + offs);
84 : : }
85 : :
86 : : int
87 : 0 : pci_vfio_write_config(const struct rte_pci_device *dev,
88 : : const void *buf, size_t len, off_t offs)
89 : : {
90 : : uint64_t size, offset;
91 : : int fd;
92 : :
93 : 0 : fd = rte_intr_dev_fd_get(dev->intr_handle);
94 [ # # ]: 0 : if (fd < 0)
95 : : return -1;
96 : :
97 [ # # ]: 0 : if (pci_vfio_get_region(dev, VFIO_PCI_CONFIG_REGION_INDEX,
98 : : &size, &offset) != 0)
99 : : return -1;
100 : :
101 [ # # ]: 0 : if ((uint64_t)len + offs > size)
102 : : return -1;
103 : :
104 : 0 : return pwrite64(fd, buf, len, offset + offs);
105 : : }
106 : :
107 : : /* get PCI BAR number where MSI-X interrupts are */
108 : : static int
109 : 0 : pci_vfio_get_msix_bar(const struct rte_pci_device *dev,
110 : : struct pci_msix_table *msix_table)
111 : : {
112 : : off_t cap_offset;
113 : :
114 : 0 : cap_offset = rte_pci_find_capability(dev, RTE_PCI_CAP_ID_MSIX);
115 [ # # ]: 0 : if (cap_offset < 0)
116 : : return -1;
117 : :
118 [ # # ]: 0 : if (cap_offset != 0) {
119 : : uint16_t flags;
120 : : uint32_t reg;
121 : :
122 [ # # ]: 0 : if (rte_pci_read_config(dev, ®, sizeof(reg), cap_offset +
123 : : RTE_PCI_MSIX_TABLE) < 0) {
124 : 0 : RTE_LOG(ERR, EAL,
125 : : "Cannot read MSIX table from PCI config space!\n");
126 : 0 : return -1;
127 : : }
128 : :
129 [ # # ]: 0 : if (rte_pci_read_config(dev, &flags, sizeof(flags), cap_offset +
130 : : RTE_PCI_MSIX_FLAGS) < 0) {
131 : 0 : RTE_LOG(ERR, EAL,
132 : : "Cannot read MSIX flags from PCI config space!\n");
133 : 0 : return -1;
134 : : }
135 : :
136 : 0 : msix_table->bar_index = reg & RTE_PCI_MSIX_TABLE_BIR;
137 : 0 : msix_table->offset = reg & RTE_PCI_MSIX_TABLE_OFFSET;
138 : 0 : msix_table->size = 16 * (1 + (flags & RTE_PCI_MSIX_FLAGS_QSIZE));
139 : : }
140 : :
141 : : return 0;
142 : : }
143 : :
144 : : /* enable PCI bus memory space */
145 : : static int
146 [ # # ]: 0 : pci_vfio_enable_bus_memory(struct rte_pci_device *dev, int dev_fd)
147 : : {
148 : : uint64_t size, offset;
149 : : uint16_t cmd;
150 : : int ret;
151 : :
152 : : if (pci_vfio_get_region(dev, VFIO_PCI_CONFIG_REGION_INDEX,
153 : : &size, &offset) != 0) {
154 : 0 : RTE_LOG(ERR, EAL, "Cannot get offset of CONFIG region.\n");
155 : 0 : return -1;
156 : : }
157 : :
158 : 0 : ret = pread64(dev_fd, &cmd, sizeof(cmd), offset + RTE_PCI_COMMAND);
159 : :
160 [ # # ]: 0 : if (ret != sizeof(cmd)) {
161 : 0 : RTE_LOG(ERR, EAL, "Cannot read command from PCI config space!\n");
162 : 0 : return -1;
163 : : }
164 : :
165 [ # # ]: 0 : if (cmd & RTE_PCI_COMMAND_MEMORY)
166 : : return 0;
167 : :
168 : 0 : cmd |= RTE_PCI_COMMAND_MEMORY;
169 : 0 : ret = pwrite64(dev_fd, &cmd, sizeof(cmd), offset + RTE_PCI_COMMAND);
170 : :
171 [ # # ]: 0 : if (ret != sizeof(cmd)) {
172 : 0 : RTE_LOG(ERR, EAL, "Cannot write command to PCI config space!\n");
173 : 0 : return -1;
174 : : }
175 : :
176 : : return 0;
177 : : }
178 : :
179 : : /* set up interrupt support (but not enable interrupts) */
180 : : static int
181 : 0 : pci_vfio_setup_interrupts(struct rte_pci_device *dev, int vfio_dev_fd)
182 : : {
183 : : int i, ret, intr_idx;
184 : : enum rte_intr_mode intr_mode;
185 : :
186 : : /* default to invalid index */
187 : : intr_idx = VFIO_PCI_NUM_IRQS;
188 : :
189 : : /* Get default / configured intr_mode */
190 : 0 : intr_mode = rte_eal_vfio_intr_mode();
191 : :
192 : : /* get interrupt type from internal config (MSI-X by default, can be
193 : : * overridden from the command line
194 : : */
195 : : switch (intr_mode) {
196 : : case RTE_INTR_MODE_MSIX:
197 : : intr_idx = VFIO_PCI_MSIX_IRQ_INDEX;
198 : : break;
199 : : case RTE_INTR_MODE_MSI:
200 : : intr_idx = VFIO_PCI_MSI_IRQ_INDEX;
201 : : break;
202 : : case RTE_INTR_MODE_LEGACY:
203 : : intr_idx = VFIO_PCI_INTX_IRQ_INDEX;
204 : : break;
205 : : /* don't do anything if we want to automatically determine interrupt type */
206 : : case RTE_INTR_MODE_NONE:
207 : : break;
208 : 0 : default:
209 : 0 : RTE_LOG(ERR, EAL, "Unknown default interrupt type!\n");
210 : 0 : return -1;
211 : : }
212 : :
213 : : /* start from MSI-X interrupt type */
214 [ # # ]: 0 : for (i = VFIO_PCI_MSIX_IRQ_INDEX; i >= 0; i--) {
215 : 0 : struct vfio_irq_info irq = { .argsz = sizeof(irq) };
216 : : int fd = -1;
217 : :
218 : : /* skip interrupt modes we don't want */
219 : 0 : if (intr_mode != RTE_INTR_MODE_NONE &&
220 [ # # ]: 0 : i != intr_idx)
221 : 0 : continue;
222 : :
223 : 0 : irq.index = i;
224 : :
225 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_IRQ_INFO, &irq);
226 [ # # ]: 0 : if (ret < 0) {
227 : 0 : RTE_LOG(ERR, EAL, "Cannot get VFIO IRQ info, error "
228 : : "%i (%s)\n", errno, strerror(errno));
229 : 0 : return -1;
230 : : }
231 : :
232 : : /* if this vector cannot be used with eventfd, fail if we explicitly
233 : : * specified interrupt type, otherwise continue */
234 [ # # ]: 0 : if ((irq.flags & VFIO_IRQ_INFO_EVENTFD) == 0) {
235 [ # # ]: 0 : if (intr_mode != RTE_INTR_MODE_NONE) {
236 : 0 : RTE_LOG(ERR, EAL,
237 : : "Interrupt vector does not support eventfd!\n");
238 : 0 : return -1;
239 : : } else
240 : 0 : continue;
241 : : }
242 : :
243 : : /* Reallocate the efds and elist fields of intr_handle based
244 : : * on PCI device MSIX size.
245 : : */
246 [ # # ]: 0 : if (i == VFIO_PCI_MSIX_IRQ_INDEX &&
247 [ # # # # ]: 0 : (uint32_t)rte_intr_nb_intr_get(dev->intr_handle) < irq.count &&
248 : 0 : rte_intr_event_list_update(dev->intr_handle, irq.count))
249 : : return -1;
250 : :
251 : : /* set up an eventfd for interrupts */
252 : 0 : fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
253 [ # # ]: 0 : if (fd < 0) {
254 : 0 : RTE_LOG(ERR, EAL, "Cannot set up eventfd, error "
255 : : "%i (%s)\n", errno, strerror(errno));
256 : 0 : return -1;
257 : : }
258 : :
259 [ # # ]: 0 : if (rte_intr_fd_set(dev->intr_handle, fd))
260 : : return -1;
261 : :
262 [ # # # ]: 0 : switch (i) {
263 : 0 : case VFIO_PCI_MSIX_IRQ_INDEX:
264 : : intr_mode = RTE_INTR_MODE_MSIX;
265 : 0 : rte_intr_type_set(dev->intr_handle,
266 : : RTE_INTR_HANDLE_VFIO_MSIX);
267 : 0 : break;
268 : 0 : case VFIO_PCI_MSI_IRQ_INDEX:
269 : : intr_mode = RTE_INTR_MODE_MSI;
270 : 0 : rte_intr_type_set(dev->intr_handle,
271 : : RTE_INTR_HANDLE_VFIO_MSI);
272 : 0 : break;
273 : 0 : case VFIO_PCI_INTX_IRQ_INDEX:
274 : : intr_mode = RTE_INTR_MODE_LEGACY;
275 : 0 : rte_intr_type_set(dev->intr_handle,
276 : : RTE_INTR_HANDLE_VFIO_LEGACY);
277 : 0 : break;
278 : : default:
279 : : RTE_LOG(ERR, EAL, "Unknown interrupt type!\n");
280 : : return -1;
281 : : }
282 : :
283 : : return 0;
284 : : }
285 : :
286 : : /* if we're here, we haven't found a suitable interrupt vector */
287 : : return -1;
288 : : }
289 : :
290 : : #ifdef HAVE_VFIO_DEV_REQ_INTERFACE
291 : : /*
292 : : * Spinlock for device hot-unplug failure handling.
293 : : * If it tries to access bus or device, such as handle sigbus on bus
294 : : * or handle memory failure for device, just need to use this lock.
295 : : * It could protect the bus and the device to avoid race condition.
296 : : */
297 : : static rte_spinlock_t failure_handle_lock = RTE_SPINLOCK_INITIALIZER;
298 : :
299 : : static void
300 : 0 : pci_vfio_req_handler(void *param)
301 : : {
302 : : struct rte_bus *bus;
303 : : int ret;
304 : : struct rte_device *device = (struct rte_device *)param;
305 : :
306 : : rte_spinlock_lock(&failure_handle_lock);
307 : 0 : bus = rte_bus_find_by_device(device);
308 [ # # ]: 0 : if (bus == NULL) {
309 : 0 : RTE_LOG(ERR, EAL, "Cannot find bus for device (%s)\n",
310 : : device->name);
311 : 0 : goto handle_end;
312 : : }
313 : :
314 : : /*
315 : : * vfio kernel module request user space to release allocated
316 : : * resources before device be deleted in kernel, so it can directly
317 : : * call the vfio bus hot-unplug handler to process it.
318 : : */
319 : 0 : ret = bus->hot_unplug_handler(device);
320 [ # # ]: 0 : if (ret)
321 : 0 : RTE_LOG(ERR, EAL,
322 : : "Can not handle hot-unplug for device (%s)\n",
323 : : device->name);
324 : 0 : handle_end:
325 : : rte_spinlock_unlock(&failure_handle_lock);
326 : 0 : }
327 : :
328 : : /* enable notifier (only enable req now) */
329 : : static int
330 : 0 : pci_vfio_enable_notifier(struct rte_pci_device *dev, int vfio_dev_fd)
331 : : {
332 : : int ret;
333 : : int fd = -1;
334 : :
335 : : /* set up an eventfd for req notifier */
336 : 0 : fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
337 [ # # ]: 0 : if (fd < 0) {
338 : 0 : RTE_LOG(ERR, EAL, "Cannot set up eventfd, error %i (%s)\n",
339 : : errno, strerror(errno));
340 : 0 : return -1;
341 : : }
342 : :
343 [ # # ]: 0 : if (rte_intr_fd_set(dev->vfio_req_intr_handle, fd))
344 : : return -1;
345 : :
346 [ # # ]: 0 : if (rte_intr_type_set(dev->vfio_req_intr_handle, RTE_INTR_HANDLE_VFIO_REQ))
347 : : return -1;
348 : :
349 [ # # ]: 0 : if (rte_intr_dev_fd_set(dev->vfio_req_intr_handle, vfio_dev_fd))
350 : : return -1;
351 : :
352 : 0 : ret = rte_intr_callback_register(dev->vfio_req_intr_handle,
353 : : pci_vfio_req_handler,
354 : 0 : (void *)&dev->device);
355 [ # # ]: 0 : if (ret) {
356 : 0 : RTE_LOG(ERR, EAL, "Fail to register req notifier handler.\n");
357 : 0 : goto error;
358 : : }
359 : :
360 : 0 : ret = rte_intr_enable(dev->vfio_req_intr_handle);
361 [ # # ]: 0 : if (ret) {
362 : 0 : RTE_LOG(ERR, EAL, "Fail to enable req notifier.\n");
363 : 0 : ret = rte_intr_callback_unregister(dev->vfio_req_intr_handle,
364 : : pci_vfio_req_handler,
365 : : (void *)&dev->device);
366 [ # # ]: 0 : if (ret < 0)
367 : 0 : RTE_LOG(ERR, EAL,
368 : : "Fail to unregister req notifier handler.\n");
369 : 0 : goto error;
370 : : }
371 : :
372 : : return 0;
373 : 0 : error:
374 : 0 : close(fd);
375 : :
376 : 0 : rte_intr_fd_set(dev->vfio_req_intr_handle, -1);
377 : 0 : rte_intr_type_set(dev->vfio_req_intr_handle, RTE_INTR_HANDLE_UNKNOWN);
378 : 0 : rte_intr_dev_fd_set(dev->vfio_req_intr_handle, -1);
379 : :
380 : 0 : return -1;
381 : : }
382 : :
383 : : /* disable notifier (only disable req now) */
384 : : static int
385 : 0 : pci_vfio_disable_notifier(struct rte_pci_device *dev)
386 : : {
387 : : int ret;
388 : :
389 : 0 : ret = rte_intr_disable(dev->vfio_req_intr_handle);
390 [ # # ]: 0 : if (ret) {
391 : 0 : RTE_LOG(ERR, EAL, "fail to disable req notifier.\n");
392 : 0 : return -1;
393 : : }
394 : :
395 : 0 : ret = rte_intr_callback_unregister_sync(dev->vfio_req_intr_handle,
396 : : pci_vfio_req_handler,
397 : 0 : (void *)&dev->device);
398 [ # # ]: 0 : if (ret < 0) {
399 : 0 : RTE_LOG(ERR, EAL,
400 : : "fail to unregister req notifier handler.\n");
401 : 0 : return -1;
402 : : }
403 : :
404 : 0 : close(rte_intr_fd_get(dev->vfio_req_intr_handle));
405 : :
406 : 0 : rte_intr_fd_set(dev->vfio_req_intr_handle, -1);
407 : 0 : rte_intr_type_set(dev->vfio_req_intr_handle, RTE_INTR_HANDLE_UNKNOWN);
408 : 0 : rte_intr_dev_fd_set(dev->vfio_req_intr_handle, -1);
409 : :
410 : 0 : return 0;
411 : : }
412 : : #endif
413 : :
414 : : static int
415 [ # # ]: 0 : pci_vfio_is_ioport_bar(const struct rte_pci_device *dev, int vfio_dev_fd,
416 : : int bar_index)
417 : : {
418 : : uint64_t size, offset;
419 : : uint32_t ioport_bar;
420 : : int ret;
421 : :
422 : : if (pci_vfio_get_region(dev, VFIO_PCI_CONFIG_REGION_INDEX,
423 : : &size, &offset) != 0) {
424 : 0 : RTE_LOG(ERR, EAL, "Cannot get offset of CONFIG region.\n");
425 : 0 : return -1;
426 : : }
427 : :
428 : 0 : ret = pread64(vfio_dev_fd, &ioport_bar, sizeof(ioport_bar),
429 : 0 : offset + RTE_PCI_BASE_ADDRESS_0 + bar_index * 4);
430 [ # # ]: 0 : if (ret != sizeof(ioport_bar)) {
431 : 0 : RTE_LOG(ERR, EAL, "Cannot read command (%x) from config space!\n",
432 : : RTE_PCI_BASE_ADDRESS_0 + bar_index*4);
433 : 0 : return -1;
434 : : }
435 : :
436 : 0 : return (ioport_bar & RTE_PCI_BASE_ADDRESS_SPACE_IO) != 0;
437 : : }
438 : :
439 : : static int
440 : 0 : pci_rte_vfio_setup_device(struct rte_pci_device *dev, int vfio_dev_fd)
441 : : {
442 [ # # ]: 0 : if (pci_vfio_setup_interrupts(dev, vfio_dev_fd) != 0) {
443 : 0 : RTE_LOG(ERR, EAL, "Error setting up interrupts!\n");
444 : 0 : return -1;
445 : : }
446 : :
447 [ # # ]: 0 : if (pci_vfio_enable_bus_memory(dev, vfio_dev_fd)) {
448 : 0 : RTE_LOG(ERR, EAL, "Cannot enable bus memory!\n");
449 : 0 : return -1;
450 : : }
451 : :
452 [ # # ]: 0 : if (rte_pci_set_bus_master(dev, true)) {
453 : 0 : RTE_LOG(ERR, EAL, "Cannot set up bus mastering!\n");
454 : 0 : return -1;
455 : : }
456 : :
457 : : /*
458 : : * Reset the device. If the device is not capable of resetting,
459 : : * then it updates errno as EINVAL.
460 : : */
461 [ # # # # ]: 0 : if (ioctl(vfio_dev_fd, VFIO_DEVICE_RESET) && errno != EINVAL) {
462 : 0 : RTE_LOG(ERR, EAL, "Unable to reset device! Error: %d (%s)\n",
463 : : errno, strerror(errno));
464 : 0 : return -1;
465 : : }
466 : :
467 : : return 0;
468 : : }
469 : :
470 : : static int
471 : 0 : pci_vfio_mmap_bar(int vfio_dev_fd, struct mapped_pci_resource *vfio_res,
472 : : int bar_index, int additional_flags)
473 : : {
474 : : struct memreg {
475 : : uint64_t offset;
476 : : size_t size;
477 : : } memreg[2] = {};
478 : : void *bar_addr;
479 : : struct pci_msix_table *msix_table = &vfio_res->msix_table;
480 : : struct pci_map *bar = &vfio_res->maps[bar_index];
481 : :
482 [ # # ]: 0 : if (bar->size == 0) {
483 : 0 : RTE_LOG(DEBUG, EAL, "Bar size is 0, skip BAR%d\n", bar_index);
484 : 0 : return 0;
485 : : }
486 : :
487 [ # # ]: 0 : if (msix_table->bar_index == bar_index) {
488 : : /*
489 : : * VFIO will not let us map the MSI-X table,
490 : : * but we can map around it.
491 : : */
492 : 0 : uint32_t table_start = msix_table->offset;
493 : 0 : uint32_t table_end = table_start + msix_table->size;
494 : 0 : table_end = RTE_ALIGN(table_end, rte_mem_page_size());
495 : 0 : table_start = RTE_ALIGN_FLOOR(table_start, rte_mem_page_size());
496 : :
497 : : /* If page-aligned start of MSI-X table is less than the
498 : : * actual MSI-X table start address, reassign to the actual
499 : : * start address.
500 : : */
501 : 0 : if (table_start < msix_table->offset)
502 : : table_start = msix_table->offset;
503 : :
504 [ # # # # ]: 0 : if (table_start == 0 && table_end >= bar->size) {
505 : : /* Cannot map this BAR */
506 : 0 : RTE_LOG(DEBUG, EAL, "Skipping BAR%d\n", bar_index);
507 : 0 : bar->size = 0;
508 : 0 : bar->addr = 0;
509 : 0 : return 0;
510 : : }
511 : :
512 : 0 : memreg[0].offset = bar->offset;
513 : 0 : memreg[0].size = table_start;
514 [ # # ]: 0 : if (bar->size < table_end) {
515 : : /*
516 : : * If MSI-X table end is beyond BAR end, don't attempt
517 : : * to perform second mapping.
518 : : */
519 : : memreg[1].offset = 0;
520 : : memreg[1].size = 0;
521 : : } else {
522 : 0 : memreg[1].offset = bar->offset + table_end;
523 : 0 : memreg[1].size = bar->size - table_end;
524 : : }
525 : :
526 : 0 : RTE_LOG(DEBUG, EAL,
527 : : "Trying to map BAR%d that contains the MSI-X "
528 : : "table. Trying offsets: "
529 : : "0x%04" PRIx64 ":0x%04zx, 0x%04" PRIx64 ":0x%04zx\n",
530 : : bar_index,
531 : : memreg[0].offset, memreg[0].size,
532 : : memreg[1].offset, memreg[1].size);
533 : : } else {
534 : 0 : memreg[0].offset = bar->offset;
535 : : memreg[0].size = bar->size;
536 : : }
537 : :
538 : : /* reserve the address using an inaccessible mapping */
539 : 0 : bar_addr = mmap(bar->addr, bar->size, 0, MAP_PRIVATE |
540 : : MAP_ANONYMOUS | additional_flags, -1, 0);
541 [ # # ]: 0 : if (bar_addr != MAP_FAILED) {
542 : : void *map_addr = NULL;
543 [ # # ]: 0 : if (memreg[0].size) {
544 : : /* actual map of first part */
545 : 0 : map_addr = pci_map_resource(bar_addr, vfio_dev_fd,
546 : : memreg[0].offset,
547 : : memreg[0].size,
548 : : RTE_MAP_FORCE_ADDRESS);
549 : : }
550 : :
551 : : /*
552 : : * Regarding "memreg[0].size == 0":
553 : : * If this BAR has MSI-X table, memreg[0].size (the
554 : : * first part or the part before the table) can
555 : : * legitimately be 0 for hardware using vector table
556 : : * offset 0 (i.e. first part does not exist).
557 : : *
558 : : * When memreg[0].size is 0, "mapping the first part"
559 : : * never happens, and map_addr is NULL at this
560 : : * point. So check that mapping has been actually
561 : : * attempted.
562 : : */
563 : : /* if there's a second part, try to map it */
564 [ # # # # ]: 0 : if ((map_addr != NULL || memreg[0].size == 0)
565 [ # # # # ]: 0 : && memreg[1].offset && memreg[1].size) {
566 : 0 : void *second_addr = RTE_PTR_ADD(bar_addr,
567 : : (uintptr_t)(memreg[1].offset -
568 : : bar->offset));
569 : 0 : map_addr = pci_map_resource(second_addr,
570 : : vfio_dev_fd,
571 : : memreg[1].offset,
572 : : memreg[1].size,
573 : : RTE_MAP_FORCE_ADDRESS);
574 : : }
575 : :
576 [ # # ]: 0 : if (map_addr == NULL) {
577 : 0 : munmap(bar_addr, bar->size);
578 : : bar_addr = MAP_FAILED;
579 : 0 : RTE_LOG(ERR, EAL, "Failed to map pci BAR%d\n",
580 : : bar_index);
581 : 0 : return -1;
582 : : }
583 : : } else {
584 : 0 : RTE_LOG(ERR, EAL,
585 : : "Failed to create inaccessible mapping for BAR%d\n",
586 : : bar_index);
587 : 0 : return -1;
588 : : }
589 : :
590 : 0 : bar->addr = bar_addr;
591 : 0 : return 0;
592 : : }
593 : :
594 : : static int
595 : 0 : pci_vfio_sparse_mmap_bar(int vfio_dev_fd, struct mapped_pci_resource *vfio_res,
596 : : int bar_index, int additional_flags)
597 : : {
598 : : struct pci_map *bar = &vfio_res->maps[bar_index];
599 : : struct vfio_region_sparse_mmap_area *sparse;
600 : : void *bar_addr;
601 : : uint32_t i;
602 : :
603 [ # # ]: 0 : if (bar->size == 0) {
604 : 0 : RTE_LOG(DEBUG, EAL, "Bar size is 0, skip BAR%d\n", bar_index);
605 : 0 : return 0;
606 : : }
607 : :
608 : : /* reserve the address using an inaccessible mapping */
609 : 0 : bar_addr = mmap(bar->addr, bar->size, 0, MAP_PRIVATE |
610 : : MAP_ANONYMOUS | additional_flags, -1, 0);
611 [ # # ]: 0 : if (bar_addr != MAP_FAILED) {
612 : : void *map_addr = NULL;
613 [ # # ]: 0 : for (i = 0; i < bar->nr_areas; i++) {
614 : 0 : sparse = &bar->areas[i];
615 [ # # ]: 0 : if (sparse->size) {
616 : 0 : void *addr = RTE_PTR_ADD(bar_addr, (uintptr_t)sparse->offset);
617 : 0 : map_addr = pci_map_resource(addr, vfio_dev_fd,
618 : 0 : bar->offset + sparse->offset, sparse->size,
619 : : RTE_MAP_FORCE_ADDRESS);
620 [ # # ]: 0 : if (map_addr == NULL) {
621 : 0 : munmap(bar_addr, bar->size);
622 : 0 : RTE_LOG(ERR, EAL, "Failed to map pci BAR%d\n",
623 : : bar_index);
624 : 0 : goto err_map;
625 : : }
626 : : }
627 : : }
628 : : } else {
629 : 0 : RTE_LOG(ERR, EAL, "Failed to create inaccessible mapping for BAR%d\n",
630 : : bar_index);
631 : 0 : goto err_map;
632 : : }
633 : :
634 : 0 : bar->addr = bar_addr;
635 : 0 : return 0;
636 : :
637 : 0 : err_map:
638 : 0 : bar->nr_areas = 0;
639 : 0 : return -1;
640 : : }
641 : :
642 : : /*
643 : : * region info may contain capability headers, so we need to keep reallocating
644 : : * the memory until we match allocated memory size with argsz.
645 : : */
646 : : static int
647 : 0 : pci_vfio_get_region_info(int vfio_dev_fd, struct vfio_region_info **info,
648 : : int region)
649 : : {
650 : : struct vfio_region_info *ri;
651 : : size_t argsz = sizeof(*ri);
652 : : int ret;
653 : :
654 : 0 : ri = malloc(sizeof(*ri));
655 [ # # ]: 0 : if (ri == NULL) {
656 : 0 : RTE_LOG(ERR, EAL,
657 : : "Cannot allocate memory for VFIO region info\n");
658 : 0 : return -1;
659 : : }
660 : 0 : again:
661 : : memset(ri, 0, argsz);
662 : 0 : ri->argsz = argsz;
663 : 0 : ri->index = region;
664 : :
665 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_REGION_INFO, ri);
666 [ # # ]: 0 : if (ret < 0) {
667 : 0 : free(ri);
668 : 0 : return ret;
669 : : }
670 [ # # ]: 0 : if (ri->argsz != argsz) {
671 : : struct vfio_region_info *tmp;
672 : :
673 : : argsz = ri->argsz;
674 : 0 : tmp = realloc(ri, argsz);
675 : :
676 [ # # ]: 0 : if (tmp == NULL) {
677 : : /* realloc failed but the ri is still there */
678 : 0 : free(ri);
679 : 0 : RTE_LOG(ERR, EAL,
680 : : "Cannot reallocate memory for VFIO region info\n");
681 : 0 : return -1;
682 : : }
683 : : ri = tmp;
684 : 0 : goto again;
685 : : }
686 : 0 : *info = ri;
687 : :
688 : 0 : return 0;
689 : : }
690 : :
691 : : static struct vfio_info_cap_header *
692 : : pci_vfio_info_cap(struct vfio_region_info *info, int cap)
693 : : {
694 : : struct vfio_info_cap_header *h;
695 : : size_t offset;
696 : :
697 : 0 : if ((info->flags & RTE_VFIO_INFO_FLAG_CAPS) == 0) {
698 : : /* VFIO info does not advertise capabilities */
699 : : return NULL;
700 : : }
701 : :
702 : 0 : offset = VFIO_CAP_OFFSET(info);
703 [ # # # # ]: 0 : while (offset != 0) {
704 : 0 : h = RTE_PTR_ADD(info, offset);
705 [ # # # # ]: 0 : if (h->id == cap)
706 : : return h;
707 : 0 : offset = h->next;
708 : : }
709 : : return NULL;
710 : : }
711 : :
712 : : static int
713 : 0 : pci_vfio_msix_is_mappable(int vfio_dev_fd, int msix_region)
714 : : {
715 : 0 : struct vfio_region_info *info = NULL;
716 : : int ret;
717 : :
718 : 0 : ret = pci_vfio_get_region_info(vfio_dev_fd, &info, msix_region);
719 [ # # ]: 0 : if (ret < 0)
720 : : return -1;
721 : :
722 [ # # ]: 0 : ret = pci_vfio_info_cap(info, RTE_VFIO_CAP_MSIX_MAPPABLE) != NULL;
723 : :
724 : : /* cleanup */
725 : 0 : free(info);
726 : :
727 : 0 : return ret;
728 : : }
729 : :
730 : : static int
731 : 0 : pci_vfio_fill_regions(struct rte_pci_device *dev, int vfio_dev_fd,
732 : : struct vfio_device_info *device_info)
733 : : {
734 : : struct rte_pci_device_internal *pdev = RTE_PCI_DEVICE_INTERNAL(dev);
735 : 0 : struct vfio_region_info *reg = NULL;
736 : : int nb_maps, i, ret;
737 : :
738 : 0 : nb_maps = RTE_MIN((int)device_info->num_regions,
739 : : VFIO_PCI_CONFIG_REGION_INDEX + 1);
740 : :
741 [ # # ]: 0 : for (i = 0; i < nb_maps; i++) {
742 : 0 : ret = pci_vfio_get_region_info(vfio_dev_fd, ®, i);
743 [ # # ]: 0 : if (ret < 0) {
744 : 0 : RTE_LOG(DEBUG, EAL, "%s cannot get device region info error %i (%s)\n",
745 : : dev->name, errno, strerror(errno));
746 : 0 : return -1;
747 : : }
748 : :
749 : 0 : pdev->region[i].size = reg->size;
750 : 0 : pdev->region[i].offset = reg->offset;
751 : :
752 : 0 : free(reg);
753 : : }
754 : :
755 : : return 0;
756 : : }
757 : :
758 : : static int
759 : 0 : pci_vfio_map_resource_primary(struct rte_pci_device *dev)
760 : : {
761 : : struct rte_pci_device_internal *pdev = RTE_PCI_DEVICE_INTERNAL(dev);
762 : 0 : struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
763 : 0 : struct vfio_region_info *reg = NULL;
764 : 0 : char pci_addr[PATH_MAX] = {0};
765 : : int vfio_dev_fd;
766 : : struct rte_pci_addr *loc = &dev->addr;
767 : : int i, j, ret;
768 : : struct mapped_pci_resource *vfio_res = NULL;
769 : : struct mapped_pci_res_list *vfio_res_list =
770 : 0 : RTE_TAILQ_CAST(rte_vfio_tailq.head, mapped_pci_res_list);
771 : :
772 : : struct pci_map *maps;
773 : :
774 [ # # ]: 0 : if (rte_intr_fd_set(dev->intr_handle, -1))
775 : : return -1;
776 : :
777 : : #ifdef HAVE_VFIO_DEV_REQ_INTERFACE
778 [ # # ]: 0 : if (rte_intr_fd_set(dev->vfio_req_intr_handle, -1))
779 : : return -1;
780 : : #endif
781 : :
782 : : /* store PCI address string */
783 : 0 : snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
784 : 0 : loc->domain, loc->bus, loc->devid, loc->function);
785 : :
786 : 0 : ret = rte_vfio_setup_device(rte_pci_get_sysfs_path(), pci_addr,
787 : : &vfio_dev_fd, &device_info);
788 [ # # ]: 0 : if (ret)
789 : : return ret;
790 : :
791 [ # # ]: 0 : if (rte_intr_dev_fd_set(dev->intr_handle, vfio_dev_fd))
792 : 0 : goto err_vfio_dev_fd;
793 : :
794 : : /* allocate vfio_res and get region info */
795 : 0 : vfio_res = rte_zmalloc("VFIO_RES", sizeof(*vfio_res), 0);
796 [ # # ]: 0 : if (vfio_res == NULL) {
797 : 0 : RTE_LOG(ERR, EAL,
798 : : "Cannot store VFIO mmap details\n");
799 : 0 : goto err_vfio_dev_fd;
800 : : }
801 : 0 : memcpy(&vfio_res->pci_addr, &dev->addr, sizeof(vfio_res->pci_addr));
802 : :
803 : : /* get number of registers (up to BAR5) */
804 : 0 : vfio_res->nb_maps = RTE_MIN((int) device_info.num_regions,
805 : : VFIO_PCI_BAR5_REGION_INDEX + 1);
806 : :
807 : : /* map BARs */
808 : 0 : maps = vfio_res->maps;
809 : :
810 : 0 : ret = pci_vfio_get_region_info(vfio_dev_fd, ®,
811 : : VFIO_PCI_CONFIG_REGION_INDEX);
812 [ # # ]: 0 : if (ret < 0) {
813 : 0 : RTE_LOG(ERR, EAL, "%s cannot get device region info error %i (%s)\n",
814 : : dev->name, errno, strerror(errno));
815 : 0 : goto err_vfio_res;
816 : : }
817 : 0 : pdev->region[VFIO_PCI_CONFIG_REGION_INDEX].size = reg->size;
818 : 0 : pdev->region[VFIO_PCI_CONFIG_REGION_INDEX].offset = reg->offset;
819 : 0 : free(reg);
820 : :
821 : 0 : vfio_res->msix_table.bar_index = -1;
822 : : /* get MSI-X BAR, if any (we have to know where it is because we can't
823 : : * easily mmap it when using VFIO)
824 : : */
825 : 0 : ret = pci_vfio_get_msix_bar(dev, &vfio_res->msix_table);
826 [ # # ]: 0 : if (ret < 0) {
827 : 0 : RTE_LOG(ERR, EAL, "%s cannot get MSI-X BAR number!\n",
828 : : pci_addr);
829 : 0 : goto err_vfio_res;
830 : : }
831 : : /* if we found our MSI-X BAR region, check if we can mmap it */
832 [ # # ]: 0 : if (vfio_res->msix_table.bar_index != -1) {
833 : 0 : int ret = pci_vfio_msix_is_mappable(vfio_dev_fd,
834 : : vfio_res->msix_table.bar_index);
835 [ # # ]: 0 : if (ret < 0) {
836 : 0 : RTE_LOG(ERR, EAL, "Couldn't check if MSI-X BAR is mappable\n");
837 : 0 : goto err_vfio_res;
838 [ # # ]: 0 : } else if (ret != 0) {
839 : : /* we can map it, so we don't care where it is */
840 : 0 : RTE_LOG(DEBUG, EAL, "VFIO reports MSI-X BAR as mappable\n");
841 : 0 : vfio_res->msix_table.bar_index = -1;
842 : : }
843 : : }
844 : :
845 [ # # ]: 0 : for (i = 0; i < vfio_res->nb_maps; i++) {
846 : : void *bar_addr;
847 : : struct vfio_info_cap_header *hdr;
848 : : struct vfio_region_info_cap_sparse_mmap *sparse;
849 : :
850 : 0 : ret = pci_vfio_get_region_info(vfio_dev_fd, ®, i);
851 [ # # ]: 0 : if (ret < 0) {
852 : 0 : RTE_LOG(ERR, EAL,
853 : : "%s cannot get device region info error "
854 : : "%i (%s)\n", pci_addr, errno, strerror(errno));
855 : 0 : goto err_map;
856 : : }
857 : :
858 : 0 : pdev->region[i].size = reg->size;
859 : 0 : pdev->region[i].offset = reg->offset;
860 : :
861 : : /* chk for io port region */
862 : 0 : ret = pci_vfio_is_ioport_bar(dev, vfio_dev_fd, i);
863 [ # # ]: 0 : if (ret < 0) {
864 : 0 : free(reg);
865 : 0 : goto err_map;
866 [ # # ]: 0 : } else if (ret) {
867 : 0 : RTE_LOG(INFO, EAL, "Ignore mapping IO port bar(%d)\n",
868 : : i);
869 : 0 : free(reg);
870 : 0 : continue;
871 : : }
872 : :
873 : : /* skip non-mmappable BARs */
874 [ # # ]: 0 : if ((reg->flags & VFIO_REGION_INFO_FLAG_MMAP) == 0) {
875 : 0 : free(reg);
876 : 0 : continue;
877 : : }
878 : :
879 : : /* try mapping somewhere close to the end of hugepages */
880 [ # # ]: 0 : if (pci_map_addr == NULL)
881 : 0 : pci_map_addr = pci_find_max_end_va();
882 : :
883 : 0 : bar_addr = pci_map_addr;
884 : 0 : pci_map_addr = RTE_PTR_ADD(bar_addr, (size_t) reg->size);
885 : :
886 : 0 : pci_map_addr = RTE_PTR_ALIGN(pci_map_addr,
887 : : sysconf(_SC_PAGE_SIZE));
888 : :
889 : 0 : maps[i].addr = bar_addr;
890 : 0 : maps[i].offset = reg->offset;
891 : 0 : maps[i].size = reg->size;
892 [ # # ]: 0 : maps[i].path = NULL; /* vfio doesn't have per-resource paths */
893 : :
894 : : hdr = pci_vfio_info_cap(reg, VFIO_REGION_INFO_CAP_SPARSE_MMAP);
895 : :
896 [ # # ]: 0 : if (hdr != NULL) {
897 : : sparse = container_of(hdr,
898 : : struct vfio_region_info_cap_sparse_mmap, header);
899 [ # # ]: 0 : if (sparse->nr_areas > 0) {
900 : 0 : maps[i].nr_areas = sparse->nr_areas;
901 : 0 : maps[i].areas = rte_zmalloc(NULL,
902 : 0 : sizeof(*maps[i].areas) * maps[i].nr_areas, 0);
903 [ # # ]: 0 : if (maps[i].areas == NULL) {
904 : 0 : RTE_LOG(ERR, EAL,
905 : : "Cannot alloc memory for sparse map areas\n");
906 : 0 : goto err_map;
907 : : }
908 : 0 : memcpy(maps[i].areas, sparse->areas,
909 : 0 : sizeof(*maps[i].areas) * maps[i].nr_areas);
910 : : }
911 : : }
912 : :
913 [ # # ]: 0 : if (maps[i].nr_areas > 0) {
914 : 0 : ret = pci_vfio_sparse_mmap_bar(vfio_dev_fd, vfio_res, i, 0);
915 [ # # ]: 0 : if (ret < 0) {
916 : 0 : RTE_LOG(ERR, EAL, "%s sparse mapping BAR%i failed: %s\n",
917 : : pci_addr, i, strerror(errno));
918 : 0 : free(reg);
919 : 0 : goto err_map;
920 : : }
921 : : } else {
922 : 0 : ret = pci_vfio_mmap_bar(vfio_dev_fd, vfio_res, i, 0);
923 [ # # ]: 0 : if (ret < 0) {
924 : 0 : RTE_LOG(ERR, EAL, "%s mapping BAR%i failed: %s\n",
925 : : pci_addr, i, strerror(errno));
926 : 0 : free(reg);
927 : 0 : goto err_map;
928 : : }
929 : : }
930 : :
931 : 0 : dev->mem_resource[i].addr = maps[i].addr;
932 : :
933 : 0 : free(reg);
934 : : }
935 : :
936 [ # # ]: 0 : if (pci_rte_vfio_setup_device(dev, vfio_dev_fd) < 0) {
937 : 0 : RTE_LOG(ERR, EAL, "%s setup device failed\n", pci_addr);
938 : 0 : goto err_map;
939 : : }
940 : :
941 : : #ifdef HAVE_VFIO_DEV_REQ_INTERFACE
942 [ # # ]: 0 : if (pci_vfio_enable_notifier(dev, vfio_dev_fd) != 0) {
943 : 0 : RTE_LOG(ERR, EAL, "Error setting up notifier!\n");
944 : 0 : goto err_map;
945 : : }
946 : :
947 : : #endif
948 : 0 : TAILQ_INSERT_TAIL(vfio_res_list, vfio_res, next);
949 : :
950 : 0 : return 0;
951 : 0 : err_map:
952 [ # # ]: 0 : for (j = 0; j < i; j++) {
953 [ # # ]: 0 : if (maps[j].addr)
954 : 0 : pci_unmap_resource(maps[j].addr, maps[j].size);
955 [ # # ]: 0 : if (maps[j].nr_areas > 0)
956 : 0 : rte_free(maps[j].areas);
957 : : }
958 : 0 : err_vfio_res:
959 : 0 : rte_free(vfio_res);
960 : 0 : err_vfio_dev_fd:
961 : 0 : rte_vfio_release_device(rte_pci_get_sysfs_path(),
962 : : pci_addr, vfio_dev_fd);
963 : 0 : return -1;
964 : : }
965 : :
966 : : static int
967 : 0 : pci_vfio_map_resource_secondary(struct rte_pci_device *dev)
968 : : {
969 : 0 : struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
970 : 0 : char pci_addr[PATH_MAX] = {0};
971 : : int vfio_dev_fd;
972 : : struct rte_pci_addr *loc = &dev->addr;
973 : : int i, j, ret;
974 : : struct mapped_pci_resource *vfio_res = NULL;
975 : : struct mapped_pci_res_list *vfio_res_list =
976 : 0 : RTE_TAILQ_CAST(rte_vfio_tailq.head, mapped_pci_res_list);
977 : :
978 : : struct pci_map *maps;
979 : :
980 [ # # ]: 0 : if (rte_intr_fd_set(dev->intr_handle, -1))
981 : : return -1;
982 : : #ifdef HAVE_VFIO_DEV_REQ_INTERFACE
983 [ # # ]: 0 : if (rte_intr_fd_set(dev->vfio_req_intr_handle, -1))
984 : : return -1;
985 : : #endif
986 : :
987 : : /* store PCI address string */
988 : 0 : snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
989 : 0 : loc->domain, loc->bus, loc->devid, loc->function);
990 : :
991 : : /* if we're in a secondary process, just find our tailq entry */
992 [ # # ]: 0 : TAILQ_FOREACH(vfio_res, vfio_res_list, next) {
993 [ # # ]: 0 : if (rte_pci_addr_cmp(&vfio_res->pci_addr,
994 : 0 : &dev->addr))
995 : : continue;
996 : : break;
997 : : }
998 : : /* if we haven't found our tailq entry, something's wrong */
999 [ # # ]: 0 : if (vfio_res == NULL) {
1000 : 0 : RTE_LOG(ERR, EAL, "%s cannot find TAILQ entry for PCI device!\n",
1001 : : pci_addr);
1002 : 0 : return -1;
1003 : : }
1004 : :
1005 : 0 : ret = rte_vfio_setup_device(rte_pci_get_sysfs_path(), pci_addr,
1006 : : &vfio_dev_fd, &device_info);
1007 [ # # ]: 0 : if (ret)
1008 : : return ret;
1009 : :
1010 : 0 : ret = pci_vfio_fill_regions(dev, vfio_dev_fd, &device_info);
1011 [ # # ]: 0 : if (ret)
1012 : : return ret;
1013 : :
1014 : : /* map BARs */
1015 : 0 : maps = vfio_res->maps;
1016 : :
1017 [ # # ]: 0 : for (i = 0; i < vfio_res->nb_maps; i++) {
1018 [ # # ]: 0 : if (maps[i].nr_areas > 0) {
1019 : 0 : ret = pci_vfio_sparse_mmap_bar(vfio_dev_fd, vfio_res, i, MAP_FIXED);
1020 [ # # ]: 0 : if (ret < 0) {
1021 : 0 : RTE_LOG(ERR, EAL, "%s sparse mapping BAR%i failed: %s\n",
1022 : : pci_addr, i, strerror(errno));
1023 : 0 : goto err_vfio_dev_fd;
1024 : : }
1025 : : } else {
1026 : 0 : ret = pci_vfio_mmap_bar(vfio_dev_fd, vfio_res, i, MAP_FIXED);
1027 [ # # ]: 0 : if (ret < 0) {
1028 : 0 : RTE_LOG(ERR, EAL, "%s mapping BAR%i failed: %s\n",
1029 : : pci_addr, i, strerror(errno));
1030 : 0 : goto err_vfio_dev_fd;
1031 : : }
1032 : : }
1033 : :
1034 : 0 : dev->mem_resource[i].addr = maps[i].addr;
1035 : : }
1036 : :
1037 : : /* we need save vfio_dev_fd, so it can be used during release */
1038 [ # # ]: 0 : if (rte_intr_dev_fd_set(dev->intr_handle, vfio_dev_fd))
1039 : 0 : goto err_vfio_dev_fd;
1040 : : #ifdef HAVE_VFIO_DEV_REQ_INTERFACE
1041 [ # # ]: 0 : if (rte_intr_dev_fd_set(dev->vfio_req_intr_handle, vfio_dev_fd))
1042 : 0 : goto err_vfio_dev_fd;
1043 : : #endif
1044 : :
1045 : : return 0;
1046 : 0 : err_vfio_dev_fd:
1047 [ # # ]: 0 : for (j = 0; j < i; j++) {
1048 [ # # ]: 0 : if (maps[j].addr)
1049 : 0 : pci_unmap_resource(maps[j].addr, maps[j].size);
1050 : : }
1051 : 0 : rte_vfio_release_device(rte_pci_get_sysfs_path(),
1052 : : pci_addr, vfio_dev_fd);
1053 : 0 : return -1;
1054 : : }
1055 : :
1056 : : /*
1057 : : * map the PCI resources of a PCI device in virtual memory (VFIO version).
1058 : : * primary and secondary processes follow almost exactly the same path
1059 : : */
1060 : : int
1061 : 0 : pci_vfio_map_resource(struct rte_pci_device *dev)
1062 : : {
1063 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY)
1064 : 0 : return pci_vfio_map_resource_primary(dev);
1065 : : else
1066 : 0 : return pci_vfio_map_resource_secondary(dev);
1067 : : }
1068 : :
1069 : : static struct mapped_pci_resource *
1070 : 0 : find_and_unmap_vfio_resource(struct mapped_pci_res_list *vfio_res_list,
1071 : : struct rte_pci_device *dev,
1072 : : const char *pci_addr)
1073 : : {
1074 : : struct mapped_pci_resource *vfio_res = NULL;
1075 : : struct pci_map *maps;
1076 : : int i;
1077 : :
1078 : : /* Get vfio_res */
1079 [ # # ]: 0 : TAILQ_FOREACH(vfio_res, vfio_res_list, next) {
1080 [ # # ]: 0 : if (rte_pci_addr_cmp(&vfio_res->pci_addr, &dev->addr))
1081 : : continue;
1082 : : break;
1083 : : }
1084 : :
1085 [ # # ]: 0 : if (vfio_res == NULL)
1086 : : return vfio_res;
1087 : :
1088 : 0 : RTE_LOG(INFO, EAL, "Releasing PCI mapped resource for %s\n",
1089 : : pci_addr);
1090 : :
1091 : 0 : maps = vfio_res->maps;
1092 [ # # ]: 0 : for (i = 0; i < vfio_res->nb_maps; i++) {
1093 : :
1094 : : /*
1095 : : * We do not need to be aware of MSI-X table BAR mappings as
1096 : : * when mapping. Just using current maps array is enough
1097 : : */
1098 [ # # ]: 0 : if (maps[i].addr) {
1099 : 0 : RTE_LOG(INFO, EAL, "Calling pci_unmap_resource for %s at %p\n",
1100 : : pci_addr, maps[i].addr);
1101 : 0 : pci_unmap_resource(maps[i].addr, maps[i].size);
1102 : : }
1103 : :
1104 [ # # ]: 0 : if (maps[i].nr_areas > 0)
1105 : 0 : rte_free(maps[i].areas);
1106 : : }
1107 : :
1108 : : return vfio_res;
1109 : : }
1110 : :
1111 : : static int
1112 : 0 : pci_vfio_unmap_resource_primary(struct rte_pci_device *dev)
1113 : : {
1114 : 0 : char pci_addr[PATH_MAX] = {0};
1115 : : struct rte_pci_addr *loc = &dev->addr;
1116 : : struct mapped_pci_resource *vfio_res = NULL;
1117 : : struct mapped_pci_res_list *vfio_res_list;
1118 : : int ret, vfio_dev_fd;
1119 : :
1120 : : /* store PCI address string */
1121 : 0 : snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
1122 : 0 : loc->domain, loc->bus, loc->devid, loc->function);
1123 : :
1124 : : #ifdef HAVE_VFIO_DEV_REQ_INTERFACE
1125 : 0 : ret = pci_vfio_disable_notifier(dev);
1126 [ # # ]: 0 : if (ret) {
1127 : 0 : RTE_LOG(ERR, EAL, "fail to disable req notifier.\n");
1128 : 0 : return -1;
1129 : : }
1130 : :
1131 : : #endif
1132 [ # # ]: 0 : if (rte_intr_fd_get(dev->intr_handle) < 0)
1133 : : return -1;
1134 : :
1135 [ # # ]: 0 : if (close(rte_intr_fd_get(dev->intr_handle)) < 0) {
1136 : 0 : RTE_LOG(INFO, EAL, "Error when closing eventfd file descriptor for %s\n",
1137 : : pci_addr);
1138 : 0 : return -1;
1139 : : }
1140 : :
1141 : 0 : vfio_dev_fd = rte_intr_dev_fd_get(dev->intr_handle);
1142 [ # # ]: 0 : if (vfio_dev_fd < 0)
1143 : : return -1;
1144 : :
1145 [ # # ]: 0 : if (rte_pci_set_bus_master(dev, false)) {
1146 : 0 : RTE_LOG(ERR, EAL, "%s cannot unset bus mastering for PCI device!\n",
1147 : : pci_addr);
1148 : 0 : return -1;
1149 : : }
1150 : :
1151 : 0 : ret = rte_vfio_release_device(rte_pci_get_sysfs_path(), pci_addr,
1152 : : vfio_dev_fd);
1153 [ # # ]: 0 : if (ret < 0) {
1154 : 0 : RTE_LOG(ERR, EAL, "Cannot release VFIO device\n");
1155 : 0 : return ret;
1156 : : }
1157 : :
1158 : 0 : vfio_res_list =
1159 : 0 : RTE_TAILQ_CAST(rte_vfio_tailq.head, mapped_pci_res_list);
1160 : 0 : vfio_res = find_and_unmap_vfio_resource(vfio_res_list, dev, pci_addr);
1161 : :
1162 : : /* if we haven't found our tailq entry, something's wrong */
1163 [ # # ]: 0 : if (vfio_res == NULL) {
1164 : 0 : RTE_LOG(ERR, EAL, "%s cannot find TAILQ entry for PCI device!\n",
1165 : : pci_addr);
1166 : 0 : return -1;
1167 : : }
1168 : :
1169 [ # # ]: 0 : TAILQ_REMOVE(vfio_res_list, vfio_res, next);
1170 : 0 : rte_free(vfio_res);
1171 : 0 : return 0;
1172 : : }
1173 : :
1174 : : static int
1175 : 0 : pci_vfio_unmap_resource_secondary(struct rte_pci_device *dev)
1176 : : {
1177 : 0 : char pci_addr[PATH_MAX] = {0};
1178 : : struct rte_pci_addr *loc = &dev->addr;
1179 : : struct mapped_pci_resource *vfio_res = NULL;
1180 : : struct mapped_pci_res_list *vfio_res_list;
1181 : : int ret, vfio_dev_fd;
1182 : :
1183 : : /* store PCI address string */
1184 : 0 : snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
1185 : 0 : loc->domain, loc->bus, loc->devid, loc->function);
1186 : :
1187 : 0 : vfio_dev_fd = rte_intr_dev_fd_get(dev->intr_handle);
1188 [ # # ]: 0 : if (vfio_dev_fd < 0)
1189 : : return -1;
1190 : :
1191 : 0 : ret = rte_vfio_release_device(rte_pci_get_sysfs_path(), pci_addr,
1192 : : vfio_dev_fd);
1193 [ # # ]: 0 : if (ret < 0) {
1194 : 0 : RTE_LOG(ERR, EAL, "Cannot release VFIO device\n");
1195 : 0 : return ret;
1196 : : }
1197 : :
1198 : 0 : vfio_res_list =
1199 : 0 : RTE_TAILQ_CAST(rte_vfio_tailq.head, mapped_pci_res_list);
1200 : 0 : vfio_res = find_and_unmap_vfio_resource(vfio_res_list, dev, pci_addr);
1201 : :
1202 : : /* if we haven't found our tailq entry, something's wrong */
1203 [ # # ]: 0 : if (vfio_res == NULL) {
1204 : 0 : RTE_LOG(ERR, EAL, "%s cannot find TAILQ entry for PCI device!\n",
1205 : : pci_addr);
1206 : 0 : return -1;
1207 : : }
1208 : :
1209 : : return 0;
1210 : : }
1211 : :
1212 : : int
1213 : 0 : pci_vfio_unmap_resource(struct rte_pci_device *dev)
1214 : : {
1215 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY)
1216 : 0 : return pci_vfio_unmap_resource_primary(dev);
1217 : : else
1218 : 0 : return pci_vfio_unmap_resource_secondary(dev);
1219 : : }
1220 : :
1221 : : int
1222 : 0 : pci_vfio_ioport_map(struct rte_pci_device *dev, int bar,
1223 : : struct rte_pci_ioport *p)
1224 : : {
1225 : : uint64_t size, offset;
1226 : :
1227 [ # # ]: 0 : if (bar < VFIO_PCI_BAR0_REGION_INDEX ||
1228 : : bar > VFIO_PCI_BAR5_REGION_INDEX) {
1229 : 0 : RTE_LOG(ERR, EAL, "invalid bar (%d)!\n", bar);
1230 : 0 : return -1;
1231 : : }
1232 : :
1233 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
1234 : 0 : struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
1235 : : char pci_addr[PATH_MAX];
1236 : : int vfio_dev_fd;
1237 : : struct rte_pci_addr *loc = &dev->addr;
1238 : :
1239 : : /* store PCI address string */
1240 : 0 : snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
1241 : 0 : loc->domain, loc->bus, loc->devid, loc->function);
1242 : :
1243 : 0 : vfio_dev_fd = rte_intr_dev_fd_get(dev->intr_handle);
1244 [ # # ]: 0 : if (vfio_dev_fd < 0) {
1245 : 0 : return -1;
1246 [ # # ]: 0 : } else if (vfio_dev_fd == 0) {
1247 [ # # ]: 0 : if (rte_vfio_get_device_info(rte_pci_get_sysfs_path(), pci_addr,
1248 : : &vfio_dev_fd, &device_info) != 0)
1249 : : return -1;
1250 : : /* save vfio_dev_fd so it can be used during release */
1251 [ # # ]: 0 : if (rte_intr_dev_fd_set(dev->intr_handle, vfio_dev_fd) != 0)
1252 : : return -1;
1253 : :
1254 [ # # ]: 0 : if (pci_vfio_fill_regions(dev, vfio_dev_fd, &device_info) != 0)
1255 : : return -1;
1256 : : }
1257 : : }
1258 : :
1259 : : if (pci_vfio_get_region(dev, bar, &size, &offset) != 0) {
1260 : 0 : RTE_LOG(ERR, EAL, "Cannot get offset of region %d.\n", bar);
1261 : 0 : return -1;
1262 : : }
1263 : :
1264 : 0 : p->dev = dev;
1265 : 0 : p->base = offset;
1266 : 0 : return 0;
1267 : : }
1268 : :
1269 : : void
1270 : 0 : pci_vfio_ioport_read(struct rte_pci_ioport *p,
1271 : : void *data, size_t len, off_t offset)
1272 : : {
1273 : 0 : const struct rte_intr_handle *intr_handle = p->dev->intr_handle;
1274 : 0 : int vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
1275 : :
1276 [ # # ]: 0 : if (vfio_dev_fd < 0)
1277 : : return;
1278 : :
1279 [ # # ]: 0 : if (pread64(vfio_dev_fd, data,
1280 [ # # ]: 0 : len, p->base + offset) <= 0)
1281 : 0 : RTE_LOG(ERR, EAL,
1282 : : "Can't read from PCI bar (%" PRIu64 ") : offset (%x)\n",
1283 : : VFIO_GET_REGION_IDX(p->base), (int)offset);
1284 : : }
1285 : :
1286 : : void
1287 : 0 : pci_vfio_ioport_write(struct rte_pci_ioport *p,
1288 : : const void *data, size_t len, off_t offset)
1289 : : {
1290 : 0 : const struct rte_intr_handle *intr_handle = p->dev->intr_handle;
1291 : 0 : int vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
1292 : :
1293 [ # # ]: 0 : if (vfio_dev_fd < 0)
1294 : : return;
1295 : :
1296 [ # # ]: 0 : if (pwrite64(vfio_dev_fd, data,
1297 : 0 : len, p->base + offset) <= 0)
1298 : 0 : RTE_LOG(ERR, EAL,
1299 : : "Can't write to PCI bar (%" PRIu64 ") : offset (%x)\n",
1300 : : VFIO_GET_REGION_IDX(p->base), (int)offset);
1301 : : }
1302 : :
1303 : : int
1304 : 0 : pci_vfio_ioport_unmap(struct rte_pci_ioport *p)
1305 : : {
1306 : : RTE_SET_USED(p);
1307 : 0 : return -1;
1308 : : }
1309 : :
1310 : : int
1311 : 0 : pci_vfio_mmio_read(const struct rte_pci_device *dev, int bar,
1312 : : void *buf, size_t len, off_t offs)
1313 : : {
1314 : : uint64_t size, offset;
1315 : : int fd;
1316 : :
1317 : 0 : fd = rte_intr_dev_fd_get(dev->intr_handle);
1318 [ # # ]: 0 : if (fd < 0)
1319 : : return -1;
1320 : :
1321 [ # # ]: 0 : if (pci_vfio_get_region(dev, bar, &size, &offset) != 0)
1322 : : return -1;
1323 : :
1324 [ # # ]: 0 : if ((uint64_t)len + offs > size)
1325 : : return -1;
1326 : :
1327 [ # # ]: 0 : return pread64(fd, buf, len, offset + offs);
1328 : : }
1329 : :
1330 : : int
1331 : 0 : pci_vfio_mmio_write(const struct rte_pci_device *dev, int bar,
1332 : : const void *buf, size_t len, off_t offs)
1333 : : {
1334 : : uint64_t size, offset;
1335 : : int fd;
1336 : :
1337 : 0 : fd = rte_intr_dev_fd_get(dev->intr_handle);
1338 [ # # ]: 0 : if (fd < 0)
1339 : : return -1;
1340 : :
1341 [ # # ]: 0 : if (pci_vfio_get_region(dev, bar, &size, &offset) != 0)
1342 : : return -1;
1343 : :
1344 [ # # ]: 0 : if ((uint64_t)len + offs > size)
1345 : : return -1;
1346 : :
1347 : 0 : return pwrite64(fd, buf, len, offset + offs);
1348 : : }
1349 : :
1350 : : int
1351 : 0 : pci_vfio_is_enabled(void)
1352 : : {
1353 : 0 : return rte_vfio_is_enabled("vfio_pci");
1354 : : }
1355 : : #endif
|