168c07d76SCédric Le Goater /* 268c07d76SCédric Le Goater * VFIO device 368c07d76SCédric Le Goater * 468c07d76SCédric Le Goater * Copyright Red Hat, Inc. 2012 568c07d76SCédric Le Goater * 668c07d76SCédric Le Goater * Authors: 768c07d76SCédric Le Goater * Alex Williamson <alex.williamson@redhat.com> 868c07d76SCédric Le Goater * 968c07d76SCédric Le Goater * This work is licensed under the terms of the GNU GPL, version 2. See 1068c07d76SCédric Le Goater * the COPYING file in the top-level directory. 1168c07d76SCédric Le Goater * 1268c07d76SCédric Le Goater * Based on qemu-kvm device-assignment: 1368c07d76SCédric Le Goater * Adapted for KVM by Qumranet. 1468c07d76SCédric Le Goater * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com) 1568c07d76SCédric Le Goater * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com) 1668c07d76SCédric Le Goater * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com) 1768c07d76SCédric Le Goater * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com) 1868c07d76SCédric Le Goater * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com) 1968c07d76SCédric Le Goater */ 2068c07d76SCédric Le Goater 2168c07d76SCédric Le Goater #include "qemu/osdep.h" 2268c07d76SCédric Le Goater #include <sys/ioctl.h> 2368c07d76SCédric Le Goater 2411b8b9d5SCédric Le Goater #include "hw/vfio/vfio-device.h" 2568c07d76SCédric Le Goater #include "hw/vfio/pci.h" 2668c07d76SCédric Le Goater #include "hw/hw.h" 2768c07d76SCédric Le Goater #include "trace.h" 2868c07d76SCédric Le Goater #include "qapi/error.h" 2968c07d76SCédric Le Goater #include "qemu/error-report.h" 3068c07d76SCédric Le Goater #include "qemu/units.h" 31a434fd8fSSteve Sistare #include "migration/cpr.h" 32a434fd8fSSteve Sistare #include "migration/blocker.h" 3368c07d76SCédric Le Goater #include "monitor/monitor.h" 3468c07d76SCédric Le Goater #include "vfio-helpers.h" 3568c07d76SCédric Le Goater 36a997b506SCédric Le Goater VFIODeviceList vfio_device_list = 37a997b506SCédric Le Goater QLIST_HEAD_INITIALIZER(vfio_device_list); 38a997b506SCédric Le Goater 3968c07d76SCédric Le Goater /* 40819a5865SCédric Le Goater * We want to differentiate hot reset of multiple in-use devices vs 41819a5865SCédric Le Goater * hot reset of a single in-use device. VFIO_DEVICE_RESET will already 42819a5865SCédric Le Goater * handle the case of doing hot resets when there is only a single 43819a5865SCédric Le Goater * device per bus. The in-use here refers to how many VFIODevices are 44819a5865SCédric Le Goater * affected. A hot reset that affects multiple devices, but only a 45819a5865SCédric Le Goater * single in-use device, means that we can call it from our bus 46819a5865SCédric Le Goater * ->reset() callback since the extent is effectively a single 47819a5865SCédric Le Goater * device. This allows us to make use of it in the hotplug path. When 48819a5865SCédric Le Goater * there are multiple in-use devices, we can only trigger the hot 49819a5865SCédric Le Goater * reset during a system reset and thus from our reset handler. We 50819a5865SCédric Le Goater * separate _one vs _multi here so that we don't overlap and do a 51819a5865SCédric Le Goater * double reset on the system reset path where both our reset handler 52819a5865SCédric Le Goater * and ->reset() callback are used. Calling _one() will only do a hot 53819a5865SCédric Le Goater * reset for the one in-use devices case, calling _multi() will do 54819a5865SCédric Le Goater * nothing if a _one() would have been sufficient. 55819a5865SCédric Le Goater */ 56e218ccf0SCédric Le Goater void vfio_device_reset_handler(void *opaque) 57819a5865SCédric Le Goater { 58819a5865SCédric Le Goater VFIODevice *vbasedev; 59819a5865SCédric Le Goater 60e218ccf0SCédric Le Goater trace_vfio_device_reset_handler(); 61819a5865SCédric Le Goater QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) { 62819a5865SCédric Le Goater if (vbasedev->dev->realized) { 63819a5865SCédric Le Goater vbasedev->ops->vfio_compute_needs_reset(vbasedev); 64819a5865SCédric Le Goater } 65819a5865SCédric Le Goater } 66819a5865SCédric Le Goater 67819a5865SCédric Le Goater QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) { 68819a5865SCédric Le Goater if (vbasedev->dev->realized && vbasedev->needs_reset) { 69819a5865SCédric Le Goater vbasedev->ops->vfio_hot_reset_multi(vbasedev); 70819a5865SCédric Le Goater } 71819a5865SCédric Le Goater } 72819a5865SCédric Le Goater } 73819a5865SCédric Le Goater 74819a5865SCédric Le Goater /* 7568c07d76SCédric Le Goater * Common VFIO interrupt disable 7668c07d76SCédric Le Goater */ 77e218ccf0SCédric Le Goater void vfio_device_irq_disable(VFIODevice *vbasedev, int index) 7868c07d76SCédric Le Goater { 7968c07d76SCédric Le Goater struct vfio_irq_set irq_set = { 8068c07d76SCédric Le Goater .argsz = sizeof(irq_set), 8168c07d76SCédric Le Goater .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER, 8268c07d76SCédric Le Goater .index = index, 8368c07d76SCédric Le Goater .start = 0, 8468c07d76SCédric Le Goater .count = 0, 8568c07d76SCédric Le Goater }; 8668c07d76SCédric Le Goater 8738bf025dSJohn Levon vbasedev->io_ops->set_irqs(vbasedev, &irq_set); 8868c07d76SCédric Le Goater } 8968c07d76SCédric Le Goater 90e218ccf0SCédric Le Goater void vfio_device_irq_unmask(VFIODevice *vbasedev, int index) 9168c07d76SCédric Le Goater { 9268c07d76SCédric Le Goater struct vfio_irq_set irq_set = { 9368c07d76SCédric Le Goater .argsz = sizeof(irq_set), 9468c07d76SCédric Le Goater .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK, 9568c07d76SCédric Le Goater .index = index, 9668c07d76SCédric Le Goater .start = 0, 9768c07d76SCédric Le Goater .count = 1, 9868c07d76SCédric Le Goater }; 9968c07d76SCédric Le Goater 10038bf025dSJohn Levon vbasedev->io_ops->set_irqs(vbasedev, &irq_set); 10168c07d76SCédric Le Goater } 10268c07d76SCédric Le Goater 103e218ccf0SCédric Le Goater void vfio_device_irq_mask(VFIODevice *vbasedev, int index) 10468c07d76SCédric Le Goater { 10568c07d76SCédric Le Goater struct vfio_irq_set irq_set = { 10668c07d76SCédric Le Goater .argsz = sizeof(irq_set), 10768c07d76SCédric Le Goater .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK, 10868c07d76SCédric Le Goater .index = index, 10968c07d76SCédric Le Goater .start = 0, 11068c07d76SCédric Le Goater .count = 1, 11168c07d76SCédric Le Goater }; 11268c07d76SCédric Le Goater 11338bf025dSJohn Levon vbasedev->io_ops->set_irqs(vbasedev, &irq_set); 11468c07d76SCédric Le Goater } 11568c07d76SCédric Le Goater 11668c07d76SCédric Le Goater static inline const char *action_to_str(int action) 11768c07d76SCédric Le Goater { 11868c07d76SCédric Le Goater switch (action) { 11968c07d76SCédric Le Goater case VFIO_IRQ_SET_ACTION_MASK: 12068c07d76SCédric Le Goater return "MASK"; 12168c07d76SCédric Le Goater case VFIO_IRQ_SET_ACTION_UNMASK: 12268c07d76SCédric Le Goater return "UNMASK"; 12368c07d76SCédric Le Goater case VFIO_IRQ_SET_ACTION_TRIGGER: 12468c07d76SCédric Le Goater return "TRIGGER"; 12568c07d76SCédric Le Goater default: 12668c07d76SCédric Le Goater return "UNKNOWN ACTION"; 12768c07d76SCédric Le Goater } 12868c07d76SCédric Le Goater } 12968c07d76SCédric Le Goater 13068c07d76SCédric Le Goater static const char *index_to_str(VFIODevice *vbasedev, int index) 13168c07d76SCédric Le Goater { 13268c07d76SCédric Le Goater if (vbasedev->type != VFIO_DEVICE_TYPE_PCI) { 13368c07d76SCédric Le Goater return NULL; 13468c07d76SCédric Le Goater } 13568c07d76SCédric Le Goater 13668c07d76SCédric Le Goater switch (index) { 13768c07d76SCédric Le Goater case VFIO_PCI_INTX_IRQ_INDEX: 13868c07d76SCédric Le Goater return "INTX"; 13968c07d76SCédric Le Goater case VFIO_PCI_MSI_IRQ_INDEX: 14068c07d76SCédric Le Goater return "MSI"; 14168c07d76SCédric Le Goater case VFIO_PCI_MSIX_IRQ_INDEX: 14268c07d76SCédric Le Goater return "MSIX"; 14368c07d76SCédric Le Goater case VFIO_PCI_ERR_IRQ_INDEX: 14468c07d76SCédric Le Goater return "ERR"; 14568c07d76SCédric Le Goater case VFIO_PCI_REQ_IRQ_INDEX: 14668c07d76SCédric Le Goater return "REQ"; 14768c07d76SCédric Le Goater default: 14868c07d76SCédric Le Goater return NULL; 14968c07d76SCédric Le Goater } 15068c07d76SCédric Le Goater } 15168c07d76SCédric Le Goater 152e218ccf0SCédric Le Goater bool vfio_device_irq_set_signaling(VFIODevice *vbasedev, int index, int subindex, 15368c07d76SCédric Le Goater int action, int fd, Error **errp) 15468c07d76SCédric Le Goater { 15568c07d76SCédric Le Goater ERRP_GUARD(); 15668c07d76SCédric Le Goater g_autofree struct vfio_irq_set *irq_set = NULL; 15768c07d76SCédric Le Goater int argsz; 15868c07d76SCédric Le Goater const char *name; 15968c07d76SCédric Le Goater int32_t *pfd; 16068c07d76SCédric Le Goater 16168c07d76SCédric Le Goater argsz = sizeof(*irq_set) + sizeof(*pfd); 16268c07d76SCédric Le Goater 16368c07d76SCédric Le Goater irq_set = g_malloc0(argsz); 16468c07d76SCédric Le Goater irq_set->argsz = argsz; 16568c07d76SCédric Le Goater irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | action; 16668c07d76SCédric Le Goater irq_set->index = index; 16768c07d76SCédric Le Goater irq_set->start = subindex; 16868c07d76SCédric Le Goater irq_set->count = 1; 16968c07d76SCédric Le Goater pfd = (int32_t *)&irq_set->data; 17068c07d76SCédric Le Goater *pfd = fd; 17168c07d76SCédric Le Goater 17238bf025dSJohn Levon if (!vbasedev->io_ops->set_irqs(vbasedev, irq_set)) { 17368c07d76SCédric Le Goater return true; 17468c07d76SCédric Le Goater } 17568c07d76SCédric Le Goater 17668c07d76SCédric Le Goater error_setg_errno(errp, errno, "VFIO_DEVICE_SET_IRQS failure"); 17768c07d76SCédric Le Goater 17868c07d76SCédric Le Goater name = index_to_str(vbasedev, index); 17968c07d76SCédric Le Goater if (name) { 18068c07d76SCédric Le Goater error_prepend(errp, "%s-%d: ", name, subindex); 18168c07d76SCédric Le Goater } else { 18268c07d76SCédric Le Goater error_prepend(errp, "index %d-%d: ", index, subindex); 18368c07d76SCédric Le Goater } 18468c07d76SCédric Le Goater error_prepend(errp, 18568c07d76SCédric Le Goater "Failed to %s %s eventfd signaling for interrupt ", 18668c07d76SCédric Le Goater fd < 0 ? "tear down" : "set up", action_to_str(action)); 18768c07d76SCédric Le Goater return false; 18868c07d76SCédric Le Goater } 18968c07d76SCédric Le Goater 1905321e623SJohn Levon int vfio_device_get_irq_info(VFIODevice *vbasedev, int index, 1915321e623SJohn Levon struct vfio_irq_info *info) 1925321e623SJohn Levon { 1935321e623SJohn Levon memset(info, 0, sizeof(*info)); 1945321e623SJohn Levon 1955321e623SJohn Levon info->argsz = sizeof(*info); 1965321e623SJohn Levon info->index = index; 1975321e623SJohn Levon 19838bf025dSJohn Levon return vbasedev->io_ops->get_irq_info(vbasedev, info); 1995321e623SJohn Levon } 2005321e623SJohn Levon 201e218ccf0SCédric Le Goater int vfio_device_get_region_info(VFIODevice *vbasedev, int index, 20268c07d76SCédric Le Goater struct vfio_region_info **info) 20368c07d76SCédric Le Goater { 20468c07d76SCédric Le Goater size_t argsz = sizeof(struct vfio_region_info); 20559adfc6fSJohn Levon int fd = -1; 20638bf025dSJohn Levon int ret; 20768c07d76SCédric Le Goater 20895cdb024SJohn Levon /* check cache */ 20995cdb024SJohn Levon if (vbasedev->reginfo[index] != NULL) { 21095cdb024SJohn Levon *info = vbasedev->reginfo[index]; 21195cdb024SJohn Levon return 0; 21295cdb024SJohn Levon } 21395cdb024SJohn Levon 21468c07d76SCédric Le Goater *info = g_malloc0(argsz); 21568c07d76SCédric Le Goater 21668c07d76SCédric Le Goater (*info)->index = index; 21768c07d76SCédric Le Goater retry: 21868c07d76SCédric Le Goater (*info)->argsz = argsz; 21968c07d76SCédric Le Goater 22059adfc6fSJohn Levon ret = vbasedev->io_ops->get_region_info(vbasedev, *info, &fd); 22138bf025dSJohn Levon if (ret != 0) { 22268c07d76SCédric Le Goater g_free(*info); 22368c07d76SCédric Le Goater *info = NULL; 22438bf025dSJohn Levon return ret; 22568c07d76SCédric Le Goater } 22668c07d76SCédric Le Goater 22768c07d76SCédric Le Goater if ((*info)->argsz > argsz) { 22868c07d76SCédric Le Goater argsz = (*info)->argsz; 22968c07d76SCédric Le Goater *info = g_realloc(*info, argsz); 23068c07d76SCédric Le Goater 23159adfc6fSJohn Levon if (fd != -1) { 23259adfc6fSJohn Levon close(fd); 23359adfc6fSJohn Levon fd = -1; 23459adfc6fSJohn Levon } 23559adfc6fSJohn Levon 23668c07d76SCédric Le Goater goto retry; 23768c07d76SCédric Le Goater } 23868c07d76SCédric Le Goater 23995cdb024SJohn Levon /* fill cache */ 24095cdb024SJohn Levon vbasedev->reginfo[index] = *info; 24159adfc6fSJohn Levon if (vbasedev->region_fds != NULL) { 24259adfc6fSJohn Levon vbasedev->region_fds[index] = fd; 24359adfc6fSJohn Levon } 24495cdb024SJohn Levon 24568c07d76SCédric Le Goater return 0; 24668c07d76SCédric Le Goater } 24768c07d76SCédric Le Goater 248b1f521deSJohn Levon int vfio_device_get_region_fd(VFIODevice *vbasedev, int index) 249b1f521deSJohn Levon { 250b1f521deSJohn Levon return vbasedev->region_fds ? 251b1f521deSJohn Levon vbasedev->region_fds[index] : 252b1f521deSJohn Levon vbasedev->fd; 253b1f521deSJohn Levon } 254b1f521deSJohn Levon 255e218ccf0SCédric Le Goater int vfio_device_get_region_info_type(VFIODevice *vbasedev, uint32_t type, 25668c07d76SCédric Le Goater uint32_t subtype, struct vfio_region_info **info) 25768c07d76SCédric Le Goater { 25868c07d76SCédric Le Goater int i; 25968c07d76SCédric Le Goater 26068c07d76SCédric Le Goater for (i = 0; i < vbasedev->num_regions; i++) { 26168c07d76SCédric Le Goater struct vfio_info_cap_header *hdr; 26268c07d76SCédric Le Goater struct vfio_region_info_cap_type *cap_type; 26368c07d76SCédric Le Goater 264e218ccf0SCédric Le Goater if (vfio_device_get_region_info(vbasedev, i, info)) { 26568c07d76SCédric Le Goater continue; 26668c07d76SCédric Le Goater } 26768c07d76SCédric Le Goater 26868c07d76SCédric Le Goater hdr = vfio_get_region_info_cap(*info, VFIO_REGION_INFO_CAP_TYPE); 26968c07d76SCédric Le Goater if (!hdr) { 27068c07d76SCédric Le Goater continue; 27168c07d76SCédric Le Goater } 27268c07d76SCédric Le Goater 27368c07d76SCédric Le Goater cap_type = container_of(hdr, struct vfio_region_info_cap_type, header); 27468c07d76SCédric Le Goater 275e218ccf0SCédric Le Goater trace_vfio_device_get_region_info_type(vbasedev->name, i, 27668c07d76SCédric Le Goater cap_type->type, cap_type->subtype); 27768c07d76SCédric Le Goater 27868c07d76SCédric Le Goater if (cap_type->type == type && cap_type->subtype == subtype) { 27968c07d76SCédric Le Goater return 0; 28068c07d76SCédric Le Goater } 28168c07d76SCédric Le Goater } 28268c07d76SCédric Le Goater 28368c07d76SCédric Le Goater *info = NULL; 28468c07d76SCédric Le Goater return -ENODEV; 28568c07d76SCédric Le Goater } 28668c07d76SCédric Le Goater 287e218ccf0SCédric Le Goater bool vfio_device_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type) 28868c07d76SCédric Le Goater { 28995cdb024SJohn Levon struct vfio_region_info *info = NULL; 29068c07d76SCédric Le Goater bool ret = false; 29168c07d76SCédric Le Goater 292e218ccf0SCédric Le Goater if (!vfio_device_get_region_info(vbasedev, region, &info)) { 29368c07d76SCédric Le Goater if (vfio_get_region_info_cap(info, cap_type)) { 29468c07d76SCédric Le Goater ret = true; 29568c07d76SCédric Le Goater } 29668c07d76SCédric Le Goater } 29768c07d76SCédric Le Goater 29868c07d76SCédric Le Goater return ret; 29968c07d76SCédric Le Goater } 30068c07d76SCédric Le Goater 30168c07d76SCédric Le Goater bool vfio_device_get_name(VFIODevice *vbasedev, Error **errp) 30268c07d76SCédric Le Goater { 30368c07d76SCédric Le Goater ERRP_GUARD(); 30468c07d76SCédric Le Goater struct stat st; 30568c07d76SCédric Le Goater 30668c07d76SCédric Le Goater if (vbasedev->fd < 0) { 30768c07d76SCédric Le Goater if (stat(vbasedev->sysfsdev, &st) < 0) { 30868c07d76SCédric Le Goater error_setg_errno(errp, errno, "no such host device"); 30968c07d76SCédric Le Goater error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->sysfsdev); 31068c07d76SCédric Le Goater return false; 31168c07d76SCédric Le Goater } 31268c07d76SCédric Le Goater /* User may specify a name, e.g: VFIO platform device */ 31368c07d76SCédric Le Goater if (!vbasedev->name) { 31468c07d76SCédric Le Goater vbasedev->name = g_path_get_basename(vbasedev->sysfsdev); 31568c07d76SCédric Le Goater } 31668c07d76SCédric Le Goater } else { 31768c07d76SCédric Le Goater if (!vbasedev->iommufd) { 31868c07d76SCédric Le Goater error_setg(errp, "Use FD passing only with iommufd backend"); 31968c07d76SCédric Le Goater return false; 32068c07d76SCédric Le Goater } 32168c07d76SCédric Le Goater if (!vbasedev->name) { 322b9b389b9SSteve Sistare 323b9b389b9SSteve Sistare if (vbasedev->dev->id) { 324b9b389b9SSteve Sistare vbasedev->name = g_strdup(vbasedev->dev->id); 325b9b389b9SSteve Sistare return true; 326b9b389b9SSteve Sistare } else { 327b9b389b9SSteve Sistare /* 328b9b389b9SSteve Sistare * Assign a name so any function printing it will not break. 329a434fd8fSSteve Sistare * The fd number changes across processes, so this cannot be 330a434fd8fSSteve Sistare * used as an invariant name for CPR. 331b9b389b9SSteve Sistare */ 33268c07d76SCédric Le Goater vbasedev->name = g_strdup_printf("VFIO_FD%d", vbasedev->fd); 333a434fd8fSSteve Sistare error_setg(&vbasedev->cpr.id_blocker, 334a434fd8fSSteve Sistare "vfio device with fd=%d needs an id property", 335a434fd8fSSteve Sistare vbasedev->fd); 336a434fd8fSSteve Sistare return migrate_add_blocker_modes(&vbasedev->cpr.id_blocker, 337a434fd8fSSteve Sistare errp, MIG_MODE_CPR_TRANSFER, 338a434fd8fSSteve Sistare -1) == 0; 33968c07d76SCédric Le Goater } 34068c07d76SCédric Le Goater } 341b9b389b9SSteve Sistare } 34268c07d76SCédric Le Goater 34368c07d76SCédric Le Goater return true; 34468c07d76SCédric Le Goater } 34568c07d76SCédric Le Goater 346184053f0SSteve Sistare void vfio_device_free_name(VFIODevice *vbasedev) 347184053f0SSteve Sistare { 348184053f0SSteve Sistare g_clear_pointer(&vbasedev->name, g_free); 349a434fd8fSSteve Sistare migrate_del_blocker(&vbasedev->cpr.id_blocker); 350184053f0SSteve Sistare } 351184053f0SSteve Sistare 35268c07d76SCédric Le Goater void vfio_device_set_fd(VFIODevice *vbasedev, const char *str, Error **errp) 35368c07d76SCédric Le Goater { 3542a3f0a59SSteve Sistare vbasedev->fd = cpr_get_fd_param(vbasedev->dev->id, str, 0, errp); 35568c07d76SCédric Le Goater } 35668c07d76SCédric Le Goater 35738bf025dSJohn Levon static VFIODeviceIOOps vfio_device_io_ops_ioctl; 35838bf025dSJohn Levon 35968c07d76SCédric Le Goater void vfio_device_init(VFIODevice *vbasedev, int type, VFIODeviceOps *ops, 36068c07d76SCédric Le Goater DeviceState *dev, bool ram_discard) 36168c07d76SCédric Le Goater { 36268c07d76SCédric Le Goater vbasedev->type = type; 36368c07d76SCédric Le Goater vbasedev->ops = ops; 36438bf025dSJohn Levon vbasedev->io_ops = &vfio_device_io_ops_ioctl; 36568c07d76SCédric Le Goater vbasedev->dev = dev; 36668c07d76SCédric Le Goater vbasedev->fd = -1; 36759adfc6fSJohn Levon vbasedev->use_region_fds = false; 36868c07d76SCédric Le Goater 36968c07d76SCédric Le Goater vbasedev->ram_block_discard_allowed = ram_discard; 37068c07d76SCédric Le Goater } 37168c07d76SCédric Le Goater 37268c07d76SCédric Le Goater int vfio_device_get_aw_bits(VFIODevice *vdev) 37368c07d76SCédric Le Goater { 37468c07d76SCédric Le Goater /* 37568c07d76SCédric Le Goater * iova_ranges is a sorted list. For old kernels that support 37668c07d76SCédric Le Goater * VFIO but not support query of iova ranges, iova_ranges is NULL, 37768c07d76SCédric Le Goater * in this case HOST_IOMMU_DEVICE_CAP_AW_BITS_MAX(64) is returned. 37868c07d76SCédric Le Goater */ 37968c07d76SCédric Le Goater GList *l = g_list_last(vdev->bcontainer->iova_ranges); 38068c07d76SCédric Le Goater 38168c07d76SCédric Le Goater if (l) { 38268c07d76SCédric Le Goater Range *range = l->data; 38368c07d76SCédric Le Goater return range_get_last_bit(range) + 1; 38468c07d76SCédric Le Goater } 38568c07d76SCédric Le Goater 38668c07d76SCédric Le Goater return HOST_IOMMU_DEVICE_CAP_AW_BITS_MAX; 38768c07d76SCédric Le Goater } 38868c07d76SCédric Le Goater 38968c07d76SCédric Le Goater bool vfio_device_is_mdev(VFIODevice *vbasedev) 39068c07d76SCédric Le Goater { 39168c07d76SCédric Le Goater g_autofree char *subsys = NULL; 39268c07d76SCédric Le Goater g_autofree char *tmp = NULL; 39368c07d76SCédric Le Goater 39468c07d76SCédric Le Goater if (!vbasedev->sysfsdev) { 39568c07d76SCédric Le Goater return false; 39668c07d76SCédric Le Goater } 39768c07d76SCédric Le Goater 39868c07d76SCédric Le Goater tmp = g_strdup_printf("%s/subsystem", vbasedev->sysfsdev); 39968c07d76SCédric Le Goater subsys = realpath(tmp, NULL); 40068c07d76SCédric Le Goater return subsys && (strcmp(subsys, "/sys/bus/mdev") == 0); 40168c07d76SCédric Le Goater } 40268c07d76SCédric Le Goater 4030805f829SZhenzhong Duan bool vfio_device_hiod_create_and_realize(VFIODevice *vbasedev, 4040805f829SZhenzhong Duan const char *typename, Error **errp) 40568c07d76SCédric Le Goater { 4060805f829SZhenzhong Duan HostIOMMUDevice *hiod; 40768c07d76SCédric Le Goater 4080805f829SZhenzhong Duan if (vbasedev->mdev) { 40968c07d76SCédric Le Goater return true; 41068c07d76SCédric Le Goater } 41168c07d76SCédric Le Goater 4120805f829SZhenzhong Duan hiod = HOST_IOMMU_DEVICE(object_new(typename)); 4130805f829SZhenzhong Duan 4140805f829SZhenzhong Duan if (!HOST_IOMMU_DEVICE_GET_CLASS(hiod)->realize(hiod, vbasedev, errp)) { 4150805f829SZhenzhong Duan object_unref(hiod); 4160805f829SZhenzhong Duan return false; 4170805f829SZhenzhong Duan } 4180805f829SZhenzhong Duan 4190805f829SZhenzhong Duan vbasedev->hiod = hiod; 4200805f829SZhenzhong Duan return true; 42168c07d76SCédric Le Goater } 42268c07d76SCédric Le Goater 42368c07d76SCédric Le Goater VFIODevice *vfio_get_vfio_device(Object *obj) 42468c07d76SCédric Le Goater { 42568c07d76SCédric Le Goater if (object_dynamic_cast(obj, TYPE_VFIO_PCI)) { 426d4e392d0SJohn Levon return &VFIO_PCI_BASE(obj)->vbasedev; 42768c07d76SCédric Le Goater } else { 42868c07d76SCédric Le Goater return NULL; 42968c07d76SCédric Le Goater } 43068c07d76SCédric Le Goater } 431923b1141SCédric Le Goater 432ef73671fSJohn Levon bool vfio_device_attach_by_iommu_type(const char *iommu_type, char *name, 433ef73671fSJohn Levon VFIODevice *vbasedev, AddressSpace *as, 434ef73671fSJohn Levon Error **errp) 435923b1141SCédric Le Goater { 436923b1141SCédric Le Goater const VFIOIOMMUClass *ops = 437ef73671fSJohn Levon VFIO_IOMMU_CLASS(object_class_by_name(iommu_type)); 438923b1141SCédric Le Goater 439923b1141SCédric Le Goater assert(ops); 440923b1141SCédric Le Goater 4410805f829SZhenzhong Duan return ops->attach_device(name, vbasedev, as, errp); 442923b1141SCédric Le Goater } 443923b1141SCédric Le Goater 444ef73671fSJohn Levon bool vfio_device_attach(char *name, VFIODevice *vbasedev, 445ef73671fSJohn Levon AddressSpace *as, Error **errp) 446ef73671fSJohn Levon { 447ef73671fSJohn Levon const char *iommu_type = vbasedev->iommufd ? 448ef73671fSJohn Levon TYPE_VFIO_IOMMU_IOMMUFD : 449ef73671fSJohn Levon TYPE_VFIO_IOMMU_LEGACY; 450ef73671fSJohn Levon 451ef73671fSJohn Levon return vfio_device_attach_by_iommu_type(iommu_type, name, vbasedev, 452ef73671fSJohn Levon as, errp); 453ef73671fSJohn Levon } 454ef73671fSJohn Levon 455e218ccf0SCédric Le Goater void vfio_device_detach(VFIODevice *vbasedev) 456923b1141SCédric Le Goater { 457923b1141SCédric Le Goater if (!vbasedev->bcontainer) { 458923b1141SCédric Le Goater return; 459923b1141SCédric Le Goater } 460923b1141SCédric Le Goater VFIO_IOMMU_GET_CLASS(vbasedev->bcontainer)->detach_device(vbasedev); 461923b1141SCédric Le Goater } 462a901682fSJohn Levon 463a901682fSJohn Levon void vfio_device_prepare(VFIODevice *vbasedev, VFIOContainerBase *bcontainer, 464a901682fSJohn Levon struct vfio_device_info *info) 465a901682fSJohn Levon { 466*09353802SJohn Levon int i; 467*09353802SJohn Levon 468a901682fSJohn Levon vbasedev->num_irqs = info->num_irqs; 469a901682fSJohn Levon vbasedev->num_regions = info->num_regions; 470a901682fSJohn Levon vbasedev->flags = info->flags; 471a901682fSJohn Levon vbasedev->reset_works = !!(info->flags & VFIO_DEVICE_FLAGS_RESET); 472a901682fSJohn Levon 473a901682fSJohn Levon vbasedev->bcontainer = bcontainer; 474a901682fSJohn Levon QLIST_INSERT_HEAD(&bcontainer->device_list, vbasedev, container_next); 475a901682fSJohn Levon 476a901682fSJohn Levon QLIST_INSERT_HEAD(&vfio_device_list, vbasedev, global_next); 47795cdb024SJohn Levon 47895cdb024SJohn Levon vbasedev->reginfo = g_new0(struct vfio_region_info *, 47995cdb024SJohn Levon vbasedev->num_regions); 48059adfc6fSJohn Levon if (vbasedev->use_region_fds) { 48159adfc6fSJohn Levon vbasedev->region_fds = g_new0(int, vbasedev->num_regions); 482*09353802SJohn Levon for (i = 0; i < vbasedev->num_regions; i++) { 483*09353802SJohn Levon vbasedev->region_fds[i] = -1; 484*09353802SJohn Levon } 48559adfc6fSJohn Levon } 486a901682fSJohn Levon } 487d60fb709SJohn Levon 488d60fb709SJohn Levon void vfio_device_unprepare(VFIODevice *vbasedev) 489d60fb709SJohn Levon { 49095cdb024SJohn Levon int i; 49195cdb024SJohn Levon 49295cdb024SJohn Levon for (i = 0; i < vbasedev->num_regions; i++) { 49395cdb024SJohn Levon g_free(vbasedev->reginfo[i]); 49459adfc6fSJohn Levon if (vbasedev->region_fds != NULL && vbasedev->region_fds[i] != -1) { 49559adfc6fSJohn Levon close(vbasedev->region_fds[i]); 49695cdb024SJohn Levon } 49759adfc6fSJohn Levon } 49859adfc6fSJohn Levon 49959adfc6fSJohn Levon g_clear_pointer(&vbasedev->reginfo, g_free); 50059adfc6fSJohn Levon g_clear_pointer(&vbasedev->region_fds, g_free); 50195cdb024SJohn Levon 502d60fb709SJohn Levon QLIST_REMOVE(vbasedev, container_next); 503d60fb709SJohn Levon QLIST_REMOVE(vbasedev, global_next); 504d60fb709SJohn Levon vbasedev->bcontainer = NULL; 505d60fb709SJohn Levon } 50638bf025dSJohn Levon 50738bf025dSJohn Levon /* 50838bf025dSJohn Levon * Traditional ioctl() based io 50938bf025dSJohn Levon */ 51038bf025dSJohn Levon 51138bf025dSJohn Levon static int vfio_device_io_device_feature(VFIODevice *vbasedev, 51238bf025dSJohn Levon struct vfio_device_feature *feature) 51338bf025dSJohn Levon { 51438bf025dSJohn Levon int ret; 51538bf025dSJohn Levon 51638bf025dSJohn Levon ret = ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature); 51738bf025dSJohn Levon 51838bf025dSJohn Levon return ret < 0 ? -errno : ret; 51938bf025dSJohn Levon } 52038bf025dSJohn Levon 52138bf025dSJohn Levon static int vfio_device_io_get_region_info(VFIODevice *vbasedev, 52259adfc6fSJohn Levon struct vfio_region_info *info, 52359adfc6fSJohn Levon int *fd) 52438bf025dSJohn Levon { 52538bf025dSJohn Levon int ret; 52638bf025dSJohn Levon 52759adfc6fSJohn Levon *fd = -1; 52859adfc6fSJohn Levon 52938bf025dSJohn Levon ret = ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, info); 53038bf025dSJohn Levon 53138bf025dSJohn Levon return ret < 0 ? -errno : ret; 53238bf025dSJohn Levon } 53338bf025dSJohn Levon 53438bf025dSJohn Levon static int vfio_device_io_get_irq_info(VFIODevice *vbasedev, 53538bf025dSJohn Levon struct vfio_irq_info *info) 53638bf025dSJohn Levon { 53738bf025dSJohn Levon int ret; 53838bf025dSJohn Levon 53938bf025dSJohn Levon ret = ioctl(vbasedev->fd, VFIO_DEVICE_GET_IRQ_INFO, info); 54038bf025dSJohn Levon 54138bf025dSJohn Levon return ret < 0 ? -errno : ret; 54238bf025dSJohn Levon } 54338bf025dSJohn Levon 54438bf025dSJohn Levon static int vfio_device_io_set_irqs(VFIODevice *vbasedev, 54538bf025dSJohn Levon struct vfio_irq_set *irqs) 54638bf025dSJohn Levon { 54738bf025dSJohn Levon int ret; 54838bf025dSJohn Levon 54938bf025dSJohn Levon ret = ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, irqs); 55038bf025dSJohn Levon 55138bf025dSJohn Levon return ret < 0 ? -errno : ret; 55238bf025dSJohn Levon } 55338bf025dSJohn Levon 554776066acSJohn Levon static int vfio_device_io_region_read(VFIODevice *vbasedev, uint8_t index, 555776066acSJohn Levon off_t off, uint32_t size, void *data) 556776066acSJohn Levon { 557776066acSJohn Levon struct vfio_region_info *info; 558776066acSJohn Levon int ret; 559776066acSJohn Levon 560776066acSJohn Levon ret = vfio_device_get_region_info(vbasedev, index, &info); 561776066acSJohn Levon if (ret != 0) { 562776066acSJohn Levon return ret; 563776066acSJohn Levon } 564776066acSJohn Levon 565776066acSJohn Levon ret = pread(vbasedev->fd, data, size, info->offset + off); 566776066acSJohn Levon 567776066acSJohn Levon return ret < 0 ? -errno : ret; 568776066acSJohn Levon } 569776066acSJohn Levon 570776066acSJohn Levon static int vfio_device_io_region_write(VFIODevice *vbasedev, uint8_t index, 571a574b061SJohn Levon off_t off, uint32_t size, void *data, 572a574b061SJohn Levon bool post) 573776066acSJohn Levon { 574776066acSJohn Levon struct vfio_region_info *info; 575776066acSJohn Levon int ret; 576776066acSJohn Levon 577776066acSJohn Levon ret = vfio_device_get_region_info(vbasedev, index, &info); 578776066acSJohn Levon if (ret != 0) { 579776066acSJohn Levon return ret; 580776066acSJohn Levon } 581776066acSJohn Levon 582776066acSJohn Levon ret = pwrite(vbasedev->fd, data, size, info->offset + off); 583776066acSJohn Levon 584776066acSJohn Levon return ret < 0 ? -errno : ret; 585776066acSJohn Levon } 586776066acSJohn Levon 58738bf025dSJohn Levon static VFIODeviceIOOps vfio_device_io_ops_ioctl = { 58838bf025dSJohn Levon .device_feature = vfio_device_io_device_feature, 58938bf025dSJohn Levon .get_region_info = vfio_device_io_get_region_info, 59038bf025dSJohn Levon .get_irq_info = vfio_device_io_get_irq_info, 59138bf025dSJohn Levon .set_irqs = vfio_device_io_set_irqs, 592776066acSJohn Levon .region_read = vfio_device_io_region_read, 593776066acSJohn Levon .region_write = vfio_device_io_region_write, 59438bf025dSJohn Levon }; 595