]>
Commit | Line | Data |
---|---|---|
82d375d1 ZW |
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 | * Authors: | |
24 | * Eddie Dong <eddie.dong@intel.com> | |
25 | * Kevin Tian <kevin.tian@intel.com> | |
26 | * | |
27 | * Contributors: | |
28 | * Ping Gao <ping.a.gao@intel.com> | |
29 | * Zhi Wang <zhi.a.wang@intel.com> | |
30 | * Bing Niu <bing.niu@intel.com> | |
31 | * | |
32 | */ | |
33 | ||
34 | #include "i915_drv.h" | |
feddf6e8 ZW |
35 | #include "gvt.h" |
36 | #include "i915_pvinfo.h" | |
82d375d1 | 37 | |
23736d1b | 38 | void populate_pvinfo_page(struct intel_vgpu *vgpu) |
82d375d1 ZW |
39 | { |
40 | /* setup the ballooning information */ | |
41 | vgpu_vreg64(vgpu, vgtif_reg(magic)) = VGT_MAGIC; | |
42 | vgpu_vreg(vgpu, vgtif_reg(version_major)) = 1; | |
43 | vgpu_vreg(vgpu, vgtif_reg(version_minor)) = 0; | |
44 | vgpu_vreg(vgpu, vgtif_reg(display_ready)) = 0; | |
45 | vgpu_vreg(vgpu, vgtif_reg(vgt_id)) = vgpu->id; | |
46 | vgpu_vreg(vgpu, vgtif_reg(avail_rs.mappable_gmadr.base)) = | |
47 | vgpu_aperture_gmadr_base(vgpu); | |
48 | vgpu_vreg(vgpu, vgtif_reg(avail_rs.mappable_gmadr.size)) = | |
49 | vgpu_aperture_sz(vgpu); | |
50 | vgpu_vreg(vgpu, vgtif_reg(avail_rs.nonmappable_gmadr.base)) = | |
51 | vgpu_hidden_gmadr_base(vgpu); | |
52 | vgpu_vreg(vgpu, vgtif_reg(avail_rs.nonmappable_gmadr.size)) = | |
53 | vgpu_hidden_sz(vgpu); | |
54 | ||
55 | vgpu_vreg(vgpu, vgtif_reg(avail_rs.fence_num)) = vgpu_fence_sz(vgpu); | |
56 | ||
57 | gvt_dbg_core("Populate PVINFO PAGE for vGPU %d\n", vgpu->id); | |
58 | gvt_dbg_core("aperture base [GMADR] 0x%llx size 0x%llx\n", | |
59 | vgpu_aperture_gmadr_base(vgpu), vgpu_aperture_sz(vgpu)); | |
60 | gvt_dbg_core("hidden base [GMADR] 0x%llx size=0x%llx\n", | |
61 | vgpu_hidden_gmadr_base(vgpu), vgpu_hidden_sz(vgpu)); | |
62 | gvt_dbg_core("fence size %d\n", vgpu_fence_sz(vgpu)); | |
63 | ||
64 | WARN_ON(sizeof(struct vgt_if) != VGT_PVINFO_SIZE); | |
65 | } | |
66 | ||
bc90d097 PG |
67 | #define VGPU_MAX_WEIGHT 16 |
68 | #define VGPU_WEIGHT(vgpu_num) \ | |
69 | (VGPU_MAX_WEIGHT / (vgpu_num)) | |
70 | ||
191020b6 ZW |
71 | static struct { |
72 | unsigned int low_mm; | |
73 | unsigned int high_mm; | |
74 | unsigned int fence; | |
bc90d097 PG |
75 | |
76 | /* A vGPU with a weight of 8 will get twice as much GPU as a vGPU | |
77 | * with a weight of 4 on a contended host, different vGPU type has | |
78 | * different weight set. Legal weights range from 1 to 16. | |
79 | */ | |
80 | unsigned int weight; | |
d1a513be | 81 | enum intel_vgpu_edid edid; |
191020b6 ZW |
82 | char *name; |
83 | } vgpu_types[] = { | |
84 | /* Fixed vGPU type table */ | |
bc90d097 PG |
85 | { MB_TO_BYTES(64), MB_TO_BYTES(384), 4, VGPU_WEIGHT(8), GVT_EDID_1024_768, "8" }, |
86 | { MB_TO_BYTES(128), MB_TO_BYTES(512), 4, VGPU_WEIGHT(4), GVT_EDID_1920_1200, "4" }, | |
87 | { MB_TO_BYTES(256), MB_TO_BYTES(1024), 4, VGPU_WEIGHT(2), GVT_EDID_1920_1200, "2" }, | |
88 | { MB_TO_BYTES(512), MB_TO_BYTES(2048), 4, VGPU_WEIGHT(1), GVT_EDID_1920_1200, "1" }, | |
191020b6 ZW |
89 | }; |
90 | ||
1f31c829 ZW |
91 | /** |
92 | * intel_gvt_init_vgpu_types - initialize vGPU type list | |
93 | * @gvt : GVT device | |
94 | * | |
95 | * Initialize vGPU type list based on available resource. | |
96 | * | |
97 | */ | |
98 | int intel_gvt_init_vgpu_types(struct intel_gvt *gvt) | |
99 | { | |
100 | unsigned int num_types; | |
2d6ceb8e | 101 | unsigned int i, low_avail, high_avail; |
1f31c829 ZW |
102 | unsigned int min_low; |
103 | ||
104 | /* vGPU type name is defined as GVTg_Vx_y which contains | |
191020b6 ZW |
105 | * physical GPU generation type (e.g V4 as BDW server, V5 as |
106 | * SKL server). | |
1f31c829 ZW |
107 | * |
108 | * Depend on physical SKU resource, might see vGPU types like | |
109 | * GVTg_V4_8, GVTg_V4_4, GVTg_V4_2, etc. We can create | |
110 | * different types of vGPU on same physical GPU depending on | |
111 | * available resource. Each vGPU type will have "avail_instance" | |
112 | * to indicate how many vGPU instance can be created for this | |
113 | * type. | |
114 | * | |
1f31c829 | 115 | */ |
2d6ceb8e ZW |
116 | low_avail = gvt_aperture_sz(gvt) - HOST_LOW_GM_SIZE; |
117 | high_avail = gvt_hidden_sz(gvt) - HOST_HIGH_GM_SIZE; | |
191020b6 | 118 | num_types = sizeof(vgpu_types) / sizeof(vgpu_types[0]); |
1f31c829 ZW |
119 | |
120 | gvt->types = kzalloc(num_types * sizeof(struct intel_vgpu_type), | |
121 | GFP_KERNEL); | |
122 | if (!gvt->types) | |
123 | return -ENOMEM; | |
124 | ||
125 | min_low = MB_TO_BYTES(32); | |
126 | for (i = 0; i < num_types; ++i) { | |
191020b6 | 127 | if (low_avail / vgpu_types[i].low_mm == 0) |
1f31c829 | 128 | break; |
191020b6 ZW |
129 | |
130 | gvt->types[i].low_gm_size = vgpu_types[i].low_mm; | |
131 | gvt->types[i].high_gm_size = vgpu_types[i].high_mm; | |
132 | gvt->types[i].fence = vgpu_types[i].fence; | |
bc90d097 PG |
133 | |
134 | if (vgpu_types[i].weight < 1 || | |
135 | vgpu_types[i].weight > VGPU_MAX_WEIGHT) | |
136 | return -EINVAL; | |
137 | ||
138 | gvt->types[i].weight = vgpu_types[i].weight; | |
d1a513be | 139 | gvt->types[i].resolution = vgpu_types[i].edid; |
191020b6 ZW |
140 | gvt->types[i].avail_instance = min(low_avail / vgpu_types[i].low_mm, |
141 | high_avail / vgpu_types[i].high_mm); | |
1f31c829 ZW |
142 | |
143 | if (IS_GEN8(gvt->dev_priv)) | |
191020b6 ZW |
144 | sprintf(gvt->types[i].name, "GVTg_V4_%s", |
145 | vgpu_types[i].name); | |
1f31c829 | 146 | else if (IS_GEN9(gvt->dev_priv)) |
191020b6 ZW |
147 | sprintf(gvt->types[i].name, "GVTg_V5_%s", |
148 | vgpu_types[i].name); | |
1f31c829 | 149 | |
bc90d097 | 150 | gvt_dbg_core("type[%d]: %s avail %u low %u high %u fence %u weight %u res %s\n", |
191020b6 | 151 | i, gvt->types[i].name, |
1f31c829 ZW |
152 | gvt->types[i].avail_instance, |
153 | gvt->types[i].low_gm_size, | |
d1a513be | 154 | gvt->types[i].high_gm_size, gvt->types[i].fence, |
bc90d097 | 155 | gvt->types[i].weight, |
d1a513be | 156 | vgpu_edid_str(gvt->types[i].resolution)); |
1f31c829 ZW |
157 | } |
158 | ||
159 | gvt->num_types = i; | |
160 | return 0; | |
161 | } | |
162 | ||
163 | void intel_gvt_clean_vgpu_types(struct intel_gvt *gvt) | |
164 | { | |
165 | kfree(gvt->types); | |
166 | } | |
167 | ||
168 | static void intel_gvt_update_vgpu_types(struct intel_gvt *gvt) | |
169 | { | |
170 | int i; | |
171 | unsigned int low_gm_avail, high_gm_avail, fence_avail; | |
191020b6 | 172 | unsigned int low_gm_min, high_gm_min, fence_min; |
1f31c829 ZW |
173 | |
174 | /* Need to depend on maxium hw resource size but keep on | |
175 | * static config for now. | |
176 | */ | |
2d6ceb8e | 177 | low_gm_avail = gvt_aperture_sz(gvt) - HOST_LOW_GM_SIZE - |
1f31c829 | 178 | gvt->gm.vgpu_allocated_low_gm_size; |
2d6ceb8e | 179 | high_gm_avail = gvt_hidden_sz(gvt) - HOST_HIGH_GM_SIZE - |
1f31c829 ZW |
180 | gvt->gm.vgpu_allocated_high_gm_size; |
181 | fence_avail = gvt_fence_sz(gvt) - HOST_FENCE - | |
182 | gvt->fence.vgpu_allocated_fence_num; | |
183 | ||
184 | for (i = 0; i < gvt->num_types; i++) { | |
185 | low_gm_min = low_gm_avail / gvt->types[i].low_gm_size; | |
186 | high_gm_min = high_gm_avail / gvt->types[i].high_gm_size; | |
187 | fence_min = fence_avail / gvt->types[i].fence; | |
191020b6 ZW |
188 | gvt->types[i].avail_instance = min(min(low_gm_min, high_gm_min), |
189 | fence_min); | |
1f31c829 | 190 | |
191020b6 ZW |
191 | gvt_dbg_core("update type[%d]: %s avail %u low %u high %u fence %u\n", |
192 | i, gvt->types[i].name, | |
1f31c829 ZW |
193 | gvt->types[i].avail_instance, gvt->types[i].low_gm_size, |
194 | gvt->types[i].high_gm_size, gvt->types[i].fence); | |
195 | } | |
196 | } | |
197 | ||
82d375d1 | 198 | /** |
b79c52ae | 199 | * intel_gvt_active_vgpu - activate a virtual GPU |
82d375d1 ZW |
200 | * @vgpu: virtual GPU |
201 | * | |
b79c52ae | 202 | * This function is called when user wants to activate a virtual GPU. |
82d375d1 ZW |
203 | * |
204 | */ | |
b79c52ae ZW |
205 | void intel_gvt_activate_vgpu(struct intel_vgpu *vgpu) |
206 | { | |
207 | mutex_lock(&vgpu->gvt->lock); | |
208 | vgpu->active = true; | |
209 | mutex_unlock(&vgpu->gvt->lock); | |
210 | } | |
211 | ||
212 | /** | |
213 | * intel_gvt_deactive_vgpu - deactivate a virtual GPU | |
214 | * @vgpu: virtual GPU | |
215 | * | |
216 | * This function is called when user wants to deactivate a virtual GPU. | |
217 | * All virtual GPU runtime information will be destroyed. | |
218 | * | |
219 | */ | |
220 | void intel_gvt_deactivate_vgpu(struct intel_vgpu *vgpu) | |
82d375d1 ZW |
221 | { |
222 | struct intel_gvt *gvt = vgpu->gvt; | |
223 | ||
224 | mutex_lock(&gvt->lock); | |
225 | ||
226 | vgpu->active = false; | |
82d375d1 | 227 | |
4b63960e ZW |
228 | if (atomic_read(&vgpu->running_workload_num)) { |
229 | mutex_unlock(&gvt->lock); | |
230 | intel_gvt_wait_vgpu_idle(vgpu); | |
231 | mutex_lock(&gvt->lock); | |
232 | } | |
233 | ||
234 | intel_vgpu_stop_schedule(vgpu); | |
b79c52ae ZW |
235 | |
236 | mutex_unlock(&gvt->lock); | |
237 | } | |
238 | ||
239 | /** | |
240 | * intel_gvt_destroy_vgpu - destroy a virtual GPU | |
241 | * @vgpu: virtual GPU | |
242 | * | |
243 | * This function is called when user wants to destroy a virtual GPU. | |
244 | * | |
245 | */ | |
246 | void intel_gvt_destroy_vgpu(struct intel_vgpu *vgpu) | |
247 | { | |
248 | struct intel_gvt *gvt = vgpu->gvt; | |
249 | ||
250 | mutex_lock(&gvt->lock); | |
251 | ||
252 | WARN(vgpu->active, "vGPU is still active!\n"); | |
253 | ||
254 | idr_remove(&gvt->vgpu_idr, vgpu->id); | |
4b63960e | 255 | intel_vgpu_clean_sched_policy(vgpu); |
e4734057 | 256 | intel_vgpu_clean_gvt_context(vgpu); |
28c4c6ca | 257 | intel_vgpu_clean_execlist(vgpu); |
04d348ae | 258 | intel_vgpu_clean_display(vgpu); |
4d60c5fd | 259 | intel_vgpu_clean_opregion(vgpu); |
2707e444 | 260 | intel_vgpu_clean_gtt(vgpu); |
82d375d1 ZW |
261 | intel_gvt_hypervisor_detach_vgpu(vgpu); |
262 | intel_vgpu_free_resource(vgpu); | |
cdcc4347 | 263 | intel_vgpu_clean_mmio(vgpu); |
82d375d1 ZW |
264 | vfree(vgpu); |
265 | ||
1f31c829 | 266 | intel_gvt_update_vgpu_types(gvt); |
82d375d1 ZW |
267 | mutex_unlock(&gvt->lock); |
268 | } | |
269 | ||
afe04fbe PG |
270 | #define IDLE_VGPU_IDR 0 |
271 | ||
272 | /** | |
273 | * intel_gvt_create_idle_vgpu - create an idle virtual GPU | |
274 | * @gvt: GVT device | |
275 | * | |
276 | * This function is called when user wants to create an idle virtual GPU. | |
277 | * | |
278 | * Returns: | |
279 | * pointer to intel_vgpu, error pointer if failed. | |
280 | */ | |
281 | struct intel_vgpu *intel_gvt_create_idle_vgpu(struct intel_gvt *gvt) | |
282 | { | |
283 | struct intel_vgpu *vgpu; | |
284 | enum intel_engine_id i; | |
285 | int ret; | |
286 | ||
287 | vgpu = vzalloc(sizeof(*vgpu)); | |
288 | if (!vgpu) | |
289 | return ERR_PTR(-ENOMEM); | |
290 | ||
291 | vgpu->id = IDLE_VGPU_IDR; | |
292 | vgpu->gvt = gvt; | |
293 | ||
294 | for (i = 0; i < I915_NUM_ENGINES; i++) | |
295 | INIT_LIST_HEAD(&vgpu->workload_q_head[i]); | |
296 | ||
297 | ret = intel_vgpu_init_sched_policy(vgpu); | |
298 | if (ret) | |
299 | goto out_free_vgpu; | |
300 | ||
301 | vgpu->active = false; | |
302 | ||
303 | return vgpu; | |
304 | ||
305 | out_free_vgpu: | |
306 | vfree(vgpu); | |
307 | return ERR_PTR(ret); | |
308 | } | |
309 | ||
310 | /** | |
311 | * intel_gvt_destroy_vgpu - destroy an idle virtual GPU | |
312 | * @vgpu: virtual GPU | |
313 | * | |
314 | * This function is called when user wants to destroy an idle virtual GPU. | |
315 | * | |
316 | */ | |
317 | void intel_gvt_destroy_idle_vgpu(struct intel_vgpu *vgpu) | |
318 | { | |
319 | intel_vgpu_clean_sched_policy(vgpu); | |
320 | vfree(vgpu); | |
321 | } | |
322 | ||
1f31c829 | 323 | static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt, |
82d375d1 ZW |
324 | struct intel_vgpu_creation_params *param) |
325 | { | |
326 | struct intel_vgpu *vgpu; | |
327 | int ret; | |
328 | ||
329 | gvt_dbg_core("handle %llu low %llu MB high %llu MB fence %llu\n", | |
330 | param->handle, param->low_gm_sz, param->high_gm_sz, | |
331 | param->fence_sz); | |
332 | ||
333 | vgpu = vzalloc(sizeof(*vgpu)); | |
334 | if (!vgpu) | |
335 | return ERR_PTR(-ENOMEM); | |
336 | ||
337 | mutex_lock(&gvt->lock); | |
338 | ||
afe04fbe PG |
339 | ret = idr_alloc(&gvt->vgpu_idr, vgpu, IDLE_VGPU_IDR + 1, GVT_MAX_VGPU, |
340 | GFP_KERNEL); | |
82d375d1 ZW |
341 | if (ret < 0) |
342 | goto out_free_vgpu; | |
343 | ||
344 | vgpu->id = ret; | |
345 | vgpu->handle = param->handle; | |
346 | vgpu->gvt = gvt; | |
bc90d097 | 347 | vgpu->sched_ctl.weight = param->weight; |
17865713 | 348 | bitmap_zero(vgpu->tlb_handle_pending, I915_NUM_ENGINES); |
82d375d1 | 349 | |
536fc234 | 350 | intel_vgpu_init_cfg_space(vgpu, param->primary); |
82d375d1 | 351 | |
cdcc4347 | 352 | ret = intel_vgpu_init_mmio(vgpu); |
82d375d1 | 353 | if (ret) |
4e537891 | 354 | goto out_clean_idr; |
82d375d1 ZW |
355 | |
356 | ret = intel_vgpu_alloc_resource(vgpu, param); | |
357 | if (ret) | |
358 | goto out_clean_vgpu_mmio; | |
359 | ||
360 | populate_pvinfo_page(vgpu); | |
361 | ||
362 | ret = intel_gvt_hypervisor_attach_vgpu(vgpu); | |
363 | if (ret) | |
364 | goto out_clean_vgpu_resource; | |
365 | ||
2707e444 ZW |
366 | ret = intel_vgpu_init_gtt(vgpu); |
367 | if (ret) | |
368 | goto out_detach_hypervisor_vgpu; | |
369 | ||
d1a513be | 370 | ret = intel_vgpu_init_display(vgpu, param->resolution); |
04d348ae | 371 | if (ret) |
8f89743b | 372 | goto out_clean_gtt; |
04d348ae | 373 | |
8453d674 ZW |
374 | ret = intel_vgpu_init_execlist(vgpu); |
375 | if (ret) | |
376 | goto out_clean_display; | |
377 | ||
e4734057 ZW |
378 | ret = intel_vgpu_init_gvt_context(vgpu); |
379 | if (ret) | |
380 | goto out_clean_execlist; | |
381 | ||
4b63960e ZW |
382 | ret = intel_vgpu_init_sched_policy(vgpu); |
383 | if (ret) | |
384 | goto out_clean_shadow_ctx; | |
385 | ||
82d375d1 ZW |
386 | mutex_unlock(&gvt->lock); |
387 | ||
388 | return vgpu; | |
389 | ||
4b63960e ZW |
390 | out_clean_shadow_ctx: |
391 | intel_vgpu_clean_gvt_context(vgpu); | |
e4734057 ZW |
392 | out_clean_execlist: |
393 | intel_vgpu_clean_execlist(vgpu); | |
8453d674 ZW |
394 | out_clean_display: |
395 | intel_vgpu_clean_display(vgpu); | |
4d60c5fd ZW |
396 | out_clean_gtt: |
397 | intel_vgpu_clean_gtt(vgpu); | |
2707e444 ZW |
398 | out_detach_hypervisor_vgpu: |
399 | intel_gvt_hypervisor_detach_vgpu(vgpu); | |
82d375d1 ZW |
400 | out_clean_vgpu_resource: |
401 | intel_vgpu_free_resource(vgpu); | |
402 | out_clean_vgpu_mmio: | |
cdcc4347 | 403 | intel_vgpu_clean_mmio(vgpu); |
4e537891 JS |
404 | out_clean_idr: |
405 | idr_remove(&gvt->vgpu_idr, vgpu->id); | |
82d375d1 ZW |
406 | out_free_vgpu: |
407 | vfree(vgpu); | |
408 | mutex_unlock(&gvt->lock); | |
409 | return ERR_PTR(ret); | |
410 | } | |
1f31c829 ZW |
411 | |
412 | /** | |
413 | * intel_gvt_create_vgpu - create a virtual GPU | |
414 | * @gvt: GVT device | |
415 | * @type: type of the vGPU to create | |
416 | * | |
417 | * This function is called when user wants to create a virtual GPU. | |
418 | * | |
419 | * Returns: | |
420 | * pointer to intel_vgpu, error pointer if failed. | |
421 | */ | |
422 | struct intel_vgpu *intel_gvt_create_vgpu(struct intel_gvt *gvt, | |
423 | struct intel_vgpu_type *type) | |
424 | { | |
425 | struct intel_vgpu_creation_params param; | |
426 | struct intel_vgpu *vgpu; | |
427 | ||
428 | param.handle = 0; | |
e992faee | 429 | param.primary = 1; |
1f31c829 ZW |
430 | param.low_gm_sz = type->low_gm_size; |
431 | param.high_gm_sz = type->high_gm_size; | |
432 | param.fence_sz = type->fence; | |
bc90d097 | 433 | param.weight = type->weight; |
d1a513be | 434 | param.resolution = type->resolution; |
1f31c829 ZW |
435 | |
436 | /* XXX current param based on MB */ | |
437 | param.low_gm_sz = BYTES_TO_MB(param.low_gm_sz); | |
438 | param.high_gm_sz = BYTES_TO_MB(param.high_gm_sz); | |
439 | ||
440 | vgpu = __intel_gvt_create_vgpu(gvt, ¶m); | |
441 | if (IS_ERR(vgpu)) | |
442 | return vgpu; | |
443 | ||
444 | /* calculate left instance change for types */ | |
445 | intel_gvt_update_vgpu_types(gvt); | |
446 | ||
447 | return vgpu; | |
448 | } | |
9ec1e66b JS |
449 | |
450 | /** | |
cfe65f40 CD |
451 | * intel_gvt_reset_vgpu_locked - reset a virtual GPU by DMLR or GT reset |
452 | * @vgpu: virtual GPU | |
453 | * @dmlr: vGPU Device Model Level Reset or GT Reset | |
454 | * @engine_mask: engines to reset for GT reset | |
455 | * | |
456 | * This function is called when user wants to reset a virtual GPU through | |
457 | * device model reset or GT reset. The caller should hold the gvt lock. | |
458 | * | |
459 | * vGPU Device Model Level Reset (DMLR) simulates the PCI level reset to reset | |
460 | * the whole vGPU to default state as when it is created. This vGPU function | |
461 | * is required both for functionary and security concerns.The ultimate goal | |
462 | * of vGPU FLR is that reuse a vGPU instance by virtual machines. When we | |
463 | * assign a vGPU to a virtual machine we must isse such reset first. | |
464 | * | |
465 | * Full GT Reset and Per-Engine GT Reset are soft reset flow for GPU engines | |
466 | * (Render, Blitter, Video, Video Enhancement). It is defined by GPU Spec. | |
467 | * Unlike the FLR, GT reset only reset particular resource of a vGPU per | |
468 | * the reset request. Guest driver can issue a GT reset by programming the | |
469 | * virtual GDRST register to reset specific virtual GPU engine or all | |
470 | * engines. | |
471 | * | |
472 | * The parameter dev_level is to identify if we will do DMLR or GT reset. | |
473 | * The parameter engine_mask is to specific the engines that need to be | |
474 | * resetted. If value ALL_ENGINES is given for engine_mask, it means | |
475 | * the caller requests a full GT reset that we will reset all virtual | |
476 | * GPU engines. For FLR, engine_mask is ignored. | |
477 | */ | |
478 | void intel_gvt_reset_vgpu_locked(struct intel_vgpu *vgpu, bool dmlr, | |
479 | unsigned int engine_mask) | |
480 | { | |
481 | struct intel_gvt *gvt = vgpu->gvt; | |
482 | struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler; | |
6184cc8d | 483 | unsigned int resetting_eng = dmlr ? ALL_ENGINES : engine_mask; |
cfe65f40 CD |
484 | |
485 | gvt_dbg_core("------------------------------------------\n"); | |
486 | gvt_dbg_core("resseting vgpu%d, dmlr %d, engine_mask %08x\n", | |
487 | vgpu->id, dmlr, engine_mask); | |
6184cc8d CD |
488 | |
489 | vgpu->resetting_eng = resetting_eng; | |
cfe65f40 CD |
490 | |
491 | intel_vgpu_stop_schedule(vgpu); | |
492 | /* | |
493 | * The current_vgpu will set to NULL after stopping the | |
494 | * scheduler when the reset is triggered by current vgpu. | |
495 | */ | |
496 | if (scheduler->current_vgpu == NULL) { | |
497 | mutex_unlock(&gvt->lock); | |
498 | intel_gvt_wait_vgpu_idle(vgpu); | |
499 | mutex_lock(&gvt->lock); | |
500 | } | |
501 | ||
6184cc8d | 502 | intel_vgpu_reset_execlist(vgpu, resetting_eng); |
cfe65f40 CD |
503 | |
504 | /* full GPU reset or device model level reset */ | |
505 | if (engine_mask == ALL_ENGINES || dmlr) { | |
615c16a9 | 506 | |
cfe65f40 | 507 | intel_vgpu_reset_gtt(vgpu, dmlr); |
615c16a9 | 508 | |
509 | /*fence will not be reset during virtual reset */ | |
510 | if (dmlr) | |
511 | intel_vgpu_reset_resource(vgpu); | |
512 | ||
513 | intel_vgpu_reset_mmio(vgpu, dmlr); | |
cfe65f40 | 514 | populate_pvinfo_page(vgpu); |
6294b61b | 515 | intel_vgpu_reset_display(vgpu); |
cfe65f40 | 516 | |
fd64be63 | 517 | if (dmlr) { |
cfe65f40 | 518 | intel_vgpu_reset_cfg_space(vgpu); |
fd64be63 MH |
519 | /* only reset the failsafe mode when dmlr reset */ |
520 | vgpu->failsafe = false; | |
521 | vgpu->pv_notified = false; | |
522 | } | |
cfe65f40 CD |
523 | } |
524 | ||
6184cc8d | 525 | vgpu->resetting_eng = 0; |
cfe65f40 CD |
526 | gvt_dbg_core("reset vgpu%d done\n", vgpu->id); |
527 | gvt_dbg_core("------------------------------------------\n"); | |
528 | } | |
529 | ||
530 | /** | |
531 | * intel_gvt_reset_vgpu - reset a virtual GPU (Function Level) | |
9ec1e66b JS |
532 | * @vgpu: virtual GPU |
533 | * | |
534 | * This function is called when user wants to reset a virtual GPU. | |
535 | * | |
536 | */ | |
537 | void intel_gvt_reset_vgpu(struct intel_vgpu *vgpu) | |
538 | { | |
cfe65f40 CD |
539 | mutex_lock(&vgpu->gvt->lock); |
540 | intel_gvt_reset_vgpu_locked(vgpu, true, 0); | |
541 | mutex_unlock(&vgpu->gvt->lock); | |
9ec1e66b | 542 | } |