blob: a63787be1e6b0513c4f8e43c750ee20840a082df [file] [log] [blame]
Zhi Wange4734052016-05-01 07:42:16 -04001/*
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 * Zhi Wang <zhi.a.wang@intel.com>
25 *
26 * Contributors:
27 * Ping Gao <ping.a.gao@intel.com>
28 * Tina Zhang <tina.zhang@intel.com>
29 * Chanbin Du <changbin.du@intel.com>
30 * Min He <min.he@intel.com>
31 * Bing Niu <bing.niu@intel.com>
32 * Zhenyu Wang <zhenyuw@linux.intel.com>
33 *
34 */
35
Zhi Wange4734052016-05-01 07:42:16 -040036#include <linux/kthread.h>
37
Zhenyu Wangfeddf6e2016-10-20 17:15:03 +080038#include "i915_drv.h"
39#include "gvt.h"
40
Zhi Wange4734052016-05-01 07:42:16 -040041#define RING_CTX_OFF(x) \
42 offsetof(struct execlist_ring_context, x)
43
Du, Changbin999ccb42016-10-20 14:08:47 +080044static void set_context_pdp_root_pointer(
45 struct execlist_ring_context *ring_context,
Zhi Wange4734052016-05-01 07:42:16 -040046 u32 pdp[8])
47{
48 struct execlist_mmio_pair *pdp_pair = &ring_context->pdp3_UDW;
49 int i;
50
51 for (i = 0; i < 8; i++)
52 pdp_pair[i].val = pdp[7 - i];
53}
54
55static int populate_shadow_context(struct intel_vgpu_workload *workload)
56{
57 struct intel_vgpu *vgpu = workload->vgpu;
58 struct intel_gvt *gvt = vgpu->gvt;
59 int ring_id = workload->ring_id;
60 struct i915_gem_context *shadow_ctx = workload->vgpu->shadow_ctx;
61 struct drm_i915_gem_object *ctx_obj =
62 shadow_ctx->engine[ring_id].state->obj;
63 struct execlist_ring_context *shadow_ring_context;
64 struct page *page;
65 void *dst;
66 unsigned long context_gpa, context_page_num;
67 int i;
68
69 gvt_dbg_sched("ring id %d workload lrca %x", ring_id,
70 workload->ctx_desc.lrca);
71
Joonas Lahtinen63ffbcd2017-04-28 10:53:36 +030072 context_page_num = gvt->dev_priv->engine[ring_id]->context_size;
Zhi Wange4734052016-05-01 07:42:16 -040073
74 context_page_num = context_page_num >> PAGE_SHIFT;
75
76 if (IS_BROADWELL(gvt->dev_priv) && ring_id == RCS)
77 context_page_num = 19;
78
79 i = 2;
80
81 while (i < context_page_num) {
82 context_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm,
83 (u32)((workload->ctx_desc.lrca + i) <<
84 GTT_PAGE_SHIFT));
85 if (context_gpa == INTEL_GVT_INVALID_ADDR) {
Tina Zhang695fbc02017-03-10 04:26:53 -050086 gvt_vgpu_err("Invalid guest context descriptor\n");
Zhi Wange4734052016-05-01 07:42:16 -040087 return -EINVAL;
88 }
89
Michel Thierry0b29c752017-09-13 09:56:00 +010090 page = i915_gem_object_get_page(ctx_obj, LRC_HEADER_PAGES + i);
Xiaoguang Chenc7549362016-11-03 18:38:30 +080091 dst = kmap(page);
Zhi Wange4734052016-05-01 07:42:16 -040092 intel_gvt_hypervisor_read_gpa(vgpu, context_gpa, dst,
93 GTT_PAGE_SIZE);
Xiaoguang Chenc7549362016-11-03 18:38:30 +080094 kunmap(page);
Zhi Wange4734052016-05-01 07:42:16 -040095 i++;
96 }
97
98 page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
Xiaoguang Chenc7549362016-11-03 18:38:30 +080099 shadow_ring_context = kmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400100
101#define COPY_REG(name) \
102 intel_gvt_hypervisor_read_gpa(vgpu, workload->ring_context_gpa \
103 + RING_CTX_OFF(name.val), &shadow_ring_context->name.val, 4)
104
105 COPY_REG(ctx_ctrl);
106 COPY_REG(ctx_timestamp);
107
108 if (ring_id == RCS) {
109 COPY_REG(bb_per_ctx_ptr);
110 COPY_REG(rcs_indirect_ctx);
111 COPY_REG(rcs_indirect_ctx_offset);
112 }
113#undef COPY_REG
114
115 set_context_pdp_root_pointer(shadow_ring_context,
116 workload->shadow_mm->shadow_page_table);
117
118 intel_gvt_hypervisor_read_gpa(vgpu,
119 workload->ring_context_gpa +
120 sizeof(*shadow_ring_context),
121 (void *)shadow_ring_context +
122 sizeof(*shadow_ring_context),
123 GTT_PAGE_SIZE - sizeof(*shadow_ring_context));
124
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800125 kunmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400126 return 0;
127}
128
Changbin Dubc2d4b62017-03-22 12:35:31 +0800129static inline bool is_gvt_request(struct drm_i915_gem_request *req)
130{
131 return i915_gem_context_force_single_submission(req->ctx);
132}
133
Xiong Zhang29f9e422017-11-07 05:23:02 +0800134static void save_ring_hw_state(struct intel_vgpu *vgpu, int ring_id)
135{
136 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
137 u32 ring_base = dev_priv->engine[ring_id]->mmio_base;
138 i915_reg_t reg;
139
140 reg = RING_INSTDONE(ring_base);
141 vgpu_vreg(vgpu, i915_mmio_reg_offset(reg)) = I915_READ_FW(reg);
142 reg = RING_ACTHD(ring_base);
143 vgpu_vreg(vgpu, i915_mmio_reg_offset(reg)) = I915_READ_FW(reg);
144 reg = RING_ACTHD_UDW(ring_base);
145 vgpu_vreg(vgpu, i915_mmio_reg_offset(reg)) = I915_READ_FW(reg);
146}
147
Zhi Wange4734052016-05-01 07:42:16 -0400148static int shadow_context_status_change(struct notifier_block *nb,
149 unsigned long action, void *data)
150{
Changbin Du3fc03062017-03-13 10:47:11 +0800151 struct drm_i915_gem_request *req = (struct drm_i915_gem_request *)data;
152 struct intel_gvt *gvt = container_of(nb, struct intel_gvt,
153 shadow_ctx_notifier_block[req->engine->id]);
154 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
Changbin Du0e86cc92017-05-04 10:52:38 +0800155 enum intel_engine_id ring_id = req->engine->id;
156 struct intel_vgpu_workload *workload;
Changbin Du679fd3e2017-11-13 14:58:31 +0800157 unsigned long flags;
Zhi Wange4734052016-05-01 07:42:16 -0400158
Changbin Du0e86cc92017-05-04 10:52:38 +0800159 if (!is_gvt_request(req)) {
Changbin Du679fd3e2017-11-13 14:58:31 +0800160 spin_lock_irqsave(&scheduler->mmio_context_lock, flags);
Changbin Du0e86cc92017-05-04 10:52:38 +0800161 if (action == INTEL_CONTEXT_SCHEDULE_IN &&
162 scheduler->engine_owner[ring_id]) {
163 /* Switch ring from vGPU to host. */
164 intel_gvt_switch_mmio(scheduler->engine_owner[ring_id],
165 NULL, ring_id);
166 scheduler->engine_owner[ring_id] = NULL;
167 }
Changbin Du679fd3e2017-11-13 14:58:31 +0800168 spin_unlock_irqrestore(&scheduler->mmio_context_lock, flags);
Changbin Du0e86cc92017-05-04 10:52:38 +0800169
170 return NOTIFY_OK;
171 }
172
173 workload = scheduler->current_workload[ring_id];
174 if (unlikely(!workload))
Chuanxiao Dong9272f732017-02-17 19:29:52 +0800175 return NOTIFY_OK;
176
Zhi Wange4734052016-05-01 07:42:16 -0400177 switch (action) {
178 case INTEL_CONTEXT_SCHEDULE_IN:
Changbin Du679fd3e2017-11-13 14:58:31 +0800179 spin_lock_irqsave(&scheduler->mmio_context_lock, flags);
Changbin Du0e86cc92017-05-04 10:52:38 +0800180 if (workload->vgpu != scheduler->engine_owner[ring_id]) {
181 /* Switch ring from host to vGPU or vGPU to vGPU. */
182 intel_gvt_switch_mmio(scheduler->engine_owner[ring_id],
183 workload->vgpu, ring_id);
184 scheduler->engine_owner[ring_id] = workload->vgpu;
185 } else
186 gvt_dbg_sched("skip ring %d mmio switch for vgpu%d\n",
187 ring_id, workload->vgpu->id);
Changbin Du679fd3e2017-11-13 14:58:31 +0800188 spin_unlock_irqrestore(&scheduler->mmio_context_lock, flags);
Zhi Wange4734052016-05-01 07:42:16 -0400189 atomic_set(&workload->shadow_ctx_active, 1);
190 break;
191 case INTEL_CONTEXT_SCHEDULE_OUT:
Chris Wilsond6c05112017-10-03 21:34:47 +0100192 case INTEL_CONTEXT_SCHEDULE_PREEMPTED:
Xiong Zhang29f9e422017-11-07 05:23:02 +0800193 save_ring_hw_state(workload->vgpu, ring_id);
Zhi Wange4734052016-05-01 07:42:16 -0400194 atomic_set(&workload->shadow_ctx_active, 0);
195 break;
196 default:
197 WARN_ON(1);
198 return NOTIFY_OK;
199 }
200 wake_up(&workload->shadow_ctx_status_wq);
201 return NOTIFY_OK;
202}
203
Kechen Lu9dfb8e52017-08-10 07:41:36 +0800204static void shadow_context_descriptor_update(struct i915_gem_context *ctx,
205 struct intel_engine_cs *engine)
206{
207 struct intel_context *ce = &ctx->engine[engine->id];
208 u64 desc = 0;
209
210 desc = ce->lrc_desc;
211
212 /* Update bits 0-11 of the context descriptor which includes flags
213 * like GEN8_CTX_* cached in desc_template
214 */
215 desc &= U64_MAX << 12;
216 desc |= ctx->desc_template & ((1ULL << 12) - 1);
217
218 ce->lrc_desc = desc;
219}
220
fred gao0a53bc02017-08-18 15:41:06 +0800221static int copy_workload_to_ring_buffer(struct intel_vgpu_workload *workload)
222{
223 struct intel_vgpu *vgpu = workload->vgpu;
224 void *shadow_ring_buffer_va;
225 u32 *cs;
226
227 /* allocate shadow ring buffer */
228 cs = intel_ring_begin(workload->req, workload->rb_len / sizeof(u32));
229 if (IS_ERR(cs)) {
230 gvt_vgpu_err("fail to alloc size =%ld shadow ring buffer\n",
231 workload->rb_len);
232 return PTR_ERR(cs);
233 }
234
235 shadow_ring_buffer_va = workload->shadow_ring_buffer_va;
236
237 /* get shadow ring buffer va */
238 workload->shadow_ring_buffer_va = cs;
239
240 memcpy(cs, shadow_ring_buffer_va,
241 workload->rb_len);
242
243 cs += workload->rb_len / sizeof(u32);
244 intel_ring_advance(workload->req, cs);
245
246 return 0;
247}
248
fred gaoa3cfdca2017-08-18 15:41:07 +0800249void release_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
250{
251 if (!wa_ctx->indirect_ctx.obj)
252 return;
253
254 i915_gem_object_unpin_map(wa_ctx->indirect_ctx.obj);
255 i915_gem_object_put(wa_ctx->indirect_ctx.obj);
256}
257
Ping Gao89ea20b2017-06-29 12:22:42 +0800258/**
259 * intel_gvt_scan_and_shadow_workload - audit the workload by scanning and
260 * shadow it as well, include ringbuffer,wa_ctx and ctx.
261 * @workload: an abstract entity for each execlist submission.
262 *
263 * This function is called before the workload submitting to i915, to make
264 * sure the content of the workload is valid.
265 */
266int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload)
Zhi Wange4734052016-05-01 07:42:16 -0400267{
Zhi Wange4734052016-05-01 07:42:16 -0400268 int ring_id = workload->ring_id;
269 struct i915_gem_context *shadow_ctx = workload->vgpu->shadow_ctx;
270 struct drm_i915_private *dev_priv = workload->vgpu->gvt->dev_priv;
fred gao0a53bc02017-08-18 15:41:06 +0800271 struct intel_engine_cs *engine = dev_priv->engine[ring_id];
Tina Zhang695fbc02017-03-10 04:26:53 -0500272 struct intel_vgpu *vgpu = workload->vgpu;
fred gao0a53bc02017-08-18 15:41:06 +0800273 struct intel_ring *ring;
Zhi Wange4734052016-05-01 07:42:16 -0400274 int ret;
275
Ping Gao87e919d2017-07-04 14:53:03 +0800276 lockdep_assert_held(&dev_priv->drm.struct_mutex);
277
Ping Gaod0302e72017-06-29 12:22:43 +0800278 if (workload->shadowed)
279 return 0;
Zhi Wange4734052016-05-01 07:42:16 -0400280
Zhenyu Wang03806ed2017-02-13 17:07:19 +0800281 shadow_ctx->desc_template &= ~(0x3 << GEN8_CTX_ADDRESSING_MODE_SHIFT);
282 shadow_ctx->desc_template |= workload->ctx_desc.addressing_mode <<
Zhi Wange4734052016-05-01 07:42:16 -0400283 GEN8_CTX_ADDRESSING_MODE_SHIFT;
284
Kechen Lu9dfb8e52017-08-10 07:41:36 +0800285 if (!test_and_set_bit(ring_id, vgpu->shadow_ctx_desc_updated))
286 shadow_context_descriptor_update(shadow_ctx,
287 dev_priv->engine[ring_id]);
Chuanxiao Dong3cd23b82017-03-16 09:47:58 +0800288
Ping Gao89ea20b2017-06-29 12:22:42 +0800289 ret = intel_gvt_scan_and_shadow_ringbuffer(workload);
Zhi Wangbe1da702016-05-03 18:26:57 -0400290 if (ret)
fred gaoa3cfdca2017-08-18 15:41:07 +0800291 goto err_scan;
Zhi Wangbe1da702016-05-03 18:26:57 -0400292
Tina Zhang17f1b1a2017-03-15 23:16:01 -0400293 if ((workload->ring_id == RCS) &&
294 (workload->wa_ctx.indirect_ctx.size != 0)) {
295 ret = intel_gvt_scan_and_shadow_wa_ctx(&workload->wa_ctx);
296 if (ret)
fred gaoa3cfdca2017-08-18 15:41:07 +0800297 goto err_scan;
Tina Zhang17f1b1a2017-03-15 23:16:01 -0400298 }
Zhi Wangbe1da702016-05-03 18:26:57 -0400299
Ping Gao89ea20b2017-06-29 12:22:42 +0800300 /* pin shadow context by gvt even the shadow context will be pinned
301 * when i915 alloc request. That is because gvt will update the guest
302 * context from shadow context when workload is completed, and at that
303 * moment, i915 may already unpined the shadow context to make the
304 * shadow_ctx pages invalid. So gvt need to pin itself. After update
305 * the guest context, gvt can unpin the shadow_ctx safely.
306 */
307 ring = engine->context_pin(engine, shadow_ctx);
308 if (IS_ERR(ring)) {
309 ret = PTR_ERR(ring);
310 gvt_vgpu_err("fail to pin shadow context\n");
fred gaoa3cfdca2017-08-18 15:41:07 +0800311 goto err_shadow;
Ping Gao89ea20b2017-06-29 12:22:42 +0800312 }
Zhi Wange4734052016-05-01 07:42:16 -0400313
fred gao0a53bc02017-08-18 15:41:06 +0800314 ret = populate_shadow_context(workload);
315 if (ret)
fred gaoa3cfdca2017-08-18 15:41:07 +0800316 goto err_unpin;
fred gaoc3c80f02017-11-14 17:09:35 +0800317 workload->shadowed = true;
318 return 0;
319
320err_unpin:
321 engine->context_unpin(engine, shadow_ctx);
322err_shadow:
323 release_shadow_wa_ctx(&workload->wa_ctx);
324err_scan:
325 return ret;
326}
327
328int intel_gvt_generate_request(struct intel_vgpu_workload *workload)
329{
330 int ring_id = workload->ring_id;
331 struct drm_i915_private *dev_priv = workload->vgpu->gvt->dev_priv;
332 struct intel_engine_cs *engine = dev_priv->engine[ring_id];
333 struct drm_i915_gem_request *rq;
334 struct intel_vgpu *vgpu = workload->vgpu;
335 struct i915_gem_context *shadow_ctx = vgpu->shadow_ctx;
336 int ret;
fred gao0a53bc02017-08-18 15:41:06 +0800337
338 rq = i915_gem_request_alloc(dev_priv->engine[ring_id], shadow_ctx);
339 if (IS_ERR(rq)) {
340 gvt_vgpu_err("fail to allocate gem request\n");
341 ret = PTR_ERR(rq);
fred gaoa3cfdca2017-08-18 15:41:07 +0800342 goto err_unpin;
fred gao0a53bc02017-08-18 15:41:06 +0800343 }
344
345 gvt_dbg_sched("ring id %d get i915 gem request %p\n", ring_id, rq);
346
347 workload->req = i915_gem_request_get(rq);
348 ret = copy_workload_to_ring_buffer(workload);
349 if (ret)
fred gaoa3cfdca2017-08-18 15:41:07 +0800350 goto err_unpin;
fred gaoa3cfdca2017-08-18 15:41:07 +0800351 return 0;
fred gao0a53bc02017-08-18 15:41:06 +0800352
fred gaoa3cfdca2017-08-18 15:41:07 +0800353err_unpin:
354 engine->context_unpin(engine, shadow_ctx);
fred gaoa3cfdca2017-08-18 15:41:07 +0800355 release_shadow_wa_ctx(&workload->wa_ctx);
fred gao0a53bc02017-08-18 15:41:06 +0800356 return ret;
357}
358
359static int dispatch_workload(struct intel_vgpu_workload *workload)
360{
361 int ring_id = workload->ring_id;
362 struct i915_gem_context *shadow_ctx = workload->vgpu->shadow_ctx;
363 struct drm_i915_private *dev_priv = workload->vgpu->gvt->dev_priv;
364 struct intel_engine_cs *engine = dev_priv->engine[ring_id];
365 int ret = 0;
366
367 gvt_dbg_sched("ring id %d prepare to dispatch workload %p\n",
368 ring_id, workload);
369
370 mutex_lock(&dev_priv->drm.struct_mutex);
371
372 ret = intel_gvt_scan_and_shadow_workload(workload);
373 if (ret)
374 goto out;
375
376 if (workload->prepare) {
377 ret = workload->prepare(workload);
fred gao0f437022017-08-18 15:41:10 +0800378 if (ret) {
379 engine->context_unpin(engine, shadow_ctx);
fred gao0a53bc02017-08-18 15:41:06 +0800380 goto out;
fred gao0f437022017-08-18 15:41:10 +0800381 }
fred gao0a53bc02017-08-18 15:41:06 +0800382 }
383
Pei Zhang90d27a12016-11-14 18:02:57 +0800384out:
385 if (ret)
386 workload->status = ret;
Chris Wilson0eb742d2016-10-20 17:29:36 +0800387
Ping Gao89ea20b2017-06-29 12:22:42 +0800388 if (!IS_ERR_OR_NULL(workload->req)) {
389 gvt_dbg_sched("ring id %d submit workload to i915 %p\n",
390 ring_id, workload->req);
391 i915_add_request(workload->req);
392 workload->dispatched = true;
393 }
Chuanxiao Dong3cd23b82017-03-16 09:47:58 +0800394
Pei Zhang90d27a12016-11-14 18:02:57 +0800395 mutex_unlock(&dev_priv->drm.struct_mutex);
Zhi Wange4734052016-05-01 07:42:16 -0400396 return ret;
397}
398
399static struct intel_vgpu_workload *pick_next_workload(
400 struct intel_gvt *gvt, int ring_id)
401{
402 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
403 struct intel_vgpu_workload *workload = NULL;
404
405 mutex_lock(&gvt->lock);
406
407 /*
408 * no current vgpu / will be scheduled out / no workload
409 * bail out
410 */
411 if (!scheduler->current_vgpu) {
412 gvt_dbg_sched("ring id %d stop - no current vgpu\n", ring_id);
413 goto out;
414 }
415
416 if (scheduler->need_reschedule) {
417 gvt_dbg_sched("ring id %d stop - will reschedule\n", ring_id);
418 goto out;
419 }
420
Zhenyu Wang954180a2017-04-12 14:22:50 +0800421 if (list_empty(workload_q_head(scheduler->current_vgpu, ring_id)))
Zhi Wange4734052016-05-01 07:42:16 -0400422 goto out;
Zhi Wange4734052016-05-01 07:42:16 -0400423
424 /*
425 * still have current workload, maybe the workload disptacher
426 * fail to submit it for some reason, resubmit it.
427 */
428 if (scheduler->current_workload[ring_id]) {
429 workload = scheduler->current_workload[ring_id];
430 gvt_dbg_sched("ring id %d still have current workload %p\n",
431 ring_id, workload);
432 goto out;
433 }
434
435 /*
436 * pick a workload as current workload
437 * once current workload is set, schedule policy routines
438 * will wait the current workload is finished when trying to
439 * schedule out a vgpu.
440 */
441 scheduler->current_workload[ring_id] = container_of(
442 workload_q_head(scheduler->current_vgpu, ring_id)->next,
443 struct intel_vgpu_workload, list);
444
445 workload = scheduler->current_workload[ring_id];
446
447 gvt_dbg_sched("ring id %d pick new workload %p\n", ring_id, workload);
448
449 atomic_inc(&workload->vgpu->running_workload_num);
450out:
451 mutex_unlock(&gvt->lock);
452 return workload;
453}
454
455static void update_guest_context(struct intel_vgpu_workload *workload)
456{
457 struct intel_vgpu *vgpu = workload->vgpu;
458 struct intel_gvt *gvt = vgpu->gvt;
459 int ring_id = workload->ring_id;
460 struct i915_gem_context *shadow_ctx = workload->vgpu->shadow_ctx;
461 struct drm_i915_gem_object *ctx_obj =
462 shadow_ctx->engine[ring_id].state->obj;
463 struct execlist_ring_context *shadow_ring_context;
464 struct page *page;
465 void *src;
466 unsigned long context_gpa, context_page_num;
467 int i;
468
469 gvt_dbg_sched("ring id %d workload lrca %x\n", ring_id,
470 workload->ctx_desc.lrca);
471
Joonas Lahtinen63ffbcd2017-04-28 10:53:36 +0300472 context_page_num = gvt->dev_priv->engine[ring_id]->context_size;
Zhi Wange4734052016-05-01 07:42:16 -0400473
474 context_page_num = context_page_num >> PAGE_SHIFT;
475
476 if (IS_BROADWELL(gvt->dev_priv) && ring_id == RCS)
477 context_page_num = 19;
478
479 i = 2;
480
481 while (i < context_page_num) {
482 context_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm,
483 (u32)((workload->ctx_desc.lrca + i) <<
484 GTT_PAGE_SHIFT));
485 if (context_gpa == INTEL_GVT_INVALID_ADDR) {
Tina Zhang695fbc02017-03-10 04:26:53 -0500486 gvt_vgpu_err("invalid guest context descriptor\n");
Zhi Wange4734052016-05-01 07:42:16 -0400487 return;
488 }
489
Michel Thierry0b29c752017-09-13 09:56:00 +0100490 page = i915_gem_object_get_page(ctx_obj, LRC_HEADER_PAGES + i);
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800491 src = kmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400492 intel_gvt_hypervisor_write_gpa(vgpu, context_gpa, src,
493 GTT_PAGE_SIZE);
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800494 kunmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400495 i++;
496 }
497
498 intel_gvt_hypervisor_write_gpa(vgpu, workload->ring_context_gpa +
499 RING_CTX_OFF(ring_header.val), &workload->rb_tail, 4);
500
501 page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800502 shadow_ring_context = kmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400503
504#define COPY_REG(name) \
505 intel_gvt_hypervisor_write_gpa(vgpu, workload->ring_context_gpa + \
506 RING_CTX_OFF(name.val), &shadow_ring_context->name.val, 4)
507
508 COPY_REG(ctx_ctrl);
509 COPY_REG(ctx_timestamp);
510
511#undef COPY_REG
512
513 intel_gvt_hypervisor_write_gpa(vgpu,
514 workload->ring_context_gpa +
515 sizeof(*shadow_ring_context),
516 (void *)shadow_ring_context +
517 sizeof(*shadow_ring_context),
518 GTT_PAGE_SIZE - sizeof(*shadow_ring_context));
519
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800520 kunmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400521}
522
523static void complete_current_workload(struct intel_gvt *gvt, int ring_id)
524{
525 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
526 struct intel_vgpu_workload *workload;
Changbin Du440a9b92017-01-05 16:49:03 +0800527 struct intel_vgpu *vgpu;
Zhi Wangbe1da702016-05-03 18:26:57 -0400528 int event;
Zhi Wange4734052016-05-01 07:42:16 -0400529
530 mutex_lock(&gvt->lock);
531
532 workload = scheduler->current_workload[ring_id];
Changbin Du440a9b92017-01-05 16:49:03 +0800533 vgpu = workload->vgpu;
Zhi Wange4734052016-05-01 07:42:16 -0400534
Chuanxiao Dong8f1117a2017-03-06 13:05:24 +0800535 /* For the workload w/ request, needs to wait for the context
536 * switch to make sure request is completed.
537 * For the workload w/o request, directly complete the workload.
538 */
539 if (workload->req) {
Chuanxiao Dong3cd23b82017-03-16 09:47:58 +0800540 struct drm_i915_private *dev_priv =
541 workload->vgpu->gvt->dev_priv;
542 struct intel_engine_cs *engine =
543 dev_priv->engine[workload->ring_id];
Zhi Wange4734052016-05-01 07:42:16 -0400544 wait_event(workload->shadow_ctx_status_wq,
545 !atomic_read(&workload->shadow_ctx_active));
546
Chuanxiao Dong0cf5ec42017-06-23 13:01:11 +0800547 /* If this request caused GPU hang, req->fence.error will
548 * be set to -EIO. Use -EIO to set workload status so
549 * that when this request caused GPU hang, didn't trigger
550 * context switch interrupt to guest.
551 */
552 if (likely(workload->status == -EINPROGRESS)) {
553 if (workload->req->fence.error == -EIO)
554 workload->status = -EIO;
555 else
556 workload->status = 0;
557 }
558
Chuanxiao Dong8f1117a2017-03-06 13:05:24 +0800559 i915_gem_request_put(fetch_and_zero(&workload->req));
Zhi Wangbe1da702016-05-03 18:26:57 -0400560
Chuanxiao Dong6184cc82017-08-01 17:47:25 +0800561 if (!workload->status && !(vgpu->resetting_eng &
562 ENGINE_MASK(ring_id))) {
Chuanxiao Dong8f1117a2017-03-06 13:05:24 +0800563 update_guest_context(workload);
564
565 for_each_set_bit(event, workload->pending_events,
566 INTEL_GVT_EVENT_MAX)
567 intel_vgpu_trigger_virtual_event(vgpu, event);
568 }
Chuanxiao Dong3cd23b82017-03-16 09:47:58 +0800569 mutex_lock(&dev_priv->drm.struct_mutex);
570 /* unpin shadow ctx as the shadow_ctx update is done */
571 engine->context_unpin(engine, workload->vgpu->shadow_ctx);
572 mutex_unlock(&dev_priv->drm.struct_mutex);
Zhi Wange4734052016-05-01 07:42:16 -0400573 }
574
575 gvt_dbg_sched("ring id %d complete workload %p status %d\n",
576 ring_id, workload, workload->status);
577
578 scheduler->current_workload[ring_id] = NULL;
579
Zhi Wange4734052016-05-01 07:42:16 -0400580 list_del_init(&workload->list);
581 workload->complete(workload);
582
Changbin Du440a9b92017-01-05 16:49:03 +0800583 atomic_dec(&vgpu->running_workload_num);
Zhi Wange4734052016-05-01 07:42:16 -0400584 wake_up(&scheduler->workload_complete_wq);
Ping Gaof100dae2017-05-24 09:14:11 +0800585
586 if (gvt->scheduler.need_reschedule)
587 intel_gvt_request_service(gvt, INTEL_GVT_REQUEST_EVENT_SCHED);
588
Zhi Wange4734052016-05-01 07:42:16 -0400589 mutex_unlock(&gvt->lock);
590}
591
592struct workload_thread_param {
593 struct intel_gvt *gvt;
594 int ring_id;
595};
596
597static int workload_thread(void *priv)
598{
599 struct workload_thread_param *p = (struct workload_thread_param *)priv;
600 struct intel_gvt *gvt = p->gvt;
601 int ring_id = p->ring_id;
602 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
603 struct intel_vgpu_workload *workload = NULL;
Tina Zhang695fbc02017-03-10 04:26:53 -0500604 struct intel_vgpu *vgpu = NULL;
Zhi Wange4734052016-05-01 07:42:16 -0400605 int ret;
Xu Hane3476c02017-03-29 10:13:59 +0800606 bool need_force_wake = IS_SKYLAKE(gvt->dev_priv)
607 || IS_KABYLAKE(gvt->dev_priv);
Du, Changbine45d7b72016-10-27 11:10:31 +0800608 DEFINE_WAIT_FUNC(wait, woken_wake_function);
Zhi Wange4734052016-05-01 07:42:16 -0400609
610 kfree(p);
611
612 gvt_dbg_core("workload thread for ring %d started\n", ring_id);
613
614 while (!kthread_should_stop()) {
Du, Changbine45d7b72016-10-27 11:10:31 +0800615 add_wait_queue(&scheduler->waitq[ring_id], &wait);
616 do {
617 workload = pick_next_workload(gvt, ring_id);
618 if (workload)
619 break;
620 wait_woken(&wait, TASK_INTERRUPTIBLE,
621 MAX_SCHEDULE_TIMEOUT);
622 } while (!kthread_should_stop());
623 remove_wait_queue(&scheduler->waitq[ring_id], &wait);
Zhi Wange4734052016-05-01 07:42:16 -0400624
Du, Changbine45d7b72016-10-27 11:10:31 +0800625 if (!workload)
Zhi Wange4734052016-05-01 07:42:16 -0400626 break;
627
628 gvt_dbg_sched("ring id %d next workload %p vgpu %d\n",
629 workload->ring_id, workload,
630 workload->vgpu->id);
631
632 intel_runtime_pm_get(gvt->dev_priv);
633
Zhi Wange4734052016-05-01 07:42:16 -0400634 gvt_dbg_sched("ring id %d will dispatch workload %p\n",
635 workload->ring_id, workload);
636
637 if (need_force_wake)
638 intel_uncore_forcewake_get(gvt->dev_priv,
639 FORCEWAKE_ALL);
640
Pei Zhang90d27a12016-11-14 18:02:57 +0800641 mutex_lock(&gvt->lock);
Zhi Wange4734052016-05-01 07:42:16 -0400642 ret = dispatch_workload(workload);
Pei Zhang90d27a12016-11-14 18:02:57 +0800643 mutex_unlock(&gvt->lock);
Chris Wilson66bbc3b2016-10-19 11:11:44 +0100644
Zhi Wange4734052016-05-01 07:42:16 -0400645 if (ret) {
Tina Zhang695fbc02017-03-10 04:26:53 -0500646 vgpu = workload->vgpu;
647 gvt_vgpu_err("fail to dispatch workload, skip\n");
Zhi Wange4734052016-05-01 07:42:16 -0400648 goto complete;
649 }
650
651 gvt_dbg_sched("ring id %d wait workload %p\n",
652 workload->ring_id, workload);
Chris Wilson3dce2ac2017-03-08 22:08:08 +0000653 i915_wait_request(workload->req, 0, MAX_SCHEDULE_TIMEOUT);
Zhi Wange4734052016-05-01 07:42:16 -0400654
655complete:
Changbin Du3ce32742017-02-09 10:13:16 +0800656 gvt_dbg_sched("will complete workload %p, status: %d\n",
Zhi Wange4734052016-05-01 07:42:16 -0400657 workload, workload->status);
658
Changbin Du2e51ef32017-01-05 13:28:05 +0800659 complete_current_workload(gvt, ring_id);
660
Zhi Wange4734052016-05-01 07:42:16 -0400661 if (need_force_wake)
662 intel_uncore_forcewake_put(gvt->dev_priv,
663 FORCEWAKE_ALL);
664
Zhi Wange4734052016-05-01 07:42:16 -0400665 intel_runtime_pm_put(gvt->dev_priv);
Zhi Wange4734052016-05-01 07:42:16 -0400666 }
667 return 0;
668}
669
670void intel_gvt_wait_vgpu_idle(struct intel_vgpu *vgpu)
671{
672 struct intel_gvt *gvt = vgpu->gvt;
673 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
674
675 if (atomic_read(&vgpu->running_workload_num)) {
676 gvt_dbg_sched("wait vgpu idle\n");
677
678 wait_event(scheduler->workload_complete_wq,
679 !atomic_read(&vgpu->running_workload_num));
680 }
681}
682
683void intel_gvt_clean_workload_scheduler(struct intel_gvt *gvt)
684{
685 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
Changbin Du3fc03062017-03-13 10:47:11 +0800686 struct intel_engine_cs *engine;
687 enum intel_engine_id i;
Zhi Wange4734052016-05-01 07:42:16 -0400688
689 gvt_dbg_core("clean workload scheduler\n");
690
Changbin Du3fc03062017-03-13 10:47:11 +0800691 for_each_engine(engine, gvt->dev_priv, i) {
692 atomic_notifier_chain_unregister(
693 &engine->context_status_notifier,
694 &gvt->shadow_ctx_notifier_block[i]);
695 kthread_stop(scheduler->thread[i]);
Zhi Wange4734052016-05-01 07:42:16 -0400696 }
697}
698
699int intel_gvt_init_workload_scheduler(struct intel_gvt *gvt)
700{
701 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
702 struct workload_thread_param *param = NULL;
Changbin Du3fc03062017-03-13 10:47:11 +0800703 struct intel_engine_cs *engine;
704 enum intel_engine_id i;
Zhi Wange4734052016-05-01 07:42:16 -0400705 int ret;
Zhi Wange4734052016-05-01 07:42:16 -0400706
707 gvt_dbg_core("init workload scheduler\n");
708
709 init_waitqueue_head(&scheduler->workload_complete_wq);
710
Changbin Du3fc03062017-03-13 10:47:11 +0800711 for_each_engine(engine, gvt->dev_priv, i) {
Zhi Wange4734052016-05-01 07:42:16 -0400712 init_waitqueue_head(&scheduler->waitq[i]);
713
714 param = kzalloc(sizeof(*param), GFP_KERNEL);
715 if (!param) {
716 ret = -ENOMEM;
717 goto err;
718 }
719
720 param->gvt = gvt;
721 param->ring_id = i;
722
723 scheduler->thread[i] = kthread_run(workload_thread, param,
724 "gvt workload %d", i);
725 if (IS_ERR(scheduler->thread[i])) {
726 gvt_err("fail to create workload thread\n");
727 ret = PTR_ERR(scheduler->thread[i]);
728 goto err;
729 }
Changbin Du3fc03062017-03-13 10:47:11 +0800730
731 gvt->shadow_ctx_notifier_block[i].notifier_call =
732 shadow_context_status_change;
733 atomic_notifier_chain_register(&engine->context_status_notifier,
734 &gvt->shadow_ctx_notifier_block[i]);
Zhi Wange4734052016-05-01 07:42:16 -0400735 }
736 return 0;
737err:
738 intel_gvt_clean_workload_scheduler(gvt);
739 kfree(param);
740 param = NULL;
741 return ret;
742}
743
744void intel_vgpu_clean_gvt_context(struct intel_vgpu *vgpu)
745{
Chris Wilson5f09a9c2017-06-20 12:05:46 +0100746 i915_gem_context_put(vgpu->shadow_ctx);
Zhi Wange4734052016-05-01 07:42:16 -0400747}
748
749int intel_vgpu_init_gvt_context(struct intel_vgpu *vgpu)
750{
751 atomic_set(&vgpu->running_workload_num, 0);
752
753 vgpu->shadow_ctx = i915_gem_context_create_gvt(
754 &vgpu->gvt->dev_priv->drm);
755 if (IS_ERR(vgpu->shadow_ctx))
756 return PTR_ERR(vgpu->shadow_ctx);
757
758 vgpu->shadow_ctx->engine[RCS].initialised = true;
759
Kechen Lu9dfb8e52017-08-10 07:41:36 +0800760 bitmap_zero(vgpu->shadow_ctx_desc_updated, I915_NUM_ENGINES);
761
Zhi Wange4734052016-05-01 07:42:16 -0400762 return 0;
763}