Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 1 | /* |
| 2 | * common header for vfio based device assignment support |
| 3 | * |
| 4 | * Copyright Red Hat, Inc. 2012 |
| 5 | * |
| 6 | * Authors: |
| 7 | * Alex Williamson <alex.williamson@redhat.com> |
| 8 | * |
| 9 | * This work is licensed under the terms of the GNU GPL, version 2. See |
| 10 | * the COPYING file in the top-level directory. |
| 11 | * |
| 12 | * Based on qemu-kvm device-assignment: |
| 13 | * Adapted for KVM by Qumranet. |
| 14 | * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com) |
| 15 | * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com) |
| 16 | * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com) |
| 17 | * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com) |
| 18 | * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com) |
| 19 | */ |
Markus Armbruster | 175de52 | 2016-06-29 15:29:06 +0200 | [diff] [blame] | 20 | |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 21 | #ifndef HW_VFIO_VFIO_COMMON_H |
| 22 | #define HW_VFIO_VFIO_COMMON_H |
| 23 | |
| 24 | #include "qemu-common.h" |
| 25 | #include "exec/address-spaces.h" |
| 26 | #include "exec/memory.h" |
| 27 | #include "qemu/queue.h" |
| 28 | #include "qemu/notify.h" |
Alex Williamson | 4690022 | 2016-03-10 09:39:07 -0700 | [diff] [blame] | 29 | #ifdef CONFIG_LINUX |
| 30 | #include <linux/vfio.h> |
| 31 | #endif |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 32 | |
Eric Auger | 426ec90 | 2016-10-17 10:57:56 -0600 | [diff] [blame] | 33 | #define ERR_PREFIX "vfio error: %s: " |
| 34 | #define WARN_PREFIX "vfio warning: %s: " |
| 35 | |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 36 | /*#define DEBUG_VFIO*/ |
| 37 | #ifdef DEBUG_VFIO |
| 38 | #define DPRINTF(fmt, ...) \ |
| 39 | do { fprintf(stderr, "vfio: " fmt, ## __VA_ARGS__); } while (0) |
| 40 | #else |
| 41 | #define DPRINTF(fmt, ...) \ |
| 42 | do { } while (0) |
| 43 | #endif |
| 44 | |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 45 | enum { |
| 46 | VFIO_DEVICE_TYPE_PCI = 0, |
Eric Auger | 0ea2730 | 2015-06-08 09:25:25 -0600 | [diff] [blame] | 47 | VFIO_DEVICE_TYPE_PLATFORM = 1, |
Xiao Feng Ren | 1dcac3e | 2017-05-17 02:48:07 +0200 | [diff] [blame] | 48 | VFIO_DEVICE_TYPE_CCW = 2, |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 49 | }; |
| 50 | |
Alex Williamson | db0da02 | 2016-03-10 09:39:07 -0700 | [diff] [blame] | 51 | typedef struct VFIOMmap { |
| 52 | MemoryRegion mem; |
| 53 | void *mmap; |
| 54 | off_t offset; |
| 55 | size_t size; |
| 56 | } VFIOMmap; |
| 57 | |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 58 | typedef struct VFIORegion { |
| 59 | struct VFIODevice *vbasedev; |
| 60 | off_t fd_offset; /* offset of region within device fd */ |
Alex Williamson | db0da02 | 2016-03-10 09:39:07 -0700 | [diff] [blame] | 61 | MemoryRegion *mem; /* slow, read/write access */ |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 62 | size_t size; |
| 63 | uint32_t flags; /* VFIO region flags (rd/wr/mmap) */ |
Alex Williamson | db0da02 | 2016-03-10 09:39:07 -0700 | [diff] [blame] | 64 | uint32_t nr_mmaps; |
| 65 | VFIOMmap *mmaps; |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 66 | uint8_t nr; /* cache the region number for debug */ |
| 67 | } VFIORegion; |
| 68 | |
| 69 | typedef struct VFIOAddressSpace { |
| 70 | AddressSpace *as; |
| 71 | QLIST_HEAD(, VFIOContainer) containers; |
| 72 | QLIST_ENTRY(VFIOAddressSpace) list; |
| 73 | } VFIOAddressSpace; |
| 74 | |
| 75 | struct VFIOGroup; |
| 76 | |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 77 | typedef struct VFIOContainer { |
| 78 | VFIOAddressSpace *space; |
| 79 | int fd; /* /dev/vfio/vfio, empowered by the attached groups */ |
David Gibson | ee0bf0e | 2015-09-30 12:13:51 +1000 | [diff] [blame] | 80 | MemoryListener listener; |
Alexey Kardashevskiy | 318f67c | 2016-07-04 13:33:04 +1000 | [diff] [blame] | 81 | MemoryListener prereg_listener; |
| 82 | unsigned iommu_type; |
David Gibson | ee0bf0e | 2015-09-30 12:13:51 +1000 | [diff] [blame] | 83 | int error; |
| 84 | bool initialized; |
David Gibson | 3898aad | 2015-09-30 12:13:53 +1000 | [diff] [blame] | 85 | /* |
| 86 | * This assumes the host IOMMU can support only a single |
| 87 | * contiguous IOVA window. We may need to generalize that in |
| 88 | * future |
| 89 | */ |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 90 | QLIST_HEAD(, VFIOGuestIOMMU) giommu_list; |
Alexey Kardashevskiy | f4ec5e2 | 2016-07-04 13:33:05 +1000 | [diff] [blame] | 91 | QLIST_HEAD(, VFIOHostDMAWindow) hostwin_list; |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 92 | QLIST_HEAD(, VFIOGroup) group_list; |
| 93 | QLIST_ENTRY(VFIOContainer) next; |
| 94 | } VFIOContainer; |
| 95 | |
| 96 | typedef struct VFIOGuestIOMMU { |
| 97 | VFIOContainer *container; |
| 98 | MemoryRegion *iommu; |
Alexey Kardashevskiy | d78c19b | 2016-05-26 09:43:23 -0600 | [diff] [blame] | 99 | hwaddr iommu_offset; |
Peter Xu | cdb3081 | 2016-09-23 13:02:26 +0800 | [diff] [blame] | 100 | IOMMUNotifier n; |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 101 | QLIST_ENTRY(VFIOGuestIOMMU) giommu_next; |
| 102 | } VFIOGuestIOMMU; |
| 103 | |
Alexey Kardashevskiy | f4ec5e2 | 2016-07-04 13:33:05 +1000 | [diff] [blame] | 104 | typedef struct VFIOHostDMAWindow { |
| 105 | hwaddr min_iova; |
| 106 | hwaddr max_iova; |
| 107 | uint64_t iova_pgsizes; |
| 108 | QLIST_ENTRY(VFIOHostDMAWindow) hostwin_next; |
| 109 | } VFIOHostDMAWindow; |
| 110 | |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 111 | typedef struct VFIODeviceOps VFIODeviceOps; |
| 112 | |
| 113 | typedef struct VFIODevice { |
| 114 | QLIST_ENTRY(VFIODevice) next; |
| 115 | struct VFIOGroup *group; |
Alex Williamson | 7df9381 | 2016-03-10 09:39:07 -0700 | [diff] [blame] | 116 | char *sysfsdev; |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 117 | char *name; |
| 118 | int fd; |
| 119 | int type; |
| 120 | bool reset_works; |
| 121 | bool needs_reset; |
Alex Williamson | 5e15d79 | 2015-09-23 13:04:44 -0600 | [diff] [blame] | 122 | bool no_mmap; |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 123 | VFIODeviceOps *ops; |
| 124 | unsigned int num_irqs; |
| 125 | unsigned int num_regions; |
| 126 | unsigned int flags; |
| 127 | } VFIODevice; |
| 128 | |
| 129 | struct VFIODeviceOps { |
| 130 | void (*vfio_compute_needs_reset)(VFIODevice *vdev); |
| 131 | int (*vfio_hot_reset_multi)(VFIODevice *vdev); |
| 132 | void (*vfio_eoi)(VFIODevice *vdev); |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 133 | }; |
| 134 | |
| 135 | typedef struct VFIOGroup { |
| 136 | int fd; |
| 137 | int groupid; |
| 138 | VFIOContainer *container; |
| 139 | QLIST_HEAD(, VFIODevice) device_list; |
| 140 | QLIST_ENTRY(VFIOGroup) next; |
| 141 | QLIST_ENTRY(VFIOGroup) container_next; |
| 142 | } VFIOGroup; |
| 143 | |
| 144 | void vfio_put_base_device(VFIODevice *vbasedev); |
| 145 | void vfio_disable_irqindex(VFIODevice *vbasedev, int index); |
| 146 | void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index); |
| 147 | void vfio_mask_single_irqindex(VFIODevice *vbasedev, int index); |
| 148 | void vfio_region_write(void *opaque, hwaddr addr, |
| 149 | uint64_t data, unsigned size); |
| 150 | uint64_t vfio_region_read(void *opaque, |
| 151 | hwaddr addr, unsigned size); |
Alex Williamson | db0da02 | 2016-03-10 09:39:07 -0700 | [diff] [blame] | 152 | int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region, |
| 153 | int index, const char *name); |
| 154 | int vfio_region_mmap(VFIORegion *region); |
| 155 | void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled); |
| 156 | void vfio_region_exit(VFIORegion *region); |
| 157 | void vfio_region_finalize(VFIORegion *region); |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 158 | void vfio_reset_handler(void *opaque); |
Eric Auger | 1b808d5 | 2016-10-17 10:57:59 -0600 | [diff] [blame] | 159 | VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp); |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 160 | void vfio_put_group(VFIOGroup *group); |
| 161 | int vfio_get_device(VFIOGroup *group, const char *name, |
Eric Auger | 59f7d67 | 2016-10-17 10:58:00 -0600 | [diff] [blame] | 162 | VFIODevice *vbasedev, Error **errp); |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 163 | |
| 164 | extern const MemoryRegionOps vfio_region_ops; |
Eric Auger | e2c7d02 | 2014-12-22 09:54:51 -0700 | [diff] [blame] | 165 | extern QLIST_HEAD(vfio_group_head, VFIOGroup) vfio_group_list; |
| 166 | extern QLIST_HEAD(vfio_as_head, VFIOAddressSpace) vfio_address_spaces; |
| 167 | |
Alex Williamson | 4690022 | 2016-03-10 09:39:07 -0700 | [diff] [blame] | 168 | #ifdef CONFIG_LINUX |
| 169 | int vfio_get_region_info(VFIODevice *vbasedev, int index, |
| 170 | struct vfio_region_info **info); |
Alex Williamson | e61a424 | 2016-05-26 09:43:20 -0600 | [diff] [blame] | 171 | int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, |
| 172 | uint32_t subtype, struct vfio_region_info **info); |
Alex Williamson | 4690022 | 2016-03-10 09:39:07 -0700 | [diff] [blame] | 173 | #endif |
Alexey Kardashevskiy | 318f67c | 2016-07-04 13:33:04 +1000 | [diff] [blame] | 174 | extern const MemoryListener vfio_prereg_listener; |
| 175 | |
Alexey Kardashevskiy | 2e4109d | 2016-07-04 13:33:06 +1000 | [diff] [blame] | 176 | int vfio_spapr_create_window(VFIOContainer *container, |
| 177 | MemoryRegionSection *section, |
| 178 | hwaddr *pgsize); |
| 179 | int vfio_spapr_remove_window(VFIOContainer *container, |
| 180 | hwaddr offset_within_address_space); |
| 181 | |
Markus Armbruster | 175de52 | 2016-06-29 15:29:06 +0200 | [diff] [blame] | 182 | #endif /* HW_VFIO_VFIO_COMMON_H */ |