blob: cd6f63b5a40a60da4fec524d175ac8c16b009fcb [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{
Zhi Wange4734052016-05-01 07:42:16 -040048 int i;
49
50 for (i = 0; i < 8; i++)
Xinyun Liu1417fad2018-06-07 22:48:42 +080051 ring_context->pdps[i].val = pdp[7 - i];
Zhi Wange4734052016-05-01 07:42:16 -040052}
53
Zhi Wangb20c0d52018-02-07 18:12:15 +080054static void update_shadow_pdps(struct intel_vgpu_workload *workload)
55{
Zhi Wangb20c0d52018-02-07 18:12:15 +080056 struct drm_i915_gem_object *ctx_obj =
Chris Wilson1fc44d92018-05-17 22:26:32 +010057 workload->req->hw_context->state->obj;
Zhi Wangb20c0d52018-02-07 18:12:15 +080058 struct execlist_ring_context *shadow_ring_context;
59 struct page *page;
60
61 if (WARN_ON(!workload->shadow_mm))
62 return;
63
64 if (WARN_ON(!atomic_read(&workload->shadow_mm->pincount)))
65 return;
66
67 page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
68 shadow_ring_context = kmap(page);
69 set_context_pdp_root_pointer(shadow_ring_context,
70 (void *)workload->shadow_mm->ppgtt_mm.shadow_pdps);
71 kunmap(page);
72}
73
Min Hefa3dd622018-03-02 10:00:25 +080074/*
75 * when populating shadow ctx from guest, we should not overrride oa related
76 * registers, so that they will not be overlapped by guest oa configs. Thus
77 * made it possible to capture oa data from host for both host and guests.
78 */
79static void sr_oa_regs(struct intel_vgpu_workload *workload,
80 u32 *reg_state, bool save)
81{
82 struct drm_i915_private *dev_priv = workload->vgpu->gvt->dev_priv;
83 u32 ctx_oactxctrl = dev_priv->perf.oa.ctx_oactxctrl_offset;
84 u32 ctx_flexeu0 = dev_priv->perf.oa.ctx_flexeu0_offset;
85 int i = 0;
86 u32 flex_mmio[] = {
87 i915_mmio_reg_offset(EU_PERF_CNTL0),
88 i915_mmio_reg_offset(EU_PERF_CNTL1),
89 i915_mmio_reg_offset(EU_PERF_CNTL2),
90 i915_mmio_reg_offset(EU_PERF_CNTL3),
91 i915_mmio_reg_offset(EU_PERF_CNTL4),
92 i915_mmio_reg_offset(EU_PERF_CNTL5),
93 i915_mmio_reg_offset(EU_PERF_CNTL6),
94 };
95
Gustavo A. R. Silva41e7ccc2018-03-22 13:21:54 -050096 if (workload->ring_id != RCS)
Min Hefa3dd622018-03-02 10:00:25 +080097 return;
98
99 if (save) {
100 workload->oactxctrl = reg_state[ctx_oactxctrl + 1];
101
102 for (i = 0; i < ARRAY_SIZE(workload->flex_mmio); i++) {
103 u32 state_offset = ctx_flexeu0 + i * 2;
104
105 workload->flex_mmio[i] = reg_state[state_offset + 1];
106 }
107 } else {
108 reg_state[ctx_oactxctrl] =
109 i915_mmio_reg_offset(GEN8_OACTXCONTROL);
110 reg_state[ctx_oactxctrl + 1] = workload->oactxctrl;
111
112 for (i = 0; i < ARRAY_SIZE(workload->flex_mmio); i++) {
113 u32 state_offset = ctx_flexeu0 + i * 2;
114 u32 mmio = flex_mmio[i];
115
116 reg_state[state_offset] = mmio;
117 reg_state[state_offset + 1] = workload->flex_mmio[i];
118 }
119 }
120}
121
Zhi Wange4734052016-05-01 07:42:16 -0400122static int populate_shadow_context(struct intel_vgpu_workload *workload)
123{
124 struct intel_vgpu *vgpu = workload->vgpu;
125 struct intel_gvt *gvt = vgpu->gvt;
126 int ring_id = workload->ring_id;
Zhi Wange4734052016-05-01 07:42:16 -0400127 struct drm_i915_gem_object *ctx_obj =
Chris Wilson1fc44d92018-05-17 22:26:32 +0100128 workload->req->hw_context->state->obj;
Zhi Wange4734052016-05-01 07:42:16 -0400129 struct execlist_ring_context *shadow_ring_context;
130 struct page *page;
131 void *dst;
132 unsigned long context_gpa, context_page_num;
133 int i;
134
Zhi Wange4734052016-05-01 07:42:16 -0400135 page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800136 shadow_ring_context = kmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400137
Min Hefa3dd622018-03-02 10:00:25 +0800138 sr_oa_regs(workload, (u32 *)shadow_ring_context, true);
Zhi Wange4734052016-05-01 07:42:16 -0400139#define COPY_REG(name) \
140 intel_gvt_hypervisor_read_gpa(vgpu, workload->ring_context_gpa \
141 + RING_CTX_OFF(name.val), &shadow_ring_context->name.val, 4)
Zhenyu Wangd8303072018-03-19 17:09:05 +0800142#define COPY_REG_MASKED(name) {\
143 intel_gvt_hypervisor_read_gpa(vgpu, workload->ring_context_gpa \
144 + RING_CTX_OFF(name.val),\
145 &shadow_ring_context->name.val, 4);\
146 shadow_ring_context->name.val |= 0xffff << 16;\
147 }
Zhi Wange4734052016-05-01 07:42:16 -0400148
Zhenyu Wangd8303072018-03-19 17:09:05 +0800149 COPY_REG_MASKED(ctx_ctrl);
Zhi Wange4734052016-05-01 07:42:16 -0400150 COPY_REG(ctx_timestamp);
151
152 if (ring_id == RCS) {
153 COPY_REG(bb_per_ctx_ptr);
154 COPY_REG(rcs_indirect_ctx);
155 COPY_REG(rcs_indirect_ctx_offset);
156 }
157#undef COPY_REG
Zhenyu Wangd8303072018-03-19 17:09:05 +0800158#undef COPY_REG_MASKED
Zhi Wange4734052016-05-01 07:42:16 -0400159
Zhi Wange4734052016-05-01 07:42:16 -0400160 intel_gvt_hypervisor_read_gpa(vgpu,
161 workload->ring_context_gpa +
162 sizeof(*shadow_ring_context),
163 (void *)shadow_ring_context +
164 sizeof(*shadow_ring_context),
Zhi Wang9556e112017-10-10 13:51:32 +0800165 I915_GTT_PAGE_SIZE - sizeof(*shadow_ring_context));
Zhi Wange4734052016-05-01 07:42:16 -0400166
Min Hefa3dd622018-03-02 10:00:25 +0800167 sr_oa_regs(workload, (u32 *)shadow_ring_context, false);
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800168 kunmap(page);
Zhao Yan8bfa02c2018-08-01 00:15:31 -0400169
170 if (IS_RESTORE_INHIBIT(shadow_ring_context->ctx_ctrl.val))
171 return 0;
172
173 gvt_dbg_sched("ring id %d workload lrca %x", ring_id,
174 workload->ctx_desc.lrca);
175
176 context_page_num = gvt->dev_priv->engine[ring_id]->context_size;
177
178 context_page_num = context_page_num >> PAGE_SHIFT;
179
180 if (IS_BROADWELL(gvt->dev_priv) && ring_id == RCS)
181 context_page_num = 19;
182
183 i = 2;
184 while (i < context_page_num) {
185 context_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm,
186 (u32)((workload->ctx_desc.lrca + i) <<
187 I915_GTT_PAGE_SHIFT));
188 if (context_gpa == INTEL_GVT_INVALID_ADDR) {
189 gvt_vgpu_err("Invalid guest context descriptor\n");
190 return -EFAULT;
191 }
192
193 page = i915_gem_object_get_page(ctx_obj, LRC_HEADER_PAGES + i);
194 dst = kmap(page);
195 intel_gvt_hypervisor_read_gpa(vgpu, context_gpa, dst,
196 I915_GTT_PAGE_SIZE);
197 kunmap(page);
198 i++;
199 }
Zhi Wange4734052016-05-01 07:42:16 -0400200 return 0;
201}
202
Chris Wilsone61e0f52018-02-21 09:56:36 +0000203static inline bool is_gvt_request(struct i915_request *req)
Changbin Dubc2d4b62017-03-22 12:35:31 +0800204{
Chris Wilson4e0d64d2018-05-17 22:26:30 +0100205 return i915_gem_context_force_single_submission(req->gem_context);
Changbin Dubc2d4b62017-03-22 12:35:31 +0800206}
207
Xiong Zhang295764c2017-11-07 05:23:02 +0800208static void save_ring_hw_state(struct intel_vgpu *vgpu, int ring_id)
209{
210 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
211 u32 ring_base = dev_priv->engine[ring_id]->mmio_base;
212 i915_reg_t reg;
213
214 reg = RING_INSTDONE(ring_base);
215 vgpu_vreg(vgpu, i915_mmio_reg_offset(reg)) = I915_READ_FW(reg);
216 reg = RING_ACTHD(ring_base);
217 vgpu_vreg(vgpu, i915_mmio_reg_offset(reg)) = I915_READ_FW(reg);
218 reg = RING_ACTHD_UDW(ring_base);
219 vgpu_vreg(vgpu, i915_mmio_reg_offset(reg)) = I915_READ_FW(reg);
220}
221
Zhi Wange4734052016-05-01 07:42:16 -0400222static int shadow_context_status_change(struct notifier_block *nb,
223 unsigned long action, void *data)
224{
Chris Wilsone61e0f52018-02-21 09:56:36 +0000225 struct i915_request *req = data;
Changbin Du3fc03062017-03-13 10:47:11 +0800226 struct intel_gvt *gvt = container_of(nb, struct intel_gvt,
227 shadow_ctx_notifier_block[req->engine->id]);
228 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
Changbin Du0e86cc92017-05-04 10:52:38 +0800229 enum intel_engine_id ring_id = req->engine->id;
230 struct intel_vgpu_workload *workload;
Changbin Du679fd3e2017-11-13 14:58:31 +0800231 unsigned long flags;
Zhi Wange4734052016-05-01 07:42:16 -0400232
Changbin Du0e86cc92017-05-04 10:52:38 +0800233 if (!is_gvt_request(req)) {
Changbin Du679fd3e2017-11-13 14:58:31 +0800234 spin_lock_irqsave(&scheduler->mmio_context_lock, flags);
Changbin Du0e86cc92017-05-04 10:52:38 +0800235 if (action == INTEL_CONTEXT_SCHEDULE_IN &&
236 scheduler->engine_owner[ring_id]) {
237 /* Switch ring from vGPU to host. */
238 intel_gvt_switch_mmio(scheduler->engine_owner[ring_id],
239 NULL, ring_id);
240 scheduler->engine_owner[ring_id] = NULL;
241 }
Changbin Du679fd3e2017-11-13 14:58:31 +0800242 spin_unlock_irqrestore(&scheduler->mmio_context_lock, flags);
Changbin Du0e86cc92017-05-04 10:52:38 +0800243
244 return NOTIFY_OK;
245 }
246
247 workload = scheduler->current_workload[ring_id];
248 if (unlikely(!workload))
Chuanxiao Dong9272f732017-02-17 19:29:52 +0800249 return NOTIFY_OK;
250
Zhi Wange4734052016-05-01 07:42:16 -0400251 switch (action) {
252 case INTEL_CONTEXT_SCHEDULE_IN:
Changbin Du679fd3e2017-11-13 14:58:31 +0800253 spin_lock_irqsave(&scheduler->mmio_context_lock, flags);
Changbin Du0e86cc92017-05-04 10:52:38 +0800254 if (workload->vgpu != scheduler->engine_owner[ring_id]) {
255 /* Switch ring from host to vGPU or vGPU to vGPU. */
256 intel_gvt_switch_mmio(scheduler->engine_owner[ring_id],
257 workload->vgpu, ring_id);
258 scheduler->engine_owner[ring_id] = workload->vgpu;
259 } else
260 gvt_dbg_sched("skip ring %d mmio switch for vgpu%d\n",
261 ring_id, workload->vgpu->id);
Changbin Du679fd3e2017-11-13 14:58:31 +0800262 spin_unlock_irqrestore(&scheduler->mmio_context_lock, flags);
Zhi Wange4734052016-05-01 07:42:16 -0400263 atomic_set(&workload->shadow_ctx_active, 1);
264 break;
265 case INTEL_CONTEXT_SCHEDULE_OUT:
Xiong Zhang295764c2017-11-07 05:23:02 +0800266 save_ring_hw_state(workload->vgpu, ring_id);
Zhi Wange4734052016-05-01 07:42:16 -0400267 atomic_set(&workload->shadow_ctx_active, 0);
268 break;
Zhenyu Wangda5f99e2017-12-01 14:59:53 +0800269 case INTEL_CONTEXT_SCHEDULE_PREEMPTED:
270 save_ring_hw_state(workload->vgpu, ring_id);
271 break;
Zhi Wange4734052016-05-01 07:42:16 -0400272 default:
273 WARN_ON(1);
274 return NOTIFY_OK;
275 }
276 wake_up(&workload->shadow_ctx_status_wq);
277 return NOTIFY_OK;
278}
279
Chris Wilson1fc44d92018-05-17 22:26:32 +0100280static void shadow_context_descriptor_update(struct intel_context *ce)
Kechen Lu9dfb8e52017-08-10 07:41:36 +0800281{
Kechen Lu9dfb8e52017-08-10 07:41:36 +0800282 u64 desc = 0;
283
284 desc = ce->lrc_desc;
285
286 /* Update bits 0-11 of the context descriptor which includes flags
287 * like GEN8_CTX_* cached in desc_template
288 */
289 desc &= U64_MAX << 12;
Chris Wilson1fc44d92018-05-17 22:26:32 +0100290 desc |= ce->gem_context->desc_template & ((1ULL << 12) - 1);
Kechen Lu9dfb8e52017-08-10 07:41:36 +0800291
292 ce->lrc_desc = desc;
293}
294
fred gao0a53bc02017-08-18 15:41:06 +0800295static int copy_workload_to_ring_buffer(struct intel_vgpu_workload *workload)
296{
297 struct intel_vgpu *vgpu = workload->vgpu;
Chris Wilson1fc44d92018-05-17 22:26:32 +0100298 struct i915_request *req = workload->req;
fred gao0a53bc02017-08-18 15:41:06 +0800299 void *shadow_ring_buffer_va;
300 u32 *cs;
Weinan Licd7e61b2018-02-23 14:46:45 +0800301
Colin Xu47d9d3b2018-06-11 15:39:36 +0800302 if ((IS_KABYLAKE(req->i915) || IS_BROXTON(req->i915))
303 && is_inhibit_context(req->hw_context))
Weinan Licd7e61b2018-02-23 14:46:45 +0800304 intel_vgpu_restore_inhibit_context(vgpu, req);
fred gao0a53bc02017-08-18 15:41:06 +0800305
306 /* allocate shadow ring buffer */
307 cs = intel_ring_begin(workload->req, workload->rb_len / sizeof(u32));
308 if (IS_ERR(cs)) {
309 gvt_vgpu_err("fail to alloc size =%ld shadow ring buffer\n",
310 workload->rb_len);
311 return PTR_ERR(cs);
312 }
313
314 shadow_ring_buffer_va = workload->shadow_ring_buffer_va;
315
316 /* get shadow ring buffer va */
317 workload->shadow_ring_buffer_va = cs;
318
319 memcpy(cs, shadow_ring_buffer_va,
320 workload->rb_len);
321
322 cs += workload->rb_len / sizeof(u32);
323 intel_ring_advance(workload->req, cs);
324
325 return 0;
326}
327
Chris Wilson7b302552017-11-20 13:29:58 +0000328static void release_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
fred gaoa3cfdca2017-08-18 15:41:07 +0800329{
330 if (!wa_ctx->indirect_ctx.obj)
331 return;
332
333 i915_gem_object_unpin_map(wa_ctx->indirect_ctx.obj);
334 i915_gem_object_put(wa_ctx->indirect_ctx.obj);
335}
336
Ping Gao89ea20b2017-06-29 12:22:42 +0800337/**
338 * intel_gvt_scan_and_shadow_workload - audit the workload by scanning and
339 * shadow it as well, include ringbuffer,wa_ctx and ctx.
340 * @workload: an abstract entity for each execlist submission.
341 *
342 * This function is called before the workload submitting to i915, to make
343 * sure the content of the workload is valid.
344 */
345int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload)
Zhi Wange4734052016-05-01 07:42:16 -0400346{
Zhi Wang1406a142017-09-10 21:15:18 +0800347 struct intel_vgpu *vgpu = workload->vgpu;
348 struct intel_vgpu_submission *s = &vgpu->submission;
349 struct i915_gem_context *shadow_ctx = s->shadow_ctx;
350 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
Chris Wilson1fc44d92018-05-17 22:26:32 +0100351 struct intel_engine_cs *engine = dev_priv->engine[workload->ring_id];
352 struct intel_context *ce;
Zhenyu Wang6bb2a2a2018-05-21 16:17:52 +0800353 struct i915_request *rq;
Zhi Wange4734052016-05-01 07:42:16 -0400354 int ret;
355
Ping Gao87e919d2017-07-04 14:53:03 +0800356 lockdep_assert_held(&dev_priv->drm.struct_mutex);
357
Chris Wilson1fc44d92018-05-17 22:26:32 +0100358 if (workload->req)
Ping Gaod0302e72017-06-29 12:22:43 +0800359 return 0;
Zhi Wange4734052016-05-01 07:42:16 -0400360
Ping Gao89ea20b2017-06-29 12:22:42 +0800361 /* pin shadow context by gvt even the shadow context will be pinned
362 * when i915 alloc request. That is because gvt will update the guest
363 * context from shadow context when workload is completed, and at that
364 * moment, i915 may already unpined the shadow context to make the
365 * shadow_ctx pages invalid. So gvt need to pin itself. After update
366 * the guest context, gvt can unpin the shadow_ctx safely.
367 */
Chris Wilson1fc44d92018-05-17 22:26:32 +0100368 ce = intel_context_pin(shadow_ctx, engine);
369 if (IS_ERR(ce)) {
Ping Gao89ea20b2017-06-29 12:22:42 +0800370 gvt_vgpu_err("fail to pin shadow context\n");
Chris Wilson1fc44d92018-05-17 22:26:32 +0100371 return PTR_ERR(ce);
Ping Gao89ea20b2017-06-29 12:22:42 +0800372 }
Zhi Wange4734052016-05-01 07:42:16 -0400373
Chris Wilson1fc44d92018-05-17 22:26:32 +0100374 shadow_ctx->desc_template &= ~(0x3 << GEN8_CTX_ADDRESSING_MODE_SHIFT);
375 shadow_ctx->desc_template |= workload->ctx_desc.addressing_mode <<
376 GEN8_CTX_ADDRESSING_MODE_SHIFT;
377
378 if (!test_and_set_bit(workload->ring_id, s->shadow_ctx_desc_updated))
379 shadow_context_descriptor_update(ce);
380
381 ret = intel_gvt_scan_and_shadow_ringbuffer(workload);
fred gao0a53bc02017-08-18 15:41:06 +0800382 if (ret)
fred gaoa3cfdca2017-08-18 15:41:07 +0800383 goto err_unpin;
fred gaof2880e02017-11-14 17:09:35 +0800384
Chris Wilson1fc44d92018-05-17 22:26:32 +0100385 if ((workload->ring_id == RCS) &&
386 (workload->wa_ctx.indirect_ctx.size != 0)) {
387 ret = intel_gvt_scan_and_shadow_wa_ctx(&workload->wa_ctx);
388 if (ret)
389 goto err_shadow;
Zhi Wange4734052016-05-01 07:42:16 -0400390 }
fred gaof2880e02017-11-14 17:09:35 +0800391
Zhenyu Wang6bb2a2a2018-05-21 16:17:52 +0800392 rq = i915_request_alloc(engine, shadow_ctx);
fred gao0a53bc02017-08-18 15:41:06 +0800393 if (IS_ERR(rq)) {
394 gvt_vgpu_err("fail to allocate gem request\n");
395 ret = PTR_ERR(rq);
Zhenyu Wang6bb2a2a2018-05-21 16:17:52 +0800396 goto err_shadow;
fred gao0a53bc02017-08-18 15:41:06 +0800397 }
Chris Wilsone61e0f52018-02-21 09:56:36 +0000398 workload->req = i915_request_get(rq);
fred gao0a53bc02017-08-18 15:41:06 +0800399
Zhi Wange4734052016-05-01 07:42:16 -0400400 ret = populate_shadow_context(workload);
401 if (ret)
Zhenyu Wang6bb2a2a2018-05-21 16:17:52 +0800402 goto err_req;
Chris Wilson1fc44d92018-05-17 22:26:32 +0100403
Zhi Wange4734052016-05-01 07:42:16 -0400404 return 0;
Zhenyu Wang6bb2a2a2018-05-21 16:17:52 +0800405err_req:
406 rq = fetch_and_zero(&workload->req);
407 i915_request_put(rq);
Zhi Wange4734052016-05-01 07:42:16 -0400408err_shadow:
fred gaoa3cfdca2017-08-18 15:41:07 +0800409 release_shadow_wa_ctx(&workload->wa_ctx);
Chris Wilson1fc44d92018-05-17 22:26:32 +0100410err_unpin:
411 intel_context_unpin(ce);
fred gao0a53bc02017-08-18 15:41:06 +0800412 return ret;
413}
414
Zhi Wangf52c3802017-09-24 21:53:03 +0800415static void release_shadow_batch_buffer(struct intel_vgpu_workload *workload);
416
Zhi Wangd8235b52017-09-12 22:06:39 +0800417static int prepare_shadow_batch_buffer(struct intel_vgpu_workload *workload)
418{
419 struct intel_gvt *gvt = workload->vgpu->gvt;
420 const int gmadr_bytes = gvt->device_info.gmadr_bytes_in_cmd;
Zhi Wangf52c3802017-09-24 21:53:03 +0800421 struct intel_vgpu_shadow_bb *bb;
422 int ret;
Zhi Wangd8235b52017-09-12 22:06:39 +0800423
Zhi Wangf52c3802017-09-24 21:53:03 +0800424 list_for_each_entry(bb, &workload->shadow_bb, list) {
fred gaoef75c682018-03-15 13:21:10 +0800425 /* For privilge batch buffer and not wa_ctx, the bb_start_cmd_va
426 * is only updated into ring_scan_buffer, not real ring address
427 * allocated in later copy_workload_to_ring_buffer. pls be noted
428 * shadow_ring_buffer_va is now pointed to real ring buffer va
429 * in copy_workload_to_ring_buffer.
430 */
431
432 if (bb->bb_offset)
433 bb->bb_start_cmd_va = workload->shadow_ring_buffer_va
434 + bb->bb_offset;
435
Zhao Yan96bebe32018-04-04 13:57:09 +0800436 if (bb->ppgtt) {
437 /* for non-priv bb, scan&shadow is only for
438 * debugging purpose, so the content of shadow bb
439 * is the same as original bb. Therefore,
440 * here, rather than switch to shadow bb's gma
441 * address, we directly use original batch buffer's
442 * gma address, and send original bb to hardware
443 * directly
444 */
445 if (bb->clflush & CLFLUSH_AFTER) {
446 drm_clflush_virt_range(bb->va,
447 bb->obj->base.size);
448 bb->clflush &= ~CLFLUSH_AFTER;
449 }
450 i915_gem_obj_finish_shmem_access(bb->obj);
451 bb->accessing = false;
Zhi Wangf52c3802017-09-24 21:53:03 +0800452
Zhao Yan96bebe32018-04-04 13:57:09 +0800453 } else {
454 bb->vma = i915_gem_object_ggtt_pin(bb->obj,
455 NULL, 0, 0, 0);
456 if (IS_ERR(bb->vma)) {
457 ret = PTR_ERR(bb->vma);
458 goto err;
459 }
460
461 /* relocate shadow batch buffer */
462 bb->bb_start_cmd_va[1] = i915_ggtt_offset(bb->vma);
463 if (gmadr_bytes == 8)
464 bb->bb_start_cmd_va[2] = 0;
465
466 /* No one is going to touch shadow bb from now on. */
467 if (bb->clflush & CLFLUSH_AFTER) {
468 drm_clflush_virt_range(bb->va,
469 bb->obj->base.size);
470 bb->clflush &= ~CLFLUSH_AFTER;
471 }
472
473 ret = i915_gem_object_set_to_gtt_domain(bb->obj,
474 false);
475 if (ret)
476 goto err;
477
478 i915_gem_obj_finish_shmem_access(bb->obj);
479 bb->accessing = false;
480
481 i915_vma_move_to_active(bb->vma, workload->req, 0);
Zhi Wangf52c3802017-09-24 21:53:03 +0800482 }
Zhi Wangd8235b52017-09-12 22:06:39 +0800483 }
484 return 0;
Zhi Wangf52c3802017-09-24 21:53:03 +0800485err:
486 release_shadow_batch_buffer(workload);
487 return ret;
Zhi Wangd8235b52017-09-12 22:06:39 +0800488}
489
Chris Wilson1fc44d92018-05-17 22:26:32 +0100490static void update_wa_ctx_2_shadow_ctx(struct intel_shadow_wa_ctx *wa_ctx)
Zhi Wangd8235b52017-09-12 22:06:39 +0800491{
Chris Wilson1fc44d92018-05-17 22:26:32 +0100492 struct intel_vgpu_workload *workload =
493 container_of(wa_ctx, struct intel_vgpu_workload, wa_ctx);
494 struct i915_request *rq = workload->req;
495 struct execlist_ring_context *shadow_ring_context =
496 (struct execlist_ring_context *)rq->hw_context->lrc_reg_state;
Zhi Wangd8235b52017-09-12 22:06:39 +0800497
498 shadow_ring_context->bb_per_ctx_ptr.val =
499 (shadow_ring_context->bb_per_ctx_ptr.val &
500 (~PER_CTX_ADDR_MASK)) | wa_ctx->per_ctx.shadow_gma;
501 shadow_ring_context->rcs_indirect_ctx.val =
502 (shadow_ring_context->rcs_indirect_ctx.val &
503 (~INDIRECT_CTX_ADDR_MASK)) | wa_ctx->indirect_ctx.shadow_gma;
Zhi Wangd8235b52017-09-12 22:06:39 +0800504}
505
506static int prepare_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
507{
508 struct i915_vma *vma;
509 unsigned char *per_ctx_va =
510 (unsigned char *)wa_ctx->indirect_ctx.shadow_va +
511 wa_ctx->indirect_ctx.size;
512
513 if (wa_ctx->indirect_ctx.size == 0)
514 return 0;
515
516 vma = i915_gem_object_ggtt_pin(wa_ctx->indirect_ctx.obj, NULL,
517 0, CACHELINE_BYTES, 0);
518 if (IS_ERR(vma))
519 return PTR_ERR(vma);
520
521 /* FIXME: we are not tracking our pinned VMA leaving it
522 * up to the core to fix up the stray pin_count upon
523 * free.
524 */
525
526 wa_ctx->indirect_ctx.shadow_gma = i915_ggtt_offset(vma);
527
528 wa_ctx->per_ctx.shadow_gma = *((unsigned int *)per_ctx_va + 1);
529 memset(per_ctx_va, 0, CACHELINE_BYTES);
530
531 update_wa_ctx_2_shadow_ctx(wa_ctx);
532 return 0;
533}
534
535static void release_shadow_batch_buffer(struct intel_vgpu_workload *workload)
536{
Zhi Wangf52c3802017-09-24 21:53:03 +0800537 struct intel_vgpu *vgpu = workload->vgpu;
538 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
539 struct intel_vgpu_shadow_bb *bb, *pos;
Zhi Wangd8235b52017-09-12 22:06:39 +0800540
Zhi Wangf52c3802017-09-24 21:53:03 +0800541 if (list_empty(&workload->shadow_bb))
542 return;
543
544 bb = list_first_entry(&workload->shadow_bb,
545 struct intel_vgpu_shadow_bb, list);
546
547 mutex_lock(&dev_priv->drm.struct_mutex);
548
549 list_for_each_entry_safe(bb, pos, &workload->shadow_bb, list) {
550 if (bb->obj) {
551 if (bb->accessing)
552 i915_gem_obj_finish_shmem_access(bb->obj);
553
554 if (bb->va && !IS_ERR(bb->va))
555 i915_gem_object_unpin_map(bb->obj);
556
557 if (bb->vma && !IS_ERR(bb->vma)) {
558 i915_vma_unpin(bb->vma);
559 i915_vma_close(bb->vma);
560 }
561 __i915_gem_object_release_unless_active(bb->obj);
Zhi Wangd8235b52017-09-12 22:06:39 +0800562 }
Zhi Wangf52c3802017-09-24 21:53:03 +0800563 list_del(&bb->list);
564 kfree(bb);
Zhi Wangd8235b52017-09-12 22:06:39 +0800565 }
Zhi Wangf52c3802017-09-24 21:53:03 +0800566
567 mutex_unlock(&dev_priv->drm.struct_mutex);
Zhi Wangd8235b52017-09-12 22:06:39 +0800568}
569
Zhi Wang497aa3f2017-09-12 21:51:10 +0800570static int prepare_workload(struct intel_vgpu_workload *workload)
571{
Zhi Wangd8235b52017-09-12 22:06:39 +0800572 struct intel_vgpu *vgpu = workload->vgpu;
Zhi Wang497aa3f2017-09-12 21:51:10 +0800573 int ret = 0;
574
Zhi Wangd8235b52017-09-12 22:06:39 +0800575 ret = intel_vgpu_pin_mm(workload->shadow_mm);
576 if (ret) {
577 gvt_vgpu_err("fail to vgpu pin mm\n");
578 return ret;
579 }
Zhi Wang497aa3f2017-09-12 21:51:10 +0800580
Zhi Wangb20c0d52018-02-07 18:12:15 +0800581 update_shadow_pdps(workload);
582
Zhi Wangd8235b52017-09-12 22:06:39 +0800583 ret = intel_vgpu_sync_oos_pages(workload->vgpu);
584 if (ret) {
585 gvt_vgpu_err("fail to vgpu sync oos pages\n");
586 goto err_unpin_mm;
587 }
588
589 ret = intel_vgpu_flush_post_shadow(workload->vgpu);
590 if (ret) {
591 gvt_vgpu_err("fail to flush post shadow\n");
592 goto err_unpin_mm;
593 }
594
Zhenyu Wang6bb2a2a2018-05-21 16:17:52 +0800595 ret = copy_workload_to_ring_buffer(workload);
fred gaof2880e02017-11-14 17:09:35 +0800596 if (ret) {
597 gvt_vgpu_err("fail to generate request\n");
598 goto err_unpin_mm;
599 }
600
Zhi Wangd8235b52017-09-12 22:06:39 +0800601 ret = prepare_shadow_batch_buffer(workload);
602 if (ret) {
603 gvt_vgpu_err("fail to prepare_shadow_batch_buffer\n");
604 goto err_unpin_mm;
605 }
606
607 ret = prepare_shadow_wa_ctx(&workload->wa_ctx);
608 if (ret) {
609 gvt_vgpu_err("fail to prepare_shadow_wa_ctx\n");
610 goto err_shadow_batch;
611 }
612
613 if (workload->prepare) {
614 ret = workload->prepare(workload);
615 if (ret)
616 goto err_shadow_wa_ctx;
617 }
618
619 return 0;
620err_shadow_wa_ctx:
621 release_shadow_wa_ctx(&workload->wa_ctx);
622err_shadow_batch:
623 release_shadow_batch_buffer(workload);
624err_unpin_mm:
625 intel_vgpu_unpin_mm(workload->shadow_mm);
Zhi Wang497aa3f2017-09-12 21:51:10 +0800626 return ret;
627}
628
fred gao0a53bc02017-08-18 15:41:06 +0800629static int dispatch_workload(struct intel_vgpu_workload *workload)
630{
Zhi Wang1406a142017-09-10 21:15:18 +0800631 struct intel_vgpu *vgpu = workload->vgpu;
Zhi Wang1406a142017-09-10 21:15:18 +0800632 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
fred gao0a53bc02017-08-18 15:41:06 +0800633 int ring_id = workload->ring_id;
Chris Wilson1fc44d92018-05-17 22:26:32 +0100634 int ret;
fred gao0a53bc02017-08-18 15:41:06 +0800635
636 gvt_dbg_sched("ring id %d prepare to dispatch workload %p\n",
637 ring_id, workload);
638
Colin Xuf25a49a2018-05-19 12:28:54 +0800639 mutex_lock(&vgpu->vgpu_lock);
fred gao0a53bc02017-08-18 15:41:06 +0800640 mutex_lock(&dev_priv->drm.struct_mutex);
641
642 ret = intel_gvt_scan_and_shadow_workload(workload);
643 if (ret)
644 goto out;
645
Zhi Wang497aa3f2017-09-12 21:51:10 +0800646 ret = prepare_workload(workload);
fred gao0a53bc02017-08-18 15:41:06 +0800647
Pei Zhang90d27a12016-11-14 18:02:57 +0800648out:
649 if (ret)
650 workload->status = ret;
Chris Wilson0eb742d2016-10-20 17:29:36 +0800651
Ping Gao89ea20b2017-06-29 12:22:42 +0800652 if (!IS_ERR_OR_NULL(workload->req)) {
653 gvt_dbg_sched("ring id %d submit workload to i915 %p\n",
654 ring_id, workload->req);
Chris Wilsone61e0f52018-02-21 09:56:36 +0000655 i915_request_add(workload->req);
Ping Gao89ea20b2017-06-29 12:22:42 +0800656 workload->dispatched = true;
657 }
Chuanxiao Dong3cd23b82017-03-16 09:47:58 +0800658
Pei Zhang90d27a12016-11-14 18:02:57 +0800659 mutex_unlock(&dev_priv->drm.struct_mutex);
Colin Xuf25a49a2018-05-19 12:28:54 +0800660 mutex_unlock(&vgpu->vgpu_lock);
Zhi Wange4734052016-05-01 07:42:16 -0400661 return ret;
662}
663
664static struct intel_vgpu_workload *pick_next_workload(
665 struct intel_gvt *gvt, int ring_id)
666{
667 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
668 struct intel_vgpu_workload *workload = NULL;
669
Colin Xu9a512e22018-05-19 12:28:55 +0800670 mutex_lock(&gvt->sched_lock);
Zhi Wange4734052016-05-01 07:42:16 -0400671
672 /*
673 * no current vgpu / will be scheduled out / no workload
674 * bail out
675 */
676 if (!scheduler->current_vgpu) {
677 gvt_dbg_sched("ring id %d stop - no current vgpu\n", ring_id);
678 goto out;
679 }
680
681 if (scheduler->need_reschedule) {
682 gvt_dbg_sched("ring id %d stop - will reschedule\n", ring_id);
683 goto out;
684 }
685
Zhenyu Wang954180a2017-04-12 14:22:50 +0800686 if (list_empty(workload_q_head(scheduler->current_vgpu, ring_id)))
Zhi Wange4734052016-05-01 07:42:16 -0400687 goto out;
Zhi Wange4734052016-05-01 07:42:16 -0400688
689 /*
690 * still have current workload, maybe the workload disptacher
691 * fail to submit it for some reason, resubmit it.
692 */
693 if (scheduler->current_workload[ring_id]) {
694 workload = scheduler->current_workload[ring_id];
695 gvt_dbg_sched("ring id %d still have current workload %p\n",
696 ring_id, workload);
697 goto out;
698 }
699
700 /*
701 * pick a workload as current workload
702 * once current workload is set, schedule policy routines
703 * will wait the current workload is finished when trying to
704 * schedule out a vgpu.
705 */
706 scheduler->current_workload[ring_id] = container_of(
707 workload_q_head(scheduler->current_vgpu, ring_id)->next,
708 struct intel_vgpu_workload, list);
709
710 workload = scheduler->current_workload[ring_id];
711
712 gvt_dbg_sched("ring id %d pick new workload %p\n", ring_id, workload);
713
Zhi Wang1406a142017-09-10 21:15:18 +0800714 atomic_inc(&workload->vgpu->submission.running_workload_num);
Zhi Wange4734052016-05-01 07:42:16 -0400715out:
Colin Xu9a512e22018-05-19 12:28:55 +0800716 mutex_unlock(&gvt->sched_lock);
Zhi Wange4734052016-05-01 07:42:16 -0400717 return workload;
718}
719
720static void update_guest_context(struct intel_vgpu_workload *workload)
721{
Chris Wilson1fc44d92018-05-17 22:26:32 +0100722 struct i915_request *rq = workload->req;
Zhi Wange4734052016-05-01 07:42:16 -0400723 struct intel_vgpu *vgpu = workload->vgpu;
724 struct intel_gvt *gvt = vgpu->gvt;
Chris Wilson1fc44d92018-05-17 22:26:32 +0100725 struct drm_i915_gem_object *ctx_obj = rq->hw_context->state->obj;
Zhi Wange4734052016-05-01 07:42:16 -0400726 struct execlist_ring_context *shadow_ring_context;
727 struct page *page;
728 void *src;
729 unsigned long context_gpa, context_page_num;
730 int i;
731
Chris Wilson1fc44d92018-05-17 22:26:32 +0100732 gvt_dbg_sched("ring id %d workload lrca %x\n", rq->engine->id,
733 workload->ctx_desc.lrca);
Zhi Wange4734052016-05-01 07:42:16 -0400734
Chris Wilson1fc44d92018-05-17 22:26:32 +0100735 context_page_num = rq->engine->context_size;
Zhi Wange4734052016-05-01 07:42:16 -0400736 context_page_num = context_page_num >> PAGE_SHIFT;
737
Chris Wilson1fc44d92018-05-17 22:26:32 +0100738 if (IS_BROADWELL(gvt->dev_priv) && rq->engine->id == RCS)
Zhi Wange4734052016-05-01 07:42:16 -0400739 context_page_num = 19;
740
741 i = 2;
742
743 while (i < context_page_num) {
744 context_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm,
745 (u32)((workload->ctx_desc.lrca + i) <<
Zhi Wang9556e112017-10-10 13:51:32 +0800746 I915_GTT_PAGE_SHIFT));
Zhi Wange4734052016-05-01 07:42:16 -0400747 if (context_gpa == INTEL_GVT_INVALID_ADDR) {
Tina Zhang695fbc02017-03-10 04:26:53 -0500748 gvt_vgpu_err("invalid guest context descriptor\n");
Zhi Wange4734052016-05-01 07:42:16 -0400749 return;
750 }
751
Michel Thierry0b29c752017-09-13 09:56:00 +0100752 page = i915_gem_object_get_page(ctx_obj, LRC_HEADER_PAGES + i);
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800753 src = kmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400754 intel_gvt_hypervisor_write_gpa(vgpu, context_gpa, src,
Zhi Wang9556e112017-10-10 13:51:32 +0800755 I915_GTT_PAGE_SIZE);
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800756 kunmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400757 i++;
758 }
759
760 intel_gvt_hypervisor_write_gpa(vgpu, workload->ring_context_gpa +
761 RING_CTX_OFF(ring_header.val), &workload->rb_tail, 4);
762
763 page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800764 shadow_ring_context = kmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400765
766#define COPY_REG(name) \
767 intel_gvt_hypervisor_write_gpa(vgpu, workload->ring_context_gpa + \
768 RING_CTX_OFF(name.val), &shadow_ring_context->name.val, 4)
769
770 COPY_REG(ctx_ctrl);
771 COPY_REG(ctx_timestamp);
772
773#undef COPY_REG
774
775 intel_gvt_hypervisor_write_gpa(vgpu,
776 workload->ring_context_gpa +
777 sizeof(*shadow_ring_context),
778 (void *)shadow_ring_context +
779 sizeof(*shadow_ring_context),
Zhi Wang9556e112017-10-10 13:51:32 +0800780 I915_GTT_PAGE_SIZE - sizeof(*shadow_ring_context));
Zhi Wange4734052016-05-01 07:42:16 -0400781
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800782 kunmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400783}
784
Zhi Wange2c43c02017-09-13 01:58:35 +0800785static void clean_workloads(struct intel_vgpu *vgpu, unsigned long engine_mask)
786{
787 struct intel_vgpu_submission *s = &vgpu->submission;
788 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
789 struct intel_engine_cs *engine;
790 struct intel_vgpu_workload *pos, *n;
791 unsigned int tmp;
792
793 /* free the unsubmited workloads in the queues. */
794 for_each_engine_masked(engine, dev_priv, engine_mask, tmp) {
795 list_for_each_entry_safe(pos, n,
796 &s->workload_q_head[engine->id], list) {
797 list_del_init(&pos->list);
798 intel_vgpu_destroy_workload(pos);
799 }
800 clear_bit(engine->id, s->shadow_ctx_desc_updated);
801 }
802}
803
Zhi Wange4734052016-05-01 07:42:16 -0400804static void complete_current_workload(struct intel_gvt *gvt, int ring_id)
805{
806 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
Zhi Wang1406a142017-09-10 21:15:18 +0800807 struct intel_vgpu_workload *workload =
808 scheduler->current_workload[ring_id];
809 struct intel_vgpu *vgpu = workload->vgpu;
810 struct intel_vgpu_submission *s = &vgpu->submission;
Zhenyu Wang6bb2a2a2018-05-21 16:17:52 +0800811 struct i915_request *rq = workload->req;
Zhi Wangbe1da702016-05-03 18:26:57 -0400812 int event;
Zhi Wange4734052016-05-01 07:42:16 -0400813
Colin Xuf25a49a2018-05-19 12:28:54 +0800814 mutex_lock(&vgpu->vgpu_lock);
Colin Xu9a512e22018-05-19 12:28:55 +0800815 mutex_lock(&gvt->sched_lock);
Zhi Wange4734052016-05-01 07:42:16 -0400816
Chuanxiao Dong8f1117a2017-03-06 13:05:24 +0800817 /* For the workload w/ request, needs to wait for the context
818 * switch to make sure request is completed.
819 * For the workload w/o request, directly complete the workload.
820 */
Chris Wilson1fc44d92018-05-17 22:26:32 +0100821 if (rq) {
Zhi Wange4734052016-05-01 07:42:16 -0400822 wait_event(workload->shadow_ctx_status_wq,
823 !atomic_read(&workload->shadow_ctx_active));
824
Chuanxiao Dong0cf5ec42017-06-23 13:01:11 +0800825 /* If this request caused GPU hang, req->fence.error will
826 * be set to -EIO. Use -EIO to set workload status so
827 * that when this request caused GPU hang, didn't trigger
828 * context switch interrupt to guest.
829 */
830 if (likely(workload->status == -EINPROGRESS)) {
831 if (workload->req->fence.error == -EIO)
832 workload->status = -EIO;
833 else
834 workload->status = 0;
835 }
836
Chuanxiao Dong6184cc82017-08-01 17:47:25 +0800837 if (!workload->status && !(vgpu->resetting_eng &
838 ENGINE_MASK(ring_id))) {
Chuanxiao Dong8f1117a2017-03-06 13:05:24 +0800839 update_guest_context(workload);
840
841 for_each_set_bit(event, workload->pending_events,
842 INTEL_GVT_EVENT_MAX)
843 intel_vgpu_trigger_virtual_event(vgpu, event);
844 }
Chris Wilson1fc44d92018-05-17 22:26:32 +0100845
Chuanxiao Dong3cd23b82017-03-16 09:47:58 +0800846 /* unpin shadow ctx as the shadow_ctx update is done */
Chris Wilson1fc44d92018-05-17 22:26:32 +0100847 mutex_lock(&rq->i915->drm.struct_mutex);
848 intel_context_unpin(rq->hw_context);
849 mutex_unlock(&rq->i915->drm.struct_mutex);
850
Zhenyu Wang6bb2a2a2018-05-21 16:17:52 +0800851 i915_request_put(fetch_and_zero(&workload->req));
Zhi Wange4734052016-05-01 07:42:16 -0400852 }
853
854 gvt_dbg_sched("ring id %d complete workload %p status %d\n",
855 ring_id, workload, workload->status);
856
857 scheduler->current_workload[ring_id] = NULL;
858
Zhi Wange4734052016-05-01 07:42:16 -0400859 list_del_init(&workload->list);
Zhi Wangd8235b52017-09-12 22:06:39 +0800860
861 if (!workload->status) {
862 release_shadow_batch_buffer(workload);
863 release_shadow_wa_ctx(&workload->wa_ctx);
864 }
865
Zhi Wange2c43c02017-09-13 01:58:35 +0800866 if (workload->status || (vgpu->resetting_eng & ENGINE_MASK(ring_id))) {
867 /* if workload->status is not successful means HW GPU
868 * has occurred GPU hang or something wrong with i915/GVT,
869 * and GVT won't inject context switch interrupt to guest.
870 * So this error is a vGPU hang actually to the guest.
871 * According to this we should emunlate a vGPU hang. If
872 * there are pending workloads which are already submitted
873 * from guest, we should clean them up like HW GPU does.
874 *
875 * if it is in middle of engine resetting, the pending
876 * workloads won't be submitted to HW GPU and will be
877 * cleaned up during the resetting process later, so doing
878 * the workload clean up here doesn't have any impact.
879 **/
880 clean_workloads(vgpu, ENGINE_MASK(ring_id));
881 }
882
Zhi Wange4734052016-05-01 07:42:16 -0400883 workload->complete(workload);
884
Zhi Wang1406a142017-09-10 21:15:18 +0800885 atomic_dec(&s->running_workload_num);
Zhi Wange4734052016-05-01 07:42:16 -0400886 wake_up(&scheduler->workload_complete_wq);
Ping Gaof100dae2017-05-24 09:14:11 +0800887
888 if (gvt->scheduler.need_reschedule)
889 intel_gvt_request_service(gvt, INTEL_GVT_REQUEST_EVENT_SCHED);
890
Colin Xu9a512e22018-05-19 12:28:55 +0800891 mutex_unlock(&gvt->sched_lock);
Colin Xuf25a49a2018-05-19 12:28:54 +0800892 mutex_unlock(&vgpu->vgpu_lock);
Zhi Wange4734052016-05-01 07:42:16 -0400893}
894
895struct workload_thread_param {
896 struct intel_gvt *gvt;
897 int ring_id;
898};
899
900static int workload_thread(void *priv)
901{
902 struct workload_thread_param *p = (struct workload_thread_param *)priv;
903 struct intel_gvt *gvt = p->gvt;
904 int ring_id = p->ring_id;
905 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
906 struct intel_vgpu_workload *workload = NULL;
Tina Zhang695fbc02017-03-10 04:26:53 -0500907 struct intel_vgpu *vgpu = NULL;
Zhi Wange4734052016-05-01 07:42:16 -0400908 int ret;
Xu Hane3476c02017-03-29 10:13:59 +0800909 bool need_force_wake = IS_SKYLAKE(gvt->dev_priv)
Colin Xu47d9d3b2018-06-11 15:39:36 +0800910 || IS_KABYLAKE(gvt->dev_priv)
911 || IS_BROXTON(gvt->dev_priv);
Du, Changbine45d7b72016-10-27 11:10:31 +0800912 DEFINE_WAIT_FUNC(wait, woken_wake_function);
Zhi Wange4734052016-05-01 07:42:16 -0400913
914 kfree(p);
915
916 gvt_dbg_core("workload thread for ring %d started\n", ring_id);
917
918 while (!kthread_should_stop()) {
Du, Changbine45d7b72016-10-27 11:10:31 +0800919 add_wait_queue(&scheduler->waitq[ring_id], &wait);
920 do {
921 workload = pick_next_workload(gvt, ring_id);
922 if (workload)
923 break;
924 wait_woken(&wait, TASK_INTERRUPTIBLE,
925 MAX_SCHEDULE_TIMEOUT);
926 } while (!kthread_should_stop());
927 remove_wait_queue(&scheduler->waitq[ring_id], &wait);
Zhi Wange4734052016-05-01 07:42:16 -0400928
Du, Changbine45d7b72016-10-27 11:10:31 +0800929 if (!workload)
Zhi Wange4734052016-05-01 07:42:16 -0400930 break;
931
932 gvt_dbg_sched("ring id %d next workload %p vgpu %d\n",
933 workload->ring_id, workload,
934 workload->vgpu->id);
935
936 intel_runtime_pm_get(gvt->dev_priv);
937
Zhi Wange4734052016-05-01 07:42:16 -0400938 gvt_dbg_sched("ring id %d will dispatch workload %p\n",
939 workload->ring_id, workload);
940
941 if (need_force_wake)
942 intel_uncore_forcewake_get(gvt->dev_priv,
943 FORCEWAKE_ALL);
944
945 ret = dispatch_workload(workload);
Chris Wilson66bbc3b2016-10-19 11:11:44 +0100946
Zhi Wange4734052016-05-01 07:42:16 -0400947 if (ret) {
Tina Zhang695fbc02017-03-10 04:26:53 -0500948 vgpu = workload->vgpu;
949 gvt_vgpu_err("fail to dispatch workload, skip\n");
Zhi Wange4734052016-05-01 07:42:16 -0400950 goto complete;
951 }
952
953 gvt_dbg_sched("ring id %d wait workload %p\n",
954 workload->ring_id, workload);
Chris Wilsone61e0f52018-02-21 09:56:36 +0000955 i915_request_wait(workload->req, 0, MAX_SCHEDULE_TIMEOUT);
Zhi Wange4734052016-05-01 07:42:16 -0400956
957complete:
Changbin Du3ce32742017-02-09 10:13:16 +0800958 gvt_dbg_sched("will complete workload %p, status: %d\n",
Zhi Wange4734052016-05-01 07:42:16 -0400959 workload, workload->status);
960
Changbin Du2e51ef32017-01-05 13:28:05 +0800961 complete_current_workload(gvt, ring_id);
962
Zhi Wange4734052016-05-01 07:42:16 -0400963 if (need_force_wake)
964 intel_uncore_forcewake_put(gvt->dev_priv,
965 FORCEWAKE_ALL);
966
Zhi Wange4734052016-05-01 07:42:16 -0400967 intel_runtime_pm_put(gvt->dev_priv);
Zhi Wang6d763032017-09-12 22:33:12 +0800968 if (ret && (vgpu_is_vm_unhealthy(ret)))
fred gaoe011c6c2017-09-19 15:11:28 +0800969 enter_failsafe_mode(vgpu, GVT_FAILSAFE_GUEST_ERR);
Zhi Wange4734052016-05-01 07:42:16 -0400970 }
971 return 0;
972}
973
974void intel_gvt_wait_vgpu_idle(struct intel_vgpu *vgpu)
975{
Zhi Wang1406a142017-09-10 21:15:18 +0800976 struct intel_vgpu_submission *s = &vgpu->submission;
Zhi Wange4734052016-05-01 07:42:16 -0400977 struct intel_gvt *gvt = vgpu->gvt;
978 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
979
Zhi Wang1406a142017-09-10 21:15:18 +0800980 if (atomic_read(&s->running_workload_num)) {
Zhi Wange4734052016-05-01 07:42:16 -0400981 gvt_dbg_sched("wait vgpu idle\n");
982
983 wait_event(scheduler->workload_complete_wq,
Zhi Wang1406a142017-09-10 21:15:18 +0800984 !atomic_read(&s->running_workload_num));
Zhi Wange4734052016-05-01 07:42:16 -0400985 }
986}
987
988void intel_gvt_clean_workload_scheduler(struct intel_gvt *gvt)
989{
990 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
Changbin Du3fc03062017-03-13 10:47:11 +0800991 struct intel_engine_cs *engine;
992 enum intel_engine_id i;
Zhi Wange4734052016-05-01 07:42:16 -0400993
994 gvt_dbg_core("clean workload scheduler\n");
995
Changbin Du3fc03062017-03-13 10:47:11 +0800996 for_each_engine(engine, gvt->dev_priv, i) {
997 atomic_notifier_chain_unregister(
998 &engine->context_status_notifier,
999 &gvt->shadow_ctx_notifier_block[i]);
1000 kthread_stop(scheduler->thread[i]);
Zhi Wange4734052016-05-01 07:42:16 -04001001 }
1002}
1003
1004int intel_gvt_init_workload_scheduler(struct intel_gvt *gvt)
1005{
1006 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
1007 struct workload_thread_param *param = NULL;
Changbin Du3fc03062017-03-13 10:47:11 +08001008 struct intel_engine_cs *engine;
1009 enum intel_engine_id i;
Zhi Wange4734052016-05-01 07:42:16 -04001010 int ret;
Zhi Wange4734052016-05-01 07:42:16 -04001011
1012 gvt_dbg_core("init workload scheduler\n");
1013
1014 init_waitqueue_head(&scheduler->workload_complete_wq);
1015
Changbin Du3fc03062017-03-13 10:47:11 +08001016 for_each_engine(engine, gvt->dev_priv, i) {
Zhi Wange4734052016-05-01 07:42:16 -04001017 init_waitqueue_head(&scheduler->waitq[i]);
1018
1019 param = kzalloc(sizeof(*param), GFP_KERNEL);
1020 if (!param) {
1021 ret = -ENOMEM;
1022 goto err;
1023 }
1024
1025 param->gvt = gvt;
1026 param->ring_id = i;
1027
1028 scheduler->thread[i] = kthread_run(workload_thread, param,
1029 "gvt workload %d", i);
1030 if (IS_ERR(scheduler->thread[i])) {
1031 gvt_err("fail to create workload thread\n");
1032 ret = PTR_ERR(scheduler->thread[i]);
1033 goto err;
1034 }
Changbin Du3fc03062017-03-13 10:47:11 +08001035
1036 gvt->shadow_ctx_notifier_block[i].notifier_call =
1037 shadow_context_status_change;
1038 atomic_notifier_chain_register(&engine->context_status_notifier,
1039 &gvt->shadow_ctx_notifier_block[i]);
Zhi Wange4734052016-05-01 07:42:16 -04001040 }
1041 return 0;
1042err:
1043 intel_gvt_clean_workload_scheduler(gvt);
1044 kfree(param);
1045 param = NULL;
1046 return ret;
1047}
1048
Zhi Wang874b6a92017-09-10 20:08:18 +08001049/**
1050 * intel_vgpu_clean_submission - free submission-related resource for vGPU
1051 * @vgpu: a vGPU
1052 *
1053 * This function is called when a vGPU is being destroyed.
1054 *
1055 */
1056void intel_vgpu_clean_submission(struct intel_vgpu *vgpu)
Zhi Wange4734052016-05-01 07:42:16 -04001057{
Zhi Wang1406a142017-09-10 21:15:18 +08001058 struct intel_vgpu_submission *s = &vgpu->submission;
1059
Weinan Li7569a062018-01-26 15:09:07 +08001060 intel_vgpu_select_submission_ops(vgpu, ALL_ENGINES, 0);
Zhi Wang1406a142017-09-10 21:15:18 +08001061 i915_gem_context_put(s->shadow_ctx);
1062 kmem_cache_destroy(s->workloads);
Zhi Wange4734052016-05-01 07:42:16 -04001063}
1064
Zhi Wang06bb3722017-09-13 01:41:35 +08001065
1066/**
1067 * intel_vgpu_reset_submission - reset submission-related resource for vGPU
1068 * @vgpu: a vGPU
1069 * @engine_mask: engines expected to be reset
1070 *
1071 * This function is called when a vGPU is being destroyed.
1072 *
1073 */
1074void intel_vgpu_reset_submission(struct intel_vgpu *vgpu,
1075 unsigned long engine_mask)
1076{
1077 struct intel_vgpu_submission *s = &vgpu->submission;
1078
1079 if (!s->active)
1080 return;
1081
Zhi Wange2c43c02017-09-13 01:58:35 +08001082 clean_workloads(vgpu, engine_mask);
Zhi Wang06bb3722017-09-13 01:41:35 +08001083 s->ops->reset(vgpu, engine_mask);
1084}
1085
Zhi Wang874b6a92017-09-10 20:08:18 +08001086/**
1087 * intel_vgpu_setup_submission - setup submission-related resource for vGPU
1088 * @vgpu: a vGPU
1089 *
1090 * This function is called when a vGPU is being created.
1091 *
1092 * Returns:
1093 * Zero on success, negative error code if failed.
1094 *
1095 */
1096int intel_vgpu_setup_submission(struct intel_vgpu *vgpu)
Zhi Wange4734052016-05-01 07:42:16 -04001097{
Zhi Wang1406a142017-09-10 21:15:18 +08001098 struct intel_vgpu_submission *s = &vgpu->submission;
Zhi Wang9a9829e2017-09-10 20:28:09 +08001099 enum intel_engine_id i;
1100 struct intel_engine_cs *engine;
1101 int ret;
Zhi Wange4734052016-05-01 07:42:16 -04001102
Zhi Wang1406a142017-09-10 21:15:18 +08001103 s->shadow_ctx = i915_gem_context_create_gvt(
Zhi Wange4734052016-05-01 07:42:16 -04001104 &vgpu->gvt->dev_priv->drm);
Zhi Wang1406a142017-09-10 21:15:18 +08001105 if (IS_ERR(s->shadow_ctx))
1106 return PTR_ERR(s->shadow_ctx);
Zhi Wange4734052016-05-01 07:42:16 -04001107
Zhi Wang1406a142017-09-10 21:15:18 +08001108 bitmap_zero(s->shadow_ctx_desc_updated, I915_NUM_ENGINES);
Kechen Lu9dfb8e52017-08-10 07:41:36 +08001109
Zhenyu Wang850555d2018-02-14 11:35:01 +08001110 s->workloads = kmem_cache_create_usercopy("gvt-g_vgpu_workload",
1111 sizeof(struct intel_vgpu_workload), 0,
1112 SLAB_HWCACHE_ALIGN,
1113 offsetof(struct intel_vgpu_workload, rb_tail),
1114 sizeof_field(struct intel_vgpu_workload, rb_tail),
1115 NULL);
Zhi Wang9a9829e2017-09-10 20:28:09 +08001116
Zhi Wang1406a142017-09-10 21:15:18 +08001117 if (!s->workloads) {
Zhi Wang9a9829e2017-09-10 20:28:09 +08001118 ret = -ENOMEM;
1119 goto out_shadow_ctx;
1120 }
1121
1122 for_each_engine(engine, vgpu->gvt->dev_priv, i)
Zhi Wang1406a142017-09-10 21:15:18 +08001123 INIT_LIST_HEAD(&s->workload_q_head[i]);
Zhi Wang9a9829e2017-09-10 20:28:09 +08001124
Zhi Wang1406a142017-09-10 21:15:18 +08001125 atomic_set(&s->running_workload_num, 0);
Zhi Wang91d5d852017-09-10 21:33:20 +08001126 bitmap_zero(s->tlb_handle_pending, I915_NUM_ENGINES);
Zhi Wang9a9829e2017-09-10 20:28:09 +08001127
Zhi Wange4734052016-05-01 07:42:16 -04001128 return 0;
Zhi Wang9a9829e2017-09-10 20:28:09 +08001129
1130out_shadow_ctx:
Zhi Wang1406a142017-09-10 21:15:18 +08001131 i915_gem_context_put(s->shadow_ctx);
Zhi Wang9a9829e2017-09-10 20:28:09 +08001132 return ret;
Zhi Wange4734052016-05-01 07:42:16 -04001133}
Zhi Wang21527a82017-09-12 21:42:09 +08001134
1135/**
Zhi Wangad1d3632017-09-13 00:31:29 +08001136 * intel_vgpu_select_submission_ops - select virtual submission interface
1137 * @vgpu: a vGPU
Zhenyu Wanga752b072018-07-31 11:02:12 +08001138 * @engine_mask: either ALL_ENGINES or target engine mask
Zhi Wangad1d3632017-09-13 00:31:29 +08001139 * @interface: expected vGPU virtual submission interface
1140 *
1141 * This function is called when guest configures submission interface.
1142 *
1143 * Returns:
1144 * Zero on success, negative error code if failed.
1145 *
1146 */
1147int intel_vgpu_select_submission_ops(struct intel_vgpu *vgpu,
Weinan Li7569a062018-01-26 15:09:07 +08001148 unsigned long engine_mask,
Zhi Wangad1d3632017-09-13 00:31:29 +08001149 unsigned int interface)
1150{
1151 struct intel_vgpu_submission *s = &vgpu->submission;
1152 const struct intel_vgpu_submission_ops *ops[] = {
1153 [INTEL_VGPU_EXECLIST_SUBMISSION] =
1154 &intel_vgpu_execlist_submission_ops,
1155 };
1156 int ret;
1157
1158 if (WARN_ON(interface >= ARRAY_SIZE(ops)))
1159 return -EINVAL;
1160
Weinan Li9212b132018-01-26 15:09:08 +08001161 if (WARN_ON(interface == 0 && engine_mask != ALL_ENGINES))
1162 return -EINVAL;
1163
1164 if (s->active)
Weinan Li7569a062018-01-26 15:09:07 +08001165 s->ops->clean(vgpu, engine_mask);
Zhi Wangad1d3632017-09-13 00:31:29 +08001166
1167 if (interface == 0) {
1168 s->ops = NULL;
1169 s->virtual_submission_interface = 0;
Weinan Li9212b132018-01-26 15:09:08 +08001170 s->active = false;
1171 gvt_dbg_core("vgpu%d: remove submission ops\n", vgpu->id);
Zhi Wangad1d3632017-09-13 00:31:29 +08001172 return 0;
1173 }
1174
Weinan Li7569a062018-01-26 15:09:07 +08001175 ret = ops[interface]->init(vgpu, engine_mask);
Zhi Wangad1d3632017-09-13 00:31:29 +08001176 if (ret)
1177 return ret;
1178
1179 s->ops = ops[interface];
1180 s->virtual_submission_interface = interface;
1181 s->active = true;
1182
1183 gvt_dbg_core("vgpu%d: activate ops [ %s ]\n",
1184 vgpu->id, s->ops->name);
1185
1186 return 0;
1187}
1188
1189/**
Zhi Wang21527a82017-09-12 21:42:09 +08001190 * intel_vgpu_destroy_workload - destroy a vGPU workload
Zhenyu Wanga752b072018-07-31 11:02:12 +08001191 * @workload: workload to destroy
Zhi Wang21527a82017-09-12 21:42:09 +08001192 *
1193 * This function is called when destroy a vGPU workload.
1194 *
1195 */
1196void intel_vgpu_destroy_workload(struct intel_vgpu_workload *workload)
1197{
1198 struct intel_vgpu_submission *s = &workload->vgpu->submission;
1199
1200 if (workload->shadow_mm)
Changbin Du1bc25852018-01-30 19:19:41 +08001201 intel_vgpu_mm_put(workload->shadow_mm);
Zhi Wang21527a82017-09-12 21:42:09 +08001202
1203 kmem_cache_free(s->workloads, workload);
1204}
1205
Zhi Wang6d763032017-09-12 22:33:12 +08001206static struct intel_vgpu_workload *
1207alloc_workload(struct intel_vgpu *vgpu)
Zhi Wang21527a82017-09-12 21:42:09 +08001208{
1209 struct intel_vgpu_submission *s = &vgpu->submission;
1210 struct intel_vgpu_workload *workload;
1211
1212 workload = kmem_cache_zalloc(s->workloads, GFP_KERNEL);
1213 if (!workload)
1214 return ERR_PTR(-ENOMEM);
1215
1216 INIT_LIST_HEAD(&workload->list);
1217 INIT_LIST_HEAD(&workload->shadow_bb);
1218
1219 init_waitqueue_head(&workload->shadow_ctx_status_wq);
1220 atomic_set(&workload->shadow_ctx_active, 0);
1221
1222 workload->status = -EINPROGRESS;
Zhi Wang21527a82017-09-12 21:42:09 +08001223 workload->vgpu = vgpu;
1224
1225 return workload;
1226}
Zhi Wang6d763032017-09-12 22:33:12 +08001227
1228#define RING_CTX_OFF(x) \
1229 offsetof(struct execlist_ring_context, x)
1230
1231static void read_guest_pdps(struct intel_vgpu *vgpu,
1232 u64 ring_context_gpa, u32 pdp[8])
1233{
1234 u64 gpa;
1235 int i;
1236
Xinyun Liu1417fad2018-06-07 22:48:42 +08001237 gpa = ring_context_gpa + RING_CTX_OFF(pdps[0].val);
Zhi Wang6d763032017-09-12 22:33:12 +08001238
1239 for (i = 0; i < 8; i++)
1240 intel_gvt_hypervisor_read_gpa(vgpu,
1241 gpa + i * 8, &pdp[7 - i], 4);
1242}
1243
1244static int prepare_mm(struct intel_vgpu_workload *workload)
1245{
1246 struct execlist_ctx_descriptor_format *desc = &workload->ctx_desc;
1247 struct intel_vgpu_mm *mm;
1248 struct intel_vgpu *vgpu = workload->vgpu;
Changbin Duede9d0c2018-01-30 19:19:40 +08001249 intel_gvt_gtt_type_t root_entry_type;
1250 u64 pdps[GVT_RING_CTX_NR_PDPS];
Zhi Wang6d763032017-09-12 22:33:12 +08001251
Changbin Duede9d0c2018-01-30 19:19:40 +08001252 switch (desc->addressing_mode) {
1253 case 1: /* legacy 32-bit */
1254 root_entry_type = GTT_TYPE_PPGTT_ROOT_L3_ENTRY;
1255 break;
1256 case 3: /* legacy 64-bit */
1257 root_entry_type = GTT_TYPE_PPGTT_ROOT_L4_ENTRY;
1258 break;
1259 default:
Zhi Wang6d763032017-09-12 22:33:12 +08001260 gvt_vgpu_err("Advanced Context mode(SVM) is not supported!\n");
1261 return -EINVAL;
1262 }
1263
Changbin Duede9d0c2018-01-30 19:19:40 +08001264 read_guest_pdps(workload->vgpu, workload->ring_context_gpa, (void *)pdps);
Zhi Wang6d763032017-09-12 22:33:12 +08001265
Changbin Due6e9c462018-01-30 19:19:46 +08001266 mm = intel_vgpu_get_ppgtt_mm(workload->vgpu, root_entry_type, pdps);
1267 if (IS_ERR(mm))
1268 return PTR_ERR(mm);
Zhi Wang6d763032017-09-12 22:33:12 +08001269
Zhi Wang6d763032017-09-12 22:33:12 +08001270 workload->shadow_mm = mm;
1271 return 0;
1272}
1273
1274#define same_context(a, b) (((a)->context_id == (b)->context_id) && \
1275 ((a)->lrca == (b)->lrca))
1276
1277#define get_last_workload(q) \
1278 (list_empty(q) ? NULL : container_of(q->prev, \
1279 struct intel_vgpu_workload, list))
1280/**
1281 * intel_vgpu_create_workload - create a vGPU workload
1282 * @vgpu: a vGPU
Zhenyu Wanga752b072018-07-31 11:02:12 +08001283 * @ring_id: ring index
Zhi Wang6d763032017-09-12 22:33:12 +08001284 * @desc: a guest context descriptor
1285 *
1286 * This function is called when creating a vGPU workload.
1287 *
1288 * Returns:
1289 * struct intel_vgpu_workload * on success, negative error code in
1290 * pointer if failed.
1291 *
1292 */
1293struct intel_vgpu_workload *
1294intel_vgpu_create_workload(struct intel_vgpu *vgpu, int ring_id,
1295 struct execlist_ctx_descriptor_format *desc)
1296{
1297 struct intel_vgpu_submission *s = &vgpu->submission;
1298 struct list_head *q = workload_q_head(vgpu, ring_id);
1299 struct intel_vgpu_workload *last_workload = get_last_workload(q);
1300 struct intel_vgpu_workload *workload = NULL;
1301 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
1302 u64 ring_context_gpa;
1303 u32 head, tail, start, ctl, ctx_ctl, per_ctx, indirect_ctx;
1304 int ret;
1305
1306 ring_context_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm,
Zhi Wang9556e112017-10-10 13:51:32 +08001307 (u32)((desc->lrca + 1) << I915_GTT_PAGE_SHIFT));
Zhi Wang6d763032017-09-12 22:33:12 +08001308 if (ring_context_gpa == INTEL_GVT_INVALID_ADDR) {
1309 gvt_vgpu_err("invalid guest context LRCA: %x\n", desc->lrca);
1310 return ERR_PTR(-EINVAL);
1311 }
1312
1313 intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
1314 RING_CTX_OFF(ring_header.val), &head, 4);
1315
1316 intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
1317 RING_CTX_OFF(ring_tail.val), &tail, 4);
1318
1319 head &= RB_HEAD_OFF_MASK;
1320 tail &= RB_TAIL_OFF_MASK;
1321
1322 if (last_workload && same_context(&last_workload->ctx_desc, desc)) {
1323 gvt_dbg_el("ring id %d cur workload == last\n", ring_id);
1324 gvt_dbg_el("ctx head %x real head %lx\n", head,
1325 last_workload->rb_tail);
1326 /*
1327 * cannot use guest context head pointer here,
1328 * as it might not be updated at this time
1329 */
1330 head = last_workload->rb_tail;
1331 }
1332
1333 gvt_dbg_el("ring id %d begin a new workload\n", ring_id);
1334
1335 /* record some ring buffer register values for scan and shadow */
1336 intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
1337 RING_CTX_OFF(rb_start.val), &start, 4);
1338 intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
1339 RING_CTX_OFF(rb_ctrl.val), &ctl, 4);
1340 intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
1341 RING_CTX_OFF(ctx_ctrl.val), &ctx_ctl, 4);
1342
1343 workload = alloc_workload(vgpu);
1344 if (IS_ERR(workload))
1345 return workload;
1346
1347 workload->ring_id = ring_id;
1348 workload->ctx_desc = *desc;
1349 workload->ring_context_gpa = ring_context_gpa;
1350 workload->rb_head = head;
1351 workload->rb_tail = tail;
1352 workload->rb_start = start;
1353 workload->rb_ctl = ctl;
1354
1355 if (ring_id == RCS) {
1356 intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
1357 RING_CTX_OFF(bb_per_ctx_ptr.val), &per_ctx, 4);
1358 intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
1359 RING_CTX_OFF(rcs_indirect_ctx.val), &indirect_ctx, 4);
1360
1361 workload->wa_ctx.indirect_ctx.guest_gma =
1362 indirect_ctx & INDIRECT_CTX_ADDR_MASK;
1363 workload->wa_ctx.indirect_ctx.size =
1364 (indirect_ctx & INDIRECT_CTX_SIZE_MASK) *
1365 CACHELINE_BYTES;
1366 workload->wa_ctx.per_ctx.guest_gma =
1367 per_ctx & PER_CTX_ADDR_MASK;
1368 workload->wa_ctx.per_ctx.valid = per_ctx & 1;
1369 }
1370
1371 gvt_dbg_el("workload %p ring id %d head %x tail %x start %x ctl %x\n",
1372 workload, ring_id, head, tail, start, ctl);
1373
1374 ret = prepare_mm(workload);
1375 if (ret) {
1376 kmem_cache_free(s->workloads, workload);
1377 return ERR_PTR(ret);
1378 }
1379
1380 /* Only scan and shadow the first workload in the queue
1381 * as there is only one pre-allocated buf-obj for shadow.
1382 */
1383 if (list_empty(workload_q_head(vgpu, ring_id))) {
1384 intel_runtime_pm_get(dev_priv);
1385 mutex_lock(&dev_priv->drm.struct_mutex);
1386 ret = intel_gvt_scan_and_shadow_workload(workload);
1387 mutex_unlock(&dev_priv->drm.struct_mutex);
1388 intel_runtime_pm_put(dev_priv);
1389 }
1390
1391 if (ret && (vgpu_is_vm_unhealthy(ret))) {
1392 enter_failsafe_mode(vgpu, GVT_FAILSAFE_GUEST_ERR);
1393 intel_vgpu_destroy_workload(workload);
1394 return ERR_PTR(ret);
1395 }
1396
1397 return workload;
1398}
Changbin Du59a716c2017-11-29 15:40:06 +08001399
1400/**
1401 * intel_vgpu_queue_workload - Qeue a vGPU workload
1402 * @workload: the workload to queue in
1403 */
1404void intel_vgpu_queue_workload(struct intel_vgpu_workload *workload)
1405{
1406 list_add_tail(&workload->list,
1407 workload_q_head(workload->vgpu, workload->ring_id));
Changbin Duc1304562017-11-29 15:40:07 +08001408 intel_gvt_kick_schedule(workload->vgpu->gvt);
Changbin Du59a716c2017-11-29 15:40:06 +08001409 wake_up(&workload->vgpu->gvt->scheduler.waitq[workload->ring_id]);
1410}