xref: /qemu/hw/vfio/helpers.c (revision 545256134fdcac6c342f8e7f45eb591e3b12c700)
11e09f52fSYi Liu /*
21e09f52fSYi Liu  * low level and IOMMU backend agnostic helpers used by VFIO devices,
31e09f52fSYi Liu  * related to regions, interrupts, capabilities
41e09f52fSYi Liu  *
51e09f52fSYi Liu  * Copyright Red Hat, Inc. 2012
61e09f52fSYi Liu  *
71e09f52fSYi Liu  * Authors:
81e09f52fSYi Liu  *  Alex Williamson <alex.williamson@redhat.com>
91e09f52fSYi Liu  *
101e09f52fSYi Liu  * This work is licensed under the terms of the GNU GPL, version 2.  See
111e09f52fSYi Liu  * the COPYING file in the top-level directory.
121e09f52fSYi Liu  *
131e09f52fSYi Liu  * Based on qemu-kvm device-assignment:
141e09f52fSYi Liu  *  Adapted for KVM by Qumranet.
151e09f52fSYi Liu  *  Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
161e09f52fSYi Liu  *  Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
171e09f52fSYi Liu  *  Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
181e09f52fSYi Liu  *  Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
191e09f52fSYi Liu  *  Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com)
201e09f52fSYi Liu  */
211e09f52fSYi Liu 
221e09f52fSYi Liu #include "qemu/osdep.h"
231e09f52fSYi Liu #include <sys/ioctl.h>
241e09f52fSYi Liu 
25*54525613SCédric Le Goater #include "system/kvm.h"
261e09f52fSYi Liu #include "hw/vfio/vfio-common.h"
2780936cf7SCédric Le Goater #include "hw/vfio/pci.h"
281e09f52fSYi Liu #include "hw/hw.h"
291e09f52fSYi Liu #include "trace.h"
301e09f52fSYi Liu #include "qapi/error.h"
311e09f52fSYi Liu #include "qemu/error-report.h"
3200b519c0SAlex Williamson #include "qemu/units.h"
33da3e04b2SZhenzhong Duan #include "monitor/monitor.h"
34ac28680dSCédric Le Goater #include "vfio-helpers.h"
351e09f52fSYi Liu 
361e09f52fSYi Liu /*
371e09f52fSYi Liu  * Common VFIO interrupt disable
381e09f52fSYi Liu  */
391e09f52fSYi Liu void vfio_disable_irqindex(VFIODevice *vbasedev, int index)
401e09f52fSYi Liu {
411e09f52fSYi Liu     struct vfio_irq_set irq_set = {
421e09f52fSYi Liu         .argsz = sizeof(irq_set),
431e09f52fSYi Liu         .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER,
441e09f52fSYi Liu         .index = index,
451e09f52fSYi Liu         .start = 0,
461e09f52fSYi Liu         .count = 0,
471e09f52fSYi Liu     };
481e09f52fSYi Liu 
491e09f52fSYi Liu     ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
501e09f52fSYi Liu }
511e09f52fSYi Liu 
521e09f52fSYi Liu void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index)
531e09f52fSYi Liu {
541e09f52fSYi Liu     struct vfio_irq_set irq_set = {
551e09f52fSYi Liu         .argsz = sizeof(irq_set),
561e09f52fSYi Liu         .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK,
571e09f52fSYi Liu         .index = index,
581e09f52fSYi Liu         .start = 0,
591e09f52fSYi Liu         .count = 1,
601e09f52fSYi Liu     };
611e09f52fSYi Liu 
621e09f52fSYi Liu     ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
631e09f52fSYi Liu }
641e09f52fSYi Liu 
651e09f52fSYi Liu void vfio_mask_single_irqindex(VFIODevice *vbasedev, int index)
661e09f52fSYi Liu {
671e09f52fSYi Liu     struct vfio_irq_set irq_set = {
681e09f52fSYi Liu         .argsz = sizeof(irq_set),
691e09f52fSYi Liu         .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK,
701e09f52fSYi Liu         .index = index,
711e09f52fSYi Liu         .start = 0,
721e09f52fSYi Liu         .count = 1,
731e09f52fSYi Liu     };
741e09f52fSYi Liu 
751e09f52fSYi Liu     ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
761e09f52fSYi Liu }
771e09f52fSYi Liu 
781e09f52fSYi Liu static inline const char *action_to_str(int action)
791e09f52fSYi Liu {
801e09f52fSYi Liu     switch (action) {
811e09f52fSYi Liu     case VFIO_IRQ_SET_ACTION_MASK:
821e09f52fSYi Liu         return "MASK";
831e09f52fSYi Liu     case VFIO_IRQ_SET_ACTION_UNMASK:
841e09f52fSYi Liu         return "UNMASK";
851e09f52fSYi Liu     case VFIO_IRQ_SET_ACTION_TRIGGER:
861e09f52fSYi Liu         return "TRIGGER";
871e09f52fSYi Liu     default:
881e09f52fSYi Liu         return "UNKNOWN ACTION";
891e09f52fSYi Liu     }
901e09f52fSYi Liu }
911e09f52fSYi Liu 
921e09f52fSYi Liu static const char *index_to_str(VFIODevice *vbasedev, int index)
931e09f52fSYi Liu {
941e09f52fSYi Liu     if (vbasedev->type != VFIO_DEVICE_TYPE_PCI) {
951e09f52fSYi Liu         return NULL;
961e09f52fSYi Liu     }
971e09f52fSYi Liu 
981e09f52fSYi Liu     switch (index) {
991e09f52fSYi Liu     case VFIO_PCI_INTX_IRQ_INDEX:
1001e09f52fSYi Liu         return "INTX";
1011e09f52fSYi Liu     case VFIO_PCI_MSI_IRQ_INDEX:
1021e09f52fSYi Liu         return "MSI";
1031e09f52fSYi Liu     case VFIO_PCI_MSIX_IRQ_INDEX:
1041e09f52fSYi Liu         return "MSIX";
1051e09f52fSYi Liu     case VFIO_PCI_ERR_IRQ_INDEX:
1061e09f52fSYi Liu         return "ERR";
1071e09f52fSYi Liu     case VFIO_PCI_REQ_IRQ_INDEX:
1081e09f52fSYi Liu         return "REQ";
1091e09f52fSYi Liu     default:
1101e09f52fSYi Liu         return NULL;
1111e09f52fSYi Liu     }
1121e09f52fSYi Liu }
1131e09f52fSYi Liu 
11484e37d02SZhenzhong Duan bool vfio_set_irq_signaling(VFIODevice *vbasedev, int index, int subindex,
1151e09f52fSYi Liu                             int action, int fd, Error **errp)
1161e09f52fSYi Liu {
11789a8a2e9SZhao Liu     ERRP_GUARD();
11850b632b6SZhenzhong Duan     g_autofree struct vfio_irq_set *irq_set = NULL;
11984e37d02SZhenzhong Duan     int argsz;
1201e09f52fSYi Liu     const char *name;
1211e09f52fSYi Liu     int32_t *pfd;
1221e09f52fSYi Liu 
1231e09f52fSYi Liu     argsz = sizeof(*irq_set) + sizeof(*pfd);
1241e09f52fSYi Liu 
1251e09f52fSYi Liu     irq_set = g_malloc0(argsz);
1261e09f52fSYi Liu     irq_set->argsz = argsz;
1271e09f52fSYi Liu     irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | action;
1281e09f52fSYi Liu     irq_set->index = index;
1291e09f52fSYi Liu     irq_set->start = subindex;
1301e09f52fSYi Liu     irq_set->count = 1;
1311e09f52fSYi Liu     pfd = (int32_t *)&irq_set->data;
1321e09f52fSYi Liu     *pfd = fd;
1331e09f52fSYi Liu 
13484e37d02SZhenzhong Duan     if (!ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, irq_set)) {
13584e37d02SZhenzhong Duan         return true;
1361e09f52fSYi Liu     }
1371e09f52fSYi Liu 
13884e37d02SZhenzhong Duan     error_setg_errno(errp, errno, "VFIO_DEVICE_SET_IRQS failure");
1391e09f52fSYi Liu 
1401e09f52fSYi Liu     name = index_to_str(vbasedev, index);
1411e09f52fSYi Liu     if (name) {
1421e09f52fSYi Liu         error_prepend(errp, "%s-%d: ", name, subindex);
1431e09f52fSYi Liu     } else {
1441e09f52fSYi Liu         error_prepend(errp, "index %d-%d: ", index, subindex);
1451e09f52fSYi Liu     }
1461e09f52fSYi Liu     error_prepend(errp,
1471e09f52fSYi Liu                   "Failed to %s %s eventfd signaling for interrupt ",
1481e09f52fSYi Liu                   fd < 0 ? "tear down" : "set up", action_to_str(action));
14984e37d02SZhenzhong Duan     return false;
1501e09f52fSYi Liu }
1511e09f52fSYi Liu 
1521e09f52fSYi Liu int vfio_bitmap_alloc(VFIOBitmap *vbmap, hwaddr size)
1531e09f52fSYi Liu {
1541e09f52fSYi Liu     vbmap->pages = REAL_HOST_PAGE_ALIGN(size) / qemu_real_host_page_size();
1551e09f52fSYi Liu     vbmap->size = ROUND_UP(vbmap->pages, sizeof(__u64) * BITS_PER_BYTE) /
1561e09f52fSYi Liu                                          BITS_PER_BYTE;
1571e09f52fSYi Liu     vbmap->bitmap = g_try_malloc0(vbmap->size);
1581e09f52fSYi Liu     if (!vbmap->bitmap) {
1591e09f52fSYi Liu         return -ENOMEM;
1601e09f52fSYi Liu     }
1611e09f52fSYi Liu 
1621e09f52fSYi Liu     return 0;
1631e09f52fSYi Liu }
1641e09f52fSYi Liu 
1651e09f52fSYi Liu struct vfio_info_cap_header *
1661e09f52fSYi Liu vfio_get_cap(void *ptr, uint32_t cap_offset, uint16_t id)
1671e09f52fSYi Liu {
1681e09f52fSYi Liu     struct vfio_info_cap_header *hdr;
1691e09f52fSYi Liu 
1701e09f52fSYi Liu     for (hdr = ptr + cap_offset; hdr != ptr; hdr = ptr + hdr->next) {
1711e09f52fSYi Liu         if (hdr->id == id) {
1721e09f52fSYi Liu             return hdr;
1731e09f52fSYi Liu         }
1741e09f52fSYi Liu     }
1751e09f52fSYi Liu 
1761e09f52fSYi Liu     return NULL;
1771e09f52fSYi Liu }
1781e09f52fSYi Liu 
1791e09f52fSYi Liu struct vfio_info_cap_header *
1801e09f52fSYi Liu vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id)
1811e09f52fSYi Liu {
1821e09f52fSYi Liu     if (!(info->flags & VFIO_REGION_INFO_FLAG_CAPS)) {
1831e09f52fSYi Liu         return NULL;
1841e09f52fSYi Liu     }
1851e09f52fSYi Liu 
1861e09f52fSYi Liu     return vfio_get_cap((void *)info, info->cap_offset, id);
1871e09f52fSYi Liu }
1881e09f52fSYi Liu 
1891e09f52fSYi Liu struct vfio_info_cap_header *
1901e09f52fSYi Liu vfio_get_device_info_cap(struct vfio_device_info *info, uint16_t id)
1911e09f52fSYi Liu {
1921e09f52fSYi Liu     if (!(info->flags & VFIO_DEVICE_FLAGS_CAPS)) {
1931e09f52fSYi Liu         return NULL;
1941e09f52fSYi Liu     }
1951e09f52fSYi Liu 
1961e09f52fSYi Liu     return vfio_get_cap((void *)info, info->cap_offset, id);
1971e09f52fSYi Liu }
1981e09f52fSYi Liu 
1991e09f52fSYi Liu int vfio_get_region_info(VFIODevice *vbasedev, int index,
2001e09f52fSYi Liu                          struct vfio_region_info **info)
2011e09f52fSYi Liu {
2021e09f52fSYi Liu     size_t argsz = sizeof(struct vfio_region_info);
2031e09f52fSYi Liu 
2041e09f52fSYi Liu     *info = g_malloc0(argsz);
2051e09f52fSYi Liu 
2061e09f52fSYi Liu     (*info)->index = index;
2071e09f52fSYi Liu retry:
2081e09f52fSYi Liu     (*info)->argsz = argsz;
2091e09f52fSYi Liu 
2101e09f52fSYi Liu     if (ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, *info)) {
2111e09f52fSYi Liu         g_free(*info);
2121e09f52fSYi Liu         *info = NULL;
2131e09f52fSYi Liu         return -errno;
2141e09f52fSYi Liu     }
2151e09f52fSYi Liu 
2161e09f52fSYi Liu     if ((*info)->argsz > argsz) {
2171e09f52fSYi Liu         argsz = (*info)->argsz;
2181e09f52fSYi Liu         *info = g_realloc(*info, argsz);
2191e09f52fSYi Liu 
2201e09f52fSYi Liu         goto retry;
2211e09f52fSYi Liu     }
2221e09f52fSYi Liu 
2231e09f52fSYi Liu     return 0;
2241e09f52fSYi Liu }
2251e09f52fSYi Liu 
226f6d7f5d0SCédric Le Goater struct vfio_info_cap_header *
227f6d7f5d0SCédric Le Goater vfio_get_iommu_type1_info_cap(struct vfio_iommu_type1_info *info, uint16_t id)
228f6d7f5d0SCédric Le Goater {
229f6d7f5d0SCédric Le Goater     if (!(info->flags & VFIO_IOMMU_INFO_CAPS)) {
230f6d7f5d0SCédric Le Goater         return NULL;
231f6d7f5d0SCédric Le Goater     }
232f6d7f5d0SCédric Le Goater 
233f6d7f5d0SCédric Le Goater     return vfio_get_cap((void *)info, info->cap_offset, id);
234f6d7f5d0SCédric Le Goater }
235f6d7f5d0SCédric Le Goater 
236f6d7f5d0SCédric Le Goater bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info,
237f6d7f5d0SCédric Le Goater                              unsigned int *avail)
238f6d7f5d0SCédric Le Goater {
239f6d7f5d0SCédric Le Goater     struct vfio_info_cap_header *hdr;
240f6d7f5d0SCédric Le Goater     struct vfio_iommu_type1_info_dma_avail *cap;
241f6d7f5d0SCédric Le Goater 
242f6d7f5d0SCédric Le Goater     /* If the capability cannot be found, assume no DMA limiting */
243f6d7f5d0SCédric Le Goater     hdr = vfio_get_iommu_type1_info_cap(info,
244f6d7f5d0SCédric Le Goater                                         VFIO_IOMMU_TYPE1_INFO_DMA_AVAIL);
245f6d7f5d0SCédric Le Goater     if (!hdr) {
246f6d7f5d0SCédric Le Goater         return false;
247f6d7f5d0SCédric Le Goater     }
248f6d7f5d0SCédric Le Goater 
249f6d7f5d0SCédric Le Goater     if (avail != NULL) {
250f6d7f5d0SCédric Le Goater         cap = (void *) hdr;
251f6d7f5d0SCédric Le Goater         *avail = cap->avail;
252f6d7f5d0SCédric Le Goater     }
253f6d7f5d0SCédric Le Goater 
254f6d7f5d0SCédric Le Goater     return true;
255f6d7f5d0SCédric Le Goater }
256f6d7f5d0SCédric Le Goater 
257*54525613SCédric Le Goater int vfio_kvm_device_add_fd(int fd, Error **errp)
258*54525613SCédric Le Goater {
259*54525613SCédric Le Goater #ifdef CONFIG_KVM
260*54525613SCédric Le Goater     struct kvm_device_attr attr = {
261*54525613SCédric Le Goater         .group = KVM_DEV_VFIO_FILE,
262*54525613SCédric Le Goater         .attr = KVM_DEV_VFIO_FILE_ADD,
263*54525613SCédric Le Goater         .addr = (uint64_t)(unsigned long)&fd,
264*54525613SCédric Le Goater     };
265*54525613SCédric Le Goater 
266*54525613SCédric Le Goater     if (!kvm_enabled()) {
267*54525613SCédric Le Goater         return 0;
268*54525613SCédric Le Goater     }
269*54525613SCédric Le Goater 
270*54525613SCédric Le Goater     if (vfio_kvm_device_fd < 0) {
271*54525613SCédric Le Goater         struct kvm_create_device cd = {
272*54525613SCédric Le Goater             .type = KVM_DEV_TYPE_VFIO,
273*54525613SCédric Le Goater         };
274*54525613SCédric Le Goater 
275*54525613SCédric Le Goater         if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) {
276*54525613SCédric Le Goater             error_setg_errno(errp, errno, "Failed to create KVM VFIO device");
277*54525613SCédric Le Goater             return -errno;
278*54525613SCédric Le Goater         }
279*54525613SCédric Le Goater 
280*54525613SCédric Le Goater         vfio_kvm_device_fd = cd.fd;
281*54525613SCédric Le Goater     }
282*54525613SCédric Le Goater 
283*54525613SCédric Le Goater     if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
284*54525613SCédric Le Goater         error_setg_errno(errp, errno, "Failed to add fd %d to KVM VFIO device",
285*54525613SCédric Le Goater                          fd);
286*54525613SCédric Le Goater         return -errno;
287*54525613SCédric Le Goater     }
288*54525613SCédric Le Goater #endif
289*54525613SCédric Le Goater     return 0;
290*54525613SCédric Le Goater }
291*54525613SCédric Le Goater 
292*54525613SCédric Le Goater int vfio_kvm_device_del_fd(int fd, Error **errp)
293*54525613SCédric Le Goater {
294*54525613SCédric Le Goater #ifdef CONFIG_KVM
295*54525613SCédric Le Goater     struct kvm_device_attr attr = {
296*54525613SCédric Le Goater         .group = KVM_DEV_VFIO_FILE,
297*54525613SCédric Le Goater         .attr = KVM_DEV_VFIO_FILE_DEL,
298*54525613SCédric Le Goater         .addr = (uint64_t)(unsigned long)&fd,
299*54525613SCédric Le Goater     };
300*54525613SCédric Le Goater 
301*54525613SCédric Le Goater     if (vfio_kvm_device_fd < 0) {
302*54525613SCédric Le Goater         error_setg(errp, "KVM VFIO device isn't created yet");
303*54525613SCédric Le Goater         return -EINVAL;
304*54525613SCédric Le Goater     }
305*54525613SCédric Le Goater 
306*54525613SCédric Le Goater     if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
307*54525613SCédric Le Goater         error_setg_errno(errp, errno,
308*54525613SCédric Le Goater                          "Failed to remove fd %d from KVM VFIO device", fd);
309*54525613SCédric Le Goater         return -errno;
310*54525613SCédric Le Goater     }
311*54525613SCédric Le Goater #endif
312*54525613SCédric Le Goater     return 0;
313*54525613SCédric Le Goater }
314*54525613SCédric Le Goater 
3151e09f52fSYi Liu int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type,
3161e09f52fSYi Liu                              uint32_t subtype, struct vfio_region_info **info)
3171e09f52fSYi Liu {
3181e09f52fSYi Liu     int i;
3191e09f52fSYi Liu 
3201e09f52fSYi Liu     for (i = 0; i < vbasedev->num_regions; i++) {
3211e09f52fSYi Liu         struct vfio_info_cap_header *hdr;
3221e09f52fSYi Liu         struct vfio_region_info_cap_type *cap_type;
3231e09f52fSYi Liu 
3241e09f52fSYi Liu         if (vfio_get_region_info(vbasedev, i, info)) {
3251e09f52fSYi Liu             continue;
3261e09f52fSYi Liu         }
3271e09f52fSYi Liu 
3281e09f52fSYi Liu         hdr = vfio_get_region_info_cap(*info, VFIO_REGION_INFO_CAP_TYPE);
3291e09f52fSYi Liu         if (!hdr) {
3301e09f52fSYi Liu             g_free(*info);
3311e09f52fSYi Liu             continue;
3321e09f52fSYi Liu         }
3331e09f52fSYi Liu 
3341e09f52fSYi Liu         cap_type = container_of(hdr, struct vfio_region_info_cap_type, header);
3351e09f52fSYi Liu 
3361e09f52fSYi Liu         trace_vfio_get_dev_region(vbasedev->name, i,
3371e09f52fSYi Liu                                   cap_type->type, cap_type->subtype);
3381e09f52fSYi Liu 
3391e09f52fSYi Liu         if (cap_type->type == type && cap_type->subtype == subtype) {
3401e09f52fSYi Liu             return 0;
3411e09f52fSYi Liu         }
3421e09f52fSYi Liu 
3431e09f52fSYi Liu         g_free(*info);
3441e09f52fSYi Liu     }
3451e09f52fSYi Liu 
3461e09f52fSYi Liu     *info = NULL;
3471e09f52fSYi Liu     return -ENODEV;
3481e09f52fSYi Liu }
3491e09f52fSYi Liu 
3501e09f52fSYi Liu bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type)
3511e09f52fSYi Liu {
3520d3e89beSZhenzhong Duan     g_autofree struct vfio_region_info *info = NULL;
3531e09f52fSYi Liu     bool ret = false;
3541e09f52fSYi Liu 
3551e09f52fSYi Liu     if (!vfio_get_region_info(vbasedev, region, &info)) {
3561e09f52fSYi Liu         if (vfio_get_region_info_cap(info, cap_type)) {
3571e09f52fSYi Liu             ret = true;
3581e09f52fSYi Liu         }
3591e09f52fSYi Liu     }
3601e09f52fSYi Liu 
3611e09f52fSYi Liu     return ret;
3621e09f52fSYi Liu }
363da3e04b2SZhenzhong Duan 
364c6c6cf91SZhenzhong Duan bool vfio_device_get_name(VFIODevice *vbasedev, Error **errp)
365da3e04b2SZhenzhong Duan {
36689a8a2e9SZhao Liu     ERRP_GUARD();
367da3e04b2SZhenzhong Duan     struct stat st;
368da3e04b2SZhenzhong Duan 
369da3e04b2SZhenzhong Duan     if (vbasedev->fd < 0) {
370da3e04b2SZhenzhong Duan         if (stat(vbasedev->sysfsdev, &st) < 0) {
371da3e04b2SZhenzhong Duan             error_setg_errno(errp, errno, "no such host device");
372da3e04b2SZhenzhong Duan             error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->sysfsdev);
373c6c6cf91SZhenzhong Duan             return false;
374da3e04b2SZhenzhong Duan         }
375da3e04b2SZhenzhong Duan         /* User may specify a name, e.g: VFIO platform device */
376da3e04b2SZhenzhong Duan         if (!vbasedev->name) {
377da3e04b2SZhenzhong Duan             vbasedev->name = g_path_get_basename(vbasedev->sysfsdev);
378da3e04b2SZhenzhong Duan         }
379da3e04b2SZhenzhong Duan     } else {
380da3e04b2SZhenzhong Duan         if (!vbasedev->iommufd) {
381da3e04b2SZhenzhong Duan             error_setg(errp, "Use FD passing only with iommufd backend");
382c6c6cf91SZhenzhong Duan             return false;
383da3e04b2SZhenzhong Duan         }
384da3e04b2SZhenzhong Duan         /*
385da3e04b2SZhenzhong Duan          * Give a name with fd so any function printing out vbasedev->name
386da3e04b2SZhenzhong Duan          * will not break.
387da3e04b2SZhenzhong Duan          */
388da3e04b2SZhenzhong Duan         if (!vbasedev->name) {
389da3e04b2SZhenzhong Duan             vbasedev->name = g_strdup_printf("VFIO_FD%d", vbasedev->fd);
390da3e04b2SZhenzhong Duan         }
391da3e04b2SZhenzhong Duan     }
392da3e04b2SZhenzhong Duan 
393c6c6cf91SZhenzhong Duan     return true;
394da3e04b2SZhenzhong Duan }
395da3e04b2SZhenzhong Duan 
396da3e04b2SZhenzhong Duan void vfio_device_set_fd(VFIODevice *vbasedev, const char *str, Error **errp)
397da3e04b2SZhenzhong Duan {
39889a8a2e9SZhao Liu     ERRP_GUARD();
399da3e04b2SZhenzhong Duan     int fd = monitor_fd_param(monitor_cur(), str, errp);
400da3e04b2SZhenzhong Duan 
401da3e04b2SZhenzhong Duan     if (fd < 0) {
402da3e04b2SZhenzhong Duan         error_prepend(errp, "Could not parse remote object fd %s:", str);
403da3e04b2SZhenzhong Duan         return;
404da3e04b2SZhenzhong Duan     }
405da3e04b2SZhenzhong Duan     vbasedev->fd = fd;
406da3e04b2SZhenzhong Duan }
4076106a329SZhenzhong Duan 
4086106a329SZhenzhong Duan void vfio_device_init(VFIODevice *vbasedev, int type, VFIODeviceOps *ops,
4096106a329SZhenzhong Duan                       DeviceState *dev, bool ram_discard)
4106106a329SZhenzhong Duan {
4116106a329SZhenzhong Duan     vbasedev->type = type;
4126106a329SZhenzhong Duan     vbasedev->ops = ops;
4136106a329SZhenzhong Duan     vbasedev->dev = dev;
4146106a329SZhenzhong Duan     vbasedev->fd = -1;
4156106a329SZhenzhong Duan 
4166106a329SZhenzhong Duan     vbasedev->ram_block_discard_allowed = ram_discard;
4176106a329SZhenzhong Duan }
418d441e05eSZhenzhong Duan 
419d441e05eSZhenzhong Duan int vfio_device_get_aw_bits(VFIODevice *vdev)
420d441e05eSZhenzhong Duan {
421d441e05eSZhenzhong Duan     /*
422d441e05eSZhenzhong Duan      * iova_ranges is a sorted list. For old kernels that support
423d441e05eSZhenzhong Duan      * VFIO but not support query of iova ranges, iova_ranges is NULL,
424d441e05eSZhenzhong Duan      * in this case HOST_IOMMU_DEVICE_CAP_AW_BITS_MAX(64) is returned.
425d441e05eSZhenzhong Duan      */
426d441e05eSZhenzhong Duan     GList *l = g_list_last(vdev->bcontainer->iova_ranges);
427d441e05eSZhenzhong Duan 
428d441e05eSZhenzhong Duan     if (l) {
429d441e05eSZhenzhong Duan         Range *range = l->data;
430d441e05eSZhenzhong Duan         return range_get_last_bit(range) + 1;
431d441e05eSZhenzhong Duan     }
432d441e05eSZhenzhong Duan 
433d441e05eSZhenzhong Duan     return HOST_IOMMU_DEVICE_CAP_AW_BITS_MAX;
434d441e05eSZhenzhong Duan }
43513e522f6SJoao Martins 
43613e522f6SJoao Martins bool vfio_device_is_mdev(VFIODevice *vbasedev)
43713e522f6SJoao Martins {
43813e522f6SJoao Martins     g_autofree char *subsys = NULL;
43913e522f6SJoao Martins     g_autofree char *tmp = NULL;
44013e522f6SJoao Martins 
44113e522f6SJoao Martins     if (!vbasedev->sysfsdev) {
44213e522f6SJoao Martins         return false;
44313e522f6SJoao Martins     }
44413e522f6SJoao Martins 
44513e522f6SJoao Martins     tmp = g_strdup_printf("%s/subsystem", vbasedev->sysfsdev);
44613e522f6SJoao Martins     subsys = realpath(tmp, NULL);
44713e522f6SJoao Martins     return subsys && (strcmp(subsys, "/sys/bus/mdev") == 0);
44813e522f6SJoao Martins }
44983a4d596SJoao Martins 
45083a4d596SJoao Martins bool vfio_device_hiod_realize(VFIODevice *vbasedev, Error **errp)
45183a4d596SJoao Martins {
45283a4d596SJoao Martins     HostIOMMUDevice *hiod = vbasedev->hiod;
45383a4d596SJoao Martins 
45483a4d596SJoao Martins     if (!hiod) {
45583a4d596SJoao Martins         return true;
45683a4d596SJoao Martins     }
45783a4d596SJoao Martins 
45883a4d596SJoao Martins     return HOST_IOMMU_DEVICE_GET_CLASS(hiod)->realize(hiod, vbasedev, errp);
45983a4d596SJoao Martins }
46080936cf7SCédric Le Goater 
46180936cf7SCédric Le Goater VFIODevice *vfio_get_vfio_device(Object *obj)
46280936cf7SCédric Le Goater {
46380936cf7SCédric Le Goater     if (object_dynamic_cast(obj, TYPE_VFIO_PCI)) {
46480936cf7SCédric Le Goater         return &VFIO_PCI(obj)->vbasedev;
46580936cf7SCédric Le Goater     } else {
46680936cf7SCédric Le Goater         return NULL;
46780936cf7SCédric Le Goater     }
46880936cf7SCédric Le Goater }
469