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