i915_vgpu.c revision 1.1.1.2 1 /* $NetBSD: i915_vgpu.c,v 1.1.1.2 2021/12/18 20:15:26 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.1.1.2 2021/12/18 20:15:26 riastradh Exp $");
28
29 #include "i915_vgpu.h"
30
31 /**
32 * DOC: Intel GVT-g guest support
33 *
34 * Intel GVT-g is a graphics virtualization technology which shares the
35 * GPU among multiple virtual machines on a time-sharing basis. Each
36 * virtual machine is presented a virtual GPU (vGPU), which has equivalent
37 * features as the underlying physical GPU (pGPU), so i915 driver can run
38 * seamlessly in a virtual machine. This file provides vGPU specific
39 * optimizations when running in a virtual machine, to reduce the complexity
40 * of vGPU emulation and to improve the overall performance.
41 *
42 * A primary function introduced here is so-called "address space ballooning"
43 * technique. Intel GVT-g partitions global graphics memory among multiple VMs,
44 * so each VM can directly access a portion of the memory without hypervisor's
45 * intervention, e.g. filling textures or queuing commands. However with the
46 * partitioning an unmodified i915 driver would assume a smaller graphics
47 * memory starting from address ZERO, then requires vGPU emulation module to
48 * translate the graphics address between 'guest view' and 'host view', for
49 * all registers and command opcodes which contain a graphics memory address.
50 * To reduce the complexity, Intel GVT-g introduces "address space ballooning",
51 * by telling the exact partitioning knowledge to each guest i915 driver, which
52 * then reserves and prevents non-allocated portions from allocation. Thus vGPU
53 * emulation module only needs to scan and validate graphics addresses without
54 * complexity of address translation.
55 *
56 */
57
58 /**
59 * i915_detect_vgpu - detect virtual GPU
60 * @dev_priv: i915 device private
61 *
62 * This function is called at the initialization stage, to detect whether
63 * running on a vGPU.
64 */
65 void i915_detect_vgpu(struct drm_i915_private *dev_priv)
66 {
67 struct pci_dev *pdev = dev_priv->drm.pdev;
68 u64 magic;
69 u16 version_major;
70 void __iomem *shared_area;
71
72 BUILD_BUG_ON(sizeof(struct vgt_if) != VGT_PVINFO_SIZE);
73
74 /*
75 * This is called before we setup the main MMIO BAR mappings used via
76 * the uncore structure, so we need to access the BAR directly. Since
77 * we do not support VGT on older gens, return early so we don't have
78 * to consider differently numbered or sized MMIO bars
79 */
80 if (INTEL_GEN(dev_priv) < 6)
81 return;
82
83 shared_area = pci_iomap_range(pdev, 0, VGT_PVINFO_PAGE, VGT_PVINFO_SIZE);
84 if (!shared_area) {
85 DRM_ERROR("failed to map MMIO bar to check for VGT\n");
86 return;
87 }
88
89 magic = readq(shared_area + vgtif_offset(magic));
90 if (magic != VGT_MAGIC)
91 goto out;
92
93 version_major = readw(shared_area + vgtif_offset(version_major));
94 if (version_major < VGT_VERSION_MAJOR) {
95 DRM_INFO("VGT interface version mismatch!\n");
96 goto out;
97 }
98
99 dev_priv->vgpu.caps = readl(shared_area + vgtif_offset(vgt_caps));
100
101 dev_priv->vgpu.active = true;
102 mutex_init(&dev_priv->vgpu.lock);
103 DRM_INFO("Virtual GPU for Intel GVT-g detected.\n");
104
105 out:
106 pci_iounmap(pdev, shared_area);
107 }
108
109 bool intel_vgpu_has_full_ppgtt(struct drm_i915_private *dev_priv)
110 {
111 return dev_priv->vgpu.caps & VGT_CAPS_FULL_PPGTT;
112 }
113
114 struct _balloon_info_ {
115 /*
116 * There are up to 2 regions per mappable/unmappable graphic
117 * memory that might be ballooned. Here, index 0/1 is for mappable
118 * graphic memory, 2/3 for unmappable graphic memory.
119 */
120 struct drm_mm_node space[4];
121 };
122
123 static struct _balloon_info_ bl_info;
124
125 static void vgt_deballoon_space(struct i915_ggtt *ggtt,
126 struct drm_mm_node *node)
127 {
128 if (!drm_mm_node_allocated(node))
129 return;
130
131 DRM_DEBUG_DRIVER("deballoon space: range [0x%llx - 0x%llx] %llu KiB.\n",
132 node->start,
133 node->start + node->size,
134 node->size / 1024);
135
136 ggtt->vm.reserved -= node->size;
137 drm_mm_remove_node(node);
138 }
139
140 /**
141 * intel_vgt_deballoon - deballoon reserved graphics address trunks
142 * @ggtt: the global GGTT from which we reserved earlier
143 *
144 * This function is called to deallocate the ballooned-out graphic memory, when
145 * driver is unloaded or when ballooning fails.
146 */
147 void intel_vgt_deballoon(struct i915_ggtt *ggtt)
148 {
149 int i;
150
151 if (!intel_vgpu_active(ggtt->vm.i915))
152 return;
153
154 DRM_DEBUG("VGT deballoon.\n");
155
156 for (i = 0; i < 4; i++)
157 vgt_deballoon_space(ggtt, &bl_info.space[i]);
158 }
159
160 static int vgt_balloon_space(struct i915_ggtt *ggtt,
161 struct drm_mm_node *node,
162 unsigned long start, unsigned long end)
163 {
164 unsigned long size = end - start;
165 int ret;
166
167 if (start >= end)
168 return -EINVAL;
169
170 DRM_INFO("balloon space: range [ 0x%lx - 0x%lx ] %lu KiB.\n",
171 start, end, size / 1024);
172 ret = i915_gem_gtt_reserve(&ggtt->vm, node,
173 size, start, I915_COLOR_UNEVICTABLE,
174 0);
175 if (!ret)
176 ggtt->vm.reserved += size;
177
178 return ret;
179 }
180
181 /**
182 * intel_vgt_balloon - balloon out reserved graphics address trunks
183 * @ggtt: the global GGTT from which to reserve
184 *
185 * This function is called at the initialization stage, to balloon out the
186 * graphic address space allocated to other vGPUs, by marking these spaces as
187 * reserved. The ballooning related knowledge(starting address and size of
188 * the mappable/unmappable graphic memory) is described in the vgt_if structure
189 * in a reserved mmio range.
190 *
191 * To give an example, the drawing below depicts one typical scenario after
192 * ballooning. Here the vGPU1 has 2 pieces of graphic address spaces ballooned
193 * out each for the mappable and the non-mappable part. From the vGPU1 point of
194 * view, the total size is the same as the physical one, with the start address
195 * of its graphic space being zero. Yet there are some portions ballooned out(
196 * the shadow part, which are marked as reserved by drm allocator). From the
197 * host point of view, the graphic address space is partitioned by multiple
198 * vGPUs in different VMs. ::
199 *
200 * vGPU1 view Host view
201 * 0 ------> +-----------+ +-----------+
202 * ^ |###########| | vGPU3 |
203 * | |###########| +-----------+
204 * | |###########| | vGPU2 |
205 * | +-----------+ +-----------+
206 * mappable GM | available | ==> | vGPU1 |
207 * | +-----------+ +-----------+
208 * | |###########| | |
209 * v |###########| | Host |
210 * +=======+===========+ +===========+
211 * ^ |###########| | vGPU3 |
212 * | |###########| +-----------+
213 * | |###########| | vGPU2 |
214 * | +-----------+ +-----------+
215 * unmappable GM | available | ==> | vGPU1 |
216 * | +-----------+ +-----------+
217 * | |###########| | |
218 * | |###########| | Host |
219 * v |###########| | |
220 * total GM size ------> +-----------+ +-----------+
221 *
222 * Returns:
223 * zero on success, non-zero if configuration invalid or ballooning failed
224 */
225 int intel_vgt_balloon(struct i915_ggtt *ggtt)
226 {
227 struct intel_uncore *uncore = &ggtt->vm.i915->uncore;
228 unsigned long ggtt_end = ggtt->vm.total;
229
230 unsigned long mappable_base, mappable_size, mappable_end;
231 unsigned long unmappable_base, unmappable_size, unmappable_end;
232 int ret;
233
234 if (!intel_vgpu_active(ggtt->vm.i915))
235 return 0;
236
237 mappable_base =
238 intel_uncore_read(uncore, vgtif_reg(avail_rs.mappable_gmadr.base));
239 mappable_size =
240 intel_uncore_read(uncore, vgtif_reg(avail_rs.mappable_gmadr.size));
241 unmappable_base =
242 intel_uncore_read(uncore, vgtif_reg(avail_rs.nonmappable_gmadr.base));
243 unmappable_size =
244 intel_uncore_read(uncore, vgtif_reg(avail_rs.nonmappable_gmadr.size));
245
246 mappable_end = mappable_base + mappable_size;
247 unmappable_end = unmappable_base + unmappable_size;
248
249 DRM_INFO("VGT ballooning configuration:\n");
250 DRM_INFO("Mappable graphic memory: base 0x%lx size %ldKiB\n",
251 mappable_base, mappable_size / 1024);
252 DRM_INFO("Unmappable graphic memory: base 0x%lx size %ldKiB\n",
253 unmappable_base, unmappable_size / 1024);
254
255 if (mappable_end > ggtt->mappable_end ||
256 unmappable_base < ggtt->mappable_end ||
257 unmappable_end > ggtt_end) {
258 DRM_ERROR("Invalid ballooning configuration!\n");
259 return -EINVAL;
260 }
261
262 /* Unmappable graphic memory ballooning */
263 if (unmappable_base > ggtt->mappable_end) {
264 ret = vgt_balloon_space(ggtt, &bl_info.space[2],
265 ggtt->mappable_end, unmappable_base);
266
267 if (ret)
268 goto err;
269 }
270
271 if (unmappable_end < ggtt_end) {
272 ret = vgt_balloon_space(ggtt, &bl_info.space[3],
273 unmappable_end, ggtt_end);
274 if (ret)
275 goto err_upon_mappable;
276 }
277
278 /* Mappable graphic memory ballooning */
279 if (mappable_base) {
280 ret = vgt_balloon_space(ggtt, &bl_info.space[0],
281 0, mappable_base);
282
283 if (ret)
284 goto err_upon_unmappable;
285 }
286
287 if (mappable_end < ggtt->mappable_end) {
288 ret = vgt_balloon_space(ggtt, &bl_info.space[1],
289 mappable_end, ggtt->mappable_end);
290
291 if (ret)
292 goto err_below_mappable;
293 }
294
295 DRM_INFO("VGT balloon successfully\n");
296 return 0;
297
298 err_below_mappable:
299 vgt_deballoon_space(ggtt, &bl_info.space[0]);
300 err_upon_unmappable:
301 vgt_deballoon_space(ggtt, &bl_info.space[3]);
302 err_upon_mappable:
303 vgt_deballoon_space(ggtt, &bl_info.space[2]);
304 err:
305 DRM_ERROR("VGT balloon fail\n");
306 return ret;
307 }
308