vfio: enable independently of PCI bus
[dpdk.git] / lib / librte_eal / linuxapp / eal / eal_pci_vfio.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <string.h>
35 #include <fcntl.h>
36 #include <linux/pci_regs.h>
37 #include <sys/eventfd.h>
38 #include <sys/socket.h>
39 #include <sys/ioctl.h>
40 #include <sys/mman.h>
41 #include <stdbool.h>
42
43 #include <rte_log.h>
44 #include <rte_pci.h>
45 #include <rte_eal_memconfig.h>
46 #include <rte_malloc.h>
47
48 #include "eal_filesystem.h"
49 #include "eal_pci_init.h"
50 #include "eal_vfio.h"
51 #include "eal_private.h"
52
53 /**
54  * @file
55  * PCI probing under linux (VFIO version)
56  *
57  * This code tries to determine if the PCI device is bound to VFIO driver,
58  * and initialize it (map BARs, set up interrupts) if that's the case.
59  *
60  * This file is only compiled if CONFIG_RTE_EAL_VFIO is set to "y".
61  */
62
63 #ifdef VFIO_PRESENT
64
65 #define PAGE_SIZE   (sysconf(_SC_PAGESIZE))
66 #define PAGE_MASK   (~(PAGE_SIZE - 1))
67
68 static struct rte_tailq_elem rte_vfio_tailq = {
69         .name = "VFIO_RESOURCE_LIST",
70 };
71 EAL_REGISTER_TAILQ(rte_vfio_tailq)
72
73 int
74 pci_vfio_read_config(const struct rte_intr_handle *intr_handle,
75                     void *buf, size_t len, off_t offs)
76 {
77         return pread64(intr_handle->vfio_dev_fd, buf, len,
78                VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) + offs);
79 }
80
81 int
82 pci_vfio_write_config(const struct rte_intr_handle *intr_handle,
83                     const void *buf, size_t len, off_t offs)
84 {
85         return pwrite64(intr_handle->vfio_dev_fd, buf, len,
86                VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) + offs);
87 }
88
89 /* get PCI BAR number where MSI-X interrupts are */
90 static int
91 pci_vfio_get_msix_bar(int fd, struct pci_msix_table *msix_table)
92 {
93         int ret;
94         uint32_t reg;
95         uint16_t flags;
96         uint8_t cap_id, cap_offset;
97
98         /* read PCI capability pointer from config space */
99         ret = pread64(fd, &reg, sizeof(reg),
100                         VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) +
101                         PCI_CAPABILITY_LIST);
102         if (ret != sizeof(reg)) {
103                 RTE_LOG(ERR, EAL, "Cannot read capability pointer from PCI "
104                                 "config space!\n");
105                 return -1;
106         }
107
108         /* we need first byte */
109         cap_offset = reg & 0xFF;
110
111         while (cap_offset) {
112
113                 /* read PCI capability ID */
114                 ret = pread64(fd, &reg, sizeof(reg),
115                                 VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) +
116                                 cap_offset);
117                 if (ret != sizeof(reg)) {
118                         RTE_LOG(ERR, EAL, "Cannot read capability ID from PCI "
119                                         "config space!\n");
120                         return -1;
121                 }
122
123                 /* we need first byte */
124                 cap_id = reg & 0xFF;
125
126                 /* if we haven't reached MSI-X, check next capability */
127                 if (cap_id != PCI_CAP_ID_MSIX) {
128                         ret = pread64(fd, &reg, sizeof(reg),
129                                         VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) +
130                                         cap_offset);
131                         if (ret != sizeof(reg)) {
132                                 RTE_LOG(ERR, EAL, "Cannot read capability pointer from PCI "
133                                                 "config space!\n");
134                                 return -1;
135                         }
136
137                         /* we need second byte */
138                         cap_offset = (reg & 0xFF00) >> 8;
139
140                         continue;
141                 }
142                 /* else, read table offset */
143                 else {
144                         /* table offset resides in the next 4 bytes */
145                         ret = pread64(fd, &reg, sizeof(reg),
146                                         VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) +
147                                         cap_offset + 4);
148                         if (ret != sizeof(reg)) {
149                                 RTE_LOG(ERR, EAL, "Cannot read table offset from PCI config "
150                                                 "space!\n");
151                                 return -1;
152                         }
153
154                         ret = pread64(fd, &flags, sizeof(flags),
155                                         VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) +
156                                         cap_offset + 2);
157                         if (ret != sizeof(flags)) {
158                                 RTE_LOG(ERR, EAL, "Cannot read table flags from PCI config "
159                                                 "space!\n");
160                                 return -1;
161                         }
162
163                         msix_table->bar_index = reg & RTE_PCI_MSIX_TABLE_BIR;
164                         msix_table->offset = reg & RTE_PCI_MSIX_TABLE_OFFSET;
165                         msix_table->size =
166                                 16 * (1 + (flags & RTE_PCI_MSIX_FLAGS_QSIZE));
167
168                         return 0;
169                 }
170         }
171         return 0;
172 }
173
174 /* set PCI bus mastering */
175 static int
176 pci_vfio_set_bus_master(int dev_fd, bool op)
177 {
178         uint16_t reg;
179         int ret;
180
181         ret = pread64(dev_fd, &reg, sizeof(reg),
182                         VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) +
183                         PCI_COMMAND);
184         if (ret != sizeof(reg)) {
185                 RTE_LOG(ERR, EAL, "Cannot read command from PCI config space!\n");
186                 return -1;
187         }
188
189         if (op)
190                 /* set the master bit */
191                 reg |= PCI_COMMAND_MASTER;
192         else
193                 reg &= ~(PCI_COMMAND_MASTER);
194
195         ret = pwrite64(dev_fd, &reg, sizeof(reg),
196                         VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) +
197                         PCI_COMMAND);
198
199         if (ret != sizeof(reg)) {
200                 RTE_LOG(ERR, EAL, "Cannot write command to PCI config space!\n");
201                 return -1;
202         }
203
204         return 0;
205 }
206
207 /* set up interrupt support (but not enable interrupts) */
208 static int
209 pci_vfio_setup_interrupts(struct rte_pci_device *dev, int vfio_dev_fd)
210 {
211         int i, ret, intr_idx;
212
213         /* default to invalid index */
214         intr_idx = VFIO_PCI_NUM_IRQS;
215
216         /* get interrupt type from internal config (MSI-X by default, can be
217          * overridden from the command line
218          */
219         switch (internal_config.vfio_intr_mode) {
220         case RTE_INTR_MODE_MSIX:
221                 intr_idx = VFIO_PCI_MSIX_IRQ_INDEX;
222                 break;
223         case RTE_INTR_MODE_MSI:
224                 intr_idx = VFIO_PCI_MSI_IRQ_INDEX;
225                 break;
226         case RTE_INTR_MODE_LEGACY:
227                 intr_idx = VFIO_PCI_INTX_IRQ_INDEX;
228                 break;
229         /* don't do anything if we want to automatically determine interrupt type */
230         case RTE_INTR_MODE_NONE:
231                 break;
232         default:
233                 RTE_LOG(ERR, EAL, "  unknown default interrupt type!\n");
234                 return -1;
235         }
236
237         /* start from MSI-X interrupt type */
238         for (i = VFIO_PCI_MSIX_IRQ_INDEX; i >= 0; i--) {
239                 struct vfio_irq_info irq = { .argsz = sizeof(irq) };
240                 int fd = -1;
241
242                 /* skip interrupt modes we don't want */
243                 if (internal_config.vfio_intr_mode != RTE_INTR_MODE_NONE &&
244                                 i != intr_idx)
245                         continue;
246
247                 irq.index = i;
248
249                 ret = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_IRQ_INFO, &irq);
250                 if (ret < 0) {
251                         RTE_LOG(ERR, EAL, "  cannot get IRQ info, "
252                                         "error %i (%s)\n", errno, strerror(errno));
253                         return -1;
254                 }
255
256                 /* if this vector cannot be used with eventfd, fail if we explicitly
257                  * specified interrupt type, otherwise continue */
258                 if ((irq.flags & VFIO_IRQ_INFO_EVENTFD) == 0) {
259                         if (internal_config.vfio_intr_mode != RTE_INTR_MODE_NONE) {
260                                 RTE_LOG(ERR, EAL,
261                                                 "  interrupt vector does not support eventfd!\n");
262                                 return -1;
263                         } else
264                                 continue;
265                 }
266
267                 /* set up an eventfd for interrupts */
268                 fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
269                 if (fd < 0) {
270                         RTE_LOG(ERR, EAL, "  cannot set up eventfd, "
271                                         "error %i (%s)\n", errno, strerror(errno));
272                         return -1;
273                 }
274
275                 dev->intr_handle.fd = fd;
276                 dev->intr_handle.vfio_dev_fd = vfio_dev_fd;
277
278                 switch (i) {
279                 case VFIO_PCI_MSIX_IRQ_INDEX:
280                         internal_config.vfio_intr_mode = RTE_INTR_MODE_MSIX;
281                         dev->intr_handle.type = RTE_INTR_HANDLE_VFIO_MSIX;
282                         break;
283                 case VFIO_PCI_MSI_IRQ_INDEX:
284                         internal_config.vfio_intr_mode = RTE_INTR_MODE_MSI;
285                         dev->intr_handle.type = RTE_INTR_HANDLE_VFIO_MSI;
286                         break;
287                 case VFIO_PCI_INTX_IRQ_INDEX:
288                         internal_config.vfio_intr_mode = RTE_INTR_MODE_LEGACY;
289                         dev->intr_handle.type = RTE_INTR_HANDLE_VFIO_LEGACY;
290                         break;
291                 default:
292                         RTE_LOG(ERR, EAL, "  unknown interrupt type!\n");
293                         return -1;
294                 }
295
296                 return 0;
297         }
298
299         /* if we're here, we haven't found a suitable interrupt vector */
300         return -1;
301 }
302
303 static int
304 pci_vfio_is_ioport_bar(int vfio_dev_fd, int bar_index)
305 {
306         uint32_t ioport_bar;
307         int ret;
308
309         ret = pread64(vfio_dev_fd, &ioport_bar, sizeof(ioport_bar),
310                           VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX)
311                           + PCI_BASE_ADDRESS_0 + bar_index*4);
312         if (ret != sizeof(ioport_bar)) {
313                 RTE_LOG(ERR, EAL, "Cannot read command (%x) from config space!\n",
314                         PCI_BASE_ADDRESS_0 + bar_index*4);
315                 return -1;
316         }
317
318         return (ioport_bar & PCI_BASE_ADDRESS_SPACE_IO) != 0;
319 }
320
321 static int
322 pci_vfio_setup_device(struct rte_pci_device *dev, int vfio_dev_fd)
323 {
324         if (pci_vfio_setup_interrupts(dev, vfio_dev_fd) != 0) {
325                 RTE_LOG(ERR, EAL, "Error setting up interrupts!\n");
326                 return -1;
327         }
328
329         /* set bus mastering for the device */
330         if (pci_vfio_set_bus_master(vfio_dev_fd, true)) {
331                 RTE_LOG(ERR, EAL, "Cannot set up bus mastering!\n");
332                 return -1;
333         }
334
335         /* Reset the device */
336         ioctl(vfio_dev_fd, VFIO_DEVICE_RESET);
337
338         return 0;
339 }
340
341 static int
342 pci_vfio_mmap_bar(int vfio_dev_fd, struct mapped_pci_resource *vfio_res,
343                 int bar_index, int additional_flags)
344 {
345         struct memreg {
346                 unsigned long offset, size;
347         } memreg[2] = {};
348         void *bar_addr;
349         struct pci_msix_table *msix_table = &vfio_res->msix_table;
350         struct pci_map *bar = &vfio_res->maps[bar_index];
351
352         if (bar->size == 0)
353                 /* Skip this BAR */
354                 return 0;
355
356         if (msix_table->bar_index == bar_index) {
357                 /*
358                  * VFIO will not let us map the MSI-X table,
359                  * but we can map around it.
360                  */
361                 uint32_t table_start = msix_table->offset;
362                 uint32_t table_end = table_start + msix_table->size;
363                 table_end = (table_end + ~PAGE_MASK) & PAGE_MASK;
364                 table_start &= PAGE_MASK;
365
366                 if (table_start == 0 && table_end >= bar->size) {
367                         /* Cannot map this BAR */
368                         RTE_LOG(DEBUG, EAL, "Skipping BAR%d\n", bar_index);
369                         bar->size = 0;
370                         bar->addr = 0;
371                         return 0;
372                 }
373
374                 memreg[0].offset = bar->offset;
375                 memreg[0].size = table_start;
376                 memreg[1].offset = bar->offset + table_end;
377                 memreg[1].size = bar->size - table_end;
378
379                 RTE_LOG(DEBUG, EAL,
380                         "Trying to map BAR%d that contains the MSI-X "
381                         "table. Trying offsets: "
382                         "0x%04lx:0x%04lx, 0x%04lx:0x%04lx\n", bar_index,
383                         memreg[0].offset, memreg[0].size,
384                         memreg[1].offset, memreg[1].size);
385         } else {
386                 memreg[0].offset = bar->offset;
387                 memreg[0].size = bar->size;
388         }
389
390         /* reserve the address using an inaccessible mapping */
391         bar_addr = mmap(bar->addr, bar->size, 0, MAP_PRIVATE |
392                         MAP_ANONYMOUS | additional_flags, -1, 0);
393         if (bar_addr != MAP_FAILED) {
394                 void *map_addr = NULL;
395                 if (memreg[0].size) {
396                         /* actual map of first part */
397                         map_addr = pci_map_resource(bar_addr, vfio_dev_fd,
398                                                         memreg[0].offset,
399                                                         memreg[0].size,
400                                                         MAP_FIXED);
401                 }
402
403                 /* if there's a second part, try to map it */
404                 if (map_addr != MAP_FAILED
405                         && memreg[1].offset && memreg[1].size) {
406                         void *second_addr = RTE_PTR_ADD(bar_addr,
407                                                         memreg[1].offset -
408                                                         (uintptr_t)bar->offset);
409                         map_addr = pci_map_resource(second_addr,
410                                                         vfio_dev_fd,
411                                                         memreg[1].offset,
412                                                         memreg[1].size,
413                                                         MAP_FIXED);
414                 }
415
416                 if (map_addr == MAP_FAILED || !map_addr) {
417                         munmap(bar_addr, bar->size);
418                         bar_addr = MAP_FAILED;
419                         RTE_LOG(ERR, EAL, "Failed to map pci BAR%d\n",
420                                         bar_index);
421                         return -1;
422                 }
423         } else {
424                 RTE_LOG(ERR, EAL,
425                                 "Failed to create inaccessible mapping for BAR%d\n",
426                                 bar_index);
427                 return -1;
428         }
429
430         bar->addr = bar_addr;
431         return 0;
432 }
433
434 static int
435 pci_vfio_map_resource_primary(struct rte_pci_device *dev)
436 {
437         struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
438         char pci_addr[PATH_MAX] = {0};
439         int vfio_dev_fd;
440         struct rte_pci_addr *loc = &dev->addr;
441         int i, ret;
442         struct mapped_pci_resource *vfio_res = NULL;
443         struct mapped_pci_res_list *vfio_res_list =
444                 RTE_TAILQ_CAST(rte_vfio_tailq.head, mapped_pci_res_list);
445
446         struct pci_map *maps;
447
448         dev->intr_handle.fd = -1;
449         dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
450
451         /* store PCI address string */
452         snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
453                         loc->domain, loc->bus, loc->devid, loc->function);
454
455         ret = vfio_setup_device(pci_get_sysfs_path(), pci_addr,
456                                         &vfio_dev_fd, &device_info);
457         if (ret)
458                 return ret;
459
460         /* allocate vfio_res and get region info */
461         vfio_res = rte_zmalloc("VFIO_RES", sizeof(*vfio_res), 0);
462         if (vfio_res == NULL) {
463                 RTE_LOG(ERR, EAL,
464                         "%s(): cannot store uio mmap details\n", __func__);
465                 goto err_vfio_dev_fd;
466         }
467         memcpy(&vfio_res->pci_addr, &dev->addr, sizeof(vfio_res->pci_addr));
468
469         /* get number of registers (up to BAR5) */
470         vfio_res->nb_maps = RTE_MIN((int) device_info.num_regions,
471                         VFIO_PCI_BAR5_REGION_INDEX + 1);
472
473         /* map BARs */
474         maps = vfio_res->maps;
475
476         vfio_res->msix_table.bar_index = -1;
477         /* get MSI-X BAR, if any (we have to know where it is because we can't
478          * easily mmap it when using VFIO)
479          */
480         ret = pci_vfio_get_msix_bar(vfio_dev_fd, &vfio_res->msix_table);
481         if (ret < 0) {
482                 RTE_LOG(ERR, EAL, "  %s cannot get MSI-X BAR number!\n",
483                                 pci_addr);
484                 goto err_vfio_dev_fd;
485         }
486
487         for (i = 0; i < (int) vfio_res->nb_maps; i++) {
488                 struct vfio_region_info reg = { .argsz = sizeof(reg) };
489                 void *bar_addr;
490
491                 reg.index = i;
492
493                 ret = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_REGION_INFO, &reg);
494                 if (ret) {
495                         RTE_LOG(ERR, EAL, "  %s cannot get device region info "
496                                         "error %i (%s)\n", pci_addr, errno, strerror(errno));
497                         goto err_vfio_res;
498                 }
499
500                 /* chk for io port region */
501                 ret = pci_vfio_is_ioport_bar(vfio_dev_fd, i);
502                 if (ret < 0)
503                         goto err_vfio_res;
504                 else if (ret) {
505                         RTE_LOG(INFO, EAL, "Ignore mapping IO port bar(%d)\n",
506                                         i);
507                         continue;
508                 }
509
510                 /* skip non-mmapable BARs */
511                 if ((reg.flags & VFIO_REGION_INFO_FLAG_MMAP) == 0)
512                         continue;
513
514                 /* try mapping somewhere close to the end of hugepages */
515                 if (pci_map_addr == NULL)
516                         pci_map_addr = pci_find_max_end_va();
517
518                 bar_addr = pci_map_addr;
519                 pci_map_addr = RTE_PTR_ADD(bar_addr, (size_t) reg.size);
520
521                 maps[i].addr = bar_addr;
522                 maps[i].offset = reg.offset;
523                 maps[i].size = reg.size;
524                 maps[i].path = NULL; /* vfio doesn't have per-resource paths */
525
526                 ret = pci_vfio_mmap_bar(vfio_dev_fd, vfio_res, i, 0);
527                 if (ret < 0) {
528                         RTE_LOG(ERR, EAL, "  %s mapping BAR%i failed: %s\n",
529                                         pci_addr, i, strerror(errno));
530                         goto err_vfio_res;
531                 }
532
533                 dev->mem_resource[i].addr = maps[i].addr;
534         }
535
536         if (pci_vfio_setup_device(dev, vfio_dev_fd) < 0) {
537                 RTE_LOG(ERR, EAL, "  %s setup device failed\n", pci_addr);
538                 goto err_vfio_res;
539         }
540
541         TAILQ_INSERT_TAIL(vfio_res_list, vfio_res, next);
542
543         return 0;
544 err_vfio_res:
545         rte_free(vfio_res);
546 err_vfio_dev_fd:
547         close(vfio_dev_fd);
548         return -1;
549 }
550
551 static int
552 pci_vfio_map_resource_secondary(struct rte_pci_device *dev)
553 {
554         struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
555         char pci_addr[PATH_MAX] = {0};
556         int vfio_dev_fd;
557         struct rte_pci_addr *loc = &dev->addr;
558         int i, ret;
559         struct mapped_pci_resource *vfio_res = NULL;
560         struct mapped_pci_res_list *vfio_res_list =
561                 RTE_TAILQ_CAST(rte_vfio_tailq.head, mapped_pci_res_list);
562
563         struct pci_map *maps;
564
565         dev->intr_handle.fd = -1;
566         dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
567
568         /* store PCI address string */
569         snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
570                         loc->domain, loc->bus, loc->devid, loc->function);
571
572         ret = vfio_setup_device(pci_get_sysfs_path(), pci_addr,
573                                         &vfio_dev_fd, &device_info);
574         if (ret)
575                 return ret;
576
577         /* if we're in a secondary process, just find our tailq entry */
578         TAILQ_FOREACH(vfio_res, vfio_res_list, next) {
579                 if (rte_eal_compare_pci_addr(&vfio_res->pci_addr,
580                                                  &dev->addr))
581                         continue;
582                 break;
583         }
584         /* if we haven't found our tailq entry, something's wrong */
585         if (vfio_res == NULL) {
586                 RTE_LOG(ERR, EAL, "  %s cannot find TAILQ entry for PCI device!\n",
587                                 pci_addr);
588                 goto err_vfio_dev_fd;
589         }
590
591         /* map BARs */
592         maps = vfio_res->maps;
593
594         for (i = 0; i < (int) vfio_res->nb_maps; i++) {
595                 ret = pci_vfio_mmap_bar(vfio_dev_fd, vfio_res, i, MAP_FIXED);
596                 if (ret < 0) {
597                         RTE_LOG(ERR, EAL, "  %s mapping BAR%i failed: %s\n",
598                                         pci_addr, i, strerror(errno));
599                         goto err_vfio_dev_fd;
600                 }
601
602                 dev->mem_resource[i].addr = maps[i].addr;
603         }
604
605         return 0;
606 err_vfio_dev_fd:
607         close(vfio_dev_fd);
608         return -1;
609 }
610
611 /*
612  * map the PCI resources of a PCI device in virtual memory (VFIO version).
613  * primary and secondary processes follow almost exactly the same path
614  */
615 int
616 pci_vfio_map_resource(struct rte_pci_device *dev)
617 {
618         if (internal_config.process_type == RTE_PROC_PRIMARY)
619                 return pci_vfio_map_resource_primary(dev);
620         else
621                 return pci_vfio_map_resource_secondary(dev);
622 }
623
624 int
625 pci_vfio_unmap_resource(struct rte_pci_device *dev)
626 {
627         char pci_addr[PATH_MAX] = {0};
628         struct rte_pci_addr *loc = &dev->addr;
629         int i, ret;
630         struct mapped_pci_resource *vfio_res = NULL;
631         struct mapped_pci_res_list *vfio_res_list;
632
633         struct pci_map *maps;
634
635         /* store PCI address string */
636         snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
637                         loc->domain, loc->bus, loc->devid, loc->function);
638
639
640         if (close(dev->intr_handle.fd) < 0) {
641                 RTE_LOG(INFO, EAL, "Error when closing eventfd file descriptor for %s\n",
642                         pci_addr);
643                 return -1;
644         }
645
646         if (pci_vfio_set_bus_master(dev->intr_handle.vfio_dev_fd, false)) {
647                 RTE_LOG(ERR, EAL, "  %s cannot unset bus mastering for PCI device!\n",
648                                 pci_addr);
649                 return -1;
650         }
651
652         ret = vfio_release_device(pci_get_sysfs_path(), pci_addr,
653                                   dev->intr_handle.vfio_dev_fd);
654         if (ret < 0) {
655                 RTE_LOG(ERR, EAL,
656                         "%s(): cannot release device\n", __func__);
657                 return ret;
658         }
659
660         vfio_res_list = RTE_TAILQ_CAST(rte_vfio_tailq.head, mapped_pci_res_list);
661         /* Get vfio_res */
662         TAILQ_FOREACH(vfio_res, vfio_res_list, next) {
663                 if (memcmp(&vfio_res->pci_addr, &dev->addr, sizeof(dev->addr)))
664                         continue;
665                 break;
666         }
667         /* if we haven't found our tailq entry, something's wrong */
668         if (vfio_res == NULL) {
669                 RTE_LOG(ERR, EAL, "  %s cannot find TAILQ entry for PCI device!\n",
670                                 pci_addr);
671                 return -1;
672         }
673
674         /* unmap BARs */
675         maps = vfio_res->maps;
676
677         RTE_LOG(INFO, EAL, "Releasing pci mapped resource for %s\n",
678                 pci_addr);
679         for (i = 0; i < (int) vfio_res->nb_maps; i++) {
680
681                 /*
682                  * We do not need to be aware of MSI-X table BAR mappings as
683                  * when mapping. Just using current maps array is enough
684                  */
685                 if (maps[i].addr) {
686                         RTE_LOG(INFO, EAL, "Calling pci_unmap_resource for %s at %p\n",
687                                 pci_addr, maps[i].addr);
688                         pci_unmap_resource(maps[i].addr, maps[i].size);
689                 }
690         }
691
692         TAILQ_REMOVE(vfio_res_list, vfio_res, next);
693
694         return 0;
695 }
696
697 int
698 pci_vfio_ioport_map(struct rte_pci_device *dev, int bar,
699                     struct rte_pci_ioport *p)
700 {
701         if (bar < VFIO_PCI_BAR0_REGION_INDEX ||
702             bar > VFIO_PCI_BAR5_REGION_INDEX) {
703                 RTE_LOG(ERR, EAL, "invalid bar (%d)!\n", bar);
704                 return -1;
705         }
706
707         p->dev = dev;
708         p->base = VFIO_GET_REGION_ADDR(bar);
709         return 0;
710 }
711
712 void
713 pci_vfio_ioport_read(struct rte_pci_ioport *p,
714                      void *data, size_t len, off_t offset)
715 {
716         const struct rte_intr_handle *intr_handle = &p->dev->intr_handle;
717
718         if (pread64(intr_handle->vfio_dev_fd, data,
719                     len, p->base + offset) <= 0)
720                 RTE_LOG(ERR, EAL,
721                         "Can't read from PCI bar (%" PRIu64 ") : offset (%x)\n",
722                         VFIO_GET_REGION_IDX(p->base), (int)offset);
723 }
724
725 void
726 pci_vfio_ioport_write(struct rte_pci_ioport *p,
727                       const void *data, size_t len, off_t offset)
728 {
729         const struct rte_intr_handle *intr_handle = &p->dev->intr_handle;
730
731         if (pwrite64(intr_handle->vfio_dev_fd, data,
732                      len, p->base + offset) <= 0)
733                 RTE_LOG(ERR, EAL,
734                         "Can't write to PCI bar (%" PRIu64 ") : offset (%x)\n",
735                         VFIO_GET_REGION_IDX(p->base), (int)offset);
736 }
737
738 int
739 pci_vfio_ioport_unmap(struct rte_pci_ioport *p)
740 {
741         RTE_SET_USED(p);
742         return -1;
743 }
744
745 int
746 pci_vfio_is_enabled(void)
747 {
748         return vfio_is_enabled("vfio_pci");
749 }
750 #endif