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
2554525613SCédric Le Goater #include "system/kvm.h"
26*11b8b9d5SCédric Le Goater #include "hw/vfio/vfio-device.h"
271e09f52fSYi Liu #include "hw/hw.h"
281e09f52fSYi Liu #include "qapi/error.h"
29ac28680dSCédric Le Goater #include "vfio-helpers.h"
301e09f52fSYi Liu
vfio_bitmap_alloc(VFIOBitmap * vbmap,hwaddr size)311e09f52fSYi Liu int vfio_bitmap_alloc(VFIOBitmap *vbmap, hwaddr size)
321e09f52fSYi Liu {
331e09f52fSYi Liu vbmap->pages = REAL_HOST_PAGE_ALIGN(size) / qemu_real_host_page_size();
341e09f52fSYi Liu vbmap->size = ROUND_UP(vbmap->pages, sizeof(__u64) * BITS_PER_BYTE) /
351e09f52fSYi Liu BITS_PER_BYTE;
361e09f52fSYi Liu vbmap->bitmap = g_try_malloc0(vbmap->size);
371e09f52fSYi Liu if (!vbmap->bitmap) {
381e09f52fSYi Liu return -ENOMEM;
391e09f52fSYi Liu }
401e09f52fSYi Liu
411e09f52fSYi Liu return 0;
421e09f52fSYi Liu }
431e09f52fSYi Liu
441e09f52fSYi Liu struct vfio_info_cap_header *
vfio_get_cap(void * ptr,uint32_t cap_offset,uint16_t id)451e09f52fSYi Liu vfio_get_cap(void *ptr, uint32_t cap_offset, uint16_t id)
461e09f52fSYi Liu {
471e09f52fSYi Liu struct vfio_info_cap_header *hdr;
481e09f52fSYi Liu
491e09f52fSYi Liu for (hdr = ptr + cap_offset; hdr != ptr; hdr = ptr + hdr->next) {
501e09f52fSYi Liu if (hdr->id == id) {
511e09f52fSYi Liu return hdr;
521e09f52fSYi Liu }
531e09f52fSYi Liu }
541e09f52fSYi Liu
551e09f52fSYi Liu return NULL;
561e09f52fSYi Liu }
571e09f52fSYi Liu
581e09f52fSYi Liu struct vfio_info_cap_header *
vfio_get_region_info_cap(struct vfio_region_info * info,uint16_t id)591e09f52fSYi Liu vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id)
601e09f52fSYi Liu {
611e09f52fSYi Liu if (!(info->flags & VFIO_REGION_INFO_FLAG_CAPS)) {
621e09f52fSYi Liu return NULL;
631e09f52fSYi Liu }
641e09f52fSYi Liu
651e09f52fSYi Liu return vfio_get_cap((void *)info, info->cap_offset, id);
661e09f52fSYi Liu }
671e09f52fSYi Liu
681e09f52fSYi Liu struct vfio_info_cap_header *
vfio_get_device_info_cap(struct vfio_device_info * info,uint16_t id)691e09f52fSYi Liu vfio_get_device_info_cap(struct vfio_device_info *info, uint16_t id)
701e09f52fSYi Liu {
711e09f52fSYi Liu if (!(info->flags & VFIO_DEVICE_FLAGS_CAPS)) {
721e09f52fSYi Liu return NULL;
731e09f52fSYi Liu }
741e09f52fSYi Liu
751e09f52fSYi Liu return vfio_get_cap((void *)info, info->cap_offset, id);
761e09f52fSYi Liu }
771e09f52fSYi Liu
78f6d7f5d0SCédric Le Goater struct vfio_info_cap_header *
vfio_get_iommu_type1_info_cap(struct vfio_iommu_type1_info * info,uint16_t id)79f6d7f5d0SCédric Le Goater vfio_get_iommu_type1_info_cap(struct vfio_iommu_type1_info *info, uint16_t id)
80f6d7f5d0SCédric Le Goater {
81f6d7f5d0SCédric Le Goater if (!(info->flags & VFIO_IOMMU_INFO_CAPS)) {
82f6d7f5d0SCédric Le Goater return NULL;
83f6d7f5d0SCédric Le Goater }
84f6d7f5d0SCédric Le Goater
85f6d7f5d0SCédric Le Goater return vfio_get_cap((void *)info, info->cap_offset, id);
86f6d7f5d0SCédric Le Goater }
87f6d7f5d0SCédric Le Goater
vfio_get_info_dma_avail(struct vfio_iommu_type1_info * info,unsigned int * avail)88f6d7f5d0SCédric Le Goater bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info,
89f6d7f5d0SCédric Le Goater unsigned int *avail)
90f6d7f5d0SCédric Le Goater {
91f6d7f5d0SCédric Le Goater struct vfio_info_cap_header *hdr;
92f6d7f5d0SCédric Le Goater struct vfio_iommu_type1_info_dma_avail *cap;
93f6d7f5d0SCédric Le Goater
94f6d7f5d0SCédric Le Goater /* If the capability cannot be found, assume no DMA limiting */
95f6d7f5d0SCédric Le Goater hdr = vfio_get_iommu_type1_info_cap(info,
96f6d7f5d0SCédric Le Goater VFIO_IOMMU_TYPE1_INFO_DMA_AVAIL);
97f6d7f5d0SCédric Le Goater if (!hdr) {
98f6d7f5d0SCédric Le Goater return false;
99f6d7f5d0SCédric Le Goater }
100f6d7f5d0SCédric Le Goater
101f6d7f5d0SCédric Le Goater if (avail != NULL) {
102f6d7f5d0SCédric Le Goater cap = (void *) hdr;
103f6d7f5d0SCédric Le Goater *avail = cap->avail;
104f6d7f5d0SCédric Le Goater }
105f6d7f5d0SCédric Le Goater
106f6d7f5d0SCédric Le Goater return true;
107f6d7f5d0SCédric Le Goater }
108f6d7f5d0SCédric Le Goater
109c3fbdba1SCédric Le Goater #ifdef CONFIG_KVM
110c3fbdba1SCédric Le Goater /*
111c3fbdba1SCédric Le Goater * We have a single VFIO pseudo device per KVM VM. Once created it lives
112c3fbdba1SCédric Le Goater * for the life of the VM. Closing the file descriptor only drops our
113c3fbdba1SCédric Le Goater * reference to it and the device's reference to kvm. Therefore once
114c3fbdba1SCédric Le Goater * initialized, this file descriptor is only released on QEMU exit and
115c3fbdba1SCédric Le Goater * we'll re-use it should another vfio device be attached before then.
116c3fbdba1SCédric Le Goater */
117c3fbdba1SCédric Le Goater int vfio_kvm_device_fd = -1;
118c3fbdba1SCédric Le Goater #endif
119c3fbdba1SCédric Le Goater
vfio_kvm_device_add_fd(int fd,Error ** errp)12054525613SCédric Le Goater int vfio_kvm_device_add_fd(int fd, Error **errp)
12154525613SCédric Le Goater {
12254525613SCédric Le Goater #ifdef CONFIG_KVM
12354525613SCédric Le Goater struct kvm_device_attr attr = {
12454525613SCédric Le Goater .group = KVM_DEV_VFIO_FILE,
12554525613SCédric Le Goater .attr = KVM_DEV_VFIO_FILE_ADD,
12654525613SCédric Le Goater .addr = (uint64_t)(unsigned long)&fd,
12754525613SCédric Le Goater };
12854525613SCédric Le Goater
12954525613SCédric Le Goater if (!kvm_enabled()) {
13054525613SCédric Le Goater return 0;
13154525613SCédric Le Goater }
13254525613SCédric Le Goater
13354525613SCédric Le Goater if (vfio_kvm_device_fd < 0) {
13454525613SCédric Le Goater struct kvm_create_device cd = {
13554525613SCédric Le Goater .type = KVM_DEV_TYPE_VFIO,
13654525613SCédric Le Goater };
13754525613SCédric Le Goater
13854525613SCédric Le Goater if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) {
13954525613SCédric Le Goater error_setg_errno(errp, errno, "Failed to create KVM VFIO device");
14054525613SCédric Le Goater return -errno;
14154525613SCédric Le Goater }
14254525613SCédric Le Goater
14354525613SCédric Le Goater vfio_kvm_device_fd = cd.fd;
14454525613SCédric Le Goater }
14554525613SCédric Le Goater
14654525613SCédric Le Goater if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
14754525613SCédric Le Goater error_setg_errno(errp, errno, "Failed to add fd %d to KVM VFIO device",
14854525613SCédric Le Goater fd);
14954525613SCédric Le Goater return -errno;
15054525613SCédric Le Goater }
15154525613SCédric Le Goater #endif
15254525613SCédric Le Goater return 0;
15354525613SCédric Le Goater }
15454525613SCédric Le Goater
vfio_kvm_device_del_fd(int fd,Error ** errp)15554525613SCédric Le Goater int vfio_kvm_device_del_fd(int fd, Error **errp)
15654525613SCédric Le Goater {
15754525613SCédric Le Goater #ifdef CONFIG_KVM
15854525613SCédric Le Goater struct kvm_device_attr attr = {
15954525613SCédric Le Goater .group = KVM_DEV_VFIO_FILE,
16054525613SCédric Le Goater .attr = KVM_DEV_VFIO_FILE_DEL,
16154525613SCédric Le Goater .addr = (uint64_t)(unsigned long)&fd,
16254525613SCédric Le Goater };
16354525613SCédric Le Goater
16454525613SCédric Le Goater if (vfio_kvm_device_fd < 0) {
16554525613SCédric Le Goater error_setg(errp, "KVM VFIO device isn't created yet");
16654525613SCédric Le Goater return -EINVAL;
16754525613SCédric Le Goater }
16854525613SCédric Le Goater
16954525613SCédric Le Goater if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
17054525613SCédric Le Goater error_setg_errno(errp, errno,
17154525613SCédric Le Goater "Failed to remove fd %d from KVM VFIO device", fd);
17254525613SCédric Le Goater return -errno;
17354525613SCédric Le Goater }
17454525613SCédric Le Goater #endif
17554525613SCédric Le Goater return 0;
17654525613SCédric Le Goater }
17754525613SCédric Le Goater
vfio_get_device_info(int fd)178005b8d10SCédric Le Goater struct vfio_device_info *vfio_get_device_info(int fd)
179005b8d10SCédric Le Goater {
180005b8d10SCédric Le Goater struct vfio_device_info *info;
181005b8d10SCédric Le Goater uint32_t argsz = sizeof(*info);
182005b8d10SCédric Le Goater
183005b8d10SCédric Le Goater info = g_malloc0(argsz);
184005b8d10SCédric Le Goater
185005b8d10SCédric Le Goater retry:
186005b8d10SCédric Le Goater info->argsz = argsz;
187005b8d10SCédric Le Goater
188005b8d10SCédric Le Goater if (ioctl(fd, VFIO_DEVICE_GET_INFO, info)) {
189005b8d10SCédric Le Goater g_free(info);
190005b8d10SCédric Le Goater return NULL;
191005b8d10SCédric Le Goater }
192005b8d10SCédric Le Goater
193005b8d10SCédric Le Goater if (info->argsz > argsz) {
194005b8d10SCédric Le Goater argsz = info->argsz;
195005b8d10SCédric Le Goater info = g_realloc(info, argsz);
196005b8d10SCédric Le Goater goto retry;
197005b8d10SCédric Le Goater }
198005b8d10SCédric Le Goater
199005b8d10SCédric Le Goater return info;
200005b8d10SCédric Le Goater }
201