xref: /openbsd/sys/dev/pci/drm/i915/gvt/execlist.c (revision 1bb76ff1)
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  *    Zhiyuan Lv <zhiyuan.lv@intel.com>
25c349dbc7Sjsg  *    Zhi Wang <zhi.a.wang@intel.com>
26c349dbc7Sjsg  *
27c349dbc7Sjsg  * Contributors:
28c349dbc7Sjsg  *    Min He <min.he@intel.com>
29c349dbc7Sjsg  *    Bing Niu <bing.niu@intel.com>
30c349dbc7Sjsg  *    Ping Gao <ping.a.gao@intel.com>
31c349dbc7Sjsg  *    Tina Zhang <tina.zhang@intel.com>
32c349dbc7Sjsg  *
33c349dbc7Sjsg  */
34c349dbc7Sjsg 
35c349dbc7Sjsg #include "i915_drv.h"
36c349dbc7Sjsg #include "gvt.h"
37c349dbc7Sjsg 
38c349dbc7Sjsg #define _EL_OFFSET_STATUS       0x234
39c349dbc7Sjsg #define _EL_OFFSET_STATUS_BUF   0x370
40c349dbc7Sjsg #define _EL_OFFSET_STATUS_PTR   0x3A0
41c349dbc7Sjsg 
42c349dbc7Sjsg #define execlist_ring_mmio(e, offset) ((e)->mmio_base + (offset))
43c349dbc7Sjsg 
44c349dbc7Sjsg #define valid_context(ctx) ((ctx)->valid)
45c349dbc7Sjsg #define same_context(a, b) (((a)->context_id == (b)->context_id) && \
46c349dbc7Sjsg 		((a)->lrca == (b)->lrca))
47c349dbc7Sjsg 
48c349dbc7Sjsg static int context_switch_events[] = {
49c349dbc7Sjsg 	[RCS0]  = RCS_AS_CONTEXT_SWITCH,
50c349dbc7Sjsg 	[BCS0]  = BCS_AS_CONTEXT_SWITCH,
51c349dbc7Sjsg 	[VCS0]  = VCS_AS_CONTEXT_SWITCH,
52c349dbc7Sjsg 	[VCS1]  = VCS2_AS_CONTEXT_SWITCH,
53c349dbc7Sjsg 	[VECS0] = VECS_AS_CONTEXT_SWITCH,
54c349dbc7Sjsg };
55c349dbc7Sjsg 
to_context_switch_event(const struct intel_engine_cs * engine)56c349dbc7Sjsg static int to_context_switch_event(const struct intel_engine_cs *engine)
57c349dbc7Sjsg {
58c349dbc7Sjsg 	if (WARN_ON(engine->id >= ARRAY_SIZE(context_switch_events)))
59c349dbc7Sjsg 		return -EINVAL;
60c349dbc7Sjsg 
61c349dbc7Sjsg 	return context_switch_events[engine->id];
62c349dbc7Sjsg }
63c349dbc7Sjsg 
switch_virtual_execlist_slot(struct intel_vgpu_execlist * execlist)64c349dbc7Sjsg static void switch_virtual_execlist_slot(struct intel_vgpu_execlist *execlist)
65c349dbc7Sjsg {
66c349dbc7Sjsg 	gvt_dbg_el("[before] running slot %d/context %x pending slot %d\n",
67c349dbc7Sjsg 			execlist->running_slot ?
68c349dbc7Sjsg 			execlist->running_slot->index : -1,
69c349dbc7Sjsg 			execlist->running_context ?
70c349dbc7Sjsg 			execlist->running_context->context_id : 0,
71c349dbc7Sjsg 			execlist->pending_slot ?
72c349dbc7Sjsg 			execlist->pending_slot->index : -1);
73c349dbc7Sjsg 
74c349dbc7Sjsg 	execlist->running_slot = execlist->pending_slot;
75c349dbc7Sjsg 	execlist->pending_slot = NULL;
76c349dbc7Sjsg 	execlist->running_context = execlist->running_context ?
77c349dbc7Sjsg 		&execlist->running_slot->ctx[0] : NULL;
78c349dbc7Sjsg 
79c349dbc7Sjsg 	gvt_dbg_el("[after] running slot %d/context %x pending slot %d\n",
80c349dbc7Sjsg 			execlist->running_slot ?
81c349dbc7Sjsg 			execlist->running_slot->index : -1,
82c349dbc7Sjsg 			execlist->running_context ?
83c349dbc7Sjsg 			execlist->running_context->context_id : 0,
84c349dbc7Sjsg 			execlist->pending_slot ?
85c349dbc7Sjsg 			execlist->pending_slot->index : -1);
86c349dbc7Sjsg }
87c349dbc7Sjsg 
emulate_execlist_status(struct intel_vgpu_execlist * execlist)88c349dbc7Sjsg static void emulate_execlist_status(struct intel_vgpu_execlist *execlist)
89c349dbc7Sjsg {
90c349dbc7Sjsg 	struct intel_vgpu_execlist_slot *running = execlist->running_slot;
91c349dbc7Sjsg 	struct intel_vgpu_execlist_slot *pending = execlist->pending_slot;
92c349dbc7Sjsg 	struct execlist_ctx_descriptor_format *desc = execlist->running_context;
93c349dbc7Sjsg 	struct intel_vgpu *vgpu = execlist->vgpu;
94c349dbc7Sjsg 	struct execlist_status_format status;
95c349dbc7Sjsg 	u32 status_reg =
96c349dbc7Sjsg 		execlist_ring_mmio(execlist->engine, _EL_OFFSET_STATUS);
97c349dbc7Sjsg 
98c349dbc7Sjsg 	status.ldw = vgpu_vreg(vgpu, status_reg);
99c349dbc7Sjsg 	status.udw = vgpu_vreg(vgpu, status_reg + 4);
100c349dbc7Sjsg 
101c349dbc7Sjsg 	if (running) {
102c349dbc7Sjsg 		status.current_execlist_pointer = !!running->index;
103c349dbc7Sjsg 		status.execlist_write_pointer = !!!running->index;
104c349dbc7Sjsg 		status.execlist_0_active = status.execlist_0_valid =
105c349dbc7Sjsg 			!!!(running->index);
106c349dbc7Sjsg 		status.execlist_1_active = status.execlist_1_valid =
107c349dbc7Sjsg 			!!(running->index);
108c349dbc7Sjsg 	} else {
109c349dbc7Sjsg 		status.context_id = 0;
110c349dbc7Sjsg 		status.execlist_0_active = status.execlist_0_valid = 0;
111c349dbc7Sjsg 		status.execlist_1_active = status.execlist_1_valid = 0;
112c349dbc7Sjsg 	}
113c349dbc7Sjsg 
114c349dbc7Sjsg 	status.context_id = desc ? desc->context_id : 0;
115c349dbc7Sjsg 	status.execlist_queue_full = !!(pending);
116c349dbc7Sjsg 
117c349dbc7Sjsg 	vgpu_vreg(vgpu, status_reg) = status.ldw;
118c349dbc7Sjsg 	vgpu_vreg(vgpu, status_reg + 4) = status.udw;
119c349dbc7Sjsg 
120c349dbc7Sjsg 	gvt_dbg_el("vgpu%d: status reg offset %x ldw %x udw %x\n",
121c349dbc7Sjsg 		vgpu->id, status_reg, status.ldw, status.udw);
122c349dbc7Sjsg }
123c349dbc7Sjsg 
emulate_csb_update(struct intel_vgpu_execlist * execlist,struct execlist_context_status_format * status,bool trigger_interrupt_later)124c349dbc7Sjsg static void emulate_csb_update(struct intel_vgpu_execlist *execlist,
125c349dbc7Sjsg 			       struct execlist_context_status_format *status,
126c349dbc7Sjsg 			       bool trigger_interrupt_later)
127c349dbc7Sjsg {
128c349dbc7Sjsg 	struct intel_vgpu *vgpu = execlist->vgpu;
129c349dbc7Sjsg 	struct execlist_context_status_pointer_format ctx_status_ptr;
130c349dbc7Sjsg 	u32 write_pointer;
131c349dbc7Sjsg 	u32 ctx_status_ptr_reg, ctx_status_buf_reg, offset;
132c349dbc7Sjsg 	unsigned long hwsp_gpa;
133c349dbc7Sjsg 
134c349dbc7Sjsg 	ctx_status_ptr_reg =
135c349dbc7Sjsg 		execlist_ring_mmio(execlist->engine, _EL_OFFSET_STATUS_PTR);
136c349dbc7Sjsg 	ctx_status_buf_reg =
137c349dbc7Sjsg 		execlist_ring_mmio(execlist->engine, _EL_OFFSET_STATUS_BUF);
138c349dbc7Sjsg 
139c349dbc7Sjsg 	ctx_status_ptr.dw = vgpu_vreg(vgpu, ctx_status_ptr_reg);
140c349dbc7Sjsg 
141c349dbc7Sjsg 	write_pointer = ctx_status_ptr.write_ptr;
142c349dbc7Sjsg 
143c349dbc7Sjsg 	if (write_pointer == 0x7)
144c349dbc7Sjsg 		write_pointer = 0;
145c349dbc7Sjsg 	else {
146c349dbc7Sjsg 		++write_pointer;
147c349dbc7Sjsg 		write_pointer %= 0x6;
148c349dbc7Sjsg 	}
149c349dbc7Sjsg 
150c349dbc7Sjsg 	offset = ctx_status_buf_reg + write_pointer * 8;
151c349dbc7Sjsg 
152c349dbc7Sjsg 	vgpu_vreg(vgpu, offset) = status->ldw;
153c349dbc7Sjsg 	vgpu_vreg(vgpu, offset + 4) = status->udw;
154c349dbc7Sjsg 
155c349dbc7Sjsg 	ctx_status_ptr.write_ptr = write_pointer;
156c349dbc7Sjsg 	vgpu_vreg(vgpu, ctx_status_ptr_reg) = ctx_status_ptr.dw;
157c349dbc7Sjsg 
158c349dbc7Sjsg 	/* Update the CSB and CSB write pointer in HWSP */
159c349dbc7Sjsg 	hwsp_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm,
160c349dbc7Sjsg 					 vgpu->hws_pga[execlist->engine->id]);
161c349dbc7Sjsg 	if (hwsp_gpa != INTEL_GVT_INVALID_ADDR) {
162*1bb76ff1Sjsg 		intel_gvt_write_gpa(vgpu,
163c349dbc7Sjsg 			hwsp_gpa + I915_HWS_CSB_BUF0_INDEX * 4 + write_pointer * 8,
164c349dbc7Sjsg 			status, 8);
165*1bb76ff1Sjsg 		intel_gvt_write_gpa(vgpu,
166*1bb76ff1Sjsg 			hwsp_gpa + INTEL_HWS_CSB_WRITE_INDEX(execlist->engine->i915) * 4,
167c349dbc7Sjsg 			&write_pointer, 4);
168c349dbc7Sjsg 	}
169c349dbc7Sjsg 
170c349dbc7Sjsg 	gvt_dbg_el("vgpu%d: w pointer %u reg %x csb l %x csb h %x\n",
171c349dbc7Sjsg 		   vgpu->id, write_pointer, offset, status->ldw, status->udw);
172c349dbc7Sjsg 
173c349dbc7Sjsg 	if (trigger_interrupt_later)
174c349dbc7Sjsg 		return;
175c349dbc7Sjsg 
176c349dbc7Sjsg 	intel_vgpu_trigger_virtual_event(vgpu,
177c349dbc7Sjsg 					 to_context_switch_event(execlist->engine));
178c349dbc7Sjsg }
179c349dbc7Sjsg 
emulate_execlist_ctx_schedule_out(struct intel_vgpu_execlist * execlist,struct execlist_ctx_descriptor_format * ctx)180c349dbc7Sjsg static int emulate_execlist_ctx_schedule_out(
181c349dbc7Sjsg 		struct intel_vgpu_execlist *execlist,
182c349dbc7Sjsg 		struct execlist_ctx_descriptor_format *ctx)
183c349dbc7Sjsg {
184c349dbc7Sjsg 	struct intel_vgpu *vgpu = execlist->vgpu;
185c349dbc7Sjsg 	struct intel_vgpu_execlist_slot *running = execlist->running_slot;
186c349dbc7Sjsg 	struct intel_vgpu_execlist_slot *pending = execlist->pending_slot;
187c349dbc7Sjsg 	struct execlist_ctx_descriptor_format *ctx0 = &running->ctx[0];
188c349dbc7Sjsg 	struct execlist_ctx_descriptor_format *ctx1 = &running->ctx[1];
189c349dbc7Sjsg 	struct execlist_context_status_format status;
190c349dbc7Sjsg 
191c349dbc7Sjsg 	memset(&status, 0, sizeof(status));
192c349dbc7Sjsg 
193c349dbc7Sjsg 	gvt_dbg_el("schedule out context id %x\n", ctx->context_id);
194c349dbc7Sjsg 
195c349dbc7Sjsg 	if (WARN_ON(!same_context(ctx, execlist->running_context))) {
196c349dbc7Sjsg 		gvt_vgpu_err("schedule out context is not running context,"
197c349dbc7Sjsg 				"ctx id %x running ctx id %x\n",
198c349dbc7Sjsg 				ctx->context_id,
199c349dbc7Sjsg 				execlist->running_context->context_id);
200c349dbc7Sjsg 		return -EINVAL;
201c349dbc7Sjsg 	}
202c349dbc7Sjsg 
203c349dbc7Sjsg 	/* ctx1 is valid, ctx0/ctx is scheduled-out -> element switch */
204c349dbc7Sjsg 	if (valid_context(ctx1) && same_context(ctx0, ctx)) {
205c349dbc7Sjsg 		gvt_dbg_el("ctx 1 valid, ctx/ctx 0 is scheduled-out\n");
206c349dbc7Sjsg 
207c349dbc7Sjsg 		execlist->running_context = ctx1;
208c349dbc7Sjsg 
209c349dbc7Sjsg 		emulate_execlist_status(execlist);
210c349dbc7Sjsg 
211c349dbc7Sjsg 		status.context_complete = status.element_switch = 1;
212c349dbc7Sjsg 		status.context_id = ctx->context_id;
213c349dbc7Sjsg 
214c349dbc7Sjsg 		emulate_csb_update(execlist, &status, false);
215c349dbc7Sjsg 		/*
216c349dbc7Sjsg 		 * ctx1 is not valid, ctx == ctx0
217c349dbc7Sjsg 		 * ctx1 is valid, ctx1 == ctx
218c349dbc7Sjsg 		 *	--> last element is finished
219c349dbc7Sjsg 		 * emulate:
220c349dbc7Sjsg 		 *	active-to-idle if there is *no* pending execlist
221c349dbc7Sjsg 		 *	context-complete if there *is* pending execlist
222c349dbc7Sjsg 		 */
223c349dbc7Sjsg 	} else if ((!valid_context(ctx1) && same_context(ctx0, ctx))
224c349dbc7Sjsg 			|| (valid_context(ctx1) && same_context(ctx1, ctx))) {
225c349dbc7Sjsg 		gvt_dbg_el("need to switch virtual execlist slot\n");
226c349dbc7Sjsg 
227c349dbc7Sjsg 		switch_virtual_execlist_slot(execlist);
228c349dbc7Sjsg 
229c349dbc7Sjsg 		emulate_execlist_status(execlist);
230c349dbc7Sjsg 
231c349dbc7Sjsg 		status.context_complete = status.active_to_idle = 1;
232c349dbc7Sjsg 		status.context_id = ctx->context_id;
233c349dbc7Sjsg 
234c349dbc7Sjsg 		if (!pending) {
235c349dbc7Sjsg 			emulate_csb_update(execlist, &status, false);
236c349dbc7Sjsg 		} else {
237c349dbc7Sjsg 			emulate_csb_update(execlist, &status, true);
238c349dbc7Sjsg 
239c349dbc7Sjsg 			memset(&status, 0, sizeof(status));
240c349dbc7Sjsg 
241c349dbc7Sjsg 			status.idle_to_active = 1;
242c349dbc7Sjsg 			status.context_id = 0;
243c349dbc7Sjsg 
244c349dbc7Sjsg 			emulate_csb_update(execlist, &status, false);
245c349dbc7Sjsg 		}
246c349dbc7Sjsg 	} else {
247c349dbc7Sjsg 		WARN_ON(1);
248c349dbc7Sjsg 		return -EINVAL;
249c349dbc7Sjsg 	}
250c349dbc7Sjsg 
251c349dbc7Sjsg 	return 0;
252c349dbc7Sjsg }
253c349dbc7Sjsg 
get_next_execlist_slot(struct intel_vgpu_execlist * execlist)254c349dbc7Sjsg static struct intel_vgpu_execlist_slot *get_next_execlist_slot(
255c349dbc7Sjsg 		struct intel_vgpu_execlist *execlist)
256c349dbc7Sjsg {
257c349dbc7Sjsg 	struct intel_vgpu *vgpu = execlist->vgpu;
258c349dbc7Sjsg 	u32 status_reg =
259c349dbc7Sjsg 		execlist_ring_mmio(execlist->engine, _EL_OFFSET_STATUS);
260c349dbc7Sjsg 	struct execlist_status_format status;
261c349dbc7Sjsg 
262c349dbc7Sjsg 	status.ldw = vgpu_vreg(vgpu, status_reg);
263c349dbc7Sjsg 	status.udw = vgpu_vreg(vgpu, status_reg + 4);
264c349dbc7Sjsg 
265c349dbc7Sjsg 	if (status.execlist_queue_full) {
266c349dbc7Sjsg 		gvt_vgpu_err("virtual execlist slots are full\n");
267c349dbc7Sjsg 		return NULL;
268c349dbc7Sjsg 	}
269c349dbc7Sjsg 
270c349dbc7Sjsg 	return &execlist->slot[status.execlist_write_pointer];
271c349dbc7Sjsg }
272c349dbc7Sjsg 
emulate_execlist_schedule_in(struct intel_vgpu_execlist * execlist,struct execlist_ctx_descriptor_format ctx[2])273c349dbc7Sjsg static int emulate_execlist_schedule_in(struct intel_vgpu_execlist *execlist,
274c349dbc7Sjsg 		struct execlist_ctx_descriptor_format ctx[2])
275c349dbc7Sjsg {
276c349dbc7Sjsg 	struct intel_vgpu_execlist_slot *running = execlist->running_slot;
277c349dbc7Sjsg 	struct intel_vgpu_execlist_slot *slot =
278c349dbc7Sjsg 		get_next_execlist_slot(execlist);
279c349dbc7Sjsg 
280c349dbc7Sjsg 	struct execlist_ctx_descriptor_format *ctx0, *ctx1;
281c349dbc7Sjsg 	struct execlist_context_status_format status;
282c349dbc7Sjsg 	struct intel_vgpu *vgpu = execlist->vgpu;
283c349dbc7Sjsg 
284c349dbc7Sjsg 	gvt_dbg_el("emulate schedule-in\n");
285c349dbc7Sjsg 
286c349dbc7Sjsg 	if (!slot) {
287c349dbc7Sjsg 		gvt_vgpu_err("no available execlist slot\n");
288c349dbc7Sjsg 		return -EINVAL;
289c349dbc7Sjsg 	}
290c349dbc7Sjsg 
291c349dbc7Sjsg 	memset(&status, 0, sizeof(status));
292c349dbc7Sjsg 	memset(slot->ctx, 0, sizeof(slot->ctx));
293c349dbc7Sjsg 
294c349dbc7Sjsg 	slot->ctx[0] = ctx[0];
295c349dbc7Sjsg 	slot->ctx[1] = ctx[1];
296c349dbc7Sjsg 
297c349dbc7Sjsg 	gvt_dbg_el("alloc slot index %d ctx 0 %x ctx 1 %x\n",
298c349dbc7Sjsg 			slot->index, ctx[0].context_id,
299c349dbc7Sjsg 			ctx[1].context_id);
300c349dbc7Sjsg 
301c349dbc7Sjsg 	/*
302c349dbc7Sjsg 	 * no running execlist, make this write bundle as running execlist
303c349dbc7Sjsg 	 * -> idle-to-active
304c349dbc7Sjsg 	 */
305c349dbc7Sjsg 	if (!running) {
306c349dbc7Sjsg 		gvt_dbg_el("no current running execlist\n");
307c349dbc7Sjsg 
308c349dbc7Sjsg 		execlist->running_slot = slot;
309c349dbc7Sjsg 		execlist->pending_slot = NULL;
310c349dbc7Sjsg 		execlist->running_context = &slot->ctx[0];
311c349dbc7Sjsg 
312c349dbc7Sjsg 		gvt_dbg_el("running slot index %d running context %x\n",
313c349dbc7Sjsg 				execlist->running_slot->index,
314c349dbc7Sjsg 				execlist->running_context->context_id);
315c349dbc7Sjsg 
316c349dbc7Sjsg 		emulate_execlist_status(execlist);
317c349dbc7Sjsg 
318c349dbc7Sjsg 		status.idle_to_active = 1;
319c349dbc7Sjsg 		status.context_id = 0;
320c349dbc7Sjsg 
321c349dbc7Sjsg 		emulate_csb_update(execlist, &status, false);
322c349dbc7Sjsg 		return 0;
323c349dbc7Sjsg 	}
324c349dbc7Sjsg 
325c349dbc7Sjsg 	ctx0 = &running->ctx[0];
326c349dbc7Sjsg 	ctx1 = &running->ctx[1];
327c349dbc7Sjsg 
328c349dbc7Sjsg 	gvt_dbg_el("current running slot index %d ctx 0 %x ctx 1 %x\n",
329c349dbc7Sjsg 		running->index, ctx0->context_id, ctx1->context_id);
330c349dbc7Sjsg 
331c349dbc7Sjsg 	/*
332c349dbc7Sjsg 	 * already has an running execlist
333c349dbc7Sjsg 	 *	a. running ctx1 is valid,
334c349dbc7Sjsg 	 *	   ctx0 is finished, and running ctx1 == new execlist ctx[0]
335c349dbc7Sjsg 	 *	b. running ctx1 is not valid,
336c349dbc7Sjsg 	 *	   ctx0 == new execlist ctx[0]
337c349dbc7Sjsg 	 * ----> lite-restore + preempted
338c349dbc7Sjsg 	 */
339c349dbc7Sjsg 	if ((valid_context(ctx1) && same_context(ctx1, &slot->ctx[0]) &&
340c349dbc7Sjsg 		/* condition a */
341c349dbc7Sjsg 		(!same_context(ctx0, execlist->running_context))) ||
342c349dbc7Sjsg 			(!valid_context(ctx1) &&
343c349dbc7Sjsg 			 same_context(ctx0, &slot->ctx[0]))) { /* condition b */
344c349dbc7Sjsg 		gvt_dbg_el("need to switch virtual execlist slot\n");
345c349dbc7Sjsg 
346c349dbc7Sjsg 		execlist->pending_slot = slot;
347c349dbc7Sjsg 		switch_virtual_execlist_slot(execlist);
348c349dbc7Sjsg 
349c349dbc7Sjsg 		emulate_execlist_status(execlist);
350c349dbc7Sjsg 
351c349dbc7Sjsg 		status.lite_restore = status.preempted = 1;
352c349dbc7Sjsg 		status.context_id = ctx[0].context_id;
353c349dbc7Sjsg 
354c349dbc7Sjsg 		emulate_csb_update(execlist, &status, false);
355c349dbc7Sjsg 	} else {
356c349dbc7Sjsg 		gvt_dbg_el("emulate as pending slot\n");
357c349dbc7Sjsg 		/*
358c349dbc7Sjsg 		 * otherwise
359c349dbc7Sjsg 		 * --> emulate pending execlist exist + but no preemption case
360c349dbc7Sjsg 		 */
361c349dbc7Sjsg 		execlist->pending_slot = slot;
362c349dbc7Sjsg 		emulate_execlist_status(execlist);
363c349dbc7Sjsg 	}
364c349dbc7Sjsg 	return 0;
365c349dbc7Sjsg }
366c349dbc7Sjsg 
367c349dbc7Sjsg #define get_desc_from_elsp_dwords(ed, i) \
368c349dbc7Sjsg 	((struct execlist_ctx_descriptor_format *)&((ed)->data[i * 2]))
369c349dbc7Sjsg 
prepare_execlist_workload(struct intel_vgpu_workload * workload)370c349dbc7Sjsg static int prepare_execlist_workload(struct intel_vgpu_workload *workload)
371c349dbc7Sjsg {
372c349dbc7Sjsg 	struct intel_vgpu *vgpu = workload->vgpu;
373c349dbc7Sjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
374c349dbc7Sjsg 	struct execlist_ctx_descriptor_format ctx[2];
375c349dbc7Sjsg 	int ret;
376c349dbc7Sjsg 
377c349dbc7Sjsg 	if (!workload->emulate_schedule_in)
378c349dbc7Sjsg 		return 0;
379c349dbc7Sjsg 
380c349dbc7Sjsg 	ctx[0] = *get_desc_from_elsp_dwords(&workload->elsp_dwords, 0);
381c349dbc7Sjsg 	ctx[1] = *get_desc_from_elsp_dwords(&workload->elsp_dwords, 1);
382c349dbc7Sjsg 
383c349dbc7Sjsg 	ret = emulate_execlist_schedule_in(&s->execlist[workload->engine->id],
384c349dbc7Sjsg 					   ctx);
385c349dbc7Sjsg 	if (ret) {
386c349dbc7Sjsg 		gvt_vgpu_err("fail to emulate execlist schedule in\n");
387c349dbc7Sjsg 		return ret;
388c349dbc7Sjsg 	}
389c349dbc7Sjsg 	return 0;
390c349dbc7Sjsg }
391c349dbc7Sjsg 
complete_execlist_workload(struct intel_vgpu_workload * workload)392c349dbc7Sjsg static int complete_execlist_workload(struct intel_vgpu_workload *workload)
393c349dbc7Sjsg {
394c349dbc7Sjsg 	struct intel_vgpu *vgpu = workload->vgpu;
395c349dbc7Sjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
396c349dbc7Sjsg 	struct intel_vgpu_execlist *execlist =
397c349dbc7Sjsg 		&s->execlist[workload->engine->id];
398c349dbc7Sjsg 	struct intel_vgpu_workload *next_workload;
399c349dbc7Sjsg 	struct list_head *next = workload_q_head(vgpu, workload->engine)->next;
400c349dbc7Sjsg 	bool lite_restore = false;
401c349dbc7Sjsg 	int ret = 0;
402c349dbc7Sjsg 
403c349dbc7Sjsg 	gvt_dbg_el("complete workload %p status %d\n",
404c349dbc7Sjsg 		   workload, workload->status);
405c349dbc7Sjsg 
406c349dbc7Sjsg 	if (workload->status || vgpu->resetting_eng & workload->engine->mask)
407c349dbc7Sjsg 		goto out;
408c349dbc7Sjsg 
409c349dbc7Sjsg 	if (!list_empty(workload_q_head(vgpu, workload->engine))) {
410c349dbc7Sjsg 		struct execlist_ctx_descriptor_format *this_desc, *next_desc;
411c349dbc7Sjsg 
412c349dbc7Sjsg 		next_workload = container_of(next,
413c349dbc7Sjsg 				struct intel_vgpu_workload, list);
414c349dbc7Sjsg 		this_desc = &workload->ctx_desc;
415c349dbc7Sjsg 		next_desc = &next_workload->ctx_desc;
416c349dbc7Sjsg 
417c349dbc7Sjsg 		lite_restore = same_context(this_desc, next_desc);
418c349dbc7Sjsg 	}
419c349dbc7Sjsg 
420c349dbc7Sjsg 	if (lite_restore) {
421c349dbc7Sjsg 		gvt_dbg_el("next context == current - no schedule-out\n");
422c349dbc7Sjsg 		goto out;
423c349dbc7Sjsg 	}
424c349dbc7Sjsg 
425c349dbc7Sjsg 	ret = emulate_execlist_ctx_schedule_out(execlist, &workload->ctx_desc);
426c349dbc7Sjsg out:
427c349dbc7Sjsg 	return ret;
428c349dbc7Sjsg }
429c349dbc7Sjsg 
submit_context(struct intel_vgpu * vgpu,const struct intel_engine_cs * engine,struct execlist_ctx_descriptor_format * desc,bool emulate_schedule_in)430c349dbc7Sjsg static int submit_context(struct intel_vgpu *vgpu,
431c349dbc7Sjsg 			  const struct intel_engine_cs *engine,
432c349dbc7Sjsg 			  struct execlist_ctx_descriptor_format *desc,
433c349dbc7Sjsg 			  bool emulate_schedule_in)
434c349dbc7Sjsg {
435c349dbc7Sjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
436c349dbc7Sjsg 	struct intel_vgpu_workload *workload = NULL;
437c349dbc7Sjsg 
438c349dbc7Sjsg 	workload = intel_vgpu_create_workload(vgpu, engine, desc);
439c349dbc7Sjsg 	if (IS_ERR(workload))
440c349dbc7Sjsg 		return PTR_ERR(workload);
441c349dbc7Sjsg 
442c349dbc7Sjsg 	workload->prepare = prepare_execlist_workload;
443c349dbc7Sjsg 	workload->complete = complete_execlist_workload;
444c349dbc7Sjsg 	workload->emulate_schedule_in = emulate_schedule_in;
445c349dbc7Sjsg 
446c349dbc7Sjsg 	if (emulate_schedule_in)
447c349dbc7Sjsg 		workload->elsp_dwords = s->execlist[engine->id].elsp_dwords;
448c349dbc7Sjsg 
449c349dbc7Sjsg 	gvt_dbg_el("workload %p emulate schedule_in %d\n", workload,
450c349dbc7Sjsg 		   emulate_schedule_in);
451c349dbc7Sjsg 
452c349dbc7Sjsg 	intel_vgpu_queue_workload(workload);
453c349dbc7Sjsg 	return 0;
454c349dbc7Sjsg }
455c349dbc7Sjsg 
intel_vgpu_submit_execlist(struct intel_vgpu * vgpu,const struct intel_engine_cs * engine)456c349dbc7Sjsg int intel_vgpu_submit_execlist(struct intel_vgpu *vgpu,
457c349dbc7Sjsg 			       const struct intel_engine_cs *engine)
458c349dbc7Sjsg {
459c349dbc7Sjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
460c349dbc7Sjsg 	struct intel_vgpu_execlist *execlist = &s->execlist[engine->id];
461c349dbc7Sjsg 	struct execlist_ctx_descriptor_format *desc[2];
462c349dbc7Sjsg 	int i, ret;
463c349dbc7Sjsg 
464c349dbc7Sjsg 	desc[0] = get_desc_from_elsp_dwords(&execlist->elsp_dwords, 0);
465c349dbc7Sjsg 	desc[1] = get_desc_from_elsp_dwords(&execlist->elsp_dwords, 1);
466c349dbc7Sjsg 
467c349dbc7Sjsg 	if (!desc[0]->valid) {
468c349dbc7Sjsg 		gvt_vgpu_err("invalid elsp submission, desc0 is invalid\n");
469c349dbc7Sjsg 		goto inv_desc;
470c349dbc7Sjsg 	}
471c349dbc7Sjsg 
472c349dbc7Sjsg 	for (i = 0; i < ARRAY_SIZE(desc); i++) {
473c349dbc7Sjsg 		if (!desc[i]->valid)
474c349dbc7Sjsg 			continue;
475c349dbc7Sjsg 		if (!desc[i]->privilege_access) {
476c349dbc7Sjsg 			gvt_vgpu_err("unexpected GGTT elsp submission\n");
477c349dbc7Sjsg 			goto inv_desc;
478c349dbc7Sjsg 		}
479c349dbc7Sjsg 	}
480c349dbc7Sjsg 
481c349dbc7Sjsg 	/* submit workload */
482c349dbc7Sjsg 	for (i = 0; i < ARRAY_SIZE(desc); i++) {
483c349dbc7Sjsg 		if (!desc[i]->valid)
484c349dbc7Sjsg 			continue;
485c349dbc7Sjsg 		ret = submit_context(vgpu, engine, desc[i], i == 0);
486c349dbc7Sjsg 		if (ret) {
487c349dbc7Sjsg 			gvt_vgpu_err("failed to submit desc %d\n", i);
488c349dbc7Sjsg 			return ret;
489c349dbc7Sjsg 		}
490c349dbc7Sjsg 	}
491c349dbc7Sjsg 
492c349dbc7Sjsg 	return 0;
493c349dbc7Sjsg 
494c349dbc7Sjsg inv_desc:
495c349dbc7Sjsg 	gvt_vgpu_err("descriptors content: desc0 %08x %08x desc1 %08x %08x\n",
496c349dbc7Sjsg 		     desc[0]->udw, desc[0]->ldw, desc[1]->udw, desc[1]->ldw);
497c349dbc7Sjsg 	return -EINVAL;
498c349dbc7Sjsg }
499c349dbc7Sjsg 
init_vgpu_execlist(struct intel_vgpu * vgpu,const struct intel_engine_cs * engine)500c349dbc7Sjsg static void init_vgpu_execlist(struct intel_vgpu *vgpu,
501c349dbc7Sjsg 			       const struct intel_engine_cs *engine)
502c349dbc7Sjsg {
503c349dbc7Sjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
504c349dbc7Sjsg 	struct intel_vgpu_execlist *execlist = &s->execlist[engine->id];
505c349dbc7Sjsg 	struct execlist_context_status_pointer_format ctx_status_ptr;
506c349dbc7Sjsg 	u32 ctx_status_ptr_reg;
507c349dbc7Sjsg 
508c349dbc7Sjsg 	memset(execlist, 0, sizeof(*execlist));
509c349dbc7Sjsg 
510c349dbc7Sjsg 	execlist->vgpu = vgpu;
511c349dbc7Sjsg 	execlist->engine = engine;
512c349dbc7Sjsg 	execlist->slot[0].index = 0;
513c349dbc7Sjsg 	execlist->slot[1].index = 1;
514c349dbc7Sjsg 
515c349dbc7Sjsg 	ctx_status_ptr_reg = execlist_ring_mmio(engine, _EL_OFFSET_STATUS_PTR);
516c349dbc7Sjsg 	ctx_status_ptr.dw = vgpu_vreg(vgpu, ctx_status_ptr_reg);
517c349dbc7Sjsg 	ctx_status_ptr.read_ptr = 0;
518c349dbc7Sjsg 	ctx_status_ptr.write_ptr = 0x7;
519c349dbc7Sjsg 	vgpu_vreg(vgpu, ctx_status_ptr_reg) = ctx_status_ptr.dw;
520c349dbc7Sjsg }
521c349dbc7Sjsg 
clean_execlist(struct intel_vgpu * vgpu,intel_engine_mask_t engine_mask)522c349dbc7Sjsg static void clean_execlist(struct intel_vgpu *vgpu,
523c349dbc7Sjsg 			   intel_engine_mask_t engine_mask)
524c349dbc7Sjsg {
525c349dbc7Sjsg 	struct intel_vgpu_submission *s = &vgpu->submission;
5265ca02815Sjsg 	struct intel_engine_cs *engine;
527c349dbc7Sjsg 	intel_engine_mask_t tmp;
528c349dbc7Sjsg 
5295ca02815Sjsg 	for_each_engine_masked(engine, vgpu->gvt->gt, engine_mask, tmp) {
530c349dbc7Sjsg 		kfree(s->ring_scan_buffer[engine->id]);
531c349dbc7Sjsg 		s->ring_scan_buffer[engine->id] = NULL;
532c349dbc7Sjsg 		s->ring_scan_buffer_size[engine->id] = 0;
533c349dbc7Sjsg 	}
534c349dbc7Sjsg }
535c349dbc7Sjsg 
reset_execlist(struct intel_vgpu * vgpu,intel_engine_mask_t engine_mask)536c349dbc7Sjsg static void reset_execlist(struct intel_vgpu *vgpu,
537c349dbc7Sjsg 			   intel_engine_mask_t engine_mask)
538c349dbc7Sjsg {
539c349dbc7Sjsg 	struct intel_engine_cs *engine;
540c349dbc7Sjsg 	intel_engine_mask_t tmp;
541c349dbc7Sjsg 
5425ca02815Sjsg 	for_each_engine_masked(engine, vgpu->gvt->gt, engine_mask, tmp)
543c349dbc7Sjsg 		init_vgpu_execlist(vgpu, engine);
544c349dbc7Sjsg }
545c349dbc7Sjsg 
init_execlist(struct intel_vgpu * vgpu,intel_engine_mask_t engine_mask)546c349dbc7Sjsg static int init_execlist(struct intel_vgpu *vgpu,
547c349dbc7Sjsg 			 intel_engine_mask_t engine_mask)
548c349dbc7Sjsg {
549c349dbc7Sjsg 	reset_execlist(vgpu, engine_mask);
550c349dbc7Sjsg 	return 0;
551c349dbc7Sjsg }
552c349dbc7Sjsg 
553c349dbc7Sjsg const struct intel_vgpu_submission_ops intel_vgpu_execlist_submission_ops = {
554c349dbc7Sjsg 	.name = "execlist",
555c349dbc7Sjsg 	.init = init_execlist,
556c349dbc7Sjsg 	.reset = reset_execlist,
557c349dbc7Sjsg 	.clean = clean_execlist,
558c349dbc7Sjsg };
559