xref: /openbsd-src/sys/dev/pci/drm/i915/gvt/scheduler.c (revision f005ef32267c16bdb134f0e9fa4477dbe07c263a)
1c349dbc7Sjsg /*
2c349dbc7Sjsg  * Copyright(c) 2011-2016 Intel Corporation. All rights reserved.
3c349dbc7Sjsg  *
4c349dbc7Sjsg  * Permission is hereby granted, free of charge, to any person obtaining a
5c349dbc7Sjsg  * copy of this software and associated documentation files (the "Software"),
6c349dbc7Sjsg  * to deal in the Software without restriction, including without limitation
7c349dbc7Sjsg  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c349dbc7Sjsg  * and/or sell copies of the Software, and to permit persons to whom the
9c349dbc7Sjsg  * Software is furnished to do so, subject to the following conditions:
10c349dbc7Sjsg  *
11c349dbc7Sjsg  * The above copyright notice and this permission notice (including the next
12c349dbc7Sjsg  * paragraph) shall be included in all copies or substantial portions of the
13c349dbc7Sjsg  * Software.
14c349dbc7Sjsg  *
15c349dbc7Sjsg  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16c349dbc7Sjsg  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17c349dbc7Sjsg  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18c349dbc7Sjsg  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19c349dbc7Sjsg  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20c349dbc7Sjsg  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21c349dbc7Sjsg  * SOFTWARE.
22c349dbc7Sjsg  *
23c349dbc7Sjsg  * Authors:
24c349dbc7Sjsg  *    Zhi Wang <zhi.a.wang@intel.com>
25c349dbc7Sjsg  *
26c349dbc7Sjsg  * Contributors:
27c349dbc7Sjsg  *    Ping Gao <ping.a.gao@intel.com>
28c349dbc7Sjsg  *    Tina Zhang <tina.zhang@intel.com>
29c349dbc7Sjsg  *    Chanbin Du <changbin.du@intel.com>
30c349dbc7Sjsg  *    Min He <min.he@intel.com>
31c349dbc7Sjsg  *    Bing Niu <bing.niu@intel.com>
32c349dbc7Sjsg  *    Zhenyu Wang <zhenyuw@linux.intel.com>
33c349dbc7Sjsg  *
34c349dbc7Sjsg  */
35c349dbc7Sjsg 
36c349dbc7Sjsg #include <linux/kthread.h>
37c349dbc7Sjsg 
38c349dbc7Sjsg #include "gem/i915_gem_pm.h"
39c349dbc7Sjsg #include "gt/intel_context.h"
405ca02815Sjsg #include "gt/intel_execlists_submission.h"
411bb76ff1Sjsg #include "gt/intel_gt_regs.h"
425ca02815Sjsg #include "gt/intel_lrc.h"
43c349dbc7Sjsg #include "gt/intel_ring.h"
44c349dbc7Sjsg 
45c349dbc7Sjsg #include "i915_drv.h"
46c349dbc7Sjsg #include "i915_gem_gtt.h"
471bb76ff1Sjsg #include "i915_perf_oa_regs.h"
48c349dbc7Sjsg #include "gvt.h"
49c349dbc7Sjsg 
50c349dbc7Sjsg #define RING_CTX_OFF(x) \
51c349dbc7Sjsg 	offsetof(struct execlist_ring_context, x)
52c349dbc7Sjsg 
set_context_pdp_root_pointer(struct execlist_ring_context * ring_context,u32 pdp[8])53c349dbc7Sjsg static void set_context_pdp_root_pointer(
54c349dbc7Sjsg 		struct execlist_ring_context *ring_context,
55c349dbc7Sjsg 		u32 pdp[8])
56c349dbc7Sjsg {
57c349dbc7Sjsg 	int i;
58c349dbc7Sjsg 
59c349dbc7Sjsg 	for (i = 0; i < 8; i++)
60c349dbc7Sjsg 		ring_context->pdps[i].val = pdp[7 - i];
61c349dbc7Sjsg }
62c349dbc7Sjsg 
update_shadow_pdps(struct intel_vgpu_workload * workload)63c349dbc7Sjsg static void update_shadow_pdps(struct intel_vgpu_workload *workload)
64c349dbc7Sjsg {
65c349dbc7Sjsg 	struct execlist_ring_context *shadow_ring_context;
66ad8b1aafSjsg 	struct intel_context *ctx = workload->req->context;
67c349dbc7Sjsg 
68c349dbc7Sjsg 	if (WARN_ON(!workload->shadow_mm))
69c349dbc7Sjsg 		return;
70c349dbc7Sjsg 
71c349dbc7Sjsg 	if (WARN_ON(!atomic_read(&workload->shadow_mm->pincount)))
72c349dbc7Sjsg 		return;
73c349dbc7Sjsg 
74ad8b1aafSjsg 	shadow_ring_context = (struct execlist_ring_context *)ctx->lrc_reg_state;
75c349dbc7Sjsg 	set_context_pdp_root_pointer(shadow_ring_context,
76c349dbc7Sjsg 			(void *)workload->shadow_mm->ppgtt_mm.shadow_pdps);
77c349dbc7Sjsg }
78c349dbc7Sjsg 
79c349dbc7Sjsg /*
80c349dbc7Sjsg  * when populating shadow ctx from guest, we should not overrride oa related
81c349dbc7Sjsg  * registers, so that they will not be overlapped by guest oa configs. Thus
82c349dbc7Sjsg  * made it possible to capture oa data from host for both host and guests.
83c349dbc7Sjsg  */
sr_oa_regs(struct intel_vgpu_workload * workload,u32 * reg_state,bool save)84c349dbc7Sjsg static void sr_oa_regs(struct intel_vgpu_workload *workload,
85c349dbc7Sjsg 		u32 *reg_state, bool save)
86c349dbc7Sjsg {
87c349dbc7Sjsg 	struct drm_i915_private *dev_priv = workload->vgpu->gvt->gt->i915;
88c349dbc7Sjsg 	u32 ctx_oactxctrl = dev_priv->perf.ctx_oactxctrl_offset;
89c349dbc7Sjsg 	u32 ctx_flexeu0 = dev_priv->perf.ctx_flexeu0_offset;
90c349dbc7Sjsg 	int i = 0;
91c349dbc7Sjsg 	u32 flex_mmio[] = {
92c349dbc7Sjsg 		i915_mmio_reg_offset(EU_PERF_CNTL0),
93c349dbc7Sjsg 		i915_mmio_reg_offset(EU_PERF_CNTL1),
94c349dbc7Sjsg 		i915_mmio_reg_offset(EU_PERF_CNTL2),
95c349dbc7Sjsg 		i915_mmio_reg_offset(EU_PERF_CNTL3),
96c349dbc7Sjsg 		i915_mmio_reg_offset(EU_PERF_CNTL4),
97c349dbc7Sjsg 		i915_mmio_reg_offset(EU_PERF_CNTL5),
98c349dbc7Sjsg 		i915_mmio_reg_offset(EU_PERF_CNTL6),
99c349dbc7Sjsg 	};
100c349dbc7Sjsg 
101c349dbc7Sjsg 	if (workload->engine->id != RCS0)
102c349dbc7Sjsg 		return;
103c349dbc7Sjsg 
104c349dbc7Sjsg 	if (save) {
105c349dbc7Sjsg 		workload->oactxctrl = reg_state[ctx_oactxctrl + 1];
106c349dbc7Sjsg 
107c349dbc7Sjsg 		for (i = 0; i < ARRAY_SIZE(workload->flex_mmio); i++) {
108c349dbc7Sjsg 			u32 state_offset = ctx_flexeu0 + i * 2;
109c349dbc7Sjsg 
110c349dbc7Sjsg 			workload->flex_mmio[i] = reg_state[state_offset + 1];
111c349dbc7Sjsg 		}
112c349dbc7Sjsg 	} else {
113c349dbc7Sjsg 		reg_state[ctx_oactxctrl] =
114c349dbc7Sjsg 			i915_mmio_reg_offset(GEN8_OACTXCONTROL);
115c349dbc7Sjsg 		reg_state[ctx_oactxctrl + 1] = workload->oactxctrl;
116c349dbc7Sjsg 
117c349dbc7Sjsg 		for (i = 0; i < ARRAY_SIZE(workload->flex_mmio); i++) {
118c349dbc7Sjsg 			u32 state_offset = ctx_flexeu0 + i * 2;
119c349dbc7Sjsg 			u32 mmio = flex_mmio[i];
120c349dbc7Sjsg 
121c349dbc7Sjsg 			reg_state[state_offset] = mmio;
122c349dbc7Sjsg 			reg_state[state_offset + 1] = workload->flex_mmio[i];
123c349dbc7Sjsg 		}
124c349dbc7Sjsg 	}
125c349dbc7Sjsg }
126c349dbc7Sjsg 
populate_shadow_context(struct intel_vgpu_workload * workload)127c349dbc7Sjsg static int populate_shadow_context(struct intel_vgpu_workload *workload)
128c349dbc7Sjsg {
129c349dbc7Sjsg 	struct intel_vgpu *vgpu = workload->vgpu;
130c349dbc7Sjsg 	struct intel_gvt *gvt = vgpu->gvt;
131ad8b1aafSjsg 	struct intel_context *ctx = workload->req->context;
132c349dbc7Sjsg 	struct execlist_ring_context *shadow_ring_context;
133c349dbc7Sjsg 	void *dst;
134ad8b1aafSjsg 	void *context_base;
135c349dbc7Sjsg 	unsigned long context_gpa, context_page_num;
136ad8b1aafSjsg 	unsigned long gpa_base; /* first gpa of consecutive GPAs */
137ad8b1aafSjsg 	unsigned long gpa_size; /* size of consecutive GPAs */
138ad8b1aafSjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
139c349dbc7Sjsg 	int i;
140ad8b1aafSjsg 	bool skip = false;
141ad8b1aafSjsg 	int ring_id = workload->engine->id;
1425ca02815Sjsg 	int ret;
143c349dbc7Sjsg 
144ad8b1aafSjsg 	GEM_BUG_ON(!intel_context_is_pinned(ctx));
145ad8b1aafSjsg 
146ad8b1aafSjsg 	context_base = (void *) ctx->lrc_reg_state -
147ad8b1aafSjsg 				(LRC_STATE_PN << I915_GTT_PAGE_SHIFT);
148ad8b1aafSjsg 
149ad8b1aafSjsg 	shadow_ring_context = (void *) ctx->lrc_reg_state;
150c349dbc7Sjsg 
151c349dbc7Sjsg 	sr_oa_regs(workload, (u32 *)shadow_ring_context, true);
152c349dbc7Sjsg #define COPY_REG(name) \
1531bb76ff1Sjsg 	intel_gvt_read_gpa(vgpu, workload->ring_context_gpa \
154c349dbc7Sjsg 		+ RING_CTX_OFF(name.val), &shadow_ring_context->name.val, 4)
155c349dbc7Sjsg #define COPY_REG_MASKED(name) {\
1561bb76ff1Sjsg 		intel_gvt_read_gpa(vgpu, workload->ring_context_gpa \
157c349dbc7Sjsg 					      + RING_CTX_OFF(name.val),\
158c349dbc7Sjsg 					      &shadow_ring_context->name.val, 4);\
159c349dbc7Sjsg 		shadow_ring_context->name.val |= 0xffff << 16;\
160c349dbc7Sjsg 	}
161c349dbc7Sjsg 
162c349dbc7Sjsg 	COPY_REG_MASKED(ctx_ctrl);
163c349dbc7Sjsg 	COPY_REG(ctx_timestamp);
164c349dbc7Sjsg 
165c349dbc7Sjsg 	if (workload->engine->id == RCS0) {
166c349dbc7Sjsg 		COPY_REG(bb_per_ctx_ptr);
167c349dbc7Sjsg 		COPY_REG(rcs_indirect_ctx);
168c349dbc7Sjsg 		COPY_REG(rcs_indirect_ctx_offset);
1695ca02815Sjsg 	} else if (workload->engine->id == BCS0)
1701bb76ff1Sjsg 		intel_gvt_read_gpa(vgpu,
1715ca02815Sjsg 				workload->ring_context_gpa +
1725ca02815Sjsg 				BCS_TILE_REGISTER_VAL_OFFSET,
1735ca02815Sjsg 				(void *)shadow_ring_context +
1745ca02815Sjsg 				BCS_TILE_REGISTER_VAL_OFFSET, 4);
175c349dbc7Sjsg #undef COPY_REG
176c349dbc7Sjsg #undef COPY_REG_MASKED
177c349dbc7Sjsg 
1785ca02815Sjsg 	/* don't copy Ring Context (the first 0x50 dwords),
1795ca02815Sjsg 	 * only copy the Engine Context part from guest
1805ca02815Sjsg 	 */
1811bb76ff1Sjsg 	intel_gvt_read_gpa(vgpu,
182c349dbc7Sjsg 			workload->ring_context_gpa +
1835ca02815Sjsg 			RING_CTX_SIZE,
184c349dbc7Sjsg 			(void *)shadow_ring_context +
1855ca02815Sjsg 			RING_CTX_SIZE,
1865ca02815Sjsg 			I915_GTT_PAGE_SIZE - RING_CTX_SIZE);
187c349dbc7Sjsg 
188c349dbc7Sjsg 	sr_oa_regs(workload, (u32 *)shadow_ring_context, false);
189c349dbc7Sjsg 
190ad8b1aafSjsg 	gvt_dbg_sched("ring %s workload lrca %x, ctx_id %x, ctx gpa %llx",
191ad8b1aafSjsg 			workload->engine->name, workload->ctx_desc.lrca,
192ad8b1aafSjsg 			workload->ctx_desc.context_id,
193ad8b1aafSjsg 			workload->ring_context_gpa);
194ad8b1aafSjsg 
195ad8b1aafSjsg 	/* only need to ensure this context is not pinned/unpinned during the
196ad8b1aafSjsg 	 * period from last submission to this this submission.
197ad8b1aafSjsg 	 * Upon reaching this function, the currently submitted context is not
198ad8b1aafSjsg 	 * supposed to get unpinned. If a misbehaving guest driver ever does
199ad8b1aafSjsg 	 * this, it would corrupt itself.
200ad8b1aafSjsg 	 */
201ad8b1aafSjsg 	if (s->last_ctx[ring_id].valid &&
202ad8b1aafSjsg 			(s->last_ctx[ring_id].lrca ==
203ad8b1aafSjsg 				workload->ctx_desc.lrca) &&
204ad8b1aafSjsg 			(s->last_ctx[ring_id].ring_context_gpa ==
205ad8b1aafSjsg 				workload->ring_context_gpa))
206ad8b1aafSjsg 		skip = true;
207ad8b1aafSjsg 
208ad8b1aafSjsg 	s->last_ctx[ring_id].lrca = workload->ctx_desc.lrca;
209ad8b1aafSjsg 	s->last_ctx[ring_id].ring_context_gpa = workload->ring_context_gpa;
210ad8b1aafSjsg 
211ad8b1aafSjsg 	if (IS_RESTORE_INHIBIT(shadow_ring_context->ctx_ctrl.val) || skip)
212c349dbc7Sjsg 		return 0;
213c349dbc7Sjsg 
214ad8b1aafSjsg 	s->last_ctx[ring_id].valid = false;
215c349dbc7Sjsg 	context_page_num = workload->engine->context_size;
216c349dbc7Sjsg 	context_page_num = context_page_num >> PAGE_SHIFT;
217c349dbc7Sjsg 
218c349dbc7Sjsg 	if (IS_BROADWELL(gvt->gt->i915) && workload->engine->id == RCS0)
219c349dbc7Sjsg 		context_page_num = 19;
220c349dbc7Sjsg 
221ad8b1aafSjsg 	/* find consecutive GPAs from gma until the first inconsecutive GPA.
222ad8b1aafSjsg 	 * read from the continuous GPAs into dst virtual address
223ad8b1aafSjsg 	 */
224ad8b1aafSjsg 	gpa_size = 0;
225ad8b1aafSjsg 	for (i = 2; i < context_page_num; i++) {
226c349dbc7Sjsg 		context_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm,
227c349dbc7Sjsg 				(u32)((workload->ctx_desc.lrca + i) <<
228c349dbc7Sjsg 				I915_GTT_PAGE_SHIFT));
229c349dbc7Sjsg 		if (context_gpa == INTEL_GVT_INVALID_ADDR) {
230c349dbc7Sjsg 			gvt_vgpu_err("Invalid guest context descriptor\n");
231c349dbc7Sjsg 			return -EFAULT;
232c349dbc7Sjsg 		}
233c349dbc7Sjsg 
234ad8b1aafSjsg 		if (gpa_size == 0) {
235ad8b1aafSjsg 			gpa_base = context_gpa;
236ad8b1aafSjsg 			dst = context_base + (i << I915_GTT_PAGE_SHIFT);
237ad8b1aafSjsg 		} else if (context_gpa != gpa_base + gpa_size)
238ad8b1aafSjsg 			goto read;
239ad8b1aafSjsg 
240ad8b1aafSjsg 		gpa_size += I915_GTT_PAGE_SIZE;
241ad8b1aafSjsg 
242ad8b1aafSjsg 		if (i == context_page_num - 1)
243ad8b1aafSjsg 			goto read;
244ad8b1aafSjsg 
245ad8b1aafSjsg 		continue;
246ad8b1aafSjsg 
247ad8b1aafSjsg read:
2481bb76ff1Sjsg 		intel_gvt_read_gpa(vgpu, gpa_base, dst, gpa_size);
249ad8b1aafSjsg 		gpa_base = context_gpa;
250ad8b1aafSjsg 		gpa_size = I915_GTT_PAGE_SIZE;
251ad8b1aafSjsg 		dst = context_base + (i << I915_GTT_PAGE_SHIFT);
252c349dbc7Sjsg 	}
2535ca02815Sjsg 	ret = intel_gvt_scan_engine_context(workload);
2545ca02815Sjsg 	if (ret) {
2555ca02815Sjsg 		gvt_vgpu_err("invalid cmd found in guest context pages\n");
2565ca02815Sjsg 		return ret;
2575ca02815Sjsg 	}
258ad8b1aafSjsg 	s->last_ctx[ring_id].valid = true;
259c349dbc7Sjsg 	return 0;
260c349dbc7Sjsg }
261c349dbc7Sjsg 
is_gvt_request(struct i915_request * rq)262c349dbc7Sjsg static inline bool is_gvt_request(struct i915_request *rq)
263c349dbc7Sjsg {
264c349dbc7Sjsg 	return intel_context_force_single_submission(rq->context);
265c349dbc7Sjsg }
266c349dbc7Sjsg 
save_ring_hw_state(struct intel_vgpu * vgpu,const struct intel_engine_cs * engine)267c349dbc7Sjsg static void save_ring_hw_state(struct intel_vgpu *vgpu,
268c349dbc7Sjsg 			       const struct intel_engine_cs *engine)
269c349dbc7Sjsg {
270c349dbc7Sjsg 	struct intel_uncore *uncore = engine->uncore;
271c349dbc7Sjsg 	i915_reg_t reg;
272c349dbc7Sjsg 
273c349dbc7Sjsg 	reg = RING_INSTDONE(engine->mmio_base);
274c349dbc7Sjsg 	vgpu_vreg(vgpu, i915_mmio_reg_offset(reg)) =
275c349dbc7Sjsg 		intel_uncore_read(uncore, reg);
276c349dbc7Sjsg 
277c349dbc7Sjsg 	reg = RING_ACTHD(engine->mmio_base);
278c349dbc7Sjsg 	vgpu_vreg(vgpu, i915_mmio_reg_offset(reg)) =
279c349dbc7Sjsg 		intel_uncore_read(uncore, reg);
280c349dbc7Sjsg 
281c349dbc7Sjsg 	reg = RING_ACTHD_UDW(engine->mmio_base);
282c349dbc7Sjsg 	vgpu_vreg(vgpu, i915_mmio_reg_offset(reg)) =
283c349dbc7Sjsg 		intel_uncore_read(uncore, reg);
284c349dbc7Sjsg }
285c349dbc7Sjsg 
shadow_context_status_change(struct notifier_block * nb,unsigned long action,void * data)286c349dbc7Sjsg static int shadow_context_status_change(struct notifier_block *nb,
287c349dbc7Sjsg 		unsigned long action, void *data)
288c349dbc7Sjsg {
289c349dbc7Sjsg 	struct i915_request *rq = data;
290c349dbc7Sjsg 	struct intel_gvt *gvt = container_of(nb, struct intel_gvt,
291c349dbc7Sjsg 				shadow_ctx_notifier_block[rq->engine->id]);
292c349dbc7Sjsg 	struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
293c349dbc7Sjsg 	enum intel_engine_id ring_id = rq->engine->id;
294c349dbc7Sjsg 	struct intel_vgpu_workload *workload;
295c349dbc7Sjsg 	unsigned long flags;
296c349dbc7Sjsg 
297c349dbc7Sjsg 	if (!is_gvt_request(rq)) {
298c349dbc7Sjsg 		spin_lock_irqsave(&scheduler->mmio_context_lock, flags);
299c349dbc7Sjsg 		if (action == INTEL_CONTEXT_SCHEDULE_IN &&
300c349dbc7Sjsg 		    scheduler->engine_owner[ring_id]) {
301c349dbc7Sjsg 			/* Switch ring from vGPU to host. */
302c349dbc7Sjsg 			intel_gvt_switch_mmio(scheduler->engine_owner[ring_id],
303c349dbc7Sjsg 					      NULL, rq->engine);
304c349dbc7Sjsg 			scheduler->engine_owner[ring_id] = NULL;
305c349dbc7Sjsg 		}
306c349dbc7Sjsg 		spin_unlock_irqrestore(&scheduler->mmio_context_lock, flags);
307c349dbc7Sjsg 
308c349dbc7Sjsg 		return NOTIFY_OK;
309c349dbc7Sjsg 	}
310c349dbc7Sjsg 
311c349dbc7Sjsg 	workload = scheduler->current_workload[ring_id];
312c349dbc7Sjsg 	if (unlikely(!workload))
313c349dbc7Sjsg 		return NOTIFY_OK;
314c349dbc7Sjsg 
315c349dbc7Sjsg 	switch (action) {
316c349dbc7Sjsg 	case INTEL_CONTEXT_SCHEDULE_IN:
317c349dbc7Sjsg 		spin_lock_irqsave(&scheduler->mmio_context_lock, flags);
318c349dbc7Sjsg 		if (workload->vgpu != scheduler->engine_owner[ring_id]) {
319c349dbc7Sjsg 			/* Switch ring from host to vGPU or vGPU to vGPU. */
320c349dbc7Sjsg 			intel_gvt_switch_mmio(scheduler->engine_owner[ring_id],
321c349dbc7Sjsg 					      workload->vgpu, rq->engine);
322c349dbc7Sjsg 			scheduler->engine_owner[ring_id] = workload->vgpu;
323c349dbc7Sjsg 		} else
324c349dbc7Sjsg 			gvt_dbg_sched("skip ring %d mmio switch for vgpu%d\n",
325c349dbc7Sjsg 				      ring_id, workload->vgpu->id);
326c349dbc7Sjsg 		spin_unlock_irqrestore(&scheduler->mmio_context_lock, flags);
327c349dbc7Sjsg 		atomic_set(&workload->shadow_ctx_active, 1);
328c349dbc7Sjsg 		break;
329c349dbc7Sjsg 	case INTEL_CONTEXT_SCHEDULE_OUT:
330c349dbc7Sjsg 		save_ring_hw_state(workload->vgpu, rq->engine);
331c349dbc7Sjsg 		atomic_set(&workload->shadow_ctx_active, 0);
332c349dbc7Sjsg 		break;
333c349dbc7Sjsg 	case INTEL_CONTEXT_SCHEDULE_PREEMPTED:
334c349dbc7Sjsg 		save_ring_hw_state(workload->vgpu, rq->engine);
335c349dbc7Sjsg 		break;
336c349dbc7Sjsg 	default:
337c349dbc7Sjsg 		WARN_ON(1);
338c349dbc7Sjsg 		return NOTIFY_OK;
339c349dbc7Sjsg 	}
340c349dbc7Sjsg 	wake_up(&workload->shadow_ctx_status_wq);
341c349dbc7Sjsg 	return NOTIFY_OK;
342c349dbc7Sjsg }
343c349dbc7Sjsg 
344c349dbc7Sjsg static void
shadow_context_descriptor_update(struct intel_context * ce,struct intel_vgpu_workload * workload)345c349dbc7Sjsg shadow_context_descriptor_update(struct intel_context *ce,
346c349dbc7Sjsg 				 struct intel_vgpu_workload *workload)
347c349dbc7Sjsg {
348c349dbc7Sjsg 	u64 desc = ce->lrc.desc;
349c349dbc7Sjsg 
350c349dbc7Sjsg 	/*
351c349dbc7Sjsg 	 * Update bits 0-11 of the context descriptor which includes flags
352c349dbc7Sjsg 	 * like GEN8_CTX_* cached in desc_template
353c349dbc7Sjsg 	 */
354c349dbc7Sjsg 	desc &= ~(0x3ull << GEN8_CTX_ADDRESSING_MODE_SHIFT);
355c349dbc7Sjsg 	desc |= (u64)workload->ctx_desc.addressing_mode <<
356c349dbc7Sjsg 		GEN8_CTX_ADDRESSING_MODE_SHIFT;
357c349dbc7Sjsg 
358c349dbc7Sjsg 	ce->lrc.desc = desc;
359c349dbc7Sjsg }
360c349dbc7Sjsg 
copy_workload_to_ring_buffer(struct intel_vgpu_workload * workload)361c349dbc7Sjsg static int copy_workload_to_ring_buffer(struct intel_vgpu_workload *workload)
362c349dbc7Sjsg {
363c349dbc7Sjsg 	struct intel_vgpu *vgpu = workload->vgpu;
364c349dbc7Sjsg 	struct i915_request *req = workload->req;
365c349dbc7Sjsg 	void *shadow_ring_buffer_va;
366c349dbc7Sjsg 	u32 *cs;
367c349dbc7Sjsg 	int err;
368c349dbc7Sjsg 
3695ca02815Sjsg 	if (GRAPHICS_VER(req->engine->i915) == 9 && is_inhibit_context(req->context))
370c349dbc7Sjsg 		intel_vgpu_restore_inhibit_context(vgpu, req);
371c349dbc7Sjsg 
372c349dbc7Sjsg 	/*
373c349dbc7Sjsg 	 * To track whether a request has started on HW, we can emit a
374c349dbc7Sjsg 	 * breadcrumb at the beginning of the request and check its
375c349dbc7Sjsg 	 * timeline's HWSP to see if the breadcrumb has advanced past the
376c349dbc7Sjsg 	 * start of this request. Actually, the request must have the
377c349dbc7Sjsg 	 * init_breadcrumb if its timeline set has_init_bread_crumb, or the
378c349dbc7Sjsg 	 * scheduler might get a wrong state of it during reset. Since the
379c349dbc7Sjsg 	 * requests from gvt always set the has_init_breadcrumb flag, here
380c349dbc7Sjsg 	 * need to do the emit_init_breadcrumb for all the requests.
381c349dbc7Sjsg 	 */
382c349dbc7Sjsg 	if (req->engine->emit_init_breadcrumb) {
383c349dbc7Sjsg 		err = req->engine->emit_init_breadcrumb(req);
384c349dbc7Sjsg 		if (err) {
385c349dbc7Sjsg 			gvt_vgpu_err("fail to emit init breadcrumb\n");
386c349dbc7Sjsg 			return err;
387c349dbc7Sjsg 		}
388c349dbc7Sjsg 	}
389c349dbc7Sjsg 
390c349dbc7Sjsg 	/* allocate shadow ring buffer */
391c349dbc7Sjsg 	cs = intel_ring_begin(workload->req, workload->rb_len / sizeof(u32));
392c349dbc7Sjsg 	if (IS_ERR(cs)) {
393c349dbc7Sjsg 		gvt_vgpu_err("fail to alloc size =%ld shadow  ring buffer\n",
394c349dbc7Sjsg 			workload->rb_len);
395c349dbc7Sjsg 		return PTR_ERR(cs);
396c349dbc7Sjsg 	}
397c349dbc7Sjsg 
398c349dbc7Sjsg 	shadow_ring_buffer_va = workload->shadow_ring_buffer_va;
399c349dbc7Sjsg 
400c349dbc7Sjsg 	/* get shadow ring buffer va */
401c349dbc7Sjsg 	workload->shadow_ring_buffer_va = cs;
402c349dbc7Sjsg 
403c349dbc7Sjsg 	memcpy(cs, shadow_ring_buffer_va,
404c349dbc7Sjsg 			workload->rb_len);
405c349dbc7Sjsg 
406c349dbc7Sjsg 	cs += workload->rb_len / sizeof(u32);
407c349dbc7Sjsg 	intel_ring_advance(workload->req, cs);
408c349dbc7Sjsg 
409c349dbc7Sjsg 	return 0;
410c349dbc7Sjsg }
411c349dbc7Sjsg 
release_shadow_wa_ctx(struct intel_shadow_wa_ctx * wa_ctx)412c349dbc7Sjsg static void release_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
413c349dbc7Sjsg {
414c349dbc7Sjsg 	if (!wa_ctx->indirect_ctx.obj)
415c349dbc7Sjsg 		return;
416c349dbc7Sjsg 
4175ca02815Sjsg 	i915_gem_object_lock(wa_ctx->indirect_ctx.obj, NULL);
418c349dbc7Sjsg 	i915_gem_object_unpin_map(wa_ctx->indirect_ctx.obj);
4195ca02815Sjsg 	i915_gem_object_unlock(wa_ctx->indirect_ctx.obj);
420c349dbc7Sjsg 	i915_gem_object_put(wa_ctx->indirect_ctx.obj);
421c349dbc7Sjsg 
422c349dbc7Sjsg 	wa_ctx->indirect_ctx.obj = NULL;
423c349dbc7Sjsg 	wa_ctx->indirect_ctx.shadow_va = NULL;
424c349dbc7Sjsg }
425c349dbc7Sjsg 
set_dma_address(struct i915_page_directory * pd,dma_addr_t addr)426ad8b1aafSjsg static void set_dma_address(struct i915_page_directory *pd, dma_addr_t addr)
427ad8b1aafSjsg {
428ad8b1aafSjsg 	struct scatterlist *sg = pd->pt.base->mm.pages->sgl;
429ad8b1aafSjsg 
430ad8b1aafSjsg 	/* This is not a good idea */
431ad8b1aafSjsg 	sg->dma_address = addr;
432ad8b1aafSjsg }
433ad8b1aafSjsg 
set_context_ppgtt_from_shadow(struct intel_vgpu_workload * workload,struct intel_context * ce)434c349dbc7Sjsg static void set_context_ppgtt_from_shadow(struct intel_vgpu_workload *workload,
435c349dbc7Sjsg 					  struct intel_context *ce)
436c349dbc7Sjsg {
437c349dbc7Sjsg 	struct intel_vgpu_mm *mm = workload->shadow_mm;
438c349dbc7Sjsg 	struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(ce->vm);
439c349dbc7Sjsg 	int i = 0;
440c349dbc7Sjsg 
441c349dbc7Sjsg 	if (mm->ppgtt_mm.root_entry_type == GTT_TYPE_PPGTT_ROOT_L4_ENTRY) {
442ad8b1aafSjsg 		set_dma_address(ppgtt->pd, mm->ppgtt_mm.shadow_pdps[0]);
443c349dbc7Sjsg 	} else {
444c349dbc7Sjsg 		for (i = 0; i < GVT_RING_CTX_NR_PDPS; i++) {
445c349dbc7Sjsg 			struct i915_page_directory * const pd =
446c349dbc7Sjsg 				i915_pd_entry(ppgtt->pd, i);
447c349dbc7Sjsg 			/* skip now as current i915 ppgtt alloc won't allocate
448c349dbc7Sjsg 			   top level pdp for non 4-level table, won't impact
449c349dbc7Sjsg 			   shadow ppgtt. */
450c349dbc7Sjsg 			if (!pd)
451c349dbc7Sjsg 				break;
452ad8b1aafSjsg 
453ad8b1aafSjsg 			set_dma_address(pd, mm->ppgtt_mm.shadow_pdps[i]);
454c349dbc7Sjsg 		}
455c349dbc7Sjsg 	}
456c349dbc7Sjsg }
457c349dbc7Sjsg 
458c349dbc7Sjsg static int
intel_gvt_workload_req_alloc(struct intel_vgpu_workload * workload)459c349dbc7Sjsg intel_gvt_workload_req_alloc(struct intel_vgpu_workload *workload)
460c349dbc7Sjsg {
461c349dbc7Sjsg 	struct intel_vgpu *vgpu = workload->vgpu;
462c349dbc7Sjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
463c349dbc7Sjsg 	struct i915_request *rq;
464c349dbc7Sjsg 
465c349dbc7Sjsg 	if (workload->req)
466c349dbc7Sjsg 		return 0;
467c349dbc7Sjsg 
468c349dbc7Sjsg 	rq = i915_request_create(s->shadow[workload->engine->id]);
469c349dbc7Sjsg 	if (IS_ERR(rq)) {
470c349dbc7Sjsg 		gvt_vgpu_err("fail to allocate gem request\n");
471c349dbc7Sjsg 		return PTR_ERR(rq);
472c349dbc7Sjsg 	}
473c349dbc7Sjsg 
474c349dbc7Sjsg 	workload->req = i915_request_get(rq);
475c349dbc7Sjsg 	return 0;
476c349dbc7Sjsg }
477c349dbc7Sjsg 
478c349dbc7Sjsg /**
479c349dbc7Sjsg  * intel_gvt_scan_and_shadow_workload - audit the workload by scanning and
480c349dbc7Sjsg  * shadow it as well, include ringbuffer,wa_ctx and ctx.
481c349dbc7Sjsg  * @workload: an abstract entity for each execlist submission.
482c349dbc7Sjsg  *
483c349dbc7Sjsg  * This function is called before the workload submitting to i915, to make
484c349dbc7Sjsg  * sure the content of the workload is valid.
485c349dbc7Sjsg  */
intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload * workload)486c349dbc7Sjsg int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload)
487c349dbc7Sjsg {
488c349dbc7Sjsg 	struct intel_vgpu *vgpu = workload->vgpu;
489c349dbc7Sjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
490c349dbc7Sjsg 	int ret;
491c349dbc7Sjsg 
492c349dbc7Sjsg 	lockdep_assert_held(&vgpu->vgpu_lock);
493c349dbc7Sjsg 
494c349dbc7Sjsg 	if (workload->shadow)
495c349dbc7Sjsg 		return 0;
496c349dbc7Sjsg 
497c349dbc7Sjsg 	if (!test_and_set_bit(workload->engine->id, s->shadow_ctx_desc_updated))
498c349dbc7Sjsg 		shadow_context_descriptor_update(s->shadow[workload->engine->id],
499c349dbc7Sjsg 						 workload);
500c349dbc7Sjsg 
501c349dbc7Sjsg 	ret = intel_gvt_scan_and_shadow_ringbuffer(workload);
502c349dbc7Sjsg 	if (ret)
503c349dbc7Sjsg 		return ret;
504c349dbc7Sjsg 
505c349dbc7Sjsg 	if (workload->engine->id == RCS0 &&
506c349dbc7Sjsg 	    workload->wa_ctx.indirect_ctx.size) {
507c349dbc7Sjsg 		ret = intel_gvt_scan_and_shadow_wa_ctx(&workload->wa_ctx);
508c349dbc7Sjsg 		if (ret)
509c349dbc7Sjsg 			goto err_shadow;
510c349dbc7Sjsg 	}
511c349dbc7Sjsg 
512c349dbc7Sjsg 	workload->shadow = true;
513c349dbc7Sjsg 	return 0;
514c349dbc7Sjsg 
515c349dbc7Sjsg err_shadow:
516c349dbc7Sjsg 	release_shadow_wa_ctx(&workload->wa_ctx);
517c349dbc7Sjsg 	return ret;
518c349dbc7Sjsg }
519c349dbc7Sjsg 
520c349dbc7Sjsg static void release_shadow_batch_buffer(struct intel_vgpu_workload *workload);
521c349dbc7Sjsg 
prepare_shadow_batch_buffer(struct intel_vgpu_workload * workload)522c349dbc7Sjsg static int prepare_shadow_batch_buffer(struct intel_vgpu_workload *workload)
523c349dbc7Sjsg {
524c349dbc7Sjsg 	struct intel_gvt *gvt = workload->vgpu->gvt;
525c349dbc7Sjsg 	const int gmadr_bytes = gvt->device_info.gmadr_bytes_in_cmd;
526c349dbc7Sjsg 	struct intel_vgpu_shadow_bb *bb;
5275ca02815Sjsg 	struct i915_gem_ww_ctx ww;
528c349dbc7Sjsg 	int ret;
529c349dbc7Sjsg 
530c349dbc7Sjsg 	list_for_each_entry(bb, &workload->shadow_bb, list) {
531c349dbc7Sjsg 		/* For privilge batch buffer and not wa_ctx, the bb_start_cmd_va
532c349dbc7Sjsg 		 * is only updated into ring_scan_buffer, not real ring address
533c349dbc7Sjsg 		 * allocated in later copy_workload_to_ring_buffer. pls be noted
534c349dbc7Sjsg 		 * shadow_ring_buffer_va is now pointed to real ring buffer va
535c349dbc7Sjsg 		 * in copy_workload_to_ring_buffer.
536c349dbc7Sjsg 		 */
537c349dbc7Sjsg 
538c349dbc7Sjsg 		if (bb->bb_offset)
539c349dbc7Sjsg 			bb->bb_start_cmd_va = workload->shadow_ring_buffer_va
540c349dbc7Sjsg 				+ bb->bb_offset;
541c349dbc7Sjsg 
542ad8b1aafSjsg 		/*
543ad8b1aafSjsg 		 * For non-priv bb, scan&shadow is only for
544c349dbc7Sjsg 		 * debugging purpose, so the content of shadow bb
545c349dbc7Sjsg 		 * is the same as original bb. Therefore,
546c349dbc7Sjsg 		 * here, rather than switch to shadow bb's gma
547c349dbc7Sjsg 		 * address, we directly use original batch buffer's
548c349dbc7Sjsg 		 * gma address, and send original bb to hardware
549c349dbc7Sjsg 		 * directly
550c349dbc7Sjsg 		 */
551ad8b1aafSjsg 		if (!bb->ppgtt) {
5525ca02815Sjsg 			i915_gem_ww_ctx_init(&ww, false);
5535ca02815Sjsg retry:
5545ca02815Sjsg 			i915_gem_object_lock(bb->obj, &ww);
5555ca02815Sjsg 
5565ca02815Sjsg 			bb->vma = i915_gem_object_ggtt_pin_ww(bb->obj, &ww,
557c349dbc7Sjsg 							      NULL, 0, 0, 0);
558c349dbc7Sjsg 			if (IS_ERR(bb->vma)) {
559c349dbc7Sjsg 				ret = PTR_ERR(bb->vma);
5605ca02815Sjsg 				if (ret == -EDEADLK) {
5615ca02815Sjsg 					ret = i915_gem_ww_ctx_backoff(&ww);
5625ca02815Sjsg 					if (!ret)
5635ca02815Sjsg 						goto retry;
5645ca02815Sjsg 				}
565c349dbc7Sjsg 				goto err;
566c349dbc7Sjsg 			}
567c349dbc7Sjsg 
568c349dbc7Sjsg 			/* relocate shadow batch buffer */
569c349dbc7Sjsg 			bb->bb_start_cmd_va[1] = i915_ggtt_offset(bb->vma);
570c349dbc7Sjsg 			if (gmadr_bytes == 8)
571c349dbc7Sjsg 				bb->bb_start_cmd_va[2] = 0;
572c349dbc7Sjsg 
573*f005ef32Sjsg 			ret = i915_vma_move_to_active(bb->vma, workload->req,
574*f005ef32Sjsg 						      __EXEC_OBJECT_NO_REQUEST_AWAIT);
575c349dbc7Sjsg 			if (ret)
576c349dbc7Sjsg 				goto err;
577ad8b1aafSjsg 
578ad8b1aafSjsg 			/* No one is going to touch shadow bb from now on. */
579ad8b1aafSjsg 			i915_gem_object_flush_map(bb->obj);
5805ca02815Sjsg 			i915_gem_ww_ctx_fini(&ww);
5815ca02815Sjsg 		}
582c349dbc7Sjsg 	}
583c349dbc7Sjsg 	return 0;
584c349dbc7Sjsg err:
5855ca02815Sjsg 	i915_gem_ww_ctx_fini(&ww);
586c349dbc7Sjsg 	release_shadow_batch_buffer(workload);
587c349dbc7Sjsg 	return ret;
588c349dbc7Sjsg }
589c349dbc7Sjsg 
update_wa_ctx_2_shadow_ctx(struct intel_shadow_wa_ctx * wa_ctx)590c349dbc7Sjsg static void update_wa_ctx_2_shadow_ctx(struct intel_shadow_wa_ctx *wa_ctx)
591c349dbc7Sjsg {
592c349dbc7Sjsg 	struct intel_vgpu_workload *workload =
593c349dbc7Sjsg 		container_of(wa_ctx, struct intel_vgpu_workload, wa_ctx);
594c349dbc7Sjsg 	struct i915_request *rq = workload->req;
595c349dbc7Sjsg 	struct execlist_ring_context *shadow_ring_context =
596c349dbc7Sjsg 		(struct execlist_ring_context *)rq->context->lrc_reg_state;
597c349dbc7Sjsg 
598c349dbc7Sjsg 	shadow_ring_context->bb_per_ctx_ptr.val =
599c349dbc7Sjsg 		(shadow_ring_context->bb_per_ctx_ptr.val &
600c349dbc7Sjsg 		(~PER_CTX_ADDR_MASK)) | wa_ctx->per_ctx.shadow_gma;
601c349dbc7Sjsg 	shadow_ring_context->rcs_indirect_ctx.val =
602c349dbc7Sjsg 		(shadow_ring_context->rcs_indirect_ctx.val &
603c349dbc7Sjsg 		(~INDIRECT_CTX_ADDR_MASK)) | wa_ctx->indirect_ctx.shadow_gma;
604c349dbc7Sjsg }
605c349dbc7Sjsg 
prepare_shadow_wa_ctx(struct intel_shadow_wa_ctx * wa_ctx)606c349dbc7Sjsg static int prepare_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
607c349dbc7Sjsg {
608c349dbc7Sjsg 	struct i915_vma *vma;
609c349dbc7Sjsg 	unsigned char *per_ctx_va =
610c349dbc7Sjsg 		(unsigned char *)wa_ctx->indirect_ctx.shadow_va +
611c349dbc7Sjsg 		wa_ctx->indirect_ctx.size;
6125ca02815Sjsg 	struct i915_gem_ww_ctx ww;
6135ca02815Sjsg 	int ret;
614c349dbc7Sjsg 
615c349dbc7Sjsg 	if (wa_ctx->indirect_ctx.size == 0)
616c349dbc7Sjsg 		return 0;
617c349dbc7Sjsg 
6185ca02815Sjsg 	i915_gem_ww_ctx_init(&ww, false);
6195ca02815Sjsg retry:
6205ca02815Sjsg 	i915_gem_object_lock(wa_ctx->indirect_ctx.obj, &ww);
6215ca02815Sjsg 
6225ca02815Sjsg 	vma = i915_gem_object_ggtt_pin_ww(wa_ctx->indirect_ctx.obj, &ww, NULL,
623c349dbc7Sjsg 					  0, CACHELINE_BYTES, 0);
6245ca02815Sjsg 	if (IS_ERR(vma)) {
6255ca02815Sjsg 		ret = PTR_ERR(vma);
6265ca02815Sjsg 		if (ret == -EDEADLK) {
6275ca02815Sjsg 			ret = i915_gem_ww_ctx_backoff(&ww);
6285ca02815Sjsg 			if (!ret)
6295ca02815Sjsg 				goto retry;
6305ca02815Sjsg 		}
6315ca02815Sjsg 		return ret;
6325ca02815Sjsg 	}
6335ca02815Sjsg 
6345ca02815Sjsg 	i915_gem_ww_ctx_fini(&ww);
635c349dbc7Sjsg 
636c349dbc7Sjsg 	/* FIXME: we are not tracking our pinned VMA leaving it
637c349dbc7Sjsg 	 * up to the core to fix up the stray pin_count upon
638c349dbc7Sjsg 	 * free.
639c349dbc7Sjsg 	 */
640c349dbc7Sjsg 
641c349dbc7Sjsg 	wa_ctx->indirect_ctx.shadow_gma = i915_ggtt_offset(vma);
642c349dbc7Sjsg 
643c349dbc7Sjsg 	wa_ctx->per_ctx.shadow_gma = *((unsigned int *)per_ctx_va + 1);
644c349dbc7Sjsg 	memset(per_ctx_va, 0, CACHELINE_BYTES);
645c349dbc7Sjsg 
646c349dbc7Sjsg 	update_wa_ctx_2_shadow_ctx(wa_ctx);
647c349dbc7Sjsg 	return 0;
648c349dbc7Sjsg }
649c349dbc7Sjsg 
update_vreg_in_ctx(struct intel_vgpu_workload * workload)650c349dbc7Sjsg static void update_vreg_in_ctx(struct intel_vgpu_workload *workload)
651c349dbc7Sjsg {
652c349dbc7Sjsg 	vgpu_vreg_t(workload->vgpu, RING_START(workload->engine->mmio_base)) =
653c349dbc7Sjsg 		workload->rb_start;
654c349dbc7Sjsg }
655c349dbc7Sjsg 
release_shadow_batch_buffer(struct intel_vgpu_workload * workload)656c349dbc7Sjsg static void release_shadow_batch_buffer(struct intel_vgpu_workload *workload)
657c349dbc7Sjsg {
658c349dbc7Sjsg 	struct intel_vgpu_shadow_bb *bb, *pos;
659c349dbc7Sjsg 
660c349dbc7Sjsg 	if (list_empty(&workload->shadow_bb))
661c349dbc7Sjsg 		return;
662c349dbc7Sjsg 
663c349dbc7Sjsg 	bb = list_first_entry(&workload->shadow_bb,
664c349dbc7Sjsg 			struct intel_vgpu_shadow_bb, list);
665c349dbc7Sjsg 
666c349dbc7Sjsg 	list_for_each_entry_safe(bb, pos, &workload->shadow_bb, list) {
667c349dbc7Sjsg 		if (bb->obj) {
6685ca02815Sjsg 			i915_gem_object_lock(bb->obj, NULL);
669c349dbc7Sjsg 			if (bb->va && !IS_ERR(bb->va))
670c349dbc7Sjsg 				i915_gem_object_unpin_map(bb->obj);
671c349dbc7Sjsg 
672ad8b1aafSjsg 			if (bb->vma && !IS_ERR(bb->vma))
673c349dbc7Sjsg 				i915_vma_unpin(bb->vma);
674ad8b1aafSjsg 
6755ca02815Sjsg 			i915_gem_object_unlock(bb->obj);
676c349dbc7Sjsg 			i915_gem_object_put(bb->obj);
677c349dbc7Sjsg 		}
678c349dbc7Sjsg 		list_del(&bb->list);
679c349dbc7Sjsg 		kfree(bb);
680c349dbc7Sjsg 	}
681c349dbc7Sjsg }
682c349dbc7Sjsg 
683ad8b1aafSjsg static int
intel_vgpu_shadow_mm_pin(struct intel_vgpu_workload * workload)684ad8b1aafSjsg intel_vgpu_shadow_mm_pin(struct intel_vgpu_workload *workload)
685c349dbc7Sjsg {
686c349dbc7Sjsg 	struct intel_vgpu *vgpu = workload->vgpu;
687ad8b1aafSjsg 	struct intel_vgpu_mm *m;
688c349dbc7Sjsg 	int ret = 0;
689c349dbc7Sjsg 
690c349dbc7Sjsg 	ret = intel_vgpu_pin_mm(workload->shadow_mm);
691c349dbc7Sjsg 	if (ret) {
692c349dbc7Sjsg 		gvt_vgpu_err("fail to vgpu pin mm\n");
693c349dbc7Sjsg 		return ret;
694c349dbc7Sjsg 	}
695c349dbc7Sjsg 
696c349dbc7Sjsg 	if (workload->shadow_mm->type != INTEL_GVT_MM_PPGTT ||
697c349dbc7Sjsg 	    !workload->shadow_mm->ppgtt_mm.shadowed) {
698744fb74bSjsg 		intel_vgpu_unpin_mm(workload->shadow_mm);
699c349dbc7Sjsg 		gvt_vgpu_err("workload shadow ppgtt isn't ready\n");
700c349dbc7Sjsg 		return -EINVAL;
701c349dbc7Sjsg 	}
702c349dbc7Sjsg 
703ad8b1aafSjsg 	if (!list_empty(&workload->lri_shadow_mm)) {
704ad8b1aafSjsg 		list_for_each_entry(m, &workload->lri_shadow_mm,
705ad8b1aafSjsg 				    ppgtt_mm.link) {
706ad8b1aafSjsg 			ret = intel_vgpu_pin_mm(m);
707ad8b1aafSjsg 			if (ret) {
708ad8b1aafSjsg 				list_for_each_entry_from_reverse(m,
709ad8b1aafSjsg 								 &workload->lri_shadow_mm,
710ad8b1aafSjsg 								 ppgtt_mm.link)
711ad8b1aafSjsg 					intel_vgpu_unpin_mm(m);
712ad8b1aafSjsg 				gvt_vgpu_err("LRI shadow ppgtt fail to pin\n");
713ad8b1aafSjsg 				break;
714ad8b1aafSjsg 			}
715ad8b1aafSjsg 		}
716ad8b1aafSjsg 	}
717ad8b1aafSjsg 
718ad8b1aafSjsg 	if (ret)
719ad8b1aafSjsg 		intel_vgpu_unpin_mm(workload->shadow_mm);
720ad8b1aafSjsg 
721ad8b1aafSjsg 	return ret;
722ad8b1aafSjsg }
723ad8b1aafSjsg 
724ad8b1aafSjsg static void
intel_vgpu_shadow_mm_unpin(struct intel_vgpu_workload * workload)725ad8b1aafSjsg intel_vgpu_shadow_mm_unpin(struct intel_vgpu_workload *workload)
726ad8b1aafSjsg {
727ad8b1aafSjsg 	struct intel_vgpu_mm *m;
728ad8b1aafSjsg 
729ad8b1aafSjsg 	if (!list_empty(&workload->lri_shadow_mm)) {
730ad8b1aafSjsg 		list_for_each_entry(m, &workload->lri_shadow_mm,
731ad8b1aafSjsg 				    ppgtt_mm.link)
732ad8b1aafSjsg 			intel_vgpu_unpin_mm(m);
733ad8b1aafSjsg 	}
734ad8b1aafSjsg 	intel_vgpu_unpin_mm(workload->shadow_mm);
735ad8b1aafSjsg }
736ad8b1aafSjsg 
prepare_workload(struct intel_vgpu_workload * workload)737ad8b1aafSjsg static int prepare_workload(struct intel_vgpu_workload *workload)
738ad8b1aafSjsg {
739ad8b1aafSjsg 	struct intel_vgpu *vgpu = workload->vgpu;
740ad8b1aafSjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
741ad8b1aafSjsg 	int ret = 0;
742ad8b1aafSjsg 
743ad8b1aafSjsg 	ret = intel_vgpu_shadow_mm_pin(workload);
744ad8b1aafSjsg 	if (ret) {
745ad8b1aafSjsg 		gvt_vgpu_err("fail to pin shadow mm\n");
746ad8b1aafSjsg 		return ret;
747ad8b1aafSjsg 	}
748ad8b1aafSjsg 
749c349dbc7Sjsg 	update_shadow_pdps(workload);
750c349dbc7Sjsg 
751c349dbc7Sjsg 	set_context_ppgtt_from_shadow(workload, s->shadow[workload->engine->id]);
752c349dbc7Sjsg 
753c349dbc7Sjsg 	ret = intel_vgpu_sync_oos_pages(workload->vgpu);
754c349dbc7Sjsg 	if (ret) {
755c349dbc7Sjsg 		gvt_vgpu_err("fail to vgpu sync oos pages\n");
756c349dbc7Sjsg 		goto err_unpin_mm;
757c349dbc7Sjsg 	}
758c349dbc7Sjsg 
759c349dbc7Sjsg 	ret = intel_vgpu_flush_post_shadow(workload->vgpu);
760c349dbc7Sjsg 	if (ret) {
761c349dbc7Sjsg 		gvt_vgpu_err("fail to flush post shadow\n");
762c349dbc7Sjsg 		goto err_unpin_mm;
763c349dbc7Sjsg 	}
764c349dbc7Sjsg 
765c349dbc7Sjsg 	ret = copy_workload_to_ring_buffer(workload);
766c349dbc7Sjsg 	if (ret) {
767c349dbc7Sjsg 		gvt_vgpu_err("fail to generate request\n");
768c349dbc7Sjsg 		goto err_unpin_mm;
769c349dbc7Sjsg 	}
770c349dbc7Sjsg 
771c349dbc7Sjsg 	ret = prepare_shadow_batch_buffer(workload);
772c349dbc7Sjsg 	if (ret) {
773c349dbc7Sjsg 		gvt_vgpu_err("fail to prepare_shadow_batch_buffer\n");
774c349dbc7Sjsg 		goto err_unpin_mm;
775c349dbc7Sjsg 	}
776c349dbc7Sjsg 
777c349dbc7Sjsg 	ret = prepare_shadow_wa_ctx(&workload->wa_ctx);
778c349dbc7Sjsg 	if (ret) {
779c349dbc7Sjsg 		gvt_vgpu_err("fail to prepare_shadow_wa_ctx\n");
780c349dbc7Sjsg 		goto err_shadow_batch;
781c349dbc7Sjsg 	}
782c349dbc7Sjsg 
783c349dbc7Sjsg 	if (workload->prepare) {
784c349dbc7Sjsg 		ret = workload->prepare(workload);
785c349dbc7Sjsg 		if (ret)
786c349dbc7Sjsg 			goto err_shadow_wa_ctx;
787c349dbc7Sjsg 	}
788c349dbc7Sjsg 
789c349dbc7Sjsg 	return 0;
790c349dbc7Sjsg err_shadow_wa_ctx:
791c349dbc7Sjsg 	release_shadow_wa_ctx(&workload->wa_ctx);
792c349dbc7Sjsg err_shadow_batch:
793c349dbc7Sjsg 	release_shadow_batch_buffer(workload);
794c349dbc7Sjsg err_unpin_mm:
795ad8b1aafSjsg 	intel_vgpu_shadow_mm_unpin(workload);
796c349dbc7Sjsg 	return ret;
797c349dbc7Sjsg }
798c349dbc7Sjsg 
dispatch_workload(struct intel_vgpu_workload * workload)799c349dbc7Sjsg static int dispatch_workload(struct intel_vgpu_workload *workload)
800c349dbc7Sjsg {
801c349dbc7Sjsg 	struct intel_vgpu *vgpu = workload->vgpu;
802c349dbc7Sjsg 	struct i915_request *rq;
803c349dbc7Sjsg 	int ret;
804c349dbc7Sjsg 
805c349dbc7Sjsg 	gvt_dbg_sched("ring id %s prepare to dispatch workload %p\n",
806c349dbc7Sjsg 		      workload->engine->name, workload);
807c349dbc7Sjsg 
808c349dbc7Sjsg 	mutex_lock(&vgpu->vgpu_lock);
809c349dbc7Sjsg 
810c349dbc7Sjsg 	ret = intel_gvt_workload_req_alloc(workload);
811c349dbc7Sjsg 	if (ret)
812c349dbc7Sjsg 		goto err_req;
813c349dbc7Sjsg 
814c349dbc7Sjsg 	ret = intel_gvt_scan_and_shadow_workload(workload);
815c349dbc7Sjsg 	if (ret)
816c349dbc7Sjsg 		goto out;
817c349dbc7Sjsg 
818c349dbc7Sjsg 	ret = populate_shadow_context(workload);
819c349dbc7Sjsg 	if (ret) {
820c349dbc7Sjsg 		release_shadow_wa_ctx(&workload->wa_ctx);
821c349dbc7Sjsg 		goto out;
822c349dbc7Sjsg 	}
823c349dbc7Sjsg 
824c349dbc7Sjsg 	ret = prepare_workload(workload);
825c349dbc7Sjsg out:
826c349dbc7Sjsg 	if (ret) {
827c349dbc7Sjsg 		/* We might still need to add request with
828c349dbc7Sjsg 		 * clean ctx to retire it properly..
829c349dbc7Sjsg 		 */
830c349dbc7Sjsg 		rq = fetch_and_zero(&workload->req);
831c349dbc7Sjsg 		i915_request_put(rq);
832c349dbc7Sjsg 	}
833c349dbc7Sjsg 
834c349dbc7Sjsg 	if (!IS_ERR_OR_NULL(workload->req)) {
835c349dbc7Sjsg 		gvt_dbg_sched("ring id %s submit workload to i915 %p\n",
836c349dbc7Sjsg 			      workload->engine->name, workload->req);
837c349dbc7Sjsg 		i915_request_add(workload->req);
838c349dbc7Sjsg 		workload->dispatched = true;
839c349dbc7Sjsg 	}
840c349dbc7Sjsg err_req:
841c349dbc7Sjsg 	if (ret)
842c349dbc7Sjsg 		workload->status = ret;
843c349dbc7Sjsg 	mutex_unlock(&vgpu->vgpu_lock);
844c349dbc7Sjsg 	return ret;
845c349dbc7Sjsg }
846c349dbc7Sjsg 
847c349dbc7Sjsg static struct intel_vgpu_workload *
pick_next_workload(struct intel_gvt * gvt,struct intel_engine_cs * engine)848c349dbc7Sjsg pick_next_workload(struct intel_gvt *gvt, struct intel_engine_cs *engine)
849c349dbc7Sjsg {
850c349dbc7Sjsg 	struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
851c349dbc7Sjsg 	struct intel_vgpu_workload *workload = NULL;
852c349dbc7Sjsg 
853c349dbc7Sjsg 	mutex_lock(&gvt->sched_lock);
854c349dbc7Sjsg 
855c349dbc7Sjsg 	/*
856c349dbc7Sjsg 	 * no current vgpu / will be scheduled out / no workload
857c349dbc7Sjsg 	 * bail out
858c349dbc7Sjsg 	 */
859c349dbc7Sjsg 	if (!scheduler->current_vgpu) {
860c349dbc7Sjsg 		gvt_dbg_sched("ring %s stop - no current vgpu\n", engine->name);
861c349dbc7Sjsg 		goto out;
862c349dbc7Sjsg 	}
863c349dbc7Sjsg 
864c349dbc7Sjsg 	if (scheduler->need_reschedule) {
865c349dbc7Sjsg 		gvt_dbg_sched("ring %s stop - will reschedule\n", engine->name);
866c349dbc7Sjsg 		goto out;
867c349dbc7Sjsg 	}
868c349dbc7Sjsg 
869*f005ef32Sjsg 	if (!test_bit(INTEL_VGPU_STATUS_ACTIVE,
870*f005ef32Sjsg 		      scheduler->current_vgpu->status) ||
871c349dbc7Sjsg 	    list_empty(workload_q_head(scheduler->current_vgpu, engine)))
872c349dbc7Sjsg 		goto out;
873c349dbc7Sjsg 
874c349dbc7Sjsg 	/*
875c349dbc7Sjsg 	 * still have current workload, maybe the workload disptacher
876c349dbc7Sjsg 	 * fail to submit it for some reason, resubmit it.
877c349dbc7Sjsg 	 */
878c349dbc7Sjsg 	if (scheduler->current_workload[engine->id]) {
879c349dbc7Sjsg 		workload = scheduler->current_workload[engine->id];
880c349dbc7Sjsg 		gvt_dbg_sched("ring %s still have current workload %p\n",
881c349dbc7Sjsg 			      engine->name, workload);
882c349dbc7Sjsg 		goto out;
883c349dbc7Sjsg 	}
884c349dbc7Sjsg 
885c349dbc7Sjsg 	/*
886c349dbc7Sjsg 	 * pick a workload as current workload
887c349dbc7Sjsg 	 * once current workload is set, schedule policy routines
888c349dbc7Sjsg 	 * will wait the current workload is finished when trying to
889c349dbc7Sjsg 	 * schedule out a vgpu.
890c349dbc7Sjsg 	 */
891c349dbc7Sjsg 	scheduler->current_workload[engine->id] =
892c349dbc7Sjsg 		list_first_entry(workload_q_head(scheduler->current_vgpu,
893c349dbc7Sjsg 						 engine),
894c349dbc7Sjsg 				 struct intel_vgpu_workload, list);
895c349dbc7Sjsg 
896c349dbc7Sjsg 	workload = scheduler->current_workload[engine->id];
897c349dbc7Sjsg 
898c349dbc7Sjsg 	gvt_dbg_sched("ring %s pick new workload %p\n", engine->name, workload);
899c349dbc7Sjsg 
900c349dbc7Sjsg 	atomic_inc(&workload->vgpu->submission.running_workload_num);
901c349dbc7Sjsg out:
902c349dbc7Sjsg 	mutex_unlock(&gvt->sched_lock);
903c349dbc7Sjsg 	return workload;
904c349dbc7Sjsg }
905c349dbc7Sjsg 
update_guest_pdps(struct intel_vgpu * vgpu,u64 ring_context_gpa,u32 pdp[8])906ad8b1aafSjsg static void update_guest_pdps(struct intel_vgpu *vgpu,
907ad8b1aafSjsg 			      u64 ring_context_gpa, u32 pdp[8])
908ad8b1aafSjsg {
909ad8b1aafSjsg 	u64 gpa;
910ad8b1aafSjsg 	int i;
911ad8b1aafSjsg 
912ad8b1aafSjsg 	gpa = ring_context_gpa + RING_CTX_OFF(pdps[0].val);
913ad8b1aafSjsg 
914ad8b1aafSjsg 	for (i = 0; i < 8; i++)
9151bb76ff1Sjsg 		intel_gvt_write_gpa(vgpu, gpa + i * 8, &pdp[7 - i], 4);
916ad8b1aafSjsg }
917ad8b1aafSjsg 
918ad8b1aafSjsg static __maybe_unused bool
check_shadow_context_ppgtt(struct execlist_ring_context * c,struct intel_vgpu_mm * m)919ad8b1aafSjsg check_shadow_context_ppgtt(struct execlist_ring_context *c, struct intel_vgpu_mm *m)
920ad8b1aafSjsg {
921ad8b1aafSjsg 	if (m->ppgtt_mm.root_entry_type == GTT_TYPE_PPGTT_ROOT_L4_ENTRY) {
922ad8b1aafSjsg 		u64 shadow_pdp = c->pdps[7].val | (u64) c->pdps[6].val << 32;
923ad8b1aafSjsg 
924ad8b1aafSjsg 		if (shadow_pdp != m->ppgtt_mm.shadow_pdps[0]) {
925ad8b1aafSjsg 			gvt_dbg_mm("4-level context ppgtt not match LRI command\n");
926ad8b1aafSjsg 			return false;
927ad8b1aafSjsg 		}
928ad8b1aafSjsg 		return true;
929ad8b1aafSjsg 	} else {
930ad8b1aafSjsg 		/* see comment in LRI handler in cmd_parser.c */
931ad8b1aafSjsg 		gvt_dbg_mm("invalid shadow mm type\n");
932ad8b1aafSjsg 		return false;
933ad8b1aafSjsg 	}
934ad8b1aafSjsg }
935ad8b1aafSjsg 
update_guest_context(struct intel_vgpu_workload * workload)936c349dbc7Sjsg static void update_guest_context(struct intel_vgpu_workload *workload)
937c349dbc7Sjsg {
938c349dbc7Sjsg 	struct i915_request *rq = workload->req;
939c349dbc7Sjsg 	struct intel_vgpu *vgpu = workload->vgpu;
940c349dbc7Sjsg 	struct execlist_ring_context *shadow_ring_context;
941ad8b1aafSjsg 	struct intel_context *ctx = workload->req->context;
942ad8b1aafSjsg 	void *context_base;
943c349dbc7Sjsg 	void *src;
944c349dbc7Sjsg 	unsigned long context_gpa, context_page_num;
945ad8b1aafSjsg 	unsigned long gpa_base; /* first gpa of consecutive GPAs */
946ad8b1aafSjsg 	unsigned long gpa_size; /* size of consecutive GPAs*/
947c349dbc7Sjsg 	int i;
948c349dbc7Sjsg 	u32 ring_base;
949c349dbc7Sjsg 	u32 head, tail;
950c349dbc7Sjsg 	u16 wrap_count;
951c349dbc7Sjsg 
952c349dbc7Sjsg 	gvt_dbg_sched("ring id %d workload lrca %x\n", rq->engine->id,
953c349dbc7Sjsg 		      workload->ctx_desc.lrca);
954c349dbc7Sjsg 
955ad8b1aafSjsg 	GEM_BUG_ON(!intel_context_is_pinned(ctx));
956ad8b1aafSjsg 
957c349dbc7Sjsg 	head = workload->rb_head;
958c349dbc7Sjsg 	tail = workload->rb_tail;
959c349dbc7Sjsg 	wrap_count = workload->guest_rb_head >> RB_HEAD_WRAP_CNT_OFF;
960c349dbc7Sjsg 
961c349dbc7Sjsg 	if (tail < head) {
962c349dbc7Sjsg 		if (wrap_count == RB_HEAD_WRAP_CNT_MAX)
963c349dbc7Sjsg 			wrap_count = 0;
964c349dbc7Sjsg 		else
965c349dbc7Sjsg 			wrap_count += 1;
966c349dbc7Sjsg 	}
967c349dbc7Sjsg 
968c349dbc7Sjsg 	head = (wrap_count << RB_HEAD_WRAP_CNT_OFF) | tail;
969c349dbc7Sjsg 
970c349dbc7Sjsg 	ring_base = rq->engine->mmio_base;
971c349dbc7Sjsg 	vgpu_vreg_t(vgpu, RING_TAIL(ring_base)) = tail;
972c349dbc7Sjsg 	vgpu_vreg_t(vgpu, RING_HEAD(ring_base)) = head;
973c349dbc7Sjsg 
974c349dbc7Sjsg 	context_page_num = rq->engine->context_size;
975c349dbc7Sjsg 	context_page_num = context_page_num >> PAGE_SHIFT;
976c349dbc7Sjsg 
977*f005ef32Sjsg 	if (IS_BROADWELL(rq->i915) && rq->engine->id == RCS0)
978c349dbc7Sjsg 		context_page_num = 19;
979c349dbc7Sjsg 
980ad8b1aafSjsg 	context_base = (void *) ctx->lrc_reg_state -
981ad8b1aafSjsg 			(LRC_STATE_PN << I915_GTT_PAGE_SHIFT);
982c349dbc7Sjsg 
983ad8b1aafSjsg 	/* find consecutive GPAs from gma until the first inconsecutive GPA.
984ad8b1aafSjsg 	 * write to the consecutive GPAs from src virtual address
985ad8b1aafSjsg 	 */
986ad8b1aafSjsg 	gpa_size = 0;
987ad8b1aafSjsg 	for (i = 2; i < context_page_num; i++) {
988c349dbc7Sjsg 		context_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm,
989c349dbc7Sjsg 				(u32)((workload->ctx_desc.lrca + i) <<
990c349dbc7Sjsg 					I915_GTT_PAGE_SHIFT));
991c349dbc7Sjsg 		if (context_gpa == INTEL_GVT_INVALID_ADDR) {
992c349dbc7Sjsg 			gvt_vgpu_err("invalid guest context descriptor\n");
993c349dbc7Sjsg 			return;
994c349dbc7Sjsg 		}
995c349dbc7Sjsg 
996ad8b1aafSjsg 		if (gpa_size == 0) {
997ad8b1aafSjsg 			gpa_base = context_gpa;
998ad8b1aafSjsg 			src = context_base + (i << I915_GTT_PAGE_SHIFT);
999ad8b1aafSjsg 		} else if (context_gpa != gpa_base + gpa_size)
1000ad8b1aafSjsg 			goto write;
1001ad8b1aafSjsg 
1002ad8b1aafSjsg 		gpa_size += I915_GTT_PAGE_SIZE;
1003ad8b1aafSjsg 
1004ad8b1aafSjsg 		if (i == context_page_num - 1)
1005ad8b1aafSjsg 			goto write;
1006ad8b1aafSjsg 
1007ad8b1aafSjsg 		continue;
1008ad8b1aafSjsg 
1009ad8b1aafSjsg write:
10101bb76ff1Sjsg 		intel_gvt_write_gpa(vgpu, gpa_base, src, gpa_size);
1011ad8b1aafSjsg 		gpa_base = context_gpa;
1012ad8b1aafSjsg 		gpa_size = I915_GTT_PAGE_SIZE;
1013ad8b1aafSjsg 		src = context_base + (i << I915_GTT_PAGE_SHIFT);
1014c349dbc7Sjsg 	}
1015c349dbc7Sjsg 
10161bb76ff1Sjsg 	intel_gvt_write_gpa(vgpu, workload->ring_context_gpa +
1017c349dbc7Sjsg 		RING_CTX_OFF(ring_header.val), &workload->rb_tail, 4);
1018c349dbc7Sjsg 
1019ad8b1aafSjsg 	shadow_ring_context = (void *) ctx->lrc_reg_state;
1020ad8b1aafSjsg 
1021ad8b1aafSjsg 	if (!list_empty(&workload->lri_shadow_mm)) {
1022ad8b1aafSjsg 		struct intel_vgpu_mm *m = list_last_entry(&workload->lri_shadow_mm,
1023ad8b1aafSjsg 							  struct intel_vgpu_mm,
1024ad8b1aafSjsg 							  ppgtt_mm.link);
1025ad8b1aafSjsg 		GEM_BUG_ON(!check_shadow_context_ppgtt(shadow_ring_context, m));
1026ad8b1aafSjsg 		update_guest_pdps(vgpu, workload->ring_context_gpa,
1027ad8b1aafSjsg 				  (void *)m->ppgtt_mm.guest_pdps);
1028ad8b1aafSjsg 	}
1029c349dbc7Sjsg 
1030c349dbc7Sjsg #define COPY_REG(name) \
10311bb76ff1Sjsg 	intel_gvt_write_gpa(vgpu, workload->ring_context_gpa + \
1032c349dbc7Sjsg 		RING_CTX_OFF(name.val), &shadow_ring_context->name.val, 4)
1033c349dbc7Sjsg 
1034c349dbc7Sjsg 	COPY_REG(ctx_ctrl);
1035c349dbc7Sjsg 	COPY_REG(ctx_timestamp);
1036c349dbc7Sjsg 
1037c349dbc7Sjsg #undef COPY_REG
1038c349dbc7Sjsg 
10391bb76ff1Sjsg 	intel_gvt_write_gpa(vgpu,
1040c349dbc7Sjsg 			workload->ring_context_gpa +
1041c349dbc7Sjsg 			sizeof(*shadow_ring_context),
1042c349dbc7Sjsg 			(void *)shadow_ring_context +
1043c349dbc7Sjsg 			sizeof(*shadow_ring_context),
1044c349dbc7Sjsg 			I915_GTT_PAGE_SIZE - sizeof(*shadow_ring_context));
1045c349dbc7Sjsg }
1046c349dbc7Sjsg 
intel_vgpu_clean_workloads(struct intel_vgpu * vgpu,intel_engine_mask_t engine_mask)1047c349dbc7Sjsg void intel_vgpu_clean_workloads(struct intel_vgpu *vgpu,
1048c349dbc7Sjsg 				intel_engine_mask_t engine_mask)
1049c349dbc7Sjsg {
1050c349dbc7Sjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
1051c349dbc7Sjsg 	struct intel_engine_cs *engine;
1052c349dbc7Sjsg 	struct intel_vgpu_workload *pos, *n;
1053c349dbc7Sjsg 	intel_engine_mask_t tmp;
1054c349dbc7Sjsg 
1055c349dbc7Sjsg 	/* free the unsubmited workloads in the queues. */
10565ca02815Sjsg 	for_each_engine_masked(engine, vgpu->gvt->gt, engine_mask, tmp) {
1057c349dbc7Sjsg 		list_for_each_entry_safe(pos, n,
1058c349dbc7Sjsg 			&s->workload_q_head[engine->id], list) {
1059c349dbc7Sjsg 			list_del_init(&pos->list);
1060c349dbc7Sjsg 			intel_vgpu_destroy_workload(pos);
1061c349dbc7Sjsg 		}
1062c349dbc7Sjsg 		clear_bit(engine->id, s->shadow_ctx_desc_updated);
1063c349dbc7Sjsg 	}
1064c349dbc7Sjsg }
1065c349dbc7Sjsg 
complete_current_workload(struct intel_gvt * gvt,int ring_id)1066c349dbc7Sjsg static void complete_current_workload(struct intel_gvt *gvt, int ring_id)
1067c349dbc7Sjsg {
1068c349dbc7Sjsg 	struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
1069c349dbc7Sjsg 	struct intel_vgpu_workload *workload =
1070c349dbc7Sjsg 		scheduler->current_workload[ring_id];
1071c349dbc7Sjsg 	struct intel_vgpu *vgpu = workload->vgpu;
1072c349dbc7Sjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
1073c349dbc7Sjsg 	struct i915_request *rq = workload->req;
1074c349dbc7Sjsg 	int event;
1075c349dbc7Sjsg 
1076c349dbc7Sjsg 	mutex_lock(&vgpu->vgpu_lock);
1077c349dbc7Sjsg 	mutex_lock(&gvt->sched_lock);
1078c349dbc7Sjsg 
1079c349dbc7Sjsg 	/* For the workload w/ request, needs to wait for the context
1080c349dbc7Sjsg 	 * switch to make sure request is completed.
1081c349dbc7Sjsg 	 * For the workload w/o request, directly complete the workload.
1082c349dbc7Sjsg 	 */
1083c349dbc7Sjsg 	if (rq) {
1084c349dbc7Sjsg 		wait_event(workload->shadow_ctx_status_wq,
1085c349dbc7Sjsg 			   !atomic_read(&workload->shadow_ctx_active));
1086c349dbc7Sjsg 
1087c349dbc7Sjsg 		/* If this request caused GPU hang, req->fence.error will
1088c349dbc7Sjsg 		 * be set to -EIO. Use -EIO to set workload status so
1089c349dbc7Sjsg 		 * that when this request caused GPU hang, didn't trigger
1090c349dbc7Sjsg 		 * context switch interrupt to guest.
1091c349dbc7Sjsg 		 */
1092c349dbc7Sjsg 		if (likely(workload->status == -EINPROGRESS)) {
1093c349dbc7Sjsg 			if (workload->req->fence.error == -EIO)
1094c349dbc7Sjsg 				workload->status = -EIO;
1095c349dbc7Sjsg 			else
1096c349dbc7Sjsg 				workload->status = 0;
1097c349dbc7Sjsg 		}
1098c349dbc7Sjsg 
1099c349dbc7Sjsg 		if (!workload->status &&
1100c349dbc7Sjsg 		    !(vgpu->resetting_eng & BIT(ring_id))) {
1101c349dbc7Sjsg 			update_guest_context(workload);
1102c349dbc7Sjsg 
1103c349dbc7Sjsg 			for_each_set_bit(event, workload->pending_events,
1104c349dbc7Sjsg 					 INTEL_GVT_EVENT_MAX)
1105c349dbc7Sjsg 				intel_vgpu_trigger_virtual_event(vgpu, event);
1106c349dbc7Sjsg 		}
1107c349dbc7Sjsg 
1108c349dbc7Sjsg 		i915_request_put(fetch_and_zero(&workload->req));
1109c349dbc7Sjsg 	}
1110c349dbc7Sjsg 
1111c349dbc7Sjsg 	gvt_dbg_sched("ring id %d complete workload %p status %d\n",
1112c349dbc7Sjsg 			ring_id, workload, workload->status);
1113c349dbc7Sjsg 
1114c349dbc7Sjsg 	scheduler->current_workload[ring_id] = NULL;
1115c349dbc7Sjsg 
1116c349dbc7Sjsg 	list_del_init(&workload->list);
1117c349dbc7Sjsg 
1118c349dbc7Sjsg 	if (workload->status || vgpu->resetting_eng & BIT(ring_id)) {
1119c349dbc7Sjsg 		/* if workload->status is not successful means HW GPU
1120c349dbc7Sjsg 		 * has occurred GPU hang or something wrong with i915/GVT,
1121c349dbc7Sjsg 		 * and GVT won't inject context switch interrupt to guest.
1122c349dbc7Sjsg 		 * So this error is a vGPU hang actually to the guest.
1123c349dbc7Sjsg 		 * According to this we should emunlate a vGPU hang. If
1124c349dbc7Sjsg 		 * there are pending workloads which are already submitted
1125c349dbc7Sjsg 		 * from guest, we should clean them up like HW GPU does.
1126c349dbc7Sjsg 		 *
1127c349dbc7Sjsg 		 * if it is in middle of engine resetting, the pending
1128c349dbc7Sjsg 		 * workloads won't be submitted to HW GPU and will be
1129c349dbc7Sjsg 		 * cleaned up during the resetting process later, so doing
1130c349dbc7Sjsg 		 * the workload clean up here doesn't have any impact.
1131c349dbc7Sjsg 		 **/
1132c349dbc7Sjsg 		intel_vgpu_clean_workloads(vgpu, BIT(ring_id));
1133c349dbc7Sjsg 	}
1134c349dbc7Sjsg 
1135c349dbc7Sjsg 	workload->complete(workload);
1136c349dbc7Sjsg 
1137ad8b1aafSjsg 	intel_vgpu_shadow_mm_unpin(workload);
1138ad8b1aafSjsg 	intel_vgpu_destroy_workload(workload);
1139ad8b1aafSjsg 
1140c349dbc7Sjsg 	atomic_dec(&s->running_workload_num);
1141c349dbc7Sjsg 	wake_up(&scheduler->workload_complete_wq);
1142c349dbc7Sjsg 
1143c349dbc7Sjsg 	if (gvt->scheduler.need_reschedule)
1144c349dbc7Sjsg 		intel_gvt_request_service(gvt, INTEL_GVT_REQUEST_EVENT_SCHED);
1145c349dbc7Sjsg 
1146c349dbc7Sjsg 	mutex_unlock(&gvt->sched_lock);
1147c349dbc7Sjsg 	mutex_unlock(&vgpu->vgpu_lock);
1148c349dbc7Sjsg }
1149c349dbc7Sjsg 
workload_thread(void * arg)1150c349dbc7Sjsg static int workload_thread(void *arg)
1151c349dbc7Sjsg {
1152c349dbc7Sjsg 	struct intel_engine_cs *engine = arg;
11535ca02815Sjsg 	const bool need_force_wake = GRAPHICS_VER(engine->i915) >= 9;
1154c349dbc7Sjsg 	struct intel_gvt *gvt = engine->i915->gvt;
1155c349dbc7Sjsg 	struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
1156c349dbc7Sjsg 	struct intel_vgpu_workload *workload = NULL;
1157c349dbc7Sjsg 	struct intel_vgpu *vgpu = NULL;
1158c349dbc7Sjsg 	int ret;
1159c349dbc7Sjsg 	DEFINE_WAIT_FUNC(wait, woken_wake_function);
1160c349dbc7Sjsg 
1161c349dbc7Sjsg 	gvt_dbg_core("workload thread for ring %s started\n", engine->name);
1162c349dbc7Sjsg 
1163c349dbc7Sjsg 	while (!kthread_should_stop()) {
1164c349dbc7Sjsg 		intel_wakeref_t wakeref;
1165c349dbc7Sjsg 
1166c349dbc7Sjsg 		add_wait_queue(&scheduler->waitq[engine->id], &wait);
1167c349dbc7Sjsg 		do {
1168c349dbc7Sjsg 			workload = pick_next_workload(gvt, engine);
1169c349dbc7Sjsg 			if (workload)
1170c349dbc7Sjsg 				break;
1171c349dbc7Sjsg 			wait_woken(&wait, TASK_INTERRUPTIBLE,
1172c349dbc7Sjsg 				   MAX_SCHEDULE_TIMEOUT);
1173c349dbc7Sjsg 		} while (!kthread_should_stop());
1174c349dbc7Sjsg 		remove_wait_queue(&scheduler->waitq[engine->id], &wait);
1175c349dbc7Sjsg 
1176c349dbc7Sjsg 		if (!workload)
1177c349dbc7Sjsg 			break;
1178c349dbc7Sjsg 
1179c349dbc7Sjsg 		gvt_dbg_sched("ring %s next workload %p vgpu %d\n",
1180c349dbc7Sjsg 			      engine->name, workload,
1181c349dbc7Sjsg 			      workload->vgpu->id);
1182c349dbc7Sjsg 
1183c349dbc7Sjsg 		wakeref = intel_runtime_pm_get(engine->uncore->rpm);
1184c349dbc7Sjsg 
1185c349dbc7Sjsg 		gvt_dbg_sched("ring %s will dispatch workload %p\n",
1186c349dbc7Sjsg 			      engine->name, workload);
1187c349dbc7Sjsg 
1188c349dbc7Sjsg 		if (need_force_wake)
1189c349dbc7Sjsg 			intel_uncore_forcewake_get(engine->uncore,
1190c349dbc7Sjsg 						   FORCEWAKE_ALL);
1191c349dbc7Sjsg 		/*
1192c349dbc7Sjsg 		 * Update the vReg of the vGPU which submitted this
1193c349dbc7Sjsg 		 * workload. The vGPU may use these registers for checking
1194c349dbc7Sjsg 		 * the context state. The value comes from GPU commands
1195c349dbc7Sjsg 		 * in this workload.
1196c349dbc7Sjsg 		 */
1197c349dbc7Sjsg 		update_vreg_in_ctx(workload);
1198c349dbc7Sjsg 
1199c349dbc7Sjsg 		ret = dispatch_workload(workload);
1200c349dbc7Sjsg 
1201c349dbc7Sjsg 		if (ret) {
1202c349dbc7Sjsg 			vgpu = workload->vgpu;
1203c349dbc7Sjsg 			gvt_vgpu_err("fail to dispatch workload, skip\n");
1204c349dbc7Sjsg 			goto complete;
1205c349dbc7Sjsg 		}
1206c349dbc7Sjsg 
1207c349dbc7Sjsg 		gvt_dbg_sched("ring %s wait workload %p\n",
1208c349dbc7Sjsg 			      engine->name, workload);
1209c349dbc7Sjsg 		i915_request_wait(workload->req, 0, MAX_SCHEDULE_TIMEOUT);
1210c349dbc7Sjsg 
1211c349dbc7Sjsg complete:
1212c349dbc7Sjsg 		gvt_dbg_sched("will complete workload %p, status: %d\n",
1213c349dbc7Sjsg 			      workload, workload->status);
1214c349dbc7Sjsg 
1215c349dbc7Sjsg 		complete_current_workload(gvt, engine->id);
1216c349dbc7Sjsg 
1217c349dbc7Sjsg 		if (need_force_wake)
1218c349dbc7Sjsg 			intel_uncore_forcewake_put(engine->uncore,
1219c349dbc7Sjsg 						   FORCEWAKE_ALL);
1220c349dbc7Sjsg 
1221c349dbc7Sjsg 		intel_runtime_pm_put(engine->uncore->rpm, wakeref);
1222c349dbc7Sjsg 		if (ret && (vgpu_is_vm_unhealthy(ret)))
1223c349dbc7Sjsg 			enter_failsafe_mode(vgpu, GVT_FAILSAFE_GUEST_ERR);
1224c349dbc7Sjsg 	}
1225c349dbc7Sjsg 	return 0;
1226c349dbc7Sjsg }
1227c349dbc7Sjsg 
intel_gvt_wait_vgpu_idle(struct intel_vgpu * vgpu)1228c349dbc7Sjsg void intel_gvt_wait_vgpu_idle(struct intel_vgpu *vgpu)
1229c349dbc7Sjsg {
1230c349dbc7Sjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
1231c349dbc7Sjsg 	struct intel_gvt *gvt = vgpu->gvt;
1232c349dbc7Sjsg 	struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
1233c349dbc7Sjsg 
1234c349dbc7Sjsg 	if (atomic_read(&s->running_workload_num)) {
1235c349dbc7Sjsg 		gvt_dbg_sched("wait vgpu idle\n");
1236c349dbc7Sjsg 
1237c349dbc7Sjsg 		wait_event(scheduler->workload_complete_wq,
1238c349dbc7Sjsg 				!atomic_read(&s->running_workload_num));
1239c349dbc7Sjsg 	}
1240c349dbc7Sjsg }
1241c349dbc7Sjsg 
intel_gvt_clean_workload_scheduler(struct intel_gvt * gvt)1242c349dbc7Sjsg void intel_gvt_clean_workload_scheduler(struct intel_gvt *gvt)
1243c349dbc7Sjsg {
1244c349dbc7Sjsg 	struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
1245c349dbc7Sjsg 	struct intel_engine_cs *engine;
1246c349dbc7Sjsg 	enum intel_engine_id i;
1247c349dbc7Sjsg 
1248c349dbc7Sjsg 	gvt_dbg_core("clean workload scheduler\n");
1249c349dbc7Sjsg 
1250c349dbc7Sjsg 	for_each_engine(engine, gvt->gt, i) {
1251c349dbc7Sjsg 		atomic_notifier_chain_unregister(
1252c349dbc7Sjsg 					&engine->context_status_notifier,
1253c349dbc7Sjsg 					&gvt->shadow_ctx_notifier_block[i]);
1254c349dbc7Sjsg 		kthread_stop(scheduler->thread[i]);
1255c349dbc7Sjsg 	}
1256c349dbc7Sjsg }
1257c349dbc7Sjsg 
intel_gvt_init_workload_scheduler(struct intel_gvt * gvt)1258c349dbc7Sjsg int intel_gvt_init_workload_scheduler(struct intel_gvt *gvt)
1259c349dbc7Sjsg {
1260c349dbc7Sjsg 	struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
1261c349dbc7Sjsg 	struct intel_engine_cs *engine;
1262c349dbc7Sjsg 	enum intel_engine_id i;
1263c349dbc7Sjsg 	int ret;
1264c349dbc7Sjsg 
1265c349dbc7Sjsg 	gvt_dbg_core("init workload scheduler\n");
1266c349dbc7Sjsg 
1267c349dbc7Sjsg 	init_waitqueue_head(&scheduler->workload_complete_wq);
1268c349dbc7Sjsg 
1269c349dbc7Sjsg 	for_each_engine(engine, gvt->gt, i) {
1270c349dbc7Sjsg 		init_waitqueue_head(&scheduler->waitq[i]);
1271c349dbc7Sjsg 
1272c349dbc7Sjsg 		scheduler->thread[i] = kthread_run(workload_thread, engine,
1273c349dbc7Sjsg 						   "gvt:%s", engine->name);
1274c349dbc7Sjsg 		if (IS_ERR(scheduler->thread[i])) {
1275c349dbc7Sjsg 			gvt_err("fail to create workload thread\n");
1276c349dbc7Sjsg 			ret = PTR_ERR(scheduler->thread[i]);
1277c349dbc7Sjsg 			goto err;
1278c349dbc7Sjsg 		}
1279c349dbc7Sjsg 
1280c349dbc7Sjsg 		gvt->shadow_ctx_notifier_block[i].notifier_call =
1281c349dbc7Sjsg 					shadow_context_status_change;
1282c349dbc7Sjsg 		atomic_notifier_chain_register(&engine->context_status_notifier,
1283c349dbc7Sjsg 					&gvt->shadow_ctx_notifier_block[i]);
1284c349dbc7Sjsg 	}
1285c349dbc7Sjsg 
1286c349dbc7Sjsg 	return 0;
1287c349dbc7Sjsg 
1288c349dbc7Sjsg err:
1289c349dbc7Sjsg 	intel_gvt_clean_workload_scheduler(gvt);
1290c349dbc7Sjsg 	return ret;
1291c349dbc7Sjsg }
1292c349dbc7Sjsg 
1293c349dbc7Sjsg static void
i915_context_ppgtt_root_restore(struct intel_vgpu_submission * s,struct i915_ppgtt * ppgtt)1294c349dbc7Sjsg i915_context_ppgtt_root_restore(struct intel_vgpu_submission *s,
1295c349dbc7Sjsg 				struct i915_ppgtt *ppgtt)
1296c349dbc7Sjsg {
1297c349dbc7Sjsg 	int i;
1298c349dbc7Sjsg 
1299c349dbc7Sjsg 	if (i915_vm_is_4lvl(&ppgtt->vm)) {
1300ad8b1aafSjsg 		set_dma_address(ppgtt->pd, s->i915_context_pml4);
1301c349dbc7Sjsg 	} else {
1302c349dbc7Sjsg 		for (i = 0; i < GEN8_3LVL_PDPES; i++) {
1303c349dbc7Sjsg 			struct i915_page_directory * const pd =
1304c349dbc7Sjsg 				i915_pd_entry(ppgtt->pd, i);
1305c349dbc7Sjsg 
1306ad8b1aafSjsg 			set_dma_address(pd, s->i915_context_pdps[i]);
1307c349dbc7Sjsg 		}
1308c349dbc7Sjsg 	}
1309c349dbc7Sjsg }
1310c349dbc7Sjsg 
1311c349dbc7Sjsg /**
1312c349dbc7Sjsg  * intel_vgpu_clean_submission - free submission-related resource for vGPU
1313c349dbc7Sjsg  * @vgpu: a vGPU
1314c349dbc7Sjsg  *
1315c349dbc7Sjsg  * This function is called when a vGPU is being destroyed.
1316c349dbc7Sjsg  *
1317c349dbc7Sjsg  */
intel_vgpu_clean_submission(struct intel_vgpu * vgpu)1318c349dbc7Sjsg void intel_vgpu_clean_submission(struct intel_vgpu *vgpu)
1319c349dbc7Sjsg {
1320c349dbc7Sjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
1321c349dbc7Sjsg 	struct intel_engine_cs *engine;
1322c349dbc7Sjsg 	enum intel_engine_id id;
1323c349dbc7Sjsg 
1324c349dbc7Sjsg 	intel_vgpu_select_submission_ops(vgpu, ALL_ENGINES, 0);
1325c349dbc7Sjsg 
1326c349dbc7Sjsg 	i915_context_ppgtt_root_restore(s, i915_vm_to_ppgtt(s->shadow[0]->vm));
1327c349dbc7Sjsg 	for_each_engine(engine, vgpu->gvt->gt, id)
1328ad8b1aafSjsg 		intel_context_put(s->shadow[id]);
1329c349dbc7Sjsg 
1330c349dbc7Sjsg 	kmem_cache_destroy(s->workloads);
1331c349dbc7Sjsg }
1332c349dbc7Sjsg 
1333c349dbc7Sjsg 
1334c349dbc7Sjsg /**
1335c349dbc7Sjsg  * intel_vgpu_reset_submission - reset submission-related resource for vGPU
1336c349dbc7Sjsg  * @vgpu: a vGPU
1337c349dbc7Sjsg  * @engine_mask: engines expected to be reset
1338c349dbc7Sjsg  *
1339c349dbc7Sjsg  * This function is called when a vGPU is being destroyed.
1340c349dbc7Sjsg  *
1341c349dbc7Sjsg  */
intel_vgpu_reset_submission(struct intel_vgpu * vgpu,intel_engine_mask_t engine_mask)1342c349dbc7Sjsg void intel_vgpu_reset_submission(struct intel_vgpu *vgpu,
1343c349dbc7Sjsg 				 intel_engine_mask_t engine_mask)
1344c349dbc7Sjsg {
1345c349dbc7Sjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
1346c349dbc7Sjsg 
1347c349dbc7Sjsg 	if (!s->active)
1348c349dbc7Sjsg 		return;
1349c349dbc7Sjsg 
1350c349dbc7Sjsg 	intel_vgpu_clean_workloads(vgpu, engine_mask);
1351c349dbc7Sjsg 	s->ops->reset(vgpu, engine_mask);
1352c349dbc7Sjsg }
1353c349dbc7Sjsg 
1354c349dbc7Sjsg static void
i915_context_ppgtt_root_save(struct intel_vgpu_submission * s,struct i915_ppgtt * ppgtt)1355c349dbc7Sjsg i915_context_ppgtt_root_save(struct intel_vgpu_submission *s,
1356c349dbc7Sjsg 			     struct i915_ppgtt *ppgtt)
1357c349dbc7Sjsg {
1358c349dbc7Sjsg 	int i;
1359c349dbc7Sjsg 
1360c349dbc7Sjsg 	if (i915_vm_is_4lvl(&ppgtt->vm)) {
1361c349dbc7Sjsg 		s->i915_context_pml4 = px_dma(ppgtt->pd);
1362c349dbc7Sjsg 	} else {
1363c349dbc7Sjsg 		for (i = 0; i < GEN8_3LVL_PDPES; i++) {
1364c349dbc7Sjsg 			struct i915_page_directory * const pd =
1365c349dbc7Sjsg 				i915_pd_entry(ppgtt->pd, i);
1366c349dbc7Sjsg 
1367c349dbc7Sjsg 			s->i915_context_pdps[i] = px_dma(pd);
1368c349dbc7Sjsg 		}
1369c349dbc7Sjsg 	}
1370c349dbc7Sjsg }
1371c349dbc7Sjsg 
1372c349dbc7Sjsg /**
1373c349dbc7Sjsg  * intel_vgpu_setup_submission - setup submission-related resource for vGPU
1374c349dbc7Sjsg  * @vgpu: a vGPU
1375c349dbc7Sjsg  *
1376c349dbc7Sjsg  * This function is called when a vGPU is being created.
1377c349dbc7Sjsg  *
1378c349dbc7Sjsg  * Returns:
1379c349dbc7Sjsg  * Zero on success, negative error code if failed.
1380c349dbc7Sjsg  *
1381c349dbc7Sjsg  */
intel_vgpu_setup_submission(struct intel_vgpu * vgpu)1382c349dbc7Sjsg int intel_vgpu_setup_submission(struct intel_vgpu *vgpu)
1383c349dbc7Sjsg {
1384c349dbc7Sjsg 	struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
1385c349dbc7Sjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
1386c349dbc7Sjsg 	struct intel_engine_cs *engine;
1387c349dbc7Sjsg 	struct i915_ppgtt *ppgtt;
1388c349dbc7Sjsg 	enum intel_engine_id i;
1389c349dbc7Sjsg 	int ret;
1390c349dbc7Sjsg 
13911bb76ff1Sjsg 	ppgtt = i915_ppgtt_create(to_gt(i915), I915_BO_ALLOC_PM_EARLY);
1392c349dbc7Sjsg 	if (IS_ERR(ppgtt))
1393c349dbc7Sjsg 		return PTR_ERR(ppgtt);
1394c349dbc7Sjsg 
1395c349dbc7Sjsg 	i915_context_ppgtt_root_save(s, ppgtt);
1396c349dbc7Sjsg 
1397c349dbc7Sjsg 	for_each_engine(engine, vgpu->gvt->gt, i) {
1398c349dbc7Sjsg 		struct intel_context *ce;
1399c349dbc7Sjsg 
1400c349dbc7Sjsg 		INIT_LIST_HEAD(&s->workload_q_head[i]);
1401c349dbc7Sjsg 		s->shadow[i] = ERR_PTR(-EINVAL);
1402c349dbc7Sjsg 
1403c349dbc7Sjsg 		ce = intel_context_create(engine);
1404c349dbc7Sjsg 		if (IS_ERR(ce)) {
1405c349dbc7Sjsg 			ret = PTR_ERR(ce);
1406c349dbc7Sjsg 			goto out_shadow_ctx;
1407c349dbc7Sjsg 		}
1408c349dbc7Sjsg 
1409c349dbc7Sjsg 		i915_vm_put(ce->vm);
1410c349dbc7Sjsg 		ce->vm = i915_vm_get(&ppgtt->vm);
1411c349dbc7Sjsg 		intel_context_set_single_submission(ce);
1412c349dbc7Sjsg 
1413c349dbc7Sjsg 		/* Max ring buffer size */
14145ca02815Sjsg 		if (!intel_uc_wants_guc_submission(&engine->gt->uc))
14155ca02815Sjsg 			ce->ring_size = SZ_2M;
1416c349dbc7Sjsg 
1417c349dbc7Sjsg 		s->shadow[i] = ce;
1418c349dbc7Sjsg 	}
1419c349dbc7Sjsg 
1420c349dbc7Sjsg 	bitmap_zero(s->shadow_ctx_desc_updated, I915_NUM_ENGINES);
1421c349dbc7Sjsg 
1422c349dbc7Sjsg 	s->workloads = kmem_cache_create_usercopy("gvt-g_vgpu_workload",
1423c349dbc7Sjsg 						  sizeof(struct intel_vgpu_workload), 0,
1424c349dbc7Sjsg 						  SLAB_HWCACHE_ALIGN,
1425c349dbc7Sjsg 						  offsetof(struct intel_vgpu_workload, rb_tail),
1426c349dbc7Sjsg 						  sizeof_field(struct intel_vgpu_workload, rb_tail),
1427c349dbc7Sjsg 						  NULL);
1428c349dbc7Sjsg 
1429c349dbc7Sjsg 	if (!s->workloads) {
1430c349dbc7Sjsg 		ret = -ENOMEM;
1431c349dbc7Sjsg 		goto out_shadow_ctx;
1432c349dbc7Sjsg 	}
1433c349dbc7Sjsg 
1434c349dbc7Sjsg 	atomic_set(&s->running_workload_num, 0);
1435c349dbc7Sjsg 	bitmap_zero(s->tlb_handle_pending, I915_NUM_ENGINES);
1436c349dbc7Sjsg 
1437ad8b1aafSjsg 	memset(s->last_ctx, 0, sizeof(s->last_ctx));
1438ad8b1aafSjsg 
1439c349dbc7Sjsg 	i915_vm_put(&ppgtt->vm);
1440c349dbc7Sjsg 	return 0;
1441c349dbc7Sjsg 
1442c349dbc7Sjsg out_shadow_ctx:
1443c349dbc7Sjsg 	i915_context_ppgtt_root_restore(s, ppgtt);
1444c349dbc7Sjsg 	for_each_engine(engine, vgpu->gvt->gt, i) {
1445c349dbc7Sjsg 		if (IS_ERR(s->shadow[i]))
1446c349dbc7Sjsg 			break;
1447c349dbc7Sjsg 
1448c349dbc7Sjsg 		intel_context_put(s->shadow[i]);
1449c349dbc7Sjsg 	}
1450c349dbc7Sjsg 	i915_vm_put(&ppgtt->vm);
1451c349dbc7Sjsg 	return ret;
1452c349dbc7Sjsg }
1453c349dbc7Sjsg 
1454c349dbc7Sjsg /**
1455c349dbc7Sjsg  * intel_vgpu_select_submission_ops - select virtual submission interface
1456c349dbc7Sjsg  * @vgpu: a vGPU
1457c349dbc7Sjsg  * @engine_mask: either ALL_ENGINES or target engine mask
1458c349dbc7Sjsg  * @interface: expected vGPU virtual submission interface
1459c349dbc7Sjsg  *
1460c349dbc7Sjsg  * This function is called when guest configures submission interface.
1461c349dbc7Sjsg  *
1462c349dbc7Sjsg  * Returns:
1463c349dbc7Sjsg  * Zero on success, negative error code if failed.
1464c349dbc7Sjsg  *
1465c349dbc7Sjsg  */
intel_vgpu_select_submission_ops(struct intel_vgpu * vgpu,intel_engine_mask_t engine_mask,unsigned int interface)1466c349dbc7Sjsg int intel_vgpu_select_submission_ops(struct intel_vgpu *vgpu,
1467c349dbc7Sjsg 				     intel_engine_mask_t engine_mask,
1468c349dbc7Sjsg 				     unsigned int interface)
1469c349dbc7Sjsg {
1470c349dbc7Sjsg 	struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
1471c349dbc7Sjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
1472c349dbc7Sjsg 	const struct intel_vgpu_submission_ops *ops[] = {
1473c349dbc7Sjsg 		[INTEL_VGPU_EXECLIST_SUBMISSION] =
1474c349dbc7Sjsg 			&intel_vgpu_execlist_submission_ops,
1475c349dbc7Sjsg 	};
1476c349dbc7Sjsg 	int ret;
1477c349dbc7Sjsg 
1478c349dbc7Sjsg 	if (drm_WARN_ON(&i915->drm, interface >= ARRAY_SIZE(ops)))
1479c349dbc7Sjsg 		return -EINVAL;
1480c349dbc7Sjsg 
1481c349dbc7Sjsg 	if (drm_WARN_ON(&i915->drm,
1482c349dbc7Sjsg 			interface == 0 && engine_mask != ALL_ENGINES))
1483c349dbc7Sjsg 		return -EINVAL;
1484c349dbc7Sjsg 
1485c349dbc7Sjsg 	if (s->active)
1486c349dbc7Sjsg 		s->ops->clean(vgpu, engine_mask);
1487c349dbc7Sjsg 
1488c349dbc7Sjsg 	if (interface == 0) {
1489c349dbc7Sjsg 		s->ops = NULL;
1490c349dbc7Sjsg 		s->virtual_submission_interface = 0;
1491c349dbc7Sjsg 		s->active = false;
1492c349dbc7Sjsg 		gvt_dbg_core("vgpu%d: remove submission ops\n", vgpu->id);
1493c349dbc7Sjsg 		return 0;
1494c349dbc7Sjsg 	}
1495c349dbc7Sjsg 
1496c349dbc7Sjsg 	ret = ops[interface]->init(vgpu, engine_mask);
1497c349dbc7Sjsg 	if (ret)
1498c349dbc7Sjsg 		return ret;
1499c349dbc7Sjsg 
1500c349dbc7Sjsg 	s->ops = ops[interface];
1501c349dbc7Sjsg 	s->virtual_submission_interface = interface;
1502c349dbc7Sjsg 	s->active = true;
1503c349dbc7Sjsg 
1504c349dbc7Sjsg 	gvt_dbg_core("vgpu%d: activate ops [ %s ]\n",
1505c349dbc7Sjsg 			vgpu->id, s->ops->name);
1506c349dbc7Sjsg 
1507c349dbc7Sjsg 	return 0;
1508c349dbc7Sjsg }
1509c349dbc7Sjsg 
1510c349dbc7Sjsg /**
1511c349dbc7Sjsg  * intel_vgpu_destroy_workload - destroy a vGPU workload
1512c349dbc7Sjsg  * @workload: workload to destroy
1513c349dbc7Sjsg  *
1514c349dbc7Sjsg  * This function is called when destroy a vGPU workload.
1515c349dbc7Sjsg  *
1516c349dbc7Sjsg  */
intel_vgpu_destroy_workload(struct intel_vgpu_workload * workload)1517c349dbc7Sjsg void intel_vgpu_destroy_workload(struct intel_vgpu_workload *workload)
1518c349dbc7Sjsg {
1519c349dbc7Sjsg 	struct intel_vgpu_submission *s = &workload->vgpu->submission;
1520c349dbc7Sjsg 
1521ad8b1aafSjsg 	intel_context_unpin(s->shadow[workload->engine->id]);
1522c349dbc7Sjsg 	release_shadow_batch_buffer(workload);
1523c349dbc7Sjsg 	release_shadow_wa_ctx(&workload->wa_ctx);
1524c349dbc7Sjsg 
1525ad8b1aafSjsg 	if (!list_empty(&workload->lri_shadow_mm)) {
1526ad8b1aafSjsg 		struct intel_vgpu_mm *m, *mm;
1527ad8b1aafSjsg 		list_for_each_entry_safe(m, mm, &workload->lri_shadow_mm,
1528ad8b1aafSjsg 					 ppgtt_mm.link) {
1529ad8b1aafSjsg 			list_del(&m->ppgtt_mm.link);
1530ad8b1aafSjsg 			intel_vgpu_mm_put(m);
1531ad8b1aafSjsg 		}
1532ad8b1aafSjsg 	}
1533ad8b1aafSjsg 
1534ad8b1aafSjsg 	GEM_BUG_ON(!list_empty(&workload->lri_shadow_mm));
1535c349dbc7Sjsg 	if (workload->shadow_mm)
1536c349dbc7Sjsg 		intel_vgpu_mm_put(workload->shadow_mm);
1537c349dbc7Sjsg 
1538c349dbc7Sjsg 	kmem_cache_free(s->workloads, workload);
1539c349dbc7Sjsg }
1540c349dbc7Sjsg 
1541c349dbc7Sjsg static struct intel_vgpu_workload *
alloc_workload(struct intel_vgpu * vgpu)1542c349dbc7Sjsg alloc_workload(struct intel_vgpu *vgpu)
1543c349dbc7Sjsg {
1544c349dbc7Sjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
1545c349dbc7Sjsg 	struct intel_vgpu_workload *workload;
1546c349dbc7Sjsg 
1547c349dbc7Sjsg 	workload = kmem_cache_zalloc(s->workloads, GFP_KERNEL);
1548c349dbc7Sjsg 	if (!workload)
1549c349dbc7Sjsg 		return ERR_PTR(-ENOMEM);
1550c349dbc7Sjsg 
1551c349dbc7Sjsg 	INIT_LIST_HEAD(&workload->list);
1552c349dbc7Sjsg 	INIT_LIST_HEAD(&workload->shadow_bb);
1553ad8b1aafSjsg 	INIT_LIST_HEAD(&workload->lri_shadow_mm);
1554c349dbc7Sjsg 
1555c349dbc7Sjsg 	init_waitqueue_head(&workload->shadow_ctx_status_wq);
1556c349dbc7Sjsg 	atomic_set(&workload->shadow_ctx_active, 0);
1557c349dbc7Sjsg 
1558c349dbc7Sjsg 	workload->status = -EINPROGRESS;
1559c349dbc7Sjsg 	workload->vgpu = vgpu;
1560c349dbc7Sjsg 
1561c349dbc7Sjsg 	return workload;
1562c349dbc7Sjsg }
1563c349dbc7Sjsg 
1564c349dbc7Sjsg #define RING_CTX_OFF(x) \
1565c349dbc7Sjsg 	offsetof(struct execlist_ring_context, x)
1566c349dbc7Sjsg 
read_guest_pdps(struct intel_vgpu * vgpu,u64 ring_context_gpa,u32 pdp[8])1567c349dbc7Sjsg static void read_guest_pdps(struct intel_vgpu *vgpu,
1568c349dbc7Sjsg 		u64 ring_context_gpa, u32 pdp[8])
1569c349dbc7Sjsg {
1570c349dbc7Sjsg 	u64 gpa;
1571c349dbc7Sjsg 	int i;
1572c349dbc7Sjsg 
1573c349dbc7Sjsg 	gpa = ring_context_gpa + RING_CTX_OFF(pdps[0].val);
1574c349dbc7Sjsg 
1575c349dbc7Sjsg 	for (i = 0; i < 8; i++)
15761bb76ff1Sjsg 		intel_gvt_read_gpa(vgpu,
1577c349dbc7Sjsg 				gpa + i * 8, &pdp[7 - i], 4);
1578c349dbc7Sjsg }
1579c349dbc7Sjsg 
prepare_mm(struct intel_vgpu_workload * workload)1580c349dbc7Sjsg static int prepare_mm(struct intel_vgpu_workload *workload)
1581c349dbc7Sjsg {
1582c349dbc7Sjsg 	struct execlist_ctx_descriptor_format *desc = &workload->ctx_desc;
1583c349dbc7Sjsg 	struct intel_vgpu_mm *mm;
1584c349dbc7Sjsg 	struct intel_vgpu *vgpu = workload->vgpu;
1585c349dbc7Sjsg 	enum intel_gvt_gtt_type root_entry_type;
1586c349dbc7Sjsg 	u64 pdps[GVT_RING_CTX_NR_PDPS];
1587c349dbc7Sjsg 
1588c349dbc7Sjsg 	switch (desc->addressing_mode) {
1589c349dbc7Sjsg 	case 1: /* legacy 32-bit */
1590c349dbc7Sjsg 		root_entry_type = GTT_TYPE_PPGTT_ROOT_L3_ENTRY;
1591c349dbc7Sjsg 		break;
1592c349dbc7Sjsg 	case 3: /* legacy 64-bit */
1593c349dbc7Sjsg 		root_entry_type = GTT_TYPE_PPGTT_ROOT_L4_ENTRY;
1594c349dbc7Sjsg 		break;
1595c349dbc7Sjsg 	default:
1596c349dbc7Sjsg 		gvt_vgpu_err("Advanced Context mode(SVM) is not supported!\n");
1597c349dbc7Sjsg 		return -EINVAL;
1598c349dbc7Sjsg 	}
1599c349dbc7Sjsg 
1600c349dbc7Sjsg 	read_guest_pdps(workload->vgpu, workload->ring_context_gpa, (void *)pdps);
1601c349dbc7Sjsg 
1602c349dbc7Sjsg 	mm = intel_vgpu_get_ppgtt_mm(workload->vgpu, root_entry_type, pdps);
1603c349dbc7Sjsg 	if (IS_ERR(mm))
1604c349dbc7Sjsg 		return PTR_ERR(mm);
1605c349dbc7Sjsg 
1606c349dbc7Sjsg 	workload->shadow_mm = mm;
1607c349dbc7Sjsg 	return 0;
1608c349dbc7Sjsg }
1609c349dbc7Sjsg 
1610c349dbc7Sjsg #define same_context(a, b) (((a)->context_id == (b)->context_id) && \
1611c349dbc7Sjsg 		((a)->lrca == (b)->lrca))
1612c349dbc7Sjsg 
1613c349dbc7Sjsg /**
1614c349dbc7Sjsg  * intel_vgpu_create_workload - create a vGPU workload
1615c349dbc7Sjsg  * @vgpu: a vGPU
1616c349dbc7Sjsg  * @engine: the engine
1617c349dbc7Sjsg  * @desc: a guest context descriptor
1618c349dbc7Sjsg  *
1619c349dbc7Sjsg  * This function is called when creating a vGPU workload.
1620c349dbc7Sjsg  *
1621c349dbc7Sjsg  * Returns:
1622c349dbc7Sjsg  * struct intel_vgpu_workload * on success, negative error code in
1623c349dbc7Sjsg  * pointer if failed.
1624c349dbc7Sjsg  *
1625c349dbc7Sjsg  */
1626c349dbc7Sjsg struct intel_vgpu_workload *
intel_vgpu_create_workload(struct intel_vgpu * vgpu,const struct intel_engine_cs * engine,struct execlist_ctx_descriptor_format * desc)1627c349dbc7Sjsg intel_vgpu_create_workload(struct intel_vgpu *vgpu,
1628c349dbc7Sjsg 			   const struct intel_engine_cs *engine,
1629c349dbc7Sjsg 			   struct execlist_ctx_descriptor_format *desc)
1630c349dbc7Sjsg {
1631c349dbc7Sjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
1632c349dbc7Sjsg 	struct list_head *q = workload_q_head(vgpu, engine);
1633c349dbc7Sjsg 	struct intel_vgpu_workload *last_workload = NULL;
1634c349dbc7Sjsg 	struct intel_vgpu_workload *workload = NULL;
1635c349dbc7Sjsg 	u64 ring_context_gpa;
1636c349dbc7Sjsg 	u32 head, tail, start, ctl, ctx_ctl, per_ctx, indirect_ctx;
1637c349dbc7Sjsg 	u32 guest_head;
1638c349dbc7Sjsg 	int ret;
1639c349dbc7Sjsg 
1640c349dbc7Sjsg 	ring_context_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm,
1641c349dbc7Sjsg 			(u32)((desc->lrca + 1) << I915_GTT_PAGE_SHIFT));
1642c349dbc7Sjsg 	if (ring_context_gpa == INTEL_GVT_INVALID_ADDR) {
1643c349dbc7Sjsg 		gvt_vgpu_err("invalid guest context LRCA: %x\n", desc->lrca);
1644c349dbc7Sjsg 		return ERR_PTR(-EINVAL);
1645c349dbc7Sjsg 	}
1646c349dbc7Sjsg 
16471bb76ff1Sjsg 	intel_gvt_read_gpa(vgpu, ring_context_gpa +
1648c349dbc7Sjsg 			RING_CTX_OFF(ring_header.val), &head, 4);
1649c349dbc7Sjsg 
16501bb76ff1Sjsg 	intel_gvt_read_gpa(vgpu, ring_context_gpa +
1651c349dbc7Sjsg 			RING_CTX_OFF(ring_tail.val), &tail, 4);
1652c349dbc7Sjsg 
1653c349dbc7Sjsg 	guest_head = head;
1654c349dbc7Sjsg 
1655c349dbc7Sjsg 	head &= RB_HEAD_OFF_MASK;
1656c349dbc7Sjsg 	tail &= RB_TAIL_OFF_MASK;
1657c349dbc7Sjsg 
1658c349dbc7Sjsg 	list_for_each_entry_reverse(last_workload, q, list) {
1659c349dbc7Sjsg 
1660c349dbc7Sjsg 		if (same_context(&last_workload->ctx_desc, desc)) {
1661c349dbc7Sjsg 			gvt_dbg_el("ring %s cur workload == last\n",
1662c349dbc7Sjsg 				   engine->name);
1663c349dbc7Sjsg 			gvt_dbg_el("ctx head %x real head %lx\n", head,
1664c349dbc7Sjsg 				   last_workload->rb_tail);
1665c349dbc7Sjsg 			/*
1666c349dbc7Sjsg 			 * cannot use guest context head pointer here,
1667c349dbc7Sjsg 			 * as it might not be updated at this time
1668c349dbc7Sjsg 			 */
1669c349dbc7Sjsg 			head = last_workload->rb_tail;
1670c349dbc7Sjsg 			break;
1671c349dbc7Sjsg 		}
1672c349dbc7Sjsg 	}
1673c349dbc7Sjsg 
1674c349dbc7Sjsg 	gvt_dbg_el("ring %s begin a new workload\n", engine->name);
1675c349dbc7Sjsg 
1676c349dbc7Sjsg 	/* record some ring buffer register values for scan and shadow */
16771bb76ff1Sjsg 	intel_gvt_read_gpa(vgpu, ring_context_gpa +
1678c349dbc7Sjsg 			RING_CTX_OFF(rb_start.val), &start, 4);
16791bb76ff1Sjsg 	intel_gvt_read_gpa(vgpu, ring_context_gpa +
1680c349dbc7Sjsg 			RING_CTX_OFF(rb_ctrl.val), &ctl, 4);
16811bb76ff1Sjsg 	intel_gvt_read_gpa(vgpu, ring_context_gpa +
1682c349dbc7Sjsg 			RING_CTX_OFF(ctx_ctrl.val), &ctx_ctl, 4);
1683c349dbc7Sjsg 
1684c349dbc7Sjsg 	if (!intel_gvt_ggtt_validate_range(vgpu, start,
1685c349dbc7Sjsg 				_RING_CTL_BUF_SIZE(ctl))) {
1686c349dbc7Sjsg 		gvt_vgpu_err("context contain invalid rb at: 0x%x\n", start);
1687c349dbc7Sjsg 		return ERR_PTR(-EINVAL);
1688c349dbc7Sjsg 	}
1689c349dbc7Sjsg 
1690c349dbc7Sjsg 	workload = alloc_workload(vgpu);
1691c349dbc7Sjsg 	if (IS_ERR(workload))
1692c349dbc7Sjsg 		return workload;
1693c349dbc7Sjsg 
1694c349dbc7Sjsg 	workload->engine = engine;
1695c349dbc7Sjsg 	workload->ctx_desc = *desc;
1696c349dbc7Sjsg 	workload->ring_context_gpa = ring_context_gpa;
1697c349dbc7Sjsg 	workload->rb_head = head;
1698c349dbc7Sjsg 	workload->guest_rb_head = guest_head;
1699c349dbc7Sjsg 	workload->rb_tail = tail;
1700c349dbc7Sjsg 	workload->rb_start = start;
1701c349dbc7Sjsg 	workload->rb_ctl = ctl;
1702c349dbc7Sjsg 
1703c349dbc7Sjsg 	if (engine->id == RCS0) {
17041bb76ff1Sjsg 		intel_gvt_read_gpa(vgpu, ring_context_gpa +
1705c349dbc7Sjsg 			RING_CTX_OFF(bb_per_ctx_ptr.val), &per_ctx, 4);
17061bb76ff1Sjsg 		intel_gvt_read_gpa(vgpu, ring_context_gpa +
1707c349dbc7Sjsg 			RING_CTX_OFF(rcs_indirect_ctx.val), &indirect_ctx, 4);
1708c349dbc7Sjsg 
1709c349dbc7Sjsg 		workload->wa_ctx.indirect_ctx.guest_gma =
1710c349dbc7Sjsg 			indirect_ctx & INDIRECT_CTX_ADDR_MASK;
1711c349dbc7Sjsg 		workload->wa_ctx.indirect_ctx.size =
1712c349dbc7Sjsg 			(indirect_ctx & INDIRECT_CTX_SIZE_MASK) *
1713c349dbc7Sjsg 			CACHELINE_BYTES;
1714c349dbc7Sjsg 
1715c349dbc7Sjsg 		if (workload->wa_ctx.indirect_ctx.size != 0) {
1716c349dbc7Sjsg 			if (!intel_gvt_ggtt_validate_range(vgpu,
1717c349dbc7Sjsg 				workload->wa_ctx.indirect_ctx.guest_gma,
1718c349dbc7Sjsg 				workload->wa_ctx.indirect_ctx.size)) {
1719c349dbc7Sjsg 				gvt_vgpu_err("invalid wa_ctx at: 0x%lx\n",
1720c349dbc7Sjsg 				    workload->wa_ctx.indirect_ctx.guest_gma);
1721c349dbc7Sjsg 				kmem_cache_free(s->workloads, workload);
1722c349dbc7Sjsg 				return ERR_PTR(-EINVAL);
1723c349dbc7Sjsg 			}
1724c349dbc7Sjsg 		}
1725c349dbc7Sjsg 
1726c349dbc7Sjsg 		workload->wa_ctx.per_ctx.guest_gma =
1727c349dbc7Sjsg 			per_ctx & PER_CTX_ADDR_MASK;
1728c349dbc7Sjsg 		workload->wa_ctx.per_ctx.valid = per_ctx & 1;
1729c349dbc7Sjsg 		if (workload->wa_ctx.per_ctx.valid) {
1730c349dbc7Sjsg 			if (!intel_gvt_ggtt_validate_range(vgpu,
1731c349dbc7Sjsg 				workload->wa_ctx.per_ctx.guest_gma,
1732c349dbc7Sjsg 				CACHELINE_BYTES)) {
1733c349dbc7Sjsg 				gvt_vgpu_err("invalid per_ctx at: 0x%lx\n",
1734c349dbc7Sjsg 					workload->wa_ctx.per_ctx.guest_gma);
1735c349dbc7Sjsg 				kmem_cache_free(s->workloads, workload);
1736c349dbc7Sjsg 				return ERR_PTR(-EINVAL);
1737c349dbc7Sjsg 			}
1738c349dbc7Sjsg 		}
1739c349dbc7Sjsg 	}
1740c349dbc7Sjsg 
1741c349dbc7Sjsg 	gvt_dbg_el("workload %p ring %s head %x tail %x start %x ctl %x\n",
1742c349dbc7Sjsg 		   workload, engine->name, head, tail, start, ctl);
1743c349dbc7Sjsg 
1744c349dbc7Sjsg 	ret = prepare_mm(workload);
1745c349dbc7Sjsg 	if (ret) {
1746c349dbc7Sjsg 		kmem_cache_free(s->workloads, workload);
1747c349dbc7Sjsg 		return ERR_PTR(ret);
1748c349dbc7Sjsg 	}
1749c349dbc7Sjsg 
1750c349dbc7Sjsg 	/* Only scan and shadow the first workload in the queue
1751c349dbc7Sjsg 	 * as there is only one pre-allocated buf-obj for shadow.
1752c349dbc7Sjsg 	 */
1753c349dbc7Sjsg 	if (list_empty(q)) {
1754c349dbc7Sjsg 		intel_wakeref_t wakeref;
1755c349dbc7Sjsg 
1756c349dbc7Sjsg 		with_intel_runtime_pm(engine->gt->uncore->rpm, wakeref)
1757c349dbc7Sjsg 			ret = intel_gvt_scan_and_shadow_workload(workload);
1758c349dbc7Sjsg 	}
1759c349dbc7Sjsg 
1760c349dbc7Sjsg 	if (ret) {
1761c349dbc7Sjsg 		if (vgpu_is_vm_unhealthy(ret))
1762c349dbc7Sjsg 			enter_failsafe_mode(vgpu, GVT_FAILSAFE_GUEST_ERR);
1763c349dbc7Sjsg 		intel_vgpu_destroy_workload(workload);
1764c349dbc7Sjsg 		return ERR_PTR(ret);
1765c349dbc7Sjsg 	}
1766c349dbc7Sjsg 
1767ad8b1aafSjsg 	ret = intel_context_pin(s->shadow[engine->id]);
1768ad8b1aafSjsg 	if (ret) {
1769ad8b1aafSjsg 		intel_vgpu_destroy_workload(workload);
1770ad8b1aafSjsg 		return ERR_PTR(ret);
1771ad8b1aafSjsg 	}
1772ad8b1aafSjsg 
1773c349dbc7Sjsg 	return workload;
1774c349dbc7Sjsg }
1775c349dbc7Sjsg 
1776c349dbc7Sjsg /**
1777c349dbc7Sjsg  * intel_vgpu_queue_workload - Qeue a vGPU workload
1778c349dbc7Sjsg  * @workload: the workload to queue in
1779c349dbc7Sjsg  */
intel_vgpu_queue_workload(struct intel_vgpu_workload * workload)1780c349dbc7Sjsg void intel_vgpu_queue_workload(struct intel_vgpu_workload *workload)
1781c349dbc7Sjsg {
1782c349dbc7Sjsg 	list_add_tail(&workload->list,
1783c349dbc7Sjsg 		      workload_q_head(workload->vgpu, workload->engine));
1784c349dbc7Sjsg 	intel_gvt_kick_schedule(workload->vgpu->gvt);
1785c349dbc7Sjsg 	wake_up(&workload->vgpu->gvt->scheduler.waitq[workload->engine->id]);
1786c349dbc7Sjsg }
1787