blob: 462cf560492e3453a41d3ad3274e3fe60fc33e57 [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
135 gvt_dbg_sched("ring id %d workload lrca %x", ring_id,
136 workload->ctx_desc.lrca);
137
Joonas Lahtinen63ffbcd2017-04-28 10:53:36 +0300138 context_page_num = gvt->dev_priv->engine[ring_id]->context_size;
Zhi Wange4734052016-05-01 07:42:16 -0400139
140 context_page_num = context_page_num >> PAGE_SHIFT;
141
142 if (IS_BROADWELL(gvt->dev_priv) && ring_id == RCS)
143 context_page_num = 19;
144
145 i = 2;
146
147 while (i < context_page_num) {
148 context_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm,
149 (u32)((workload->ctx_desc.lrca + i) <<
Zhi Wang9556e112017-10-10 13:51:32 +0800150 I915_GTT_PAGE_SHIFT));
Zhi Wange4734052016-05-01 07:42:16 -0400151 if (context_gpa == INTEL_GVT_INVALID_ADDR) {
Tina Zhang695fbc02017-03-10 04:26:53 -0500152 gvt_vgpu_err("Invalid guest context descriptor\n");
fred gao5c568832017-09-20 05:36:47 +0800153 return -EFAULT;
Zhi Wange4734052016-05-01 07:42:16 -0400154 }
155
Michel Thierry0b29c752017-09-13 09:56:00 +0100156 page = i915_gem_object_get_page(ctx_obj, LRC_HEADER_PAGES + i);
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800157 dst = kmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400158 intel_gvt_hypervisor_read_gpa(vgpu, context_gpa, dst,
Zhi Wang9556e112017-10-10 13:51:32 +0800159 I915_GTT_PAGE_SIZE);
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800160 kunmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400161 i++;
162 }
163
164 page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800165 shadow_ring_context = kmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400166
Min Hefa3dd622018-03-02 10:00:25 +0800167 sr_oa_regs(workload, (u32 *)shadow_ring_context, true);
Zhi Wange4734052016-05-01 07:42:16 -0400168#define COPY_REG(name) \
169 intel_gvt_hypervisor_read_gpa(vgpu, workload->ring_context_gpa \
170 + RING_CTX_OFF(name.val), &shadow_ring_context->name.val, 4)
Zhenyu Wangd8303072018-03-19 17:09:05 +0800171#define COPY_REG_MASKED(name) {\
172 intel_gvt_hypervisor_read_gpa(vgpu, workload->ring_context_gpa \
173 + RING_CTX_OFF(name.val),\
174 &shadow_ring_context->name.val, 4);\
175 shadow_ring_context->name.val |= 0xffff << 16;\
176 }
Zhi Wange4734052016-05-01 07:42:16 -0400177
Zhenyu Wangd8303072018-03-19 17:09:05 +0800178 COPY_REG_MASKED(ctx_ctrl);
Zhi Wange4734052016-05-01 07:42:16 -0400179 COPY_REG(ctx_timestamp);
180
181 if (ring_id == RCS) {
182 COPY_REG(bb_per_ctx_ptr);
183 COPY_REG(rcs_indirect_ctx);
184 COPY_REG(rcs_indirect_ctx_offset);
185 }
186#undef COPY_REG
Zhenyu Wangd8303072018-03-19 17:09:05 +0800187#undef COPY_REG_MASKED
Zhi Wange4734052016-05-01 07:42:16 -0400188
Zhi Wange4734052016-05-01 07:42:16 -0400189 intel_gvt_hypervisor_read_gpa(vgpu,
190 workload->ring_context_gpa +
191 sizeof(*shadow_ring_context),
192 (void *)shadow_ring_context +
193 sizeof(*shadow_ring_context),
Zhi Wang9556e112017-10-10 13:51:32 +0800194 I915_GTT_PAGE_SIZE - sizeof(*shadow_ring_context));
Zhi Wange4734052016-05-01 07:42:16 -0400195
Min Hefa3dd622018-03-02 10:00:25 +0800196 sr_oa_regs(workload, (u32 *)shadow_ring_context, false);
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800197 kunmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400198 return 0;
199}
200
Chris Wilsone61e0f52018-02-21 09:56:36 +0000201static inline bool is_gvt_request(struct i915_request *req)
Changbin Dubc2d4b62017-03-22 12:35:31 +0800202{
Chris Wilson4e0d64d2018-05-17 22:26:30 +0100203 return i915_gem_context_force_single_submission(req->gem_context);
Changbin Dubc2d4b62017-03-22 12:35:31 +0800204}
205
Xiong Zhang295764c2017-11-07 05:23:02 +0800206static void save_ring_hw_state(struct intel_vgpu *vgpu, int ring_id)
207{
208 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
209 u32 ring_base = dev_priv->engine[ring_id]->mmio_base;
210 i915_reg_t reg;
211
212 reg = RING_INSTDONE(ring_base);
213 vgpu_vreg(vgpu, i915_mmio_reg_offset(reg)) = I915_READ_FW(reg);
214 reg = RING_ACTHD(ring_base);
215 vgpu_vreg(vgpu, i915_mmio_reg_offset(reg)) = I915_READ_FW(reg);
216 reg = RING_ACTHD_UDW(ring_base);
217 vgpu_vreg(vgpu, i915_mmio_reg_offset(reg)) = I915_READ_FW(reg);
218}
219
Zhi Wange4734052016-05-01 07:42:16 -0400220static int shadow_context_status_change(struct notifier_block *nb,
221 unsigned long action, void *data)
222{
Chris Wilsone61e0f52018-02-21 09:56:36 +0000223 struct i915_request *req = data;
Changbin Du3fc03062017-03-13 10:47:11 +0800224 struct intel_gvt *gvt = container_of(nb, struct intel_gvt,
225 shadow_ctx_notifier_block[req->engine->id]);
226 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
Changbin Du0e86cc92017-05-04 10:52:38 +0800227 enum intel_engine_id ring_id = req->engine->id;
228 struct intel_vgpu_workload *workload;
Changbin Du679fd3e2017-11-13 14:58:31 +0800229 unsigned long flags;
Zhi Wange4734052016-05-01 07:42:16 -0400230
Changbin Du0e86cc92017-05-04 10:52:38 +0800231 if (!is_gvt_request(req)) {
Changbin Du679fd3e2017-11-13 14:58:31 +0800232 spin_lock_irqsave(&scheduler->mmio_context_lock, flags);
Changbin Du0e86cc92017-05-04 10:52:38 +0800233 if (action == INTEL_CONTEXT_SCHEDULE_IN &&
234 scheduler->engine_owner[ring_id]) {
235 /* Switch ring from vGPU to host. */
236 intel_gvt_switch_mmio(scheduler->engine_owner[ring_id],
237 NULL, ring_id);
238 scheduler->engine_owner[ring_id] = NULL;
239 }
Changbin Du679fd3e2017-11-13 14:58:31 +0800240 spin_unlock_irqrestore(&scheduler->mmio_context_lock, flags);
Changbin Du0e86cc92017-05-04 10:52:38 +0800241
242 return NOTIFY_OK;
243 }
244
245 workload = scheduler->current_workload[ring_id];
246 if (unlikely(!workload))
Chuanxiao Dong9272f732017-02-17 19:29:52 +0800247 return NOTIFY_OK;
248
Zhi Wange4734052016-05-01 07:42:16 -0400249 switch (action) {
250 case INTEL_CONTEXT_SCHEDULE_IN:
Changbin Du679fd3e2017-11-13 14:58:31 +0800251 spin_lock_irqsave(&scheduler->mmio_context_lock, flags);
Changbin Du0e86cc92017-05-04 10:52:38 +0800252 if (workload->vgpu != scheduler->engine_owner[ring_id]) {
253 /* Switch ring from host to vGPU or vGPU to vGPU. */
254 intel_gvt_switch_mmio(scheduler->engine_owner[ring_id],
255 workload->vgpu, ring_id);
256 scheduler->engine_owner[ring_id] = workload->vgpu;
257 } else
258 gvt_dbg_sched("skip ring %d mmio switch for vgpu%d\n",
259 ring_id, workload->vgpu->id);
Changbin Du679fd3e2017-11-13 14:58:31 +0800260 spin_unlock_irqrestore(&scheduler->mmio_context_lock, flags);
Zhi Wange4734052016-05-01 07:42:16 -0400261 atomic_set(&workload->shadow_ctx_active, 1);
262 break;
263 case INTEL_CONTEXT_SCHEDULE_OUT:
Xiong Zhang295764c2017-11-07 05:23:02 +0800264 save_ring_hw_state(workload->vgpu, ring_id);
Zhi Wange4734052016-05-01 07:42:16 -0400265 atomic_set(&workload->shadow_ctx_active, 0);
266 break;
Zhenyu Wangda5f99e2017-12-01 14:59:53 +0800267 case INTEL_CONTEXT_SCHEDULE_PREEMPTED:
268 save_ring_hw_state(workload->vgpu, ring_id);
269 break;
Zhi Wange4734052016-05-01 07:42:16 -0400270 default:
271 WARN_ON(1);
272 return NOTIFY_OK;
273 }
274 wake_up(&workload->shadow_ctx_status_wq);
275 return NOTIFY_OK;
276}
277
Chris Wilson1fc44d92018-05-17 22:26:32 +0100278static void shadow_context_descriptor_update(struct intel_context *ce)
Kechen Lu9dfb8e52017-08-10 07:41:36 +0800279{
Kechen Lu9dfb8e52017-08-10 07:41:36 +0800280 u64 desc = 0;
281
282 desc = ce->lrc_desc;
283
284 /* Update bits 0-11 of the context descriptor which includes flags
285 * like GEN8_CTX_* cached in desc_template
286 */
287 desc &= U64_MAX << 12;
Chris Wilson1fc44d92018-05-17 22:26:32 +0100288 desc |= ce->gem_context->desc_template & ((1ULL << 12) - 1);
Kechen Lu9dfb8e52017-08-10 07:41:36 +0800289
290 ce->lrc_desc = desc;
291}
292
fred gao0a53bc02017-08-18 15:41:06 +0800293static int copy_workload_to_ring_buffer(struct intel_vgpu_workload *workload)
294{
295 struct intel_vgpu *vgpu = workload->vgpu;
Chris Wilson1fc44d92018-05-17 22:26:32 +0100296 struct i915_request *req = workload->req;
fred gao0a53bc02017-08-18 15:41:06 +0800297 void *shadow_ring_buffer_va;
298 u32 *cs;
Weinan Licd7e61b2018-02-23 14:46:45 +0800299
Chris Wilson1fc44d92018-05-17 22:26:32 +0100300 if (IS_KABYLAKE(req->i915) && is_inhibit_context(req->hw_context))
Weinan Licd7e61b2018-02-23 14:46:45 +0800301 intel_vgpu_restore_inhibit_context(vgpu, req);
fred gao0a53bc02017-08-18 15:41:06 +0800302
303 /* allocate shadow ring buffer */
304 cs = intel_ring_begin(workload->req, workload->rb_len / sizeof(u32));
305 if (IS_ERR(cs)) {
306 gvt_vgpu_err("fail to alloc size =%ld shadow ring buffer\n",
307 workload->rb_len);
308 return PTR_ERR(cs);
309 }
310
311 shadow_ring_buffer_va = workload->shadow_ring_buffer_va;
312
313 /* get shadow ring buffer va */
314 workload->shadow_ring_buffer_va = cs;
315
316 memcpy(cs, shadow_ring_buffer_va,
317 workload->rb_len);
318
319 cs += workload->rb_len / sizeof(u32);
320 intel_ring_advance(workload->req, cs);
321
322 return 0;
323}
324
Chris Wilson7b302552017-11-20 13:29:58 +0000325static void release_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
fred gaoa3cfdca2017-08-18 15:41:07 +0800326{
327 if (!wa_ctx->indirect_ctx.obj)
328 return;
329
330 i915_gem_object_unpin_map(wa_ctx->indirect_ctx.obj);
331 i915_gem_object_put(wa_ctx->indirect_ctx.obj);
332}
333
Ping Gao89ea20b2017-06-29 12:22:42 +0800334/**
335 * intel_gvt_scan_and_shadow_workload - audit the workload by scanning and
336 * shadow it as well, include ringbuffer,wa_ctx and ctx.
337 * @workload: an abstract entity for each execlist submission.
338 *
339 * This function is called before the workload submitting to i915, to make
340 * sure the content of the workload is valid.
341 */
342int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload)
Zhi Wange4734052016-05-01 07:42:16 -0400343{
Zhi Wang1406a142017-09-10 21:15:18 +0800344 struct intel_vgpu *vgpu = workload->vgpu;
345 struct intel_vgpu_submission *s = &vgpu->submission;
346 struct i915_gem_context *shadow_ctx = s->shadow_ctx;
347 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
Chris Wilson1fc44d92018-05-17 22:26:32 +0100348 struct intel_engine_cs *engine = dev_priv->engine[workload->ring_id];
349 struct intel_context *ce;
Zhenyu Wang6bb2a2a2018-05-21 16:17:52 +0800350 struct i915_request *rq;
Zhi Wange4734052016-05-01 07:42:16 -0400351 int ret;
352
Ping Gao87e919d2017-07-04 14:53:03 +0800353 lockdep_assert_held(&dev_priv->drm.struct_mutex);
354
Chris Wilson1fc44d92018-05-17 22:26:32 +0100355 if (workload->req)
Ping Gaod0302e72017-06-29 12:22:43 +0800356 return 0;
Zhi Wange4734052016-05-01 07:42:16 -0400357
Ping Gao89ea20b2017-06-29 12:22:42 +0800358 /* pin shadow context by gvt even the shadow context will be pinned
359 * when i915 alloc request. That is because gvt will update the guest
360 * context from shadow context when workload is completed, and at that
361 * moment, i915 may already unpined the shadow context to make the
362 * shadow_ctx pages invalid. So gvt need to pin itself. After update
363 * the guest context, gvt can unpin the shadow_ctx safely.
364 */
Chris Wilson1fc44d92018-05-17 22:26:32 +0100365 ce = intel_context_pin(shadow_ctx, engine);
366 if (IS_ERR(ce)) {
Ping Gao89ea20b2017-06-29 12:22:42 +0800367 gvt_vgpu_err("fail to pin shadow context\n");
Chris Wilson1fc44d92018-05-17 22:26:32 +0100368 return PTR_ERR(ce);
Ping Gao89ea20b2017-06-29 12:22:42 +0800369 }
Zhi Wange4734052016-05-01 07:42:16 -0400370
Chris Wilson1fc44d92018-05-17 22:26:32 +0100371 shadow_ctx->desc_template &= ~(0x3 << GEN8_CTX_ADDRESSING_MODE_SHIFT);
372 shadow_ctx->desc_template |= workload->ctx_desc.addressing_mode <<
373 GEN8_CTX_ADDRESSING_MODE_SHIFT;
374
375 if (!test_and_set_bit(workload->ring_id, s->shadow_ctx_desc_updated))
376 shadow_context_descriptor_update(ce);
377
378 ret = intel_gvt_scan_and_shadow_ringbuffer(workload);
fred gao0a53bc02017-08-18 15:41:06 +0800379 if (ret)
fred gaoa3cfdca2017-08-18 15:41:07 +0800380 goto err_unpin;
fred gaof2880e02017-11-14 17:09:35 +0800381
Chris Wilson1fc44d92018-05-17 22:26:32 +0100382 if ((workload->ring_id == RCS) &&
383 (workload->wa_ctx.indirect_ctx.size != 0)) {
384 ret = intel_gvt_scan_and_shadow_wa_ctx(&workload->wa_ctx);
385 if (ret)
386 goto err_shadow;
Zhi Wange4734052016-05-01 07:42:16 -0400387 }
fred gaof2880e02017-11-14 17:09:35 +0800388
Zhenyu Wang6bb2a2a2018-05-21 16:17:52 +0800389 rq = i915_request_alloc(engine, shadow_ctx);
fred gao0a53bc02017-08-18 15:41:06 +0800390 if (IS_ERR(rq)) {
391 gvt_vgpu_err("fail to allocate gem request\n");
392 ret = PTR_ERR(rq);
Zhenyu Wang6bb2a2a2018-05-21 16:17:52 +0800393 goto err_shadow;
fred gao0a53bc02017-08-18 15:41:06 +0800394 }
Chris Wilsone61e0f52018-02-21 09:56:36 +0000395 workload->req = i915_request_get(rq);
fred gao0a53bc02017-08-18 15:41:06 +0800396
Zhi Wange4734052016-05-01 07:42:16 -0400397 ret = populate_shadow_context(workload);
398 if (ret)
Zhenyu Wang6bb2a2a2018-05-21 16:17:52 +0800399 goto err_req;
Chris Wilson1fc44d92018-05-17 22:26:32 +0100400
Zhi Wange4734052016-05-01 07:42:16 -0400401 return 0;
Zhenyu Wang6bb2a2a2018-05-21 16:17:52 +0800402err_req:
403 rq = fetch_and_zero(&workload->req);
404 i915_request_put(rq);
Zhi Wange4734052016-05-01 07:42:16 -0400405err_shadow:
fred gaoa3cfdca2017-08-18 15:41:07 +0800406 release_shadow_wa_ctx(&workload->wa_ctx);
Chris Wilson1fc44d92018-05-17 22:26:32 +0100407err_unpin:
408 intel_context_unpin(ce);
fred gao0a53bc02017-08-18 15:41:06 +0800409 return ret;
410}
411
Zhi Wangf52c3802017-09-24 21:53:03 +0800412static void release_shadow_batch_buffer(struct intel_vgpu_workload *workload);
413
Zhi Wangd8235b52017-09-12 22:06:39 +0800414static int prepare_shadow_batch_buffer(struct intel_vgpu_workload *workload)
415{
416 struct intel_gvt *gvt = workload->vgpu->gvt;
417 const int gmadr_bytes = gvt->device_info.gmadr_bytes_in_cmd;
Zhi Wangf52c3802017-09-24 21:53:03 +0800418 struct intel_vgpu_shadow_bb *bb;
419 int ret;
Zhi Wangd8235b52017-09-12 22:06:39 +0800420
Zhi Wangf52c3802017-09-24 21:53:03 +0800421 list_for_each_entry(bb, &workload->shadow_bb, list) {
fred gaoef75c682018-03-15 13:21:10 +0800422 /* For privilge batch buffer and not wa_ctx, the bb_start_cmd_va
423 * is only updated into ring_scan_buffer, not real ring address
424 * allocated in later copy_workload_to_ring_buffer. pls be noted
425 * shadow_ring_buffer_va is now pointed to real ring buffer va
426 * in copy_workload_to_ring_buffer.
427 */
428
429 if (bb->bb_offset)
430 bb->bb_start_cmd_va = workload->shadow_ring_buffer_va
431 + bb->bb_offset;
432
Zhao Yan96bebe32018-04-04 13:57:09 +0800433 if (bb->ppgtt) {
434 /* for non-priv bb, scan&shadow is only for
435 * debugging purpose, so the content of shadow bb
436 * is the same as original bb. Therefore,
437 * here, rather than switch to shadow bb's gma
438 * address, we directly use original batch buffer's
439 * gma address, and send original bb to hardware
440 * directly
441 */
442 if (bb->clflush & CLFLUSH_AFTER) {
443 drm_clflush_virt_range(bb->va,
444 bb->obj->base.size);
445 bb->clflush &= ~CLFLUSH_AFTER;
446 }
447 i915_gem_obj_finish_shmem_access(bb->obj);
448 bb->accessing = false;
Zhi Wangf52c3802017-09-24 21:53:03 +0800449
Zhao Yan96bebe32018-04-04 13:57:09 +0800450 } else {
451 bb->vma = i915_gem_object_ggtt_pin(bb->obj,
452 NULL, 0, 0, 0);
453 if (IS_ERR(bb->vma)) {
454 ret = PTR_ERR(bb->vma);
455 goto err;
456 }
457
458 /* relocate shadow batch buffer */
459 bb->bb_start_cmd_va[1] = i915_ggtt_offset(bb->vma);
460 if (gmadr_bytes == 8)
461 bb->bb_start_cmd_va[2] = 0;
462
463 /* No one is going to touch shadow bb from now on. */
464 if (bb->clflush & CLFLUSH_AFTER) {
465 drm_clflush_virt_range(bb->va,
466 bb->obj->base.size);
467 bb->clflush &= ~CLFLUSH_AFTER;
468 }
469
470 ret = i915_gem_object_set_to_gtt_domain(bb->obj,
471 false);
472 if (ret)
473 goto err;
474
475 i915_gem_obj_finish_shmem_access(bb->obj);
476 bb->accessing = false;
477
478 i915_vma_move_to_active(bb->vma, workload->req, 0);
Zhi Wangf52c3802017-09-24 21:53:03 +0800479 }
Zhi Wangd8235b52017-09-12 22:06:39 +0800480 }
481 return 0;
Zhi Wangf52c3802017-09-24 21:53:03 +0800482err:
483 release_shadow_batch_buffer(workload);
484 return ret;
Zhi Wangd8235b52017-09-12 22:06:39 +0800485}
486
Chris Wilson1fc44d92018-05-17 22:26:32 +0100487static void update_wa_ctx_2_shadow_ctx(struct intel_shadow_wa_ctx *wa_ctx)
Zhi Wangd8235b52017-09-12 22:06:39 +0800488{
Chris Wilson1fc44d92018-05-17 22:26:32 +0100489 struct intel_vgpu_workload *workload =
490 container_of(wa_ctx, struct intel_vgpu_workload, wa_ctx);
491 struct i915_request *rq = workload->req;
492 struct execlist_ring_context *shadow_ring_context =
493 (struct execlist_ring_context *)rq->hw_context->lrc_reg_state;
Zhi Wangd8235b52017-09-12 22:06:39 +0800494
495 shadow_ring_context->bb_per_ctx_ptr.val =
496 (shadow_ring_context->bb_per_ctx_ptr.val &
497 (~PER_CTX_ADDR_MASK)) | wa_ctx->per_ctx.shadow_gma;
498 shadow_ring_context->rcs_indirect_ctx.val =
499 (shadow_ring_context->rcs_indirect_ctx.val &
500 (~INDIRECT_CTX_ADDR_MASK)) | wa_ctx->indirect_ctx.shadow_gma;
Zhi Wangd8235b52017-09-12 22:06:39 +0800501}
502
503static int prepare_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
504{
505 struct i915_vma *vma;
506 unsigned char *per_ctx_va =
507 (unsigned char *)wa_ctx->indirect_ctx.shadow_va +
508 wa_ctx->indirect_ctx.size;
509
510 if (wa_ctx->indirect_ctx.size == 0)
511 return 0;
512
513 vma = i915_gem_object_ggtt_pin(wa_ctx->indirect_ctx.obj, NULL,
514 0, CACHELINE_BYTES, 0);
515 if (IS_ERR(vma))
516 return PTR_ERR(vma);
517
518 /* FIXME: we are not tracking our pinned VMA leaving it
519 * up to the core to fix up the stray pin_count upon
520 * free.
521 */
522
523 wa_ctx->indirect_ctx.shadow_gma = i915_ggtt_offset(vma);
524
525 wa_ctx->per_ctx.shadow_gma = *((unsigned int *)per_ctx_va + 1);
526 memset(per_ctx_va, 0, CACHELINE_BYTES);
527
528 update_wa_ctx_2_shadow_ctx(wa_ctx);
529 return 0;
530}
531
532static void release_shadow_batch_buffer(struct intel_vgpu_workload *workload)
533{
Zhi Wangf52c3802017-09-24 21:53:03 +0800534 struct intel_vgpu *vgpu = workload->vgpu;
535 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
536 struct intel_vgpu_shadow_bb *bb, *pos;
Zhi Wangd8235b52017-09-12 22:06:39 +0800537
Zhi Wangf52c3802017-09-24 21:53:03 +0800538 if (list_empty(&workload->shadow_bb))
539 return;
540
541 bb = list_first_entry(&workload->shadow_bb,
542 struct intel_vgpu_shadow_bb, list);
543
544 mutex_lock(&dev_priv->drm.struct_mutex);
545
546 list_for_each_entry_safe(bb, pos, &workload->shadow_bb, list) {
547 if (bb->obj) {
548 if (bb->accessing)
549 i915_gem_obj_finish_shmem_access(bb->obj);
550
551 if (bb->va && !IS_ERR(bb->va))
552 i915_gem_object_unpin_map(bb->obj);
553
554 if (bb->vma && !IS_ERR(bb->vma)) {
555 i915_vma_unpin(bb->vma);
556 i915_vma_close(bb->vma);
557 }
558 __i915_gem_object_release_unless_active(bb->obj);
Zhi Wangd8235b52017-09-12 22:06:39 +0800559 }
Zhi Wangf52c3802017-09-24 21:53:03 +0800560 list_del(&bb->list);
561 kfree(bb);
Zhi Wangd8235b52017-09-12 22:06:39 +0800562 }
Zhi Wangf52c3802017-09-24 21:53:03 +0800563
564 mutex_unlock(&dev_priv->drm.struct_mutex);
Zhi Wangd8235b52017-09-12 22:06:39 +0800565}
566
Zhi Wang497aa3f2017-09-12 21:51:10 +0800567static int prepare_workload(struct intel_vgpu_workload *workload)
568{
Zhi Wangd8235b52017-09-12 22:06:39 +0800569 struct intel_vgpu *vgpu = workload->vgpu;
Zhi Wang497aa3f2017-09-12 21:51:10 +0800570 int ret = 0;
571
Zhi Wangd8235b52017-09-12 22:06:39 +0800572 ret = intel_vgpu_pin_mm(workload->shadow_mm);
573 if (ret) {
574 gvt_vgpu_err("fail to vgpu pin mm\n");
575 return ret;
576 }
Zhi Wang497aa3f2017-09-12 21:51:10 +0800577
Zhi Wangb20c0d52018-02-07 18:12:15 +0800578 update_shadow_pdps(workload);
579
Zhi Wangd8235b52017-09-12 22:06:39 +0800580 ret = intel_vgpu_sync_oos_pages(workload->vgpu);
581 if (ret) {
582 gvt_vgpu_err("fail to vgpu sync oos pages\n");
583 goto err_unpin_mm;
584 }
585
586 ret = intel_vgpu_flush_post_shadow(workload->vgpu);
587 if (ret) {
588 gvt_vgpu_err("fail to flush post shadow\n");
589 goto err_unpin_mm;
590 }
591
Zhenyu Wang6bb2a2a2018-05-21 16:17:52 +0800592 ret = copy_workload_to_ring_buffer(workload);
fred gaof2880e02017-11-14 17:09:35 +0800593 if (ret) {
594 gvt_vgpu_err("fail to generate request\n");
595 goto err_unpin_mm;
596 }
597
Zhi Wangd8235b52017-09-12 22:06:39 +0800598 ret = prepare_shadow_batch_buffer(workload);
599 if (ret) {
600 gvt_vgpu_err("fail to prepare_shadow_batch_buffer\n");
601 goto err_unpin_mm;
602 }
603
604 ret = prepare_shadow_wa_ctx(&workload->wa_ctx);
605 if (ret) {
606 gvt_vgpu_err("fail to prepare_shadow_wa_ctx\n");
607 goto err_shadow_batch;
608 }
609
610 if (workload->prepare) {
611 ret = workload->prepare(workload);
612 if (ret)
613 goto err_shadow_wa_ctx;
614 }
615
616 return 0;
617err_shadow_wa_ctx:
618 release_shadow_wa_ctx(&workload->wa_ctx);
619err_shadow_batch:
620 release_shadow_batch_buffer(workload);
621err_unpin_mm:
622 intel_vgpu_unpin_mm(workload->shadow_mm);
Zhi Wang497aa3f2017-09-12 21:51:10 +0800623 return ret;
624}
625
fred gao0a53bc02017-08-18 15:41:06 +0800626static int dispatch_workload(struct intel_vgpu_workload *workload)
627{
Zhi Wang1406a142017-09-10 21:15:18 +0800628 struct intel_vgpu *vgpu = workload->vgpu;
Zhi Wang1406a142017-09-10 21:15:18 +0800629 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
fred gao0a53bc02017-08-18 15:41:06 +0800630 int ring_id = workload->ring_id;
Chris Wilson1fc44d92018-05-17 22:26:32 +0100631 int ret;
fred gao0a53bc02017-08-18 15:41:06 +0800632
633 gvt_dbg_sched("ring id %d prepare to dispatch workload %p\n",
634 ring_id, workload);
635
Colin Xuf25a49a2018-05-19 12:28:54 +0800636 mutex_lock(&vgpu->vgpu_lock);
fred gao0a53bc02017-08-18 15:41:06 +0800637 mutex_lock(&dev_priv->drm.struct_mutex);
638
639 ret = intel_gvt_scan_and_shadow_workload(workload);
640 if (ret)
641 goto out;
642
Zhi Wang497aa3f2017-09-12 21:51:10 +0800643 ret = prepare_workload(workload);
fred gao0a53bc02017-08-18 15:41:06 +0800644
Pei Zhang90d27a12016-11-14 18:02:57 +0800645out:
646 if (ret)
647 workload->status = ret;
Chris Wilson0eb742d2016-10-20 17:29:36 +0800648
Ping Gao89ea20b2017-06-29 12:22:42 +0800649 if (!IS_ERR_OR_NULL(workload->req)) {
650 gvt_dbg_sched("ring id %d submit workload to i915 %p\n",
651 ring_id, workload->req);
Chris Wilsone61e0f52018-02-21 09:56:36 +0000652 i915_request_add(workload->req);
Ping Gao89ea20b2017-06-29 12:22:42 +0800653 workload->dispatched = true;
654 }
Chuanxiao Dong3cd23b82017-03-16 09:47:58 +0800655
Pei Zhang90d27a12016-11-14 18:02:57 +0800656 mutex_unlock(&dev_priv->drm.struct_mutex);
Colin Xuf25a49a2018-05-19 12:28:54 +0800657 mutex_unlock(&vgpu->vgpu_lock);
Zhi Wange4734052016-05-01 07:42:16 -0400658 return ret;
659}
660
661static struct intel_vgpu_workload *pick_next_workload(
662 struct intel_gvt *gvt, int ring_id)
663{
664 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
665 struct intel_vgpu_workload *workload = NULL;
666
Colin Xu9a512e22018-05-19 12:28:55 +0800667 mutex_lock(&gvt->sched_lock);
Zhi Wange4734052016-05-01 07:42:16 -0400668
669 /*
670 * no current vgpu / will be scheduled out / no workload
671 * bail out
672 */
673 if (!scheduler->current_vgpu) {
674 gvt_dbg_sched("ring id %d stop - no current vgpu\n", ring_id);
675 goto out;
676 }
677
678 if (scheduler->need_reschedule) {
679 gvt_dbg_sched("ring id %d stop - will reschedule\n", ring_id);
680 goto out;
681 }
682
Zhenyu Wang954180a2017-04-12 14:22:50 +0800683 if (list_empty(workload_q_head(scheduler->current_vgpu, ring_id)))
Zhi Wange4734052016-05-01 07:42:16 -0400684 goto out;
Zhi Wange4734052016-05-01 07:42:16 -0400685
686 /*
687 * still have current workload, maybe the workload disptacher
688 * fail to submit it for some reason, resubmit it.
689 */
690 if (scheduler->current_workload[ring_id]) {
691 workload = scheduler->current_workload[ring_id];
692 gvt_dbg_sched("ring id %d still have current workload %p\n",
693 ring_id, workload);
694 goto out;
695 }
696
697 /*
698 * pick a workload as current workload
699 * once current workload is set, schedule policy routines
700 * will wait the current workload is finished when trying to
701 * schedule out a vgpu.
702 */
703 scheduler->current_workload[ring_id] = container_of(
704 workload_q_head(scheduler->current_vgpu, ring_id)->next,
705 struct intel_vgpu_workload, list);
706
707 workload = scheduler->current_workload[ring_id];
708
709 gvt_dbg_sched("ring id %d pick new workload %p\n", ring_id, workload);
710
Zhi Wang1406a142017-09-10 21:15:18 +0800711 atomic_inc(&workload->vgpu->submission.running_workload_num);
Zhi Wange4734052016-05-01 07:42:16 -0400712out:
Colin Xu9a512e22018-05-19 12:28:55 +0800713 mutex_unlock(&gvt->sched_lock);
Zhi Wange4734052016-05-01 07:42:16 -0400714 return workload;
715}
716
717static void update_guest_context(struct intel_vgpu_workload *workload)
718{
Chris Wilson1fc44d92018-05-17 22:26:32 +0100719 struct i915_request *rq = workload->req;
Zhi Wange4734052016-05-01 07:42:16 -0400720 struct intel_vgpu *vgpu = workload->vgpu;
721 struct intel_gvt *gvt = vgpu->gvt;
Chris Wilson1fc44d92018-05-17 22:26:32 +0100722 struct drm_i915_gem_object *ctx_obj = rq->hw_context->state->obj;
Zhi Wange4734052016-05-01 07:42:16 -0400723 struct execlist_ring_context *shadow_ring_context;
724 struct page *page;
725 void *src;
726 unsigned long context_gpa, context_page_num;
727 int i;
728
Chris Wilson1fc44d92018-05-17 22:26:32 +0100729 gvt_dbg_sched("ring id %d workload lrca %x\n", rq->engine->id,
730 workload->ctx_desc.lrca);
Zhi Wange4734052016-05-01 07:42:16 -0400731
Chris Wilson1fc44d92018-05-17 22:26:32 +0100732 context_page_num = rq->engine->context_size;
Zhi Wange4734052016-05-01 07:42:16 -0400733 context_page_num = context_page_num >> PAGE_SHIFT;
734
Chris Wilson1fc44d92018-05-17 22:26:32 +0100735 if (IS_BROADWELL(gvt->dev_priv) && rq->engine->id == RCS)
Zhi Wange4734052016-05-01 07:42:16 -0400736 context_page_num = 19;
737
738 i = 2;
739
740 while (i < context_page_num) {
741 context_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm,
742 (u32)((workload->ctx_desc.lrca + i) <<
Zhi Wang9556e112017-10-10 13:51:32 +0800743 I915_GTT_PAGE_SHIFT));
Zhi Wange4734052016-05-01 07:42:16 -0400744 if (context_gpa == INTEL_GVT_INVALID_ADDR) {
Tina Zhang695fbc02017-03-10 04:26:53 -0500745 gvt_vgpu_err("invalid guest context descriptor\n");
Zhi Wange4734052016-05-01 07:42:16 -0400746 return;
747 }
748
Michel Thierry0b29c752017-09-13 09:56:00 +0100749 page = i915_gem_object_get_page(ctx_obj, LRC_HEADER_PAGES + i);
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800750 src = kmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400751 intel_gvt_hypervisor_write_gpa(vgpu, context_gpa, src,
Zhi Wang9556e112017-10-10 13:51:32 +0800752 I915_GTT_PAGE_SIZE);
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800753 kunmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400754 i++;
755 }
756
757 intel_gvt_hypervisor_write_gpa(vgpu, workload->ring_context_gpa +
758 RING_CTX_OFF(ring_header.val), &workload->rb_tail, 4);
759
760 page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800761 shadow_ring_context = kmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400762
763#define COPY_REG(name) \
764 intel_gvt_hypervisor_write_gpa(vgpu, workload->ring_context_gpa + \
765 RING_CTX_OFF(name.val), &shadow_ring_context->name.val, 4)
766
767 COPY_REG(ctx_ctrl);
768 COPY_REG(ctx_timestamp);
769
770#undef COPY_REG
771
772 intel_gvt_hypervisor_write_gpa(vgpu,
773 workload->ring_context_gpa +
774 sizeof(*shadow_ring_context),
775 (void *)shadow_ring_context +
776 sizeof(*shadow_ring_context),
Zhi Wang9556e112017-10-10 13:51:32 +0800777 I915_GTT_PAGE_SIZE - sizeof(*shadow_ring_context));
Zhi Wange4734052016-05-01 07:42:16 -0400778
Xiaoguang Chenc7549362016-11-03 18:38:30 +0800779 kunmap(page);
Zhi Wange4734052016-05-01 07:42:16 -0400780}
781
Zhi Wange2c43c02017-09-13 01:58:35 +0800782static void clean_workloads(struct intel_vgpu *vgpu, unsigned long engine_mask)
783{
784 struct intel_vgpu_submission *s = &vgpu->submission;
785 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
786 struct intel_engine_cs *engine;
787 struct intel_vgpu_workload *pos, *n;
788 unsigned int tmp;
789
790 /* free the unsubmited workloads in the queues. */
791 for_each_engine_masked(engine, dev_priv, engine_mask, tmp) {
792 list_for_each_entry_safe(pos, n,
793 &s->workload_q_head[engine->id], list) {
794 list_del_init(&pos->list);
795 intel_vgpu_destroy_workload(pos);
796 }
797 clear_bit(engine->id, s->shadow_ctx_desc_updated);
798 }
799}
800
Zhi Wange4734052016-05-01 07:42:16 -0400801static void complete_current_workload(struct intel_gvt *gvt, int ring_id)
802{
803 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
Zhi Wang1406a142017-09-10 21:15:18 +0800804 struct intel_vgpu_workload *workload =
805 scheduler->current_workload[ring_id];
806 struct intel_vgpu *vgpu = workload->vgpu;
807 struct intel_vgpu_submission *s = &vgpu->submission;
Zhenyu Wang6bb2a2a2018-05-21 16:17:52 +0800808 struct i915_request *rq = workload->req;
Zhi Wangbe1da702016-05-03 18:26:57 -0400809 int event;
Zhi Wange4734052016-05-01 07:42:16 -0400810
Colin Xuf25a49a2018-05-19 12:28:54 +0800811 mutex_lock(&vgpu->vgpu_lock);
Colin Xu9a512e22018-05-19 12:28:55 +0800812 mutex_lock(&gvt->sched_lock);
Zhi Wange4734052016-05-01 07:42:16 -0400813
Chuanxiao Dong8f1117a2017-03-06 13:05:24 +0800814 /* For the workload w/ request, needs to wait for the context
815 * switch to make sure request is completed.
816 * For the workload w/o request, directly complete the workload.
817 */
Chris Wilson1fc44d92018-05-17 22:26:32 +0100818 if (rq) {
Zhi Wange4734052016-05-01 07:42:16 -0400819 wait_event(workload->shadow_ctx_status_wq,
820 !atomic_read(&workload->shadow_ctx_active));
821
Chuanxiao Dong0cf5ec42017-06-23 13:01:11 +0800822 /* If this request caused GPU hang, req->fence.error will
823 * be set to -EIO. Use -EIO to set workload status so
824 * that when this request caused GPU hang, didn't trigger
825 * context switch interrupt to guest.
826 */
827 if (likely(workload->status == -EINPROGRESS)) {
828 if (workload->req->fence.error == -EIO)
829 workload->status = -EIO;
830 else
831 workload->status = 0;
832 }
833
Chuanxiao Dong6184cc82017-08-01 17:47:25 +0800834 if (!workload->status && !(vgpu->resetting_eng &
835 ENGINE_MASK(ring_id))) {
Chuanxiao Dong8f1117a2017-03-06 13:05:24 +0800836 update_guest_context(workload);
837
838 for_each_set_bit(event, workload->pending_events,
839 INTEL_GVT_EVENT_MAX)
840 intel_vgpu_trigger_virtual_event(vgpu, event);
841 }
Chris Wilson1fc44d92018-05-17 22:26:32 +0100842
Chuanxiao Dong3cd23b82017-03-16 09:47:58 +0800843 /* unpin shadow ctx as the shadow_ctx update is done */
Chris Wilson1fc44d92018-05-17 22:26:32 +0100844 mutex_lock(&rq->i915->drm.struct_mutex);
845 intel_context_unpin(rq->hw_context);
846 mutex_unlock(&rq->i915->drm.struct_mutex);
847
Zhenyu Wang6bb2a2a2018-05-21 16:17:52 +0800848 i915_request_put(fetch_and_zero(&workload->req));
Zhi Wange4734052016-05-01 07:42:16 -0400849 }
850
851 gvt_dbg_sched("ring id %d complete workload %p status %d\n",
852 ring_id, workload, workload->status);
853
854 scheduler->current_workload[ring_id] = NULL;
855
Zhi Wange4734052016-05-01 07:42:16 -0400856 list_del_init(&workload->list);
Zhi Wangd8235b52017-09-12 22:06:39 +0800857
858 if (!workload->status) {
859 release_shadow_batch_buffer(workload);
860 release_shadow_wa_ctx(&workload->wa_ctx);
861 }
862
Zhi Wange2c43c02017-09-13 01:58:35 +0800863 if (workload->status || (vgpu->resetting_eng & ENGINE_MASK(ring_id))) {
864 /* if workload->status is not successful means HW GPU
865 * has occurred GPU hang or something wrong with i915/GVT,
866 * and GVT won't inject context switch interrupt to guest.
867 * So this error is a vGPU hang actually to the guest.
868 * According to this we should emunlate a vGPU hang. If
869 * there are pending workloads which are already submitted
870 * from guest, we should clean them up like HW GPU does.
871 *
872 * if it is in middle of engine resetting, the pending
873 * workloads won't be submitted to HW GPU and will be
874 * cleaned up during the resetting process later, so doing
875 * the workload clean up here doesn't have any impact.
876 **/
877 clean_workloads(vgpu, ENGINE_MASK(ring_id));
878 }
879
Zhi Wange4734052016-05-01 07:42:16 -0400880 workload->complete(workload);
881
Zhi Wang1406a142017-09-10 21:15:18 +0800882 atomic_dec(&s->running_workload_num);
Zhi Wange4734052016-05-01 07:42:16 -0400883 wake_up(&scheduler->workload_complete_wq);
Ping Gaof100dae2017-05-24 09:14:11 +0800884
885 if (gvt->scheduler.need_reschedule)
886 intel_gvt_request_service(gvt, INTEL_GVT_REQUEST_EVENT_SCHED);
887
Colin Xu9a512e22018-05-19 12:28:55 +0800888 mutex_unlock(&gvt->sched_lock);
Colin Xuf25a49a2018-05-19 12:28:54 +0800889 mutex_unlock(&vgpu->vgpu_lock);
Zhi Wange4734052016-05-01 07:42:16 -0400890}
891
892struct workload_thread_param {
893 struct intel_gvt *gvt;
894 int ring_id;
895};
896
897static int workload_thread(void *priv)
898{
899 struct workload_thread_param *p = (struct workload_thread_param *)priv;
900 struct intel_gvt *gvt = p->gvt;
901 int ring_id = p->ring_id;
902 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
903 struct intel_vgpu_workload *workload = NULL;
Tina Zhang695fbc02017-03-10 04:26:53 -0500904 struct intel_vgpu *vgpu = NULL;
Zhi Wange4734052016-05-01 07:42:16 -0400905 int ret;
Xu Hane3476c02017-03-29 10:13:59 +0800906 bool need_force_wake = IS_SKYLAKE(gvt->dev_priv)
907 || IS_KABYLAKE(gvt->dev_priv);
Du, Changbine45d7b72016-10-27 11:10:31 +0800908 DEFINE_WAIT_FUNC(wait, woken_wake_function);
Zhi Wange4734052016-05-01 07:42:16 -0400909
910 kfree(p);
911
912 gvt_dbg_core("workload thread for ring %d started\n", ring_id);
913
914 while (!kthread_should_stop()) {
Du, Changbine45d7b72016-10-27 11:10:31 +0800915 add_wait_queue(&scheduler->waitq[ring_id], &wait);
916 do {
917 workload = pick_next_workload(gvt, ring_id);
918 if (workload)
919 break;
920 wait_woken(&wait, TASK_INTERRUPTIBLE,
921 MAX_SCHEDULE_TIMEOUT);
922 } while (!kthread_should_stop());
923 remove_wait_queue(&scheduler->waitq[ring_id], &wait);
Zhi Wange4734052016-05-01 07:42:16 -0400924
Du, Changbine45d7b72016-10-27 11:10:31 +0800925 if (!workload)
Zhi Wange4734052016-05-01 07:42:16 -0400926 break;
927
928 gvt_dbg_sched("ring id %d next workload %p vgpu %d\n",
929 workload->ring_id, workload,
930 workload->vgpu->id);
931
932 intel_runtime_pm_get(gvt->dev_priv);
933
Zhi Wange4734052016-05-01 07:42:16 -0400934 gvt_dbg_sched("ring id %d will dispatch workload %p\n",
935 workload->ring_id, workload);
936
937 if (need_force_wake)
938 intel_uncore_forcewake_get(gvt->dev_priv,
939 FORCEWAKE_ALL);
940
941 ret = dispatch_workload(workload);
Chris Wilson66bbc3b2016-10-19 11:11:44 +0100942
Zhi Wange4734052016-05-01 07:42:16 -0400943 if (ret) {
Tina Zhang695fbc02017-03-10 04:26:53 -0500944 vgpu = workload->vgpu;
945 gvt_vgpu_err("fail to dispatch workload, skip\n");
Zhi Wange4734052016-05-01 07:42:16 -0400946 goto complete;
947 }
948
949 gvt_dbg_sched("ring id %d wait workload %p\n",
950 workload->ring_id, workload);
Chris Wilsone61e0f52018-02-21 09:56:36 +0000951 i915_request_wait(workload->req, 0, MAX_SCHEDULE_TIMEOUT);
Zhi Wange4734052016-05-01 07:42:16 -0400952
953complete:
Changbin Du3ce32742017-02-09 10:13:16 +0800954 gvt_dbg_sched("will complete workload %p, status: %d\n",
Zhi Wange4734052016-05-01 07:42:16 -0400955 workload, workload->status);
956
Changbin Du2e51ef32017-01-05 13:28:05 +0800957 complete_current_workload(gvt, ring_id);
958
Zhi Wange4734052016-05-01 07:42:16 -0400959 if (need_force_wake)
960 intel_uncore_forcewake_put(gvt->dev_priv,
961 FORCEWAKE_ALL);
962
Zhi Wange4734052016-05-01 07:42:16 -0400963 intel_runtime_pm_put(gvt->dev_priv);
Zhi Wang6d763032017-09-12 22:33:12 +0800964 if (ret && (vgpu_is_vm_unhealthy(ret)))
fred gaoe011c6c2017-09-19 15:11:28 +0800965 enter_failsafe_mode(vgpu, GVT_FAILSAFE_GUEST_ERR);
Zhi Wange4734052016-05-01 07:42:16 -0400966 }
967 return 0;
968}
969
970void intel_gvt_wait_vgpu_idle(struct intel_vgpu *vgpu)
971{
Zhi Wang1406a142017-09-10 21:15:18 +0800972 struct intel_vgpu_submission *s = &vgpu->submission;
Zhi Wange4734052016-05-01 07:42:16 -0400973 struct intel_gvt *gvt = vgpu->gvt;
974 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
975
Zhi Wang1406a142017-09-10 21:15:18 +0800976 if (atomic_read(&s->running_workload_num)) {
Zhi Wange4734052016-05-01 07:42:16 -0400977 gvt_dbg_sched("wait vgpu idle\n");
978
979 wait_event(scheduler->workload_complete_wq,
Zhi Wang1406a142017-09-10 21:15:18 +0800980 !atomic_read(&s->running_workload_num));
Zhi Wange4734052016-05-01 07:42:16 -0400981 }
982}
983
984void intel_gvt_clean_workload_scheduler(struct intel_gvt *gvt)
985{
986 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
Changbin Du3fc03062017-03-13 10:47:11 +0800987 struct intel_engine_cs *engine;
988 enum intel_engine_id i;
Zhi Wange4734052016-05-01 07:42:16 -0400989
990 gvt_dbg_core("clean workload scheduler\n");
991
Changbin Du3fc03062017-03-13 10:47:11 +0800992 for_each_engine(engine, gvt->dev_priv, i) {
993 atomic_notifier_chain_unregister(
994 &engine->context_status_notifier,
995 &gvt->shadow_ctx_notifier_block[i]);
996 kthread_stop(scheduler->thread[i]);
Zhi Wange4734052016-05-01 07:42:16 -0400997 }
998}
999
1000int intel_gvt_init_workload_scheduler(struct intel_gvt *gvt)
1001{
1002 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
1003 struct workload_thread_param *param = NULL;
Changbin Du3fc03062017-03-13 10:47:11 +08001004 struct intel_engine_cs *engine;
1005 enum intel_engine_id i;
Zhi Wange4734052016-05-01 07:42:16 -04001006 int ret;
Zhi Wange4734052016-05-01 07:42:16 -04001007
1008 gvt_dbg_core("init workload scheduler\n");
1009
1010 init_waitqueue_head(&scheduler->workload_complete_wq);
1011
Changbin Du3fc03062017-03-13 10:47:11 +08001012 for_each_engine(engine, gvt->dev_priv, i) {
Zhi Wange4734052016-05-01 07:42:16 -04001013 init_waitqueue_head(&scheduler->waitq[i]);
1014
1015 param = kzalloc(sizeof(*param), GFP_KERNEL);
1016 if (!param) {
1017 ret = -ENOMEM;
1018 goto err;
1019 }
1020
1021 param->gvt = gvt;
1022 param->ring_id = i;
1023
1024 scheduler->thread[i] = kthread_run(workload_thread, param,
1025 "gvt workload %d", i);
1026 if (IS_ERR(scheduler->thread[i])) {
1027 gvt_err("fail to create workload thread\n");
1028 ret = PTR_ERR(scheduler->thread[i]);
1029 goto err;
1030 }
Changbin Du3fc03062017-03-13 10:47:11 +08001031
1032 gvt->shadow_ctx_notifier_block[i].notifier_call =
1033 shadow_context_status_change;
1034 atomic_notifier_chain_register(&engine->context_status_notifier,
1035 &gvt->shadow_ctx_notifier_block[i]);
Zhi Wange4734052016-05-01 07:42:16 -04001036 }
1037 return 0;
1038err:
1039 intel_gvt_clean_workload_scheduler(gvt);
1040 kfree(param);
1041 param = NULL;
1042 return ret;
1043}
1044
Zhi Wang874b6a92017-09-10 20:08:18 +08001045/**
1046 * intel_vgpu_clean_submission - free submission-related resource for vGPU
1047 * @vgpu: a vGPU
1048 *
1049 * This function is called when a vGPU is being destroyed.
1050 *
1051 */
1052void intel_vgpu_clean_submission(struct intel_vgpu *vgpu)
Zhi Wange4734052016-05-01 07:42:16 -04001053{
Zhi Wang1406a142017-09-10 21:15:18 +08001054 struct intel_vgpu_submission *s = &vgpu->submission;
1055
Weinan Li7569a062018-01-26 15:09:07 +08001056 intel_vgpu_select_submission_ops(vgpu, ALL_ENGINES, 0);
Zhi Wang1406a142017-09-10 21:15:18 +08001057 i915_gem_context_put(s->shadow_ctx);
1058 kmem_cache_destroy(s->workloads);
Zhi Wange4734052016-05-01 07:42:16 -04001059}
1060
Zhi Wang06bb3722017-09-13 01:41:35 +08001061
1062/**
1063 * intel_vgpu_reset_submission - reset submission-related resource for vGPU
1064 * @vgpu: a vGPU
1065 * @engine_mask: engines expected to be reset
1066 *
1067 * This function is called when a vGPU is being destroyed.
1068 *
1069 */
1070void intel_vgpu_reset_submission(struct intel_vgpu *vgpu,
1071 unsigned long engine_mask)
1072{
1073 struct intel_vgpu_submission *s = &vgpu->submission;
1074
1075 if (!s->active)
1076 return;
1077
Zhi Wange2c43c02017-09-13 01:58:35 +08001078 clean_workloads(vgpu, engine_mask);
Zhi Wang06bb3722017-09-13 01:41:35 +08001079 s->ops->reset(vgpu, engine_mask);
1080}
1081
Zhi Wang874b6a92017-09-10 20:08:18 +08001082/**
1083 * intel_vgpu_setup_submission - setup submission-related resource for vGPU
1084 * @vgpu: a vGPU
1085 *
1086 * This function is called when a vGPU is being created.
1087 *
1088 * Returns:
1089 * Zero on success, negative error code if failed.
1090 *
1091 */
1092int intel_vgpu_setup_submission(struct intel_vgpu *vgpu)
Zhi Wange4734052016-05-01 07:42:16 -04001093{
Zhi Wang1406a142017-09-10 21:15:18 +08001094 struct intel_vgpu_submission *s = &vgpu->submission;
Zhi Wang9a9829e2017-09-10 20:28:09 +08001095 enum intel_engine_id i;
1096 struct intel_engine_cs *engine;
1097 int ret;
Zhi Wange4734052016-05-01 07:42:16 -04001098
Zhi Wang1406a142017-09-10 21:15:18 +08001099 s->shadow_ctx = i915_gem_context_create_gvt(
Zhi Wange4734052016-05-01 07:42:16 -04001100 &vgpu->gvt->dev_priv->drm);
Zhi Wang1406a142017-09-10 21:15:18 +08001101 if (IS_ERR(s->shadow_ctx))
1102 return PTR_ERR(s->shadow_ctx);
Zhi Wange4734052016-05-01 07:42:16 -04001103
Zhi Wang1406a142017-09-10 21:15:18 +08001104 bitmap_zero(s->shadow_ctx_desc_updated, I915_NUM_ENGINES);
Kechen Lu9dfb8e52017-08-10 07:41:36 +08001105
Zhenyu Wang850555d2018-02-14 11:35:01 +08001106 s->workloads = kmem_cache_create_usercopy("gvt-g_vgpu_workload",
1107 sizeof(struct intel_vgpu_workload), 0,
1108 SLAB_HWCACHE_ALIGN,
1109 offsetof(struct intel_vgpu_workload, rb_tail),
1110 sizeof_field(struct intel_vgpu_workload, rb_tail),
1111 NULL);
Zhi Wang9a9829e2017-09-10 20:28:09 +08001112
Zhi Wang1406a142017-09-10 21:15:18 +08001113 if (!s->workloads) {
Zhi Wang9a9829e2017-09-10 20:28:09 +08001114 ret = -ENOMEM;
1115 goto out_shadow_ctx;
1116 }
1117
1118 for_each_engine(engine, vgpu->gvt->dev_priv, i)
Zhi Wang1406a142017-09-10 21:15:18 +08001119 INIT_LIST_HEAD(&s->workload_q_head[i]);
Zhi Wang9a9829e2017-09-10 20:28:09 +08001120
Zhi Wang1406a142017-09-10 21:15:18 +08001121 atomic_set(&s->running_workload_num, 0);
Zhi Wang91d5d852017-09-10 21:33:20 +08001122 bitmap_zero(s->tlb_handle_pending, I915_NUM_ENGINES);
Zhi Wang9a9829e2017-09-10 20:28:09 +08001123
Zhi Wange4734052016-05-01 07:42:16 -04001124 return 0;
Zhi Wang9a9829e2017-09-10 20:28:09 +08001125
1126out_shadow_ctx:
Zhi Wang1406a142017-09-10 21:15:18 +08001127 i915_gem_context_put(s->shadow_ctx);
Zhi Wang9a9829e2017-09-10 20:28:09 +08001128 return ret;
Zhi Wange4734052016-05-01 07:42:16 -04001129}
Zhi Wang21527a82017-09-12 21:42:09 +08001130
1131/**
Zhi Wangad1d3632017-09-13 00:31:29 +08001132 * intel_vgpu_select_submission_ops - select virtual submission interface
1133 * @vgpu: a vGPU
1134 * @interface: expected vGPU virtual submission interface
1135 *
1136 * This function is called when guest configures submission interface.
1137 *
1138 * Returns:
1139 * Zero on success, negative error code if failed.
1140 *
1141 */
1142int intel_vgpu_select_submission_ops(struct intel_vgpu *vgpu,
Weinan Li7569a062018-01-26 15:09:07 +08001143 unsigned long engine_mask,
Zhi Wangad1d3632017-09-13 00:31:29 +08001144 unsigned int interface)
1145{
1146 struct intel_vgpu_submission *s = &vgpu->submission;
1147 const struct intel_vgpu_submission_ops *ops[] = {
1148 [INTEL_VGPU_EXECLIST_SUBMISSION] =
1149 &intel_vgpu_execlist_submission_ops,
1150 };
1151 int ret;
1152
1153 if (WARN_ON(interface >= ARRAY_SIZE(ops)))
1154 return -EINVAL;
1155
Weinan Li9212b132018-01-26 15:09:08 +08001156 if (WARN_ON(interface == 0 && engine_mask != ALL_ENGINES))
1157 return -EINVAL;
1158
1159 if (s->active)
Weinan Li7569a062018-01-26 15:09:07 +08001160 s->ops->clean(vgpu, engine_mask);
Zhi Wangad1d3632017-09-13 00:31:29 +08001161
1162 if (interface == 0) {
1163 s->ops = NULL;
1164 s->virtual_submission_interface = 0;
Weinan Li9212b132018-01-26 15:09:08 +08001165 s->active = false;
1166 gvt_dbg_core("vgpu%d: remove submission ops\n", vgpu->id);
Zhi Wangad1d3632017-09-13 00:31:29 +08001167 return 0;
1168 }
1169
Weinan Li7569a062018-01-26 15:09:07 +08001170 ret = ops[interface]->init(vgpu, engine_mask);
Zhi Wangad1d3632017-09-13 00:31:29 +08001171 if (ret)
1172 return ret;
1173
1174 s->ops = ops[interface];
1175 s->virtual_submission_interface = interface;
1176 s->active = true;
1177
1178 gvt_dbg_core("vgpu%d: activate ops [ %s ]\n",
1179 vgpu->id, s->ops->name);
1180
1181 return 0;
1182}
1183
1184/**
Zhi Wang21527a82017-09-12 21:42:09 +08001185 * intel_vgpu_destroy_workload - destroy a vGPU workload
1186 * @vgpu: a vGPU
1187 *
1188 * This function is called when destroy a vGPU workload.
1189 *
1190 */
1191void intel_vgpu_destroy_workload(struct intel_vgpu_workload *workload)
1192{
1193 struct intel_vgpu_submission *s = &workload->vgpu->submission;
1194
1195 if (workload->shadow_mm)
Changbin Du1bc25852018-01-30 19:19:41 +08001196 intel_vgpu_mm_put(workload->shadow_mm);
Zhi Wang21527a82017-09-12 21:42:09 +08001197
1198 kmem_cache_free(s->workloads, workload);
1199}
1200
Zhi Wang6d763032017-09-12 22:33:12 +08001201static struct intel_vgpu_workload *
1202alloc_workload(struct intel_vgpu *vgpu)
Zhi Wang21527a82017-09-12 21:42:09 +08001203{
1204 struct intel_vgpu_submission *s = &vgpu->submission;
1205 struct intel_vgpu_workload *workload;
1206
1207 workload = kmem_cache_zalloc(s->workloads, GFP_KERNEL);
1208 if (!workload)
1209 return ERR_PTR(-ENOMEM);
1210
1211 INIT_LIST_HEAD(&workload->list);
1212 INIT_LIST_HEAD(&workload->shadow_bb);
1213
1214 init_waitqueue_head(&workload->shadow_ctx_status_wq);
1215 atomic_set(&workload->shadow_ctx_active, 0);
1216
1217 workload->status = -EINPROGRESS;
Zhi Wang21527a82017-09-12 21:42:09 +08001218 workload->vgpu = vgpu;
1219
1220 return workload;
1221}
Zhi Wang6d763032017-09-12 22:33:12 +08001222
1223#define RING_CTX_OFF(x) \
1224 offsetof(struct execlist_ring_context, x)
1225
1226static void read_guest_pdps(struct intel_vgpu *vgpu,
1227 u64 ring_context_gpa, u32 pdp[8])
1228{
1229 u64 gpa;
1230 int i;
1231
Xinyun Liu1417fad2018-06-07 22:48:42 +08001232 gpa = ring_context_gpa + RING_CTX_OFF(pdps[0].val);
Zhi Wang6d763032017-09-12 22:33:12 +08001233
1234 for (i = 0; i < 8; i++)
1235 intel_gvt_hypervisor_read_gpa(vgpu,
1236 gpa + i * 8, &pdp[7 - i], 4);
1237}
1238
1239static int prepare_mm(struct intel_vgpu_workload *workload)
1240{
1241 struct execlist_ctx_descriptor_format *desc = &workload->ctx_desc;
1242 struct intel_vgpu_mm *mm;
1243 struct intel_vgpu *vgpu = workload->vgpu;
Changbin Duede9d0c2018-01-30 19:19:40 +08001244 intel_gvt_gtt_type_t root_entry_type;
1245 u64 pdps[GVT_RING_CTX_NR_PDPS];
Zhi Wang6d763032017-09-12 22:33:12 +08001246
Changbin Duede9d0c2018-01-30 19:19:40 +08001247 switch (desc->addressing_mode) {
1248 case 1: /* legacy 32-bit */
1249 root_entry_type = GTT_TYPE_PPGTT_ROOT_L3_ENTRY;
1250 break;
1251 case 3: /* legacy 64-bit */
1252 root_entry_type = GTT_TYPE_PPGTT_ROOT_L4_ENTRY;
1253 break;
1254 default:
Zhi Wang6d763032017-09-12 22:33:12 +08001255 gvt_vgpu_err("Advanced Context mode(SVM) is not supported!\n");
1256 return -EINVAL;
1257 }
1258
Changbin Duede9d0c2018-01-30 19:19:40 +08001259 read_guest_pdps(workload->vgpu, workload->ring_context_gpa, (void *)pdps);
Zhi Wang6d763032017-09-12 22:33:12 +08001260
Changbin Due6e9c462018-01-30 19:19:46 +08001261 mm = intel_vgpu_get_ppgtt_mm(workload->vgpu, root_entry_type, pdps);
1262 if (IS_ERR(mm))
1263 return PTR_ERR(mm);
Zhi Wang6d763032017-09-12 22:33:12 +08001264
Zhi Wang6d763032017-09-12 22:33:12 +08001265 workload->shadow_mm = mm;
1266 return 0;
1267}
1268
1269#define same_context(a, b) (((a)->context_id == (b)->context_id) && \
1270 ((a)->lrca == (b)->lrca))
1271
1272#define get_last_workload(q) \
1273 (list_empty(q) ? NULL : container_of(q->prev, \
1274 struct intel_vgpu_workload, list))
1275/**
1276 * intel_vgpu_create_workload - create a vGPU workload
1277 * @vgpu: a vGPU
1278 * @desc: a guest context descriptor
1279 *
1280 * This function is called when creating a vGPU workload.
1281 *
1282 * Returns:
1283 * struct intel_vgpu_workload * on success, negative error code in
1284 * pointer if failed.
1285 *
1286 */
1287struct intel_vgpu_workload *
1288intel_vgpu_create_workload(struct intel_vgpu *vgpu, int ring_id,
1289 struct execlist_ctx_descriptor_format *desc)
1290{
1291 struct intel_vgpu_submission *s = &vgpu->submission;
1292 struct list_head *q = workload_q_head(vgpu, ring_id);
1293 struct intel_vgpu_workload *last_workload = get_last_workload(q);
1294 struct intel_vgpu_workload *workload = NULL;
1295 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
1296 u64 ring_context_gpa;
1297 u32 head, tail, start, ctl, ctx_ctl, per_ctx, indirect_ctx;
1298 int ret;
1299
1300 ring_context_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm,
Zhi Wang9556e112017-10-10 13:51:32 +08001301 (u32)((desc->lrca + 1) << I915_GTT_PAGE_SHIFT));
Zhi Wang6d763032017-09-12 22:33:12 +08001302 if (ring_context_gpa == INTEL_GVT_INVALID_ADDR) {
1303 gvt_vgpu_err("invalid guest context LRCA: %x\n", desc->lrca);
1304 return ERR_PTR(-EINVAL);
1305 }
1306
1307 intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
1308 RING_CTX_OFF(ring_header.val), &head, 4);
1309
1310 intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
1311 RING_CTX_OFF(ring_tail.val), &tail, 4);
1312
1313 head &= RB_HEAD_OFF_MASK;
1314 tail &= RB_TAIL_OFF_MASK;
1315
1316 if (last_workload && same_context(&last_workload->ctx_desc, desc)) {
1317 gvt_dbg_el("ring id %d cur workload == last\n", ring_id);
1318 gvt_dbg_el("ctx head %x real head %lx\n", head,
1319 last_workload->rb_tail);
1320 /*
1321 * cannot use guest context head pointer here,
1322 * as it might not be updated at this time
1323 */
1324 head = last_workload->rb_tail;
1325 }
1326
1327 gvt_dbg_el("ring id %d begin a new workload\n", ring_id);
1328
1329 /* record some ring buffer register values for scan and shadow */
1330 intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
1331 RING_CTX_OFF(rb_start.val), &start, 4);
1332 intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
1333 RING_CTX_OFF(rb_ctrl.val), &ctl, 4);
1334 intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
1335 RING_CTX_OFF(ctx_ctrl.val), &ctx_ctl, 4);
1336
1337 workload = alloc_workload(vgpu);
1338 if (IS_ERR(workload))
1339 return workload;
1340
1341 workload->ring_id = ring_id;
1342 workload->ctx_desc = *desc;
1343 workload->ring_context_gpa = ring_context_gpa;
1344 workload->rb_head = head;
1345 workload->rb_tail = tail;
1346 workload->rb_start = start;
1347 workload->rb_ctl = ctl;
1348
1349 if (ring_id == RCS) {
1350 intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
1351 RING_CTX_OFF(bb_per_ctx_ptr.val), &per_ctx, 4);
1352 intel_gvt_hypervisor_read_gpa(vgpu, ring_context_gpa +
1353 RING_CTX_OFF(rcs_indirect_ctx.val), &indirect_ctx, 4);
1354
1355 workload->wa_ctx.indirect_ctx.guest_gma =
1356 indirect_ctx & INDIRECT_CTX_ADDR_MASK;
1357 workload->wa_ctx.indirect_ctx.size =
1358 (indirect_ctx & INDIRECT_CTX_SIZE_MASK) *
1359 CACHELINE_BYTES;
1360 workload->wa_ctx.per_ctx.guest_gma =
1361 per_ctx & PER_CTX_ADDR_MASK;
1362 workload->wa_ctx.per_ctx.valid = per_ctx & 1;
1363 }
1364
1365 gvt_dbg_el("workload %p ring id %d head %x tail %x start %x ctl %x\n",
1366 workload, ring_id, head, tail, start, ctl);
1367
1368 ret = prepare_mm(workload);
1369 if (ret) {
1370 kmem_cache_free(s->workloads, workload);
1371 return ERR_PTR(ret);
1372 }
1373
1374 /* Only scan and shadow the first workload in the queue
1375 * as there is only one pre-allocated buf-obj for shadow.
1376 */
1377 if (list_empty(workload_q_head(vgpu, ring_id))) {
1378 intel_runtime_pm_get(dev_priv);
1379 mutex_lock(&dev_priv->drm.struct_mutex);
1380 ret = intel_gvt_scan_and_shadow_workload(workload);
1381 mutex_unlock(&dev_priv->drm.struct_mutex);
1382 intel_runtime_pm_put(dev_priv);
1383 }
1384
1385 if (ret && (vgpu_is_vm_unhealthy(ret))) {
1386 enter_failsafe_mode(vgpu, GVT_FAILSAFE_GUEST_ERR);
1387 intel_vgpu_destroy_workload(workload);
1388 return ERR_PTR(ret);
1389 }
1390
1391 return workload;
1392}
Changbin Du59a716c2017-11-29 15:40:06 +08001393
1394/**
1395 * intel_vgpu_queue_workload - Qeue a vGPU workload
1396 * @workload: the workload to queue in
1397 */
1398void intel_vgpu_queue_workload(struct intel_vgpu_workload *workload)
1399{
1400 list_add_tail(&workload->list,
1401 workload_q_head(workload->vgpu, workload->ring_id));
Changbin Duc1304562017-11-29 15:40:07 +08001402 intel_gvt_kick_schedule(workload->vgpu->gvt);
Changbin Du59a716c2017-11-29 15:40:06 +08001403 wake_up(&workload->vgpu->gvt->scheduler.waitq[workload->ring_id]);
1404}