1 | /* |
2 | * Copyright(c) 2011-2016 Intel Corporation. All rights reserved. |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), |
6 | * to deal in the Software without restriction, including without limitation |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
8 | * and/or sell copies of the Software, and to permit persons to whom the |
9 | * Software is furnished to do so, subject to the following conditions: |
10 | * |
11 | * The above copyright notice and this permission notice (including the next |
12 | * paragraph) shall be included in all copies or substantial portions of the |
13 | * Software. |
14 | * |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
21 | * SOFTWARE. |
22 | */ |
23 | |
24 | #include "i915_drv.h" |
25 | #include "i915_vgpu.h" |
26 | #include "intel_gvt.h" |
27 | #include "gem/i915_gem_dmabuf.h" |
28 | #include "gt/intel_context.h" |
29 | #include "gt/intel_ring.h" |
30 | #include "gt/shmem_utils.h" |
31 | |
32 | /** |
33 | * DOC: Intel GVT-g host 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. |
40 | * |
41 | * To virtualize GPU resources GVT-g driver depends on hypervisor technology |
42 | * e.g KVM/VFIO/mdev, Xen, etc. to provide resource access trapping capability |
43 | * and be virtualized within GVT-g device module. More architectural design |
44 | * doc is available on https://01.org/group/2230/documentation-list. |
45 | */ |
46 | |
47 | static LIST_HEAD(intel_gvt_devices); |
48 | static const struct intel_vgpu_ops *intel_gvt_ops; |
49 | static DEFINE_MUTEX(intel_gvt_mutex); |
50 | |
51 | static bool is_supported_device(struct drm_i915_private *dev_priv) |
52 | { |
53 | if (IS_BROADWELL(dev_priv)) |
54 | return true; |
55 | if (IS_SKYLAKE(dev_priv)) |
56 | return true; |
57 | if (IS_KABYLAKE(dev_priv)) |
58 | return true; |
59 | if (IS_BROXTON(dev_priv)) |
60 | return true; |
61 | if (IS_COFFEELAKE(dev_priv)) |
62 | return true; |
63 | if (IS_COMETLAKE(dev_priv)) |
64 | return true; |
65 | |
66 | return false; |
67 | } |
68 | |
69 | static void free_initial_hw_state(struct drm_i915_private *dev_priv) |
70 | { |
71 | struct i915_virtual_gpu *vgpu = &dev_priv->vgpu; |
72 | |
73 | vfree(addr: vgpu->initial_mmio); |
74 | vgpu->initial_mmio = NULL; |
75 | |
76 | kfree(objp: vgpu->initial_cfg_space); |
77 | vgpu->initial_cfg_space = NULL; |
78 | } |
79 | |
80 | static void save_mmio(struct intel_gvt_mmio_table_iter *iter, u32 offset, |
81 | u32 size) |
82 | { |
83 | struct drm_i915_private *dev_priv = iter->i915; |
84 | u32 *mmio, i; |
85 | |
86 | for (i = offset; i < offset + size; i += 4) { |
87 | mmio = iter->data + i; |
88 | *mmio = intel_uncore_read_notrace(uncore: to_gt(i915: dev_priv)->uncore, |
89 | _MMIO(i)); |
90 | } |
91 | } |
92 | |
93 | static int handle_mmio(struct intel_gvt_mmio_table_iter *iter, |
94 | u32 offset, u32 size) |
95 | { |
96 | if (WARN_ON(!IS_ALIGNED(offset, 4))) |
97 | return -EINVAL; |
98 | |
99 | save_mmio(iter, offset, size); |
100 | return 0; |
101 | } |
102 | |
103 | static int save_initial_hw_state(struct drm_i915_private *dev_priv) |
104 | { |
105 | struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); |
106 | struct i915_virtual_gpu *vgpu = &dev_priv->vgpu; |
107 | struct intel_gvt_mmio_table_iter iter; |
108 | void *mem; |
109 | int i, ret; |
110 | |
111 | mem = kzalloc(PCI_CFG_SPACE_EXP_SIZE, GFP_KERNEL); |
112 | if (!mem) |
113 | return -ENOMEM; |
114 | |
115 | vgpu->initial_cfg_space = mem; |
116 | |
117 | for (i = 0; i < PCI_CFG_SPACE_EXP_SIZE; i += 4) |
118 | pci_read_config_dword(dev: pdev, where: i, val: mem + i); |
119 | |
120 | mem = vzalloc(size: 2 * SZ_1M); |
121 | if (!mem) { |
122 | ret = -ENOMEM; |
123 | goto err_mmio; |
124 | } |
125 | |
126 | vgpu->initial_mmio = mem; |
127 | |
128 | iter.i915 = dev_priv; |
129 | iter.data = vgpu->initial_mmio; |
130 | iter.handle_mmio_cb = handle_mmio; |
131 | |
132 | ret = intel_gvt_iterate_mmio_table(iter: &iter); |
133 | if (ret) |
134 | goto err_iterate; |
135 | |
136 | return 0; |
137 | |
138 | err_iterate: |
139 | vfree(addr: vgpu->initial_mmio); |
140 | vgpu->initial_mmio = NULL; |
141 | err_mmio: |
142 | kfree(objp: vgpu->initial_cfg_space); |
143 | vgpu->initial_cfg_space = NULL; |
144 | |
145 | return ret; |
146 | } |
147 | |
148 | static void intel_gvt_init_device(struct drm_i915_private *dev_priv) |
149 | { |
150 | if (!dev_priv->params.enable_gvt) { |
151 | drm_dbg(&dev_priv->drm, |
152 | "GVT-g is disabled by kernel params\n" ); |
153 | return; |
154 | } |
155 | |
156 | if (intel_vgpu_active(i915: dev_priv)) { |
157 | drm_info(&dev_priv->drm, "GVT-g is disabled for guest\n" ); |
158 | return; |
159 | } |
160 | |
161 | if (!is_supported_device(dev_priv)) { |
162 | drm_info(&dev_priv->drm, |
163 | "Unsupported device. GVT-g is disabled\n" ); |
164 | return; |
165 | } |
166 | |
167 | if (intel_uc_wants_guc_submission(uc: &to_gt(i915: dev_priv)->uc)) { |
168 | drm_err(&dev_priv->drm, |
169 | "Graphics virtualization is not yet supported with GuC submission\n" ); |
170 | return; |
171 | } |
172 | |
173 | if (save_initial_hw_state(dev_priv)) { |
174 | drm_dbg(&dev_priv->drm, "Failed to save initial HW state\n" ); |
175 | return; |
176 | } |
177 | |
178 | if (intel_gvt_ops->init_device(dev_priv)) |
179 | drm_dbg(&dev_priv->drm, "Fail to init GVT device\n" ); |
180 | } |
181 | |
182 | static void intel_gvt_clean_device(struct drm_i915_private *dev_priv) |
183 | { |
184 | if (dev_priv->gvt) |
185 | intel_gvt_ops->clean_device(dev_priv); |
186 | free_initial_hw_state(dev_priv); |
187 | } |
188 | |
189 | int intel_gvt_set_ops(const struct intel_vgpu_ops *ops) |
190 | { |
191 | struct drm_i915_private *dev_priv; |
192 | |
193 | mutex_lock(&intel_gvt_mutex); |
194 | if (intel_gvt_ops) { |
195 | mutex_unlock(lock: &intel_gvt_mutex); |
196 | return -EINVAL; |
197 | } |
198 | intel_gvt_ops = ops; |
199 | |
200 | list_for_each_entry(dev_priv, &intel_gvt_devices, vgpu.entry) |
201 | intel_gvt_init_device(dev_priv); |
202 | mutex_unlock(lock: &intel_gvt_mutex); |
203 | |
204 | return 0; |
205 | } |
206 | EXPORT_SYMBOL_NS_GPL(intel_gvt_set_ops, I915_GVT); |
207 | |
208 | void intel_gvt_clear_ops(const struct intel_vgpu_ops *ops) |
209 | { |
210 | struct drm_i915_private *dev_priv; |
211 | |
212 | mutex_lock(&intel_gvt_mutex); |
213 | if (intel_gvt_ops != ops) { |
214 | mutex_unlock(lock: &intel_gvt_mutex); |
215 | return; |
216 | } |
217 | |
218 | list_for_each_entry(dev_priv, &intel_gvt_devices, vgpu.entry) |
219 | intel_gvt_clean_device(dev_priv); |
220 | |
221 | intel_gvt_ops = NULL; |
222 | mutex_unlock(lock: &intel_gvt_mutex); |
223 | } |
224 | EXPORT_SYMBOL_NS_GPL(intel_gvt_clear_ops, I915_GVT); |
225 | |
226 | /** |
227 | * intel_gvt_init - initialize GVT components |
228 | * @dev_priv: drm i915 private data |
229 | * |
230 | * This function is called at the initialization stage to create a GVT device. |
231 | * |
232 | * Returns: |
233 | * Zero on success, negative error code if failed. |
234 | * |
235 | */ |
236 | int intel_gvt_init(struct drm_i915_private *dev_priv) |
237 | { |
238 | if (i915_inject_probe_failure(dev_priv)) |
239 | return -ENODEV; |
240 | |
241 | mutex_lock(&intel_gvt_mutex); |
242 | list_add_tail(new: &dev_priv->vgpu.entry, head: &intel_gvt_devices); |
243 | if (intel_gvt_ops) |
244 | intel_gvt_init_device(dev_priv); |
245 | mutex_unlock(lock: &intel_gvt_mutex); |
246 | |
247 | return 0; |
248 | } |
249 | |
250 | /** |
251 | * intel_gvt_driver_remove - cleanup GVT components when i915 driver is |
252 | * unbinding |
253 | * @dev_priv: drm i915 private * |
254 | * |
255 | * This function is called at the i915 driver unloading stage, to shutdown |
256 | * GVT components and release the related resources. |
257 | */ |
258 | void intel_gvt_driver_remove(struct drm_i915_private *dev_priv) |
259 | { |
260 | mutex_lock(&intel_gvt_mutex); |
261 | intel_gvt_clean_device(dev_priv); |
262 | list_del(entry: &dev_priv->vgpu.entry); |
263 | mutex_unlock(lock: &intel_gvt_mutex); |
264 | } |
265 | |
266 | /** |
267 | * intel_gvt_resume - GVT resume routine wapper |
268 | * |
269 | * @dev_priv: drm i915 private * |
270 | * |
271 | * This function is called at the i915 driver resume stage to restore required |
272 | * HW status for GVT so that vGPU can continue running after resumed. |
273 | */ |
274 | void intel_gvt_resume(struct drm_i915_private *dev_priv) |
275 | { |
276 | mutex_lock(&intel_gvt_mutex); |
277 | if (dev_priv->gvt) |
278 | intel_gvt_ops->pm_resume(dev_priv); |
279 | mutex_unlock(lock: &intel_gvt_mutex); |
280 | } |
281 | |
282 | /* |
283 | * Exported here so that the exports only get created when GVT support is |
284 | * actually enabled. |
285 | */ |
286 | EXPORT_SYMBOL_NS_GPL(i915_gem_object_alloc, I915_GVT); |
287 | EXPORT_SYMBOL_NS_GPL(i915_gem_object_create_shmem, I915_GVT); |
288 | EXPORT_SYMBOL_NS_GPL(i915_gem_object_init, I915_GVT); |
289 | EXPORT_SYMBOL_NS_GPL(i915_gem_object_ggtt_pin_ww, I915_GVT); |
290 | EXPORT_SYMBOL_NS_GPL(i915_gem_object_pin_map, I915_GVT); |
291 | EXPORT_SYMBOL_NS_GPL(i915_gem_object_set_to_cpu_domain, I915_GVT); |
292 | EXPORT_SYMBOL_NS_GPL(__i915_gem_object_flush_map, I915_GVT); |
293 | EXPORT_SYMBOL_NS_GPL(__i915_gem_object_set_pages, I915_GVT); |
294 | EXPORT_SYMBOL_NS_GPL(i915_gem_gtt_insert, I915_GVT); |
295 | EXPORT_SYMBOL_NS_GPL(i915_gem_prime_export, I915_GVT); |
296 | EXPORT_SYMBOL_NS_GPL(i915_gem_ww_ctx_init, I915_GVT); |
297 | EXPORT_SYMBOL_NS_GPL(i915_gem_ww_ctx_backoff, I915_GVT); |
298 | EXPORT_SYMBOL_NS_GPL(i915_gem_ww_ctx_fini, I915_GVT); |
299 | EXPORT_SYMBOL_NS_GPL(i915_ppgtt_create, I915_GVT); |
300 | EXPORT_SYMBOL_NS_GPL(i915_request_add, I915_GVT); |
301 | EXPORT_SYMBOL_NS_GPL(i915_request_create, I915_GVT); |
302 | EXPORT_SYMBOL_NS_GPL(i915_request_wait, I915_GVT); |
303 | EXPORT_SYMBOL_NS_GPL(i915_reserve_fence, I915_GVT); |
304 | EXPORT_SYMBOL_NS_GPL(i915_unreserve_fence, I915_GVT); |
305 | EXPORT_SYMBOL_NS_GPL(i915_vm_release, I915_GVT); |
306 | EXPORT_SYMBOL_NS_GPL(_i915_vma_move_to_active, I915_GVT); |
307 | EXPORT_SYMBOL_NS_GPL(intel_context_create, I915_GVT); |
308 | EXPORT_SYMBOL_NS_GPL(__intel_context_do_pin, I915_GVT); |
309 | EXPORT_SYMBOL_NS_GPL(__intel_context_do_unpin, I915_GVT); |
310 | EXPORT_SYMBOL_NS_GPL(intel_ring_begin, I915_GVT); |
311 | EXPORT_SYMBOL_NS_GPL(intel_runtime_pm_get, I915_GVT); |
312 | #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) |
313 | EXPORT_SYMBOL_NS_GPL(intel_runtime_pm_put, I915_GVT); |
314 | #endif |
315 | EXPORT_SYMBOL_NS_GPL(intel_runtime_pm_put_unchecked, I915_GVT); |
316 | EXPORT_SYMBOL_NS_GPL(intel_uncore_forcewake_for_reg, I915_GVT); |
317 | EXPORT_SYMBOL_NS_GPL(intel_uncore_forcewake_get, I915_GVT); |
318 | EXPORT_SYMBOL_NS_GPL(intel_uncore_forcewake_put, I915_GVT); |
319 | EXPORT_SYMBOL_NS_GPL(shmem_pin_map, I915_GVT); |
320 | EXPORT_SYMBOL_NS_GPL(shmem_unpin_map, I915_GVT); |
321 | EXPORT_SYMBOL_NS_GPL(__px_dma, I915_GVT); |
322 | EXPORT_SYMBOL_NS_GPL(i915_fence_ops, I915_GVT); |
323 | |