1 /* $NetBSD: i915_vgpu.c,v 1.4 2018/08/27 16:15:34 riastradh Exp $ */ 2 3 /* 4 * Copyright(c) 2011-2015 Intel Corporation. All rights reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 */ 25 26 #include <sys/cdefs.h> 27 __KERNEL_RCSID(0, "$NetBSD: i915_vgpu.c,v 1.4 2018/08/27 16:15:34 riastradh Exp $"); 28 29 #include "intel_drv.h" 30 #include "i915_vgpu.h" 31 32 /** 33 * DOC: Intel GVT-g guest support 34 * 35 * Intel GVT-g is a graphics virtualization technology which shares the 36 * GPU among multiple virtual machines on a time-sharing basis. Each 37 * virtual machine is presented a virtual GPU (vGPU), which has equivalent 38 * features as the underlying physical GPU (pGPU), so i915 driver can run 39 * seamlessly in a virtual machine. This file provides vGPU specific 40 * optimizations when running in a virtual machine, to reduce the complexity 41 * of vGPU emulation and to improve the overall performance. 42 * 43 * A primary function introduced here is so-called "address space ballooning" 44 * technique. Intel GVT-g partitions global graphics memory among multiple VMs, 45 * so each VM can directly access a portion of the memory without hypervisor's 46 * intervention, e.g. filling textures or queuing commands. However with the 47 * partitioning an unmodified i915 driver would assume a smaller graphics 48 * memory starting from address ZERO, then requires vGPU emulation module to 49 * translate the graphics address between 'guest view' and 'host view', for 50 * all registers and command opcodes which contain a graphics memory address. 51 * To reduce the complexity, Intel GVT-g introduces "address space ballooning", 52 * by telling the exact partitioning knowledge to each guest i915 driver, which 53 * then reserves and prevents non-allocated portions from allocation. Thus vGPU 54 * emulation module only needs to scan and validate graphics addresses without 55 * complexity of address translation. 56 * 57 */ 58 59 /** 60 * i915_check_vgpu - detect virtual GPU 61 * @dev: drm device * 62 * 63 * This function is called at the initialization stage, to detect whether 64 * running on a vGPU. 65 */ 66 void i915_check_vgpu(struct drm_device *dev) 67 { 68 struct drm_i915_private *dev_priv = to_i915(dev); 69 uint64_t magic; 70 uint32_t version; 71 72 BUILD_BUG_ON(sizeof(struct vgt_if) != VGT_PVINFO_SIZE); 73 74 if (!IS_HASWELL(dev)) 75 return; 76 77 #ifdef __NetBSD__ 78 # ifdef _LP64 79 magic = bus_space_read_8(dev_priv->regs_bst, dev_priv->regs_bsh, 80 vgtif_reg(magic)); 81 # else 82 magic = bus_space_read_4(dev_priv->regs_bst, dev_priv->regs_bsh, 83 vgtif_reg(magic)); 84 magic |= (uint64_t)bus_space_read_4(dev_priv->regs_bst, 85 dev_priv->regs_bsh, vgtif_reg(magic) + 4) << 32; 86 # endif 87 #else 88 magic = readq(dev_priv->regs + vgtif_reg(magic)); 89 #endif 90 if (magic != VGT_MAGIC) 91 return; 92 93 #ifdef __NetBSD__ 94 version = INTEL_VGT_IF_VERSION_ENCODE( 95 bus_space_read_2(dev_priv->regs_bst, dev_priv->regs_bsh, 96 vgtif_reg(version_major)), 97 bus_space_read_2(dev_priv->regs_bst, dev_priv->regs_bsh, 98 vgtif_reg(version_minor))); 99 #else 100 version = INTEL_VGT_IF_VERSION_ENCODE( 101 readw(dev_priv->regs + vgtif_reg(version_major)), 102 readw(dev_priv->regs + vgtif_reg(version_minor))); 103 #endif 104 if (version != INTEL_VGT_IF_VERSION) { 105 DRM_INFO("VGT interface version mismatch!\n"); 106 return; 107 } 108 109 dev_priv->vgpu.active = true; 110 DRM_INFO("Virtual GPU for Intel GVT-g detected.\n"); 111 } 112 113 struct _balloon_info_ { 114 /* 115 * There are up to 2 regions per mappable/unmappable graphic 116 * memory that might be ballooned. Here, index 0/1 is for mappable 117 * graphic memory, 2/3 for unmappable graphic memory. 118 */ 119 struct drm_mm_node space[4]; 120 }; 121 122 static struct _balloon_info_ bl_info; 123 124 /** 125 * intel_vgt_deballoon - deballoon reserved graphics address trunks 126 * 127 * This function is called to deallocate the ballooned-out graphic memory, when 128 * driver is unloaded or when ballooning fails. 129 */ 130 void intel_vgt_deballoon(void) 131 { 132 int i; 133 134 DRM_DEBUG("VGT deballoon.\n"); 135 136 for (i = 0; i < 4; i++) { 137 if (bl_info.space[i].allocated) 138 drm_mm_remove_node(&bl_info.space[i]); 139 } 140 141 memset(&bl_info, 0, sizeof(bl_info)); 142 } 143 144 static int vgt_balloon_space(struct drm_mm *mm, 145 struct drm_mm_node *node, 146 unsigned long start, unsigned long end) 147 { 148 unsigned long size = end - start; 149 150 if (start == end) 151 return -EINVAL; 152 153 DRM_INFO("balloon space: range [ 0x%lx - 0x%lx ] %lu KiB.\n", 154 start, end, size / 1024); 155 156 node->start = start; 157 node->size = size; 158 159 return drm_mm_reserve_node(mm, node); 160 } 161 162 /** 163 * intel_vgt_balloon - balloon out reserved graphics address trunks 164 * @dev: drm device 165 * 166 * This function is called at the initialization stage, to balloon out the 167 * graphic address space allocated to other vGPUs, by marking these spaces as 168 * reserved. The ballooning related knowledge(starting address and size of 169 * the mappable/unmappable graphic memory) is described in the vgt_if structure 170 * in a reserved mmio range. 171 * 172 * To give an example, the drawing below depicts one typical scenario after 173 * ballooning. Here the vGPU1 has 2 pieces of graphic address spaces ballooned 174 * out each for the mappable and the non-mappable part. From the vGPU1 point of 175 * view, the total size is the same as the physical one, with the start address 176 * of its graphic space being zero. Yet there are some portions ballooned out( 177 * the shadow part, which are marked as reserved by drm allocator). From the 178 * host point of view, the graphic address space is partitioned by multiple 179 * vGPUs in different VMs. 180 * 181 * vGPU1 view Host view 182 * 0 ------> +-----------+ +-----------+ 183 * ^ |///////////| | vGPU3 | 184 * | |///////////| +-----------+ 185 * | |///////////| | vGPU2 | 186 * | +-----------+ +-----------+ 187 * mappable GM | available | ==> | vGPU1 | 188 * | +-----------+ +-----------+ 189 * | |///////////| | | 190 * v |///////////| | Host | 191 * +=======+===========+ +===========+ 192 * ^ |///////////| | vGPU3 | 193 * | |///////////| +-----------+ 194 * | |///////////| | vGPU2 | 195 * | +-----------+ +-----------+ 196 * unmappable GM | available | ==> | vGPU1 | 197 * | +-----------+ +-----------+ 198 * | |///////////| | | 199 * | |///////////| | Host | 200 * v |///////////| | | 201 * total GM size ------> +-----------+ +-----------+ 202 * 203 * Returns: 204 * zero on success, non-zero if configuration invalid or ballooning failed 205 */ 206 int intel_vgt_balloon(struct drm_device *dev) 207 { 208 struct drm_i915_private *dev_priv = to_i915(dev); 209 struct i915_address_space *ggtt_vm = &dev_priv->gtt.base; 210 unsigned long ggtt_vm_end = ggtt_vm->start + ggtt_vm->total; 211 212 unsigned long mappable_base, mappable_size, mappable_end; 213 unsigned long unmappable_base, unmappable_size, unmappable_end; 214 int ret; 215 216 mappable_base = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.base)); 217 mappable_size = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.size)); 218 unmappable_base = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.base)); 219 unmappable_size = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.size)); 220 221 mappable_end = mappable_base + mappable_size; 222 unmappable_end = unmappable_base + unmappable_size; 223 224 DRM_INFO("VGT ballooning configuration:\n"); 225 DRM_INFO("Mappable graphic memory: base 0x%lx size %ldKiB\n", 226 mappable_base, mappable_size / 1024); 227 DRM_INFO("Unmappable graphic memory: base 0x%lx size %ldKiB\n", 228 unmappable_base, unmappable_size / 1024); 229 230 if (mappable_base < ggtt_vm->start || 231 mappable_end > dev_priv->gtt.mappable_end || 232 unmappable_base < dev_priv->gtt.mappable_end || 233 unmappable_end > ggtt_vm_end) { 234 DRM_ERROR("Invalid ballooning configuration!\n"); 235 return -EINVAL; 236 } 237 238 /* Unmappable graphic memory ballooning */ 239 if (unmappable_base > dev_priv->gtt.mappable_end) { 240 ret = vgt_balloon_space(&ggtt_vm->mm, 241 &bl_info.space[2], 242 dev_priv->gtt.mappable_end, 243 unmappable_base); 244 245 if (ret) 246 goto err; 247 } 248 249 /* 250 * No need to partition out the last physical page, 251 * because it is reserved to the guard page. 252 */ 253 if (unmappable_end < ggtt_vm_end - PAGE_SIZE) { 254 ret = vgt_balloon_space(&ggtt_vm->mm, 255 &bl_info.space[3], 256 unmappable_end, 257 ggtt_vm_end - PAGE_SIZE); 258 if (ret) 259 goto err; 260 } 261 262 /* Mappable graphic memory ballooning */ 263 if (mappable_base > ggtt_vm->start) { 264 ret = vgt_balloon_space(&ggtt_vm->mm, 265 &bl_info.space[0], 266 ggtt_vm->start, mappable_base); 267 268 if (ret) 269 goto err; 270 } 271 272 if (mappable_end < dev_priv->gtt.mappable_end) { 273 ret = vgt_balloon_space(&ggtt_vm->mm, 274 &bl_info.space[1], 275 mappable_end, 276 dev_priv->gtt.mappable_end); 277 278 if (ret) 279 goto err; 280 } 281 282 DRM_INFO("VGT balloon successfully\n"); 283 return 0; 284 285 err: 286 DRM_ERROR("VGT balloon fail\n"); 287 intel_vgt_deballoon(); 288 return ret; 289 } 290