1418026caSFam Zheng /* 2418026caSFam Zheng * VFIO utility 3418026caSFam Zheng * 4418026caSFam Zheng * Copyright 2016 - 2018 Red Hat, Inc. 5418026caSFam Zheng * 6418026caSFam Zheng * Authors: 7418026caSFam Zheng * Fam Zheng <famz@redhat.com> 8418026caSFam Zheng * 9418026caSFam Zheng * This work is licensed under the terms of the GNU GPL, version 2 or later. 10418026caSFam Zheng * See the COPYING file in the top-level directory. 11418026caSFam Zheng */ 12418026caSFam Zheng 13418026caSFam Zheng #include "qemu/osdep.h" 14418026caSFam Zheng #include <sys/ioctl.h> 15418026caSFam Zheng #include <linux/vfio.h> 16418026caSFam Zheng #include "qapi/error.h" 17418026caSFam Zheng #include "exec/ramlist.h" 18418026caSFam Zheng #include "exec/cpu-common.h" 19418026caSFam Zheng #include "trace.h" 20418026caSFam Zheng #include "qemu/error-report.h" 21418026caSFam Zheng #include "standard-headers/linux/pci_regs.h" 22418026caSFam Zheng #include "qemu/event_notifier.h" 23418026caSFam Zheng #include "qemu/vfio-helpers.h" 246e8a355dSDaniel Brodsky #include "qemu/lockable.h" 25418026caSFam Zheng #include "trace.h" 26418026caSFam Zheng 27418026caSFam Zheng #define QEMU_VFIO_DEBUG 0 28418026caSFam Zheng 29418026caSFam Zheng #define QEMU_VFIO_IOVA_MIN 0x10000ULL 30418026caSFam Zheng /* XXX: Once VFIO exposes the iova bit width in the IOMMU capability interface, 31418026caSFam Zheng * we can use a runtime limit; alternatively it's also possible to do platform 32418026caSFam Zheng * specific detection by reading sysfs entries. Until then, 39 is a safe bet. 33418026caSFam Zheng **/ 34418026caSFam Zheng #define QEMU_VFIO_IOVA_MAX (1ULL << 39) 35418026caSFam Zheng 36418026caSFam Zheng typedef struct { 37418026caSFam Zheng /* Page aligned addr. */ 38418026caSFam Zheng void *host; 39418026caSFam Zheng size_t size; 40418026caSFam Zheng uint64_t iova; 41418026caSFam Zheng } IOVAMapping; 42418026caSFam Zheng 434487d420SEric Auger struct IOVARange { 444487d420SEric Auger uint64_t start; 454487d420SEric Auger uint64_t end; 464487d420SEric Auger }; 474487d420SEric Auger 48418026caSFam Zheng struct QEMUVFIOState { 49418026caSFam Zheng QemuMutex lock; 50418026caSFam Zheng 51418026caSFam Zheng /* These fields are protected by BQL */ 52418026caSFam Zheng int container; 53418026caSFam Zheng int group; 54418026caSFam Zheng int device; 55418026caSFam Zheng RAMBlockNotifier ram_notifier; 56418026caSFam Zheng struct vfio_region_info config_region_info, bar_region_info[6]; 574487d420SEric Auger struct IOVARange *usable_iova_ranges; 584487d420SEric Auger uint8_t nb_iova_ranges; 59418026caSFam Zheng 60418026caSFam Zheng /* These fields are protected by @lock */ 61418026caSFam Zheng /* VFIO's IO virtual address space is managed by splitting into a few 62418026caSFam Zheng * sections: 63418026caSFam Zheng * 64418026caSFam Zheng * --------------- <= 0 65418026caSFam Zheng * |xxxxxxxxxxxxx| 66418026caSFam Zheng * |-------------| <= QEMU_VFIO_IOVA_MIN 67418026caSFam Zheng * | | 68418026caSFam Zheng * | Fixed | 69418026caSFam Zheng * | | 70418026caSFam Zheng * |-------------| <= low_water_mark 71418026caSFam Zheng * | | 72418026caSFam Zheng * | Free | 73418026caSFam Zheng * | | 74418026caSFam Zheng * |-------------| <= high_water_mark 75418026caSFam Zheng * | | 76418026caSFam Zheng * | Temp | 77418026caSFam Zheng * | | 78418026caSFam Zheng * |-------------| <= QEMU_VFIO_IOVA_MAX 79418026caSFam Zheng * |xxxxxxxxxxxxx| 80418026caSFam Zheng * |xxxxxxxxxxxxx| 81418026caSFam Zheng * --------------- 82418026caSFam Zheng * 83418026caSFam Zheng * - Addresses lower than QEMU_VFIO_IOVA_MIN are reserved as invalid; 84418026caSFam Zheng * 85418026caSFam Zheng * - Fixed mappings of HVAs are assigned "low" IOVAs in the range of 86418026caSFam Zheng * [QEMU_VFIO_IOVA_MIN, low_water_mark). Once allocated they will not be 87418026caSFam Zheng * reclaimed - low_water_mark never shrinks; 88418026caSFam Zheng * 89418026caSFam Zheng * - IOVAs in range [low_water_mark, high_water_mark) are free; 90418026caSFam Zheng * 91418026caSFam Zheng * - IOVAs in range [high_water_mark, QEMU_VFIO_IOVA_MAX) are volatile 92418026caSFam Zheng * mappings. At each qemu_vfio_dma_reset_temporary() call, the whole area 93418026caSFam Zheng * is recycled. The caller should make sure I/O's depending on these 94418026caSFam Zheng * mappings are completed before calling. 95418026caSFam Zheng **/ 96418026caSFam Zheng uint64_t low_water_mark; 97418026caSFam Zheng uint64_t high_water_mark; 98418026caSFam Zheng IOVAMapping *mappings; 99418026caSFam Zheng int nr_mappings; 100418026caSFam Zheng }; 101418026caSFam Zheng 102418026caSFam Zheng /** 103418026caSFam Zheng * Find group file by PCI device address as specified @device, and return the 104418026caSFam Zheng * path. The returned string is owned by caller and should be g_free'ed later. 105418026caSFam Zheng */ 106418026caSFam Zheng static char *sysfs_find_group_file(const char *device, Error **errp) 107418026caSFam Zheng { 108418026caSFam Zheng char *sysfs_link; 109418026caSFam Zheng char *sysfs_group; 110418026caSFam Zheng char *p; 111418026caSFam Zheng char *path = NULL; 112418026caSFam Zheng 113418026caSFam Zheng sysfs_link = g_strdup_printf("/sys/bus/pci/devices/%s/iommu_group", device); 11478d8c99eSPaolo Bonzini sysfs_group = g_malloc0(PATH_MAX); 115418026caSFam Zheng if (readlink(sysfs_link, sysfs_group, PATH_MAX - 1) == -1) { 116418026caSFam Zheng error_setg_errno(errp, errno, "Failed to find iommu group sysfs path"); 117418026caSFam Zheng goto out; 118418026caSFam Zheng } 119418026caSFam Zheng p = strrchr(sysfs_group, '/'); 120418026caSFam Zheng if (!p) { 121418026caSFam Zheng error_setg(errp, "Failed to find iommu group number"); 122418026caSFam Zheng goto out; 123418026caSFam Zheng } 124418026caSFam Zheng 125418026caSFam Zheng path = g_strdup_printf("/dev/vfio/%s", p + 1); 126418026caSFam Zheng out: 127418026caSFam Zheng g_free(sysfs_link); 128418026caSFam Zheng g_free(sysfs_group); 129418026caSFam Zheng return path; 130418026caSFam Zheng } 131418026caSFam Zheng 132418026caSFam Zheng static inline void assert_bar_index_valid(QEMUVFIOState *s, int index) 133418026caSFam Zheng { 134418026caSFam Zheng assert(index >= 0 && index < ARRAY_SIZE(s->bar_region_info)); 135418026caSFam Zheng } 136418026caSFam Zheng 137418026caSFam Zheng static int qemu_vfio_pci_init_bar(QEMUVFIOState *s, int index, Error **errp) 138418026caSFam Zheng { 139df058222SPhilippe Mathieu-Daudé g_autofree char *barname = NULL; 140418026caSFam Zheng assert_bar_index_valid(s, index); 141418026caSFam Zheng s->bar_region_info[index] = (struct vfio_region_info) { 142418026caSFam Zheng .index = VFIO_PCI_BAR0_REGION_INDEX + index, 143418026caSFam Zheng .argsz = sizeof(struct vfio_region_info), 144418026caSFam Zheng }; 145418026caSFam Zheng if (ioctl(s->device, VFIO_DEVICE_GET_REGION_INFO, &s->bar_region_info[index])) { 146418026caSFam Zheng error_setg_errno(errp, errno, "Failed to get BAR region info"); 147418026caSFam Zheng return -errno; 148418026caSFam Zheng } 149df058222SPhilippe Mathieu-Daudé barname = g_strdup_printf("bar[%d]", index); 150df058222SPhilippe Mathieu-Daudé trace_qemu_vfio_region_info(barname, s->bar_region_info[index].offset, 151df058222SPhilippe Mathieu-Daudé s->bar_region_info[index].size, 152df058222SPhilippe Mathieu-Daudé s->bar_region_info[index].cap_offset); 153418026caSFam Zheng 154418026caSFam Zheng return 0; 155418026caSFam Zheng } 156418026caSFam Zheng 157418026caSFam Zheng /** 158418026caSFam Zheng * Map a PCI bar area. 159418026caSFam Zheng */ 160418026caSFam Zheng void *qemu_vfio_pci_map_bar(QEMUVFIOState *s, int index, 161b02c01a5SPhilippe Mathieu-Daudé uint64_t offset, uint64_t size, int prot, 162418026caSFam Zheng Error **errp) 163418026caSFam Zheng { 164418026caSFam Zheng void *p; 165418026caSFam Zheng assert_bar_index_valid(s, index); 166418026caSFam Zheng p = mmap(NULL, MIN(size, s->bar_region_info[index].size - offset), 167b02c01a5SPhilippe Mathieu-Daudé prot, MAP_SHARED, 168418026caSFam Zheng s->device, s->bar_region_info[index].offset + offset); 1692817fbceSPhilippe Mathieu-Daudé trace_qemu_vfio_pci_map_bar(index, s->bar_region_info[index].offset , 1702817fbceSPhilippe Mathieu-Daudé size, offset, p); 171418026caSFam Zheng if (p == MAP_FAILED) { 172418026caSFam Zheng error_setg_errno(errp, errno, "Failed to map BAR region"); 173418026caSFam Zheng p = NULL; 174418026caSFam Zheng } 175418026caSFam Zheng return p; 176418026caSFam Zheng } 177418026caSFam Zheng 178418026caSFam Zheng /** 179418026caSFam Zheng * Unmap a PCI bar area. 180418026caSFam Zheng */ 181418026caSFam Zheng void qemu_vfio_pci_unmap_bar(QEMUVFIOState *s, int index, void *bar, 182418026caSFam Zheng uint64_t offset, uint64_t size) 183418026caSFam Zheng { 184418026caSFam Zheng if (bar) { 185418026caSFam Zheng munmap(bar, MIN(size, s->bar_region_info[index].size - offset)); 186418026caSFam Zheng } 187418026caSFam Zheng } 188418026caSFam Zheng 189418026caSFam Zheng /** 190a6da793aSPhilippe Mathieu-Daudé * Initialize device IRQ with @irq_type and register an event notifier. 191418026caSFam Zheng */ 192418026caSFam Zheng int qemu_vfio_pci_init_irq(QEMUVFIOState *s, EventNotifier *e, 193418026caSFam Zheng int irq_type, Error **errp) 194418026caSFam Zheng { 195418026caSFam Zheng int r; 196418026caSFam Zheng struct vfio_irq_set *irq_set; 197418026caSFam Zheng size_t irq_set_size; 198418026caSFam Zheng struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info) }; 199418026caSFam Zheng 200418026caSFam Zheng irq_info.index = irq_type; 201418026caSFam Zheng if (ioctl(s->device, VFIO_DEVICE_GET_IRQ_INFO, &irq_info)) { 202418026caSFam Zheng error_setg_errno(errp, errno, "Failed to get device interrupt info"); 203418026caSFam Zheng return -errno; 204418026caSFam Zheng } 205418026caSFam Zheng if (!(irq_info.flags & VFIO_IRQ_INFO_EVENTFD)) { 206418026caSFam Zheng error_setg(errp, "Device interrupt doesn't support eventfd"); 207418026caSFam Zheng return -EINVAL; 208418026caSFam Zheng } 209418026caSFam Zheng 210418026caSFam Zheng irq_set_size = sizeof(*irq_set) + sizeof(int); 211418026caSFam Zheng irq_set = g_malloc0(irq_set_size); 212418026caSFam Zheng 213418026caSFam Zheng /* Get to a known IRQ state */ 214418026caSFam Zheng *irq_set = (struct vfio_irq_set) { 215418026caSFam Zheng .argsz = irq_set_size, 216418026caSFam Zheng .flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER, 217418026caSFam Zheng .index = irq_info.index, 218418026caSFam Zheng .start = 0, 219418026caSFam Zheng .count = 1, 220418026caSFam Zheng }; 221418026caSFam Zheng 222418026caSFam Zheng *(int *)&irq_set->data = event_notifier_get_fd(e); 223418026caSFam Zheng r = ioctl(s->device, VFIO_DEVICE_SET_IRQS, irq_set); 224418026caSFam Zheng g_free(irq_set); 225418026caSFam Zheng if (r) { 226418026caSFam Zheng error_setg_errno(errp, errno, "Failed to setup device interrupt"); 227418026caSFam Zheng return -errno; 228418026caSFam Zheng } 229418026caSFam Zheng return 0; 230418026caSFam Zheng } 231418026caSFam Zheng 232418026caSFam Zheng static int qemu_vfio_pci_read_config(QEMUVFIOState *s, void *buf, 233418026caSFam Zheng int size, int ofs) 234418026caSFam Zheng { 235418026caSFam Zheng int ret; 236418026caSFam Zheng 2373d87c2d9SPhilippe Mathieu-Daudé trace_qemu_vfio_pci_read_config(buf, ofs, size, 2383d87c2d9SPhilippe Mathieu-Daudé s->config_region_info.offset, 2393d87c2d9SPhilippe Mathieu-Daudé s->config_region_info.size); 2403d87c2d9SPhilippe Mathieu-Daudé assert(QEMU_IS_ALIGNED(s->config_region_info.offset + ofs, size)); 241418026caSFam Zheng do { 242418026caSFam Zheng ret = pread(s->device, buf, size, s->config_region_info.offset + ofs); 243418026caSFam Zheng } while (ret == -1 && errno == EINTR); 244418026caSFam Zheng return ret == size ? 0 : -errno; 245418026caSFam Zheng } 246418026caSFam Zheng 247418026caSFam Zheng static int qemu_vfio_pci_write_config(QEMUVFIOState *s, void *buf, int size, int ofs) 248418026caSFam Zheng { 249418026caSFam Zheng int ret; 250418026caSFam Zheng 2513d87c2d9SPhilippe Mathieu-Daudé trace_qemu_vfio_pci_write_config(buf, ofs, size, 2523d87c2d9SPhilippe Mathieu-Daudé s->config_region_info.offset, 2533d87c2d9SPhilippe Mathieu-Daudé s->config_region_info.size); 2543d87c2d9SPhilippe Mathieu-Daudé assert(QEMU_IS_ALIGNED(s->config_region_info.offset + ofs, size)); 255418026caSFam Zheng do { 256418026caSFam Zheng ret = pwrite(s->device, buf, size, s->config_region_info.offset + ofs); 257418026caSFam Zheng } while (ret == -1 && errno == EINTR); 258418026caSFam Zheng return ret == size ? 0 : -errno; 259418026caSFam Zheng } 260418026caSFam Zheng 2614487d420SEric Auger static void collect_usable_iova_ranges(QEMUVFIOState *s, void *buf) 2624487d420SEric Auger { 2634487d420SEric Auger struct vfio_iommu_type1_info *info = (struct vfio_iommu_type1_info *)buf; 2644487d420SEric Auger struct vfio_info_cap_header *cap = (void *)buf + info->cap_offset; 2654487d420SEric Auger struct vfio_iommu_type1_info_cap_iova_range *cap_iova_range; 2664487d420SEric Auger int i; 2674487d420SEric Auger 2684487d420SEric Auger while (cap->id != VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE) { 2694487d420SEric Auger if (!cap->next) { 2704487d420SEric Auger return; 2714487d420SEric Auger } 2724487d420SEric Auger cap = (struct vfio_info_cap_header *)(buf + cap->next); 2734487d420SEric Auger } 2744487d420SEric Auger 2754487d420SEric Auger cap_iova_range = (struct vfio_iommu_type1_info_cap_iova_range *)cap; 2764487d420SEric Auger 2774487d420SEric Auger s->nb_iova_ranges = cap_iova_range->nr_iovas; 2784487d420SEric Auger if (s->nb_iova_ranges > 1) { 2794487d420SEric Auger s->usable_iova_ranges = 2804487d420SEric Auger g_realloc(s->usable_iova_ranges, 2814487d420SEric Auger s->nb_iova_ranges * sizeof(struct IOVARange)); 2824487d420SEric Auger } 2834487d420SEric Auger 2844487d420SEric Auger for (i = 0; i < s->nb_iova_ranges; i++) { 2854487d420SEric Auger s->usable_iova_ranges[i].start = cap_iova_range->iova_ranges[i].start; 2864487d420SEric Auger s->usable_iova_ranges[i].end = cap_iova_range->iova_ranges[i].end; 2874487d420SEric Auger } 2884487d420SEric Auger } 2894487d420SEric Auger 290418026caSFam Zheng static int qemu_vfio_init_pci(QEMUVFIOState *s, const char *device, 291418026caSFam Zheng Error **errp) 292418026caSFam Zheng { 293418026caSFam Zheng int ret; 294418026caSFam Zheng int i; 295418026caSFam Zheng uint16_t pci_cmd; 296418026caSFam Zheng struct vfio_group_status group_status = { .argsz = sizeof(group_status) }; 2974487d420SEric Auger struct vfio_iommu_type1_info *iommu_info = NULL; 2984487d420SEric Auger size_t iommu_info_size = sizeof(*iommu_info); 299418026caSFam Zheng struct vfio_device_info device_info = { .argsz = sizeof(device_info) }; 300418026caSFam Zheng char *group_file = NULL; 301418026caSFam Zheng 3024487d420SEric Auger s->usable_iova_ranges = NULL; 3034487d420SEric Auger 304418026caSFam Zheng /* Create a new container */ 305418026caSFam Zheng s->container = open("/dev/vfio/vfio", O_RDWR); 306418026caSFam Zheng 307418026caSFam Zheng if (s->container == -1) { 308418026caSFam Zheng error_setg_errno(errp, errno, "Failed to open /dev/vfio/vfio"); 309418026caSFam Zheng return -errno; 310418026caSFam Zheng } 311418026caSFam Zheng if (ioctl(s->container, VFIO_GET_API_VERSION) != VFIO_API_VERSION) { 312418026caSFam Zheng error_setg(errp, "Invalid VFIO version"); 313418026caSFam Zheng ret = -EINVAL; 314418026caSFam Zheng goto fail_container; 315418026caSFam Zheng } 316418026caSFam Zheng 317418026caSFam Zheng if (!ioctl(s->container, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU)) { 318a4bc212aSPhilippe Mathieu-Daudé error_setg_errno(errp, errno, "VFIO IOMMU Type1 is not supported"); 319418026caSFam Zheng ret = -EINVAL; 320418026caSFam Zheng goto fail_container; 321418026caSFam Zheng } 322418026caSFam Zheng 323418026caSFam Zheng /* Open the group */ 324418026caSFam Zheng group_file = sysfs_find_group_file(device, errp); 325418026caSFam Zheng if (!group_file) { 326418026caSFam Zheng ret = -EINVAL; 327418026caSFam Zheng goto fail_container; 328418026caSFam Zheng } 329418026caSFam Zheng 330418026caSFam Zheng s->group = open(group_file, O_RDWR); 331418026caSFam Zheng if (s->group == -1) { 332418026caSFam Zheng error_setg_errno(errp, errno, "Failed to open VFIO group file: %s", 333418026caSFam Zheng group_file); 334418026caSFam Zheng g_free(group_file); 335418026caSFam Zheng ret = -errno; 336418026caSFam Zheng goto fail_container; 337418026caSFam Zheng } 338418026caSFam Zheng g_free(group_file); 339418026caSFam Zheng 340418026caSFam Zheng /* Test the group is viable and available */ 341418026caSFam Zheng if (ioctl(s->group, VFIO_GROUP_GET_STATUS, &group_status)) { 342418026caSFam Zheng error_setg_errno(errp, errno, "Failed to get VFIO group status"); 343418026caSFam Zheng ret = -errno; 344418026caSFam Zheng goto fail; 345418026caSFam Zheng } 346418026caSFam Zheng 347418026caSFam Zheng if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE)) { 348418026caSFam Zheng error_setg(errp, "VFIO group is not viable"); 349418026caSFam Zheng ret = -EINVAL; 350418026caSFam Zheng goto fail; 351418026caSFam Zheng } 352418026caSFam Zheng 353418026caSFam Zheng /* Add the group to the container */ 354418026caSFam Zheng if (ioctl(s->group, VFIO_GROUP_SET_CONTAINER, &s->container)) { 355418026caSFam Zheng error_setg_errno(errp, errno, "Failed to add group to VFIO container"); 356418026caSFam Zheng ret = -errno; 357418026caSFam Zheng goto fail; 358418026caSFam Zheng } 359418026caSFam Zheng 360418026caSFam Zheng /* Enable the IOMMU model we want */ 361418026caSFam Zheng if (ioctl(s->container, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU)) { 362418026caSFam Zheng error_setg_errno(errp, errno, "Failed to set VFIO IOMMU type"); 363418026caSFam Zheng ret = -errno; 364418026caSFam Zheng goto fail; 365418026caSFam Zheng } 366418026caSFam Zheng 3674487d420SEric Auger iommu_info = g_malloc0(iommu_info_size); 3684487d420SEric Auger iommu_info->argsz = iommu_info_size; 3694487d420SEric Auger 370418026caSFam Zheng /* Get additional IOMMU info */ 3714487d420SEric Auger if (ioctl(s->container, VFIO_IOMMU_GET_INFO, iommu_info)) { 372418026caSFam Zheng error_setg_errno(errp, errno, "Failed to get IOMMU info"); 373418026caSFam Zheng ret = -errno; 374418026caSFam Zheng goto fail; 375418026caSFam Zheng } 376418026caSFam Zheng 3774487d420SEric Auger /* 3784487d420SEric Auger * if the kernel does not report usable IOVA regions, choose 3794487d420SEric Auger * the legacy [QEMU_VFIO_IOVA_MIN, QEMU_VFIO_IOVA_MAX -1] region 3804487d420SEric Auger */ 3814487d420SEric Auger s->nb_iova_ranges = 1; 3824487d420SEric Auger s->usable_iova_ranges = g_new0(struct IOVARange, 1); 3834487d420SEric Auger s->usable_iova_ranges[0].start = QEMU_VFIO_IOVA_MIN; 3844487d420SEric Auger s->usable_iova_ranges[0].end = QEMU_VFIO_IOVA_MAX - 1; 3854487d420SEric Auger 3864487d420SEric Auger if (iommu_info->argsz > iommu_info_size) { 3874487d420SEric Auger iommu_info_size = iommu_info->argsz; 3884487d420SEric Auger iommu_info = g_realloc(iommu_info, iommu_info_size); 3894487d420SEric Auger if (ioctl(s->container, VFIO_IOMMU_GET_INFO, iommu_info)) { 3904487d420SEric Auger ret = -errno; 3914487d420SEric Auger goto fail; 3924487d420SEric Auger } 3934487d420SEric Auger collect_usable_iova_ranges(s, iommu_info); 3944487d420SEric Auger } 3954487d420SEric Auger 396418026caSFam Zheng s->device = ioctl(s->group, VFIO_GROUP_GET_DEVICE_FD, device); 397418026caSFam Zheng 398418026caSFam Zheng if (s->device < 0) { 399418026caSFam Zheng error_setg_errno(errp, errno, "Failed to get device fd"); 400418026caSFam Zheng ret = -errno; 401418026caSFam Zheng goto fail; 402418026caSFam Zheng } 403418026caSFam Zheng 404418026caSFam Zheng /* Test and setup the device */ 405418026caSFam Zheng if (ioctl(s->device, VFIO_DEVICE_GET_INFO, &device_info)) { 406418026caSFam Zheng error_setg_errno(errp, errno, "Failed to get device info"); 407418026caSFam Zheng ret = -errno; 408418026caSFam Zheng goto fail; 409418026caSFam Zheng } 410418026caSFam Zheng 411418026caSFam Zheng if (device_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX) { 412418026caSFam Zheng error_setg(errp, "Invalid device regions"); 413418026caSFam Zheng ret = -EINVAL; 414418026caSFam Zheng goto fail; 415418026caSFam Zheng } 416418026caSFam Zheng 417418026caSFam Zheng s->config_region_info = (struct vfio_region_info) { 418418026caSFam Zheng .index = VFIO_PCI_CONFIG_REGION_INDEX, 419418026caSFam Zheng .argsz = sizeof(struct vfio_region_info), 420418026caSFam Zheng }; 421418026caSFam Zheng if (ioctl(s->device, VFIO_DEVICE_GET_REGION_INFO, &s->config_region_info)) { 422418026caSFam Zheng error_setg_errno(errp, errno, "Failed to get config region info"); 423418026caSFam Zheng ret = -errno; 424418026caSFam Zheng goto fail; 425418026caSFam Zheng } 426df058222SPhilippe Mathieu-Daudé trace_qemu_vfio_region_info("config", s->config_region_info.offset, 427df058222SPhilippe Mathieu-Daudé s->config_region_info.size, 428df058222SPhilippe Mathieu-Daudé s->config_region_info.cap_offset); 429418026caSFam Zheng 4309e722ebcSLi Qiang for (i = 0; i < ARRAY_SIZE(s->bar_region_info); i++) { 431418026caSFam Zheng ret = qemu_vfio_pci_init_bar(s, i, errp); 432418026caSFam Zheng if (ret) { 433418026caSFam Zheng goto fail; 434418026caSFam Zheng } 435418026caSFam Zheng } 436418026caSFam Zheng 437418026caSFam Zheng /* Enable bus master */ 438418026caSFam Zheng ret = qemu_vfio_pci_read_config(s, &pci_cmd, sizeof(pci_cmd), PCI_COMMAND); 439418026caSFam Zheng if (ret) { 440418026caSFam Zheng goto fail; 441418026caSFam Zheng } 442418026caSFam Zheng pci_cmd |= PCI_COMMAND_MASTER; 443418026caSFam Zheng ret = qemu_vfio_pci_write_config(s, &pci_cmd, sizeof(pci_cmd), PCI_COMMAND); 444418026caSFam Zheng if (ret) { 445418026caSFam Zheng goto fail; 446418026caSFam Zheng } 4474487d420SEric Auger g_free(iommu_info); 448418026caSFam Zheng return 0; 449418026caSFam Zheng fail: 4504487d420SEric Auger g_free(s->usable_iova_ranges); 4514487d420SEric Auger s->usable_iova_ranges = NULL; 4524487d420SEric Auger s->nb_iova_ranges = 0; 4534487d420SEric Auger g_free(iommu_info); 454418026caSFam Zheng close(s->group); 455418026caSFam Zheng fail_container: 456418026caSFam Zheng close(s->container); 457418026caSFam Zheng return ret; 458418026caSFam Zheng } 459418026caSFam Zheng 460418026caSFam Zheng static void qemu_vfio_ram_block_added(RAMBlockNotifier *n, 461418026caSFam Zheng void *host, size_t size) 462418026caSFam Zheng { 463418026caSFam Zheng QEMUVFIOState *s = container_of(n, QEMUVFIOState, ram_notifier); 464418026caSFam Zheng trace_qemu_vfio_ram_block_added(s, host, size); 465418026caSFam Zheng qemu_vfio_dma_map(s, host, size, false, NULL); 466418026caSFam Zheng } 467418026caSFam Zheng 468418026caSFam Zheng static void qemu_vfio_ram_block_removed(RAMBlockNotifier *n, 469418026caSFam Zheng void *host, size_t size) 470418026caSFam Zheng { 471418026caSFam Zheng QEMUVFIOState *s = container_of(n, QEMUVFIOState, ram_notifier); 472418026caSFam Zheng if (host) { 473418026caSFam Zheng trace_qemu_vfio_ram_block_removed(s, host, size); 474418026caSFam Zheng qemu_vfio_dma_unmap(s, host); 475418026caSFam Zheng } 476418026caSFam Zheng } 477418026caSFam Zheng 478754cb9c0SYury Kotov static int qemu_vfio_init_ramblock(RAMBlock *rb, void *opaque) 479418026caSFam Zheng { 480754cb9c0SYury Kotov void *host_addr = qemu_ram_get_host_addr(rb); 481754cb9c0SYury Kotov ram_addr_t length = qemu_ram_get_used_length(rb); 482418026caSFam Zheng int ret; 483418026caSFam Zheng QEMUVFIOState *s = opaque; 484418026caSFam Zheng 485418026caSFam Zheng if (!host_addr) { 486418026caSFam Zheng return 0; 487418026caSFam Zheng } 488418026caSFam Zheng ret = qemu_vfio_dma_map(s, host_addr, length, false, NULL); 489418026caSFam Zheng if (ret) { 490418026caSFam Zheng fprintf(stderr, "qemu_vfio_init_ramblock: failed %p %" PRId64 "\n", 491418026caSFam Zheng host_addr, (uint64_t)length); 492418026caSFam Zheng } 493418026caSFam Zheng return 0; 494418026caSFam Zheng } 495418026caSFam Zheng 496418026caSFam Zheng static void qemu_vfio_open_common(QEMUVFIOState *s) 497418026caSFam Zheng { 498549b50a3SMarkus Armbruster qemu_mutex_init(&s->lock); 499418026caSFam Zheng s->ram_notifier.ram_block_added = qemu_vfio_ram_block_added; 500418026caSFam Zheng s->ram_notifier.ram_block_removed = qemu_vfio_ram_block_removed; 501418026caSFam Zheng ram_block_notifier_add(&s->ram_notifier); 502418026caSFam Zheng s->low_water_mark = QEMU_VFIO_IOVA_MIN; 503418026caSFam Zheng s->high_water_mark = QEMU_VFIO_IOVA_MAX; 504418026caSFam Zheng qemu_ram_foreach_block(qemu_vfio_init_ramblock, s); 505418026caSFam Zheng } 506418026caSFam Zheng 507418026caSFam Zheng /** 508418026caSFam Zheng * Open a PCI device, e.g. "0000:00:01.0". 509418026caSFam Zheng */ 510418026caSFam Zheng QEMUVFIOState *qemu_vfio_open_pci(const char *device, Error **errp) 511418026caSFam Zheng { 512418026caSFam Zheng int r; 513418026caSFam Zheng QEMUVFIOState *s = g_new0(QEMUVFIOState, 1); 514418026caSFam Zheng 515418026caSFam Zheng r = qemu_vfio_init_pci(s, device, errp); 516418026caSFam Zheng if (r) { 517418026caSFam Zheng g_free(s); 518418026caSFam Zheng return NULL; 519418026caSFam Zheng } 520418026caSFam Zheng qemu_vfio_open_common(s); 521418026caSFam Zheng return s; 522418026caSFam Zheng } 523418026caSFam Zheng 524418026caSFam Zheng static void qemu_vfio_dump_mappings(QEMUVFIOState *s) 525418026caSFam Zheng { 526*f6b8104dSPhilippe Mathieu-Daudé for (int i = 0; i < s->nr_mappings; ++i) { 527*f6b8104dSPhilippe Mathieu-Daudé trace_qemu_vfio_dump_mapping(s->mappings[i].host, 528*f6b8104dSPhilippe Mathieu-Daudé s->mappings[i].iova, 529*f6b8104dSPhilippe Mathieu-Daudé s->mappings[i].size); 530418026caSFam Zheng } 531418026caSFam Zheng } 532418026caSFam Zheng 533418026caSFam Zheng /** 534418026caSFam Zheng * Find the mapping entry that contains [host, host + size) and set @index to 535418026caSFam Zheng * the position. If no entry contains it, @index is the position _after_ which 536418026caSFam Zheng * to insert the new mapping. IOW, it is the index of the largest element that 537418026caSFam Zheng * is smaller than @host, or -1 if no entry is. 538418026caSFam Zheng */ 539418026caSFam Zheng static IOVAMapping *qemu_vfio_find_mapping(QEMUVFIOState *s, void *host, 540418026caSFam Zheng int *index) 541418026caSFam Zheng { 542418026caSFam Zheng IOVAMapping *p = s->mappings; 543418026caSFam Zheng IOVAMapping *q = p ? p + s->nr_mappings - 1 : NULL; 544418026caSFam Zheng IOVAMapping *mid; 545418026caSFam Zheng trace_qemu_vfio_find_mapping(s, host); 546418026caSFam Zheng if (!p) { 547418026caSFam Zheng *index = -1; 548418026caSFam Zheng return NULL; 549418026caSFam Zheng } 550418026caSFam Zheng while (true) { 551418026caSFam Zheng mid = p + (q - p) / 2; 552418026caSFam Zheng if (mid == p) { 553418026caSFam Zheng break; 554418026caSFam Zheng } 555418026caSFam Zheng if (mid->host > host) { 556418026caSFam Zheng q = mid; 557418026caSFam Zheng } else if (mid->host < host) { 558418026caSFam Zheng p = mid; 559418026caSFam Zheng } else { 560418026caSFam Zheng break; 561418026caSFam Zheng } 562418026caSFam Zheng } 563418026caSFam Zheng if (mid->host > host) { 564418026caSFam Zheng mid--; 565418026caSFam Zheng } else if (mid < &s->mappings[s->nr_mappings - 1] 566418026caSFam Zheng && (mid + 1)->host <= host) { 567418026caSFam Zheng mid++; 568418026caSFam Zheng } 569418026caSFam Zheng *index = mid - &s->mappings[0]; 570418026caSFam Zheng if (mid >= &s->mappings[0] && 571418026caSFam Zheng mid->host <= host && mid->host + mid->size > host) { 572418026caSFam Zheng assert(mid < &s->mappings[s->nr_mappings]); 573418026caSFam Zheng return mid; 574418026caSFam Zheng } 575418026caSFam Zheng /* At this point *index + 1 is the right position to insert the new 576418026caSFam Zheng * mapping.*/ 577418026caSFam Zheng return NULL; 578418026caSFam Zheng } 579418026caSFam Zheng 580418026caSFam Zheng /** 581a6da793aSPhilippe Mathieu-Daudé * Allocate IOVA and create a new mapping record and insert it in @s. 582418026caSFam Zheng */ 583418026caSFam Zheng static IOVAMapping *qemu_vfio_add_mapping(QEMUVFIOState *s, 584418026caSFam Zheng void *host, size_t size, 585418026caSFam Zheng int index, uint64_t iova) 586418026caSFam Zheng { 587418026caSFam Zheng int shift; 588418026caSFam Zheng IOVAMapping m = {.host = host, .size = size, .iova = iova}; 589418026caSFam Zheng IOVAMapping *insert; 590418026caSFam Zheng 591038adc2fSWei Yang assert(QEMU_IS_ALIGNED(size, qemu_real_host_page_size)); 592038adc2fSWei Yang assert(QEMU_IS_ALIGNED(s->low_water_mark, qemu_real_host_page_size)); 593038adc2fSWei Yang assert(QEMU_IS_ALIGNED(s->high_water_mark, qemu_real_host_page_size)); 594418026caSFam Zheng trace_qemu_vfio_new_mapping(s, host, size, index, iova); 595418026caSFam Zheng 596418026caSFam Zheng assert(index >= 0); 597418026caSFam Zheng s->nr_mappings++; 598d29eb678SOlaf Hering s->mappings = g_renew(IOVAMapping, s->mappings, s->nr_mappings); 599418026caSFam Zheng insert = &s->mappings[index]; 600418026caSFam Zheng shift = s->nr_mappings - index - 1; 601418026caSFam Zheng if (shift) { 602418026caSFam Zheng memmove(insert + 1, insert, shift * sizeof(s->mappings[0])); 603418026caSFam Zheng } 604418026caSFam Zheng *insert = m; 605418026caSFam Zheng return insert; 606418026caSFam Zheng } 607418026caSFam Zheng 608418026caSFam Zheng /* Do the DMA mapping with VFIO. */ 609418026caSFam Zheng static int qemu_vfio_do_mapping(QEMUVFIOState *s, void *host, size_t size, 610418026caSFam Zheng uint64_t iova) 611418026caSFam Zheng { 612418026caSFam Zheng struct vfio_iommu_type1_dma_map dma_map = { 613418026caSFam Zheng .argsz = sizeof(dma_map), 614418026caSFam Zheng .flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE, 615418026caSFam Zheng .iova = iova, 616418026caSFam Zheng .vaddr = (uintptr_t)host, 617418026caSFam Zheng .size = size, 618418026caSFam Zheng }; 6194c946b22SPhilippe Mathieu-Daudé trace_qemu_vfio_do_mapping(s, host, iova, size); 620418026caSFam Zheng 621418026caSFam Zheng if (ioctl(s->container, VFIO_IOMMU_MAP_DMA, &dma_map)) { 622b09d51c9SMichal Privoznik error_report("VFIO_MAP_DMA failed: %s", strerror(errno)); 623418026caSFam Zheng return -errno; 624418026caSFam Zheng } 625418026caSFam Zheng return 0; 626418026caSFam Zheng } 627418026caSFam Zheng 628418026caSFam Zheng /** 629418026caSFam Zheng * Undo the DMA mapping from @s with VFIO, and remove from mapping list. 630418026caSFam Zheng */ 631418026caSFam Zheng static void qemu_vfio_undo_mapping(QEMUVFIOState *s, IOVAMapping *mapping, 632418026caSFam Zheng Error **errp) 633418026caSFam Zheng { 634418026caSFam Zheng int index; 635418026caSFam Zheng struct vfio_iommu_type1_dma_unmap unmap = { 636418026caSFam Zheng .argsz = sizeof(unmap), 637418026caSFam Zheng .flags = 0, 638418026caSFam Zheng .iova = mapping->iova, 639418026caSFam Zheng .size = mapping->size, 640418026caSFam Zheng }; 641418026caSFam Zheng 642418026caSFam Zheng index = mapping - s->mappings; 643418026caSFam Zheng assert(mapping->size > 0); 644038adc2fSWei Yang assert(QEMU_IS_ALIGNED(mapping->size, qemu_real_host_page_size)); 645418026caSFam Zheng assert(index >= 0 && index < s->nr_mappings); 646418026caSFam Zheng if (ioctl(s->container, VFIO_IOMMU_UNMAP_DMA, &unmap)) { 647b09d51c9SMichal Privoznik error_setg_errno(errp, errno, "VFIO_UNMAP_DMA failed"); 648418026caSFam Zheng } 649418026caSFam Zheng memmove(mapping, &s->mappings[index + 1], 650418026caSFam Zheng sizeof(s->mappings[0]) * (s->nr_mappings - index - 1)); 651418026caSFam Zheng s->nr_mappings--; 652d29eb678SOlaf Hering s->mappings = g_renew(IOVAMapping, s->mappings, s->nr_mappings); 653418026caSFam Zheng } 654418026caSFam Zheng 655418026caSFam Zheng /* Check if the mapping list is (ascending) ordered. */ 656418026caSFam Zheng static bool qemu_vfio_verify_mappings(QEMUVFIOState *s) 657418026caSFam Zheng { 658418026caSFam Zheng int i; 659418026caSFam Zheng if (QEMU_VFIO_DEBUG) { 660418026caSFam Zheng for (i = 0; i < s->nr_mappings - 1; ++i) { 661418026caSFam Zheng if (!(s->mappings[i].host < s->mappings[i + 1].host)) { 662418026caSFam Zheng fprintf(stderr, "item %d not sorted!\n", i); 663418026caSFam Zheng qemu_vfio_dump_mappings(s); 664418026caSFam Zheng return false; 665418026caSFam Zheng } 666418026caSFam Zheng if (!(s->mappings[i].host + s->mappings[i].size <= 667418026caSFam Zheng s->mappings[i + 1].host)) { 668418026caSFam Zheng fprintf(stderr, "item %d overlap with next!\n", i); 669418026caSFam Zheng qemu_vfio_dump_mappings(s); 670418026caSFam Zheng return false; 671418026caSFam Zheng } 672418026caSFam Zheng } 673418026caSFam Zheng } 674418026caSFam Zheng return true; 675418026caSFam Zheng } 676418026caSFam Zheng 6779ab57411SEric Auger static int 6789ab57411SEric Auger qemu_vfio_find_fixed_iova(QEMUVFIOState *s, size_t size, uint64_t *iova) 6799ab57411SEric Auger { 6809ab57411SEric Auger int i; 6819ab57411SEric Auger 6829ab57411SEric Auger for (i = 0; i < s->nb_iova_ranges; i++) { 6839ab57411SEric Auger if (s->usable_iova_ranges[i].end < s->low_water_mark) { 6849ab57411SEric Auger continue; 6859ab57411SEric Auger } 6869ab57411SEric Auger s->low_water_mark = 6879ab57411SEric Auger MAX(s->low_water_mark, s->usable_iova_ranges[i].start); 6889ab57411SEric Auger 6899ab57411SEric Auger if (s->usable_iova_ranges[i].end - s->low_water_mark + 1 >= size || 6909ab57411SEric Auger s->usable_iova_ranges[i].end - s->low_water_mark + 1 == 0) { 6919ab57411SEric Auger *iova = s->low_water_mark; 6929ab57411SEric Auger s->low_water_mark += size; 6939ab57411SEric Auger return 0; 6949ab57411SEric Auger } 6959ab57411SEric Auger } 6969ab57411SEric Auger return -ENOMEM; 6979ab57411SEric Auger } 6989ab57411SEric Auger 6999ab57411SEric Auger static int 7009ab57411SEric Auger qemu_vfio_find_temp_iova(QEMUVFIOState *s, size_t size, uint64_t *iova) 7019ab57411SEric Auger { 7029ab57411SEric Auger int i; 7039ab57411SEric Auger 7049ab57411SEric Auger for (i = s->nb_iova_ranges - 1; i >= 0; i--) { 7059ab57411SEric Auger if (s->usable_iova_ranges[i].start > s->high_water_mark) { 7069ab57411SEric Auger continue; 7079ab57411SEric Auger } 7089ab57411SEric Auger s->high_water_mark = 7099ab57411SEric Auger MIN(s->high_water_mark, s->usable_iova_ranges[i].end + 1); 7109ab57411SEric Auger 7119ab57411SEric Auger if (s->high_water_mark - s->usable_iova_ranges[i].start + 1 >= size || 7129ab57411SEric Auger s->high_water_mark - s->usable_iova_ranges[i].start + 1 == 0) { 7139ab57411SEric Auger *iova = s->high_water_mark - size; 7149ab57411SEric Auger s->high_water_mark = *iova; 7159ab57411SEric Auger return 0; 7169ab57411SEric Auger } 7179ab57411SEric Auger } 7189ab57411SEric Auger return -ENOMEM; 7199ab57411SEric Auger } 7209ab57411SEric Auger 721418026caSFam Zheng /* Map [host, host + size) area into a contiguous IOVA address space, and store 722418026caSFam Zheng * the result in @iova if not NULL. The caller need to make sure the area is 723418026caSFam Zheng * aligned to page size, and mustn't overlap with existing mapping areas (split 724418026caSFam Zheng * mapping status within this area is not allowed). 725418026caSFam Zheng */ 726418026caSFam Zheng int qemu_vfio_dma_map(QEMUVFIOState *s, void *host, size_t size, 727418026caSFam Zheng bool temporary, uint64_t *iova) 728418026caSFam Zheng { 729418026caSFam Zheng int ret = 0; 730418026caSFam Zheng int index; 731418026caSFam Zheng IOVAMapping *mapping; 732418026caSFam Zheng uint64_t iova0; 733418026caSFam Zheng 734038adc2fSWei Yang assert(QEMU_PTR_IS_ALIGNED(host, qemu_real_host_page_size)); 735038adc2fSWei Yang assert(QEMU_IS_ALIGNED(size, qemu_real_host_page_size)); 736418026caSFam Zheng trace_qemu_vfio_dma_map(s, host, size, temporary, iova); 737418026caSFam Zheng qemu_mutex_lock(&s->lock); 738418026caSFam Zheng mapping = qemu_vfio_find_mapping(s, host, &index); 739418026caSFam Zheng if (mapping) { 740418026caSFam Zheng iova0 = mapping->iova + ((uint8_t *)host - (uint8_t *)mapping->host); 741418026caSFam Zheng } else { 742418026caSFam Zheng if (s->high_water_mark - s->low_water_mark + 1 < size) { 743418026caSFam Zheng ret = -ENOMEM; 744418026caSFam Zheng goto out; 745418026caSFam Zheng } 746418026caSFam Zheng if (!temporary) { 7479ab57411SEric Auger if (qemu_vfio_find_fixed_iova(s, size, &iova0)) { 7489ab57411SEric Auger ret = -ENOMEM; 7499ab57411SEric Auger goto out; 7509ab57411SEric Auger } 7519ab57411SEric Auger 752418026caSFam Zheng mapping = qemu_vfio_add_mapping(s, host, size, index + 1, iova0); 753418026caSFam Zheng if (!mapping) { 754418026caSFam Zheng ret = -ENOMEM; 755418026caSFam Zheng goto out; 756418026caSFam Zheng } 757418026caSFam Zheng assert(qemu_vfio_verify_mappings(s)); 758418026caSFam Zheng ret = qemu_vfio_do_mapping(s, host, size, iova0); 759418026caSFam Zheng if (ret) { 760418026caSFam Zheng qemu_vfio_undo_mapping(s, mapping, NULL); 761418026caSFam Zheng goto out; 762418026caSFam Zheng } 763418026caSFam Zheng qemu_vfio_dump_mappings(s); 764418026caSFam Zheng } else { 7659ab57411SEric Auger if (qemu_vfio_find_temp_iova(s, size, &iova0)) { 7669ab57411SEric Auger ret = -ENOMEM; 7679ab57411SEric Auger goto out; 7689ab57411SEric Auger } 769418026caSFam Zheng ret = qemu_vfio_do_mapping(s, host, size, iova0); 770418026caSFam Zheng if (ret) { 771418026caSFam Zheng goto out; 772418026caSFam Zheng } 773418026caSFam Zheng } 774418026caSFam Zheng } 7754c946b22SPhilippe Mathieu-Daudé trace_qemu_vfio_dma_mapped(s, host, iova0, size); 776418026caSFam Zheng if (iova) { 777418026caSFam Zheng *iova = iova0; 778418026caSFam Zheng } 779418026caSFam Zheng out: 780418026caSFam Zheng qemu_mutex_unlock(&s->lock); 781418026caSFam Zheng return ret; 782418026caSFam Zheng } 783418026caSFam Zheng 784418026caSFam Zheng /* Reset the high watermark and free all "temporary" mappings. */ 785418026caSFam Zheng int qemu_vfio_dma_reset_temporary(QEMUVFIOState *s) 786418026caSFam Zheng { 787418026caSFam Zheng struct vfio_iommu_type1_dma_unmap unmap = { 788418026caSFam Zheng .argsz = sizeof(unmap), 789418026caSFam Zheng .flags = 0, 790418026caSFam Zheng .iova = s->high_water_mark, 791418026caSFam Zheng .size = QEMU_VFIO_IOVA_MAX - s->high_water_mark, 792418026caSFam Zheng }; 793418026caSFam Zheng trace_qemu_vfio_dma_reset_temporary(s); 7946e8a355dSDaniel Brodsky QEMU_LOCK_GUARD(&s->lock); 795418026caSFam Zheng if (ioctl(s->container, VFIO_IOMMU_UNMAP_DMA, &unmap)) { 796b09d51c9SMichal Privoznik error_report("VFIO_UNMAP_DMA failed: %s", strerror(errno)); 797418026caSFam Zheng return -errno; 798418026caSFam Zheng } 799418026caSFam Zheng s->high_water_mark = QEMU_VFIO_IOVA_MAX; 800418026caSFam Zheng return 0; 801418026caSFam Zheng } 802418026caSFam Zheng 803418026caSFam Zheng /* Unmapping the whole area that was previously mapped with 804418026caSFam Zheng * qemu_vfio_dma_map(). */ 805418026caSFam Zheng void qemu_vfio_dma_unmap(QEMUVFIOState *s, void *host) 806418026caSFam Zheng { 807418026caSFam Zheng int index = 0; 808418026caSFam Zheng IOVAMapping *m; 809418026caSFam Zheng 810418026caSFam Zheng if (!host) { 811418026caSFam Zheng return; 812418026caSFam Zheng } 813418026caSFam Zheng 814418026caSFam Zheng trace_qemu_vfio_dma_unmap(s, host); 815418026caSFam Zheng qemu_mutex_lock(&s->lock); 816418026caSFam Zheng m = qemu_vfio_find_mapping(s, host, &index); 817418026caSFam Zheng if (!m) { 818418026caSFam Zheng goto out; 819418026caSFam Zheng } 820418026caSFam Zheng qemu_vfio_undo_mapping(s, m, NULL); 821418026caSFam Zheng out: 822418026caSFam Zheng qemu_mutex_unlock(&s->lock); 823418026caSFam Zheng } 824418026caSFam Zheng 825418026caSFam Zheng static void qemu_vfio_reset(QEMUVFIOState *s) 826418026caSFam Zheng { 827418026caSFam Zheng ioctl(s->device, VFIO_DEVICE_RESET); 828418026caSFam Zheng } 829418026caSFam Zheng 830418026caSFam Zheng /* Close and free the VFIO resources. */ 831418026caSFam Zheng void qemu_vfio_close(QEMUVFIOState *s) 832418026caSFam Zheng { 833418026caSFam Zheng int i; 834418026caSFam Zheng 835418026caSFam Zheng if (!s) { 836418026caSFam Zheng return; 837418026caSFam Zheng } 838418026caSFam Zheng for (i = 0; i < s->nr_mappings; ++i) { 839418026caSFam Zheng qemu_vfio_undo_mapping(s, &s->mappings[i], NULL); 840418026caSFam Zheng } 841418026caSFam Zheng ram_block_notifier_remove(&s->ram_notifier); 8424487d420SEric Auger g_free(s->usable_iova_ranges); 8434487d420SEric Auger s->nb_iova_ranges = 0; 844418026caSFam Zheng qemu_vfio_reset(s); 845418026caSFam Zheng close(s->device); 846418026caSFam Zheng close(s->group); 847418026caSFam Zheng close(s->container); 848418026caSFam Zheng } 849