xref: /openbmc/linux/drivers/gpu/drm/i915/gvt/execlist.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
18453d674SZhi Wang /*
28453d674SZhi Wang  * Copyright(c) 2011-2016 Intel Corporation. All rights reserved.
38453d674SZhi Wang  *
48453d674SZhi Wang  * Permission is hereby granted, free of charge, to any person obtaining a
58453d674SZhi Wang  * copy of this software and associated documentation files (the "Software"),
68453d674SZhi Wang  * to deal in the Software without restriction, including without limitation
78453d674SZhi Wang  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88453d674SZhi Wang  * and/or sell copies of the Software, and to permit persons to whom the
98453d674SZhi Wang  * Software is furnished to do so, subject to the following conditions:
108453d674SZhi Wang  *
118453d674SZhi Wang  * The above copyright notice and this permission notice (including the next
128453d674SZhi Wang  * paragraph) shall be included in all copies or substantial portions of the
138453d674SZhi Wang  * Software.
148453d674SZhi Wang  *
158453d674SZhi Wang  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
168453d674SZhi Wang  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
178453d674SZhi Wang  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
188453d674SZhi Wang  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
198453d674SZhi Wang  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
208453d674SZhi Wang  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
218453d674SZhi Wang  * SOFTWARE.
228453d674SZhi Wang  *
238453d674SZhi Wang  * Authors:
248453d674SZhi Wang  *    Zhiyuan Lv <zhiyuan.lv@intel.com>
258453d674SZhi Wang  *    Zhi Wang <zhi.a.wang@intel.com>
268453d674SZhi Wang  *
278453d674SZhi Wang  * Contributors:
288453d674SZhi Wang  *    Min He <min.he@intel.com>
298453d674SZhi Wang  *    Bing Niu <bing.niu@intel.com>
308453d674SZhi Wang  *    Ping Gao <ping.a.gao@intel.com>
318453d674SZhi Wang  *    Tina Zhang <tina.zhang@intel.com>
328453d674SZhi Wang  *
338453d674SZhi Wang  */
348453d674SZhi Wang 
358453d674SZhi Wang #include "i915_drv.h"
36feddf6e8SZhenyu Wang #include "gvt.h"
378453d674SZhi Wang 
388453d674SZhi Wang #define _EL_OFFSET_STATUS       0x234
398453d674SZhi Wang #define _EL_OFFSET_STATUS_BUF   0x370
408453d674SZhi Wang #define _EL_OFFSET_STATUS_PTR   0x3A0
418453d674SZhi Wang 
428fde4107SChris Wilson #define execlist_ring_mmio(e, offset) ((e)->mmio_base + (offset))
438453d674SZhi Wang 
448453d674SZhi Wang #define valid_context(ctx) ((ctx)->valid)
458453d674SZhi Wang #define same_context(a, b) (((a)->context_id == (b)->context_id) && \
468453d674SZhi Wang 		((a)->lrca == (b)->lrca))
478453d674SZhi Wang 
488453d674SZhi Wang static int context_switch_events[] = {
498a68d464SChris Wilson 	[RCS0]  = RCS_AS_CONTEXT_SWITCH,
508a68d464SChris Wilson 	[BCS0]  = BCS_AS_CONTEXT_SWITCH,
518a68d464SChris Wilson 	[VCS0]  = VCS_AS_CONTEXT_SWITCH,
528a68d464SChris Wilson 	[VCS1]  = VCS2_AS_CONTEXT_SWITCH,
538a68d464SChris Wilson 	[VECS0] = VECS_AS_CONTEXT_SWITCH,
548453d674SZhi Wang };
558453d674SZhi Wang 
to_context_switch_event(const struct intel_engine_cs * engine)568fde4107SChris Wilson static int to_context_switch_event(const struct intel_engine_cs *engine)
578453d674SZhi Wang {
588fde4107SChris Wilson 	if (WARN_ON(engine->id >= ARRAY_SIZE(context_switch_events)))
598453d674SZhi Wang 		return -EINVAL;
608453d674SZhi Wang 
618fde4107SChris Wilson 	return context_switch_events[engine->id];
628453d674SZhi Wang }
638453d674SZhi Wang 
switch_virtual_execlist_slot(struct intel_vgpu_execlist * execlist)648453d674SZhi Wang static void switch_virtual_execlist_slot(struct intel_vgpu_execlist *execlist)
658453d674SZhi Wang {
668453d674SZhi Wang 	gvt_dbg_el("[before] running slot %d/context %x pending slot %d\n",
678453d674SZhi Wang 			execlist->running_slot ?
688453d674SZhi Wang 			execlist->running_slot->index : -1,
698453d674SZhi Wang 			execlist->running_context ?
708453d674SZhi Wang 			execlist->running_context->context_id : 0,
718453d674SZhi Wang 			execlist->pending_slot ?
728453d674SZhi Wang 			execlist->pending_slot->index : -1);
738453d674SZhi Wang 
748453d674SZhi Wang 	execlist->running_slot = execlist->pending_slot;
758453d674SZhi Wang 	execlist->pending_slot = NULL;
768453d674SZhi Wang 	execlist->running_context = execlist->running_context ?
778453d674SZhi Wang 		&execlist->running_slot->ctx[0] : NULL;
788453d674SZhi Wang 
798453d674SZhi Wang 	gvt_dbg_el("[after] running slot %d/context %x pending slot %d\n",
808453d674SZhi Wang 			execlist->running_slot ?
818453d674SZhi Wang 			execlist->running_slot->index : -1,
828453d674SZhi Wang 			execlist->running_context ?
838453d674SZhi Wang 			execlist->running_context->context_id : 0,
848453d674SZhi Wang 			execlist->pending_slot ?
858453d674SZhi Wang 			execlist->pending_slot->index : -1);
868453d674SZhi Wang }
878453d674SZhi Wang 
emulate_execlist_status(struct intel_vgpu_execlist * execlist)888453d674SZhi Wang static void emulate_execlist_status(struct intel_vgpu_execlist *execlist)
898453d674SZhi Wang {
908453d674SZhi Wang 	struct intel_vgpu_execlist_slot *running = execlist->running_slot;
918453d674SZhi Wang 	struct intel_vgpu_execlist_slot *pending = execlist->pending_slot;
928453d674SZhi Wang 	struct execlist_ctx_descriptor_format *desc = execlist->running_context;
938453d674SZhi Wang 	struct intel_vgpu *vgpu = execlist->vgpu;
948453d674SZhi Wang 	struct execlist_status_format status;
958fde4107SChris Wilson 	u32 status_reg =
968fde4107SChris Wilson 		execlist_ring_mmio(execlist->engine, _EL_OFFSET_STATUS);
978453d674SZhi Wang 
988453d674SZhi Wang 	status.ldw = vgpu_vreg(vgpu, status_reg);
998453d674SZhi Wang 	status.udw = vgpu_vreg(vgpu, status_reg + 4);
1008453d674SZhi Wang 
1018453d674SZhi Wang 	if (running) {
1028453d674SZhi Wang 		status.current_execlist_pointer = !!running->index;
1038453d674SZhi Wang 		status.execlist_write_pointer = !!!running->index;
1048453d674SZhi Wang 		status.execlist_0_active = status.execlist_0_valid =
1058453d674SZhi Wang 			!!!(running->index);
1068453d674SZhi Wang 		status.execlist_1_active = status.execlist_1_valid =
1078453d674SZhi Wang 			!!(running->index);
1088453d674SZhi Wang 	} else {
1098453d674SZhi Wang 		status.context_id = 0;
1108453d674SZhi Wang 		status.execlist_0_active = status.execlist_0_valid = 0;
1118453d674SZhi Wang 		status.execlist_1_active = status.execlist_1_valid = 0;
1128453d674SZhi Wang 	}
1138453d674SZhi Wang 
1148453d674SZhi Wang 	status.context_id = desc ? desc->context_id : 0;
1158453d674SZhi Wang 	status.execlist_queue_full = !!(pending);
1168453d674SZhi Wang 
1178453d674SZhi Wang 	vgpu_vreg(vgpu, status_reg) = status.ldw;
1188453d674SZhi Wang 	vgpu_vreg(vgpu, status_reg + 4) = status.udw;
1198453d674SZhi Wang 
1208453d674SZhi Wang 	gvt_dbg_el("vgpu%d: status reg offset %x ldw %x udw %x\n",
1218453d674SZhi Wang 		vgpu->id, status_reg, status.ldw, status.udw);
1228453d674SZhi Wang }
1238453d674SZhi Wang 
emulate_csb_update(struct intel_vgpu_execlist * execlist,struct execlist_context_status_format * status,bool trigger_interrupt_later)1248453d674SZhi Wang static void emulate_csb_update(struct intel_vgpu_execlist *execlist,
1258453d674SZhi Wang 			       struct execlist_context_status_format *status,
1268453d674SZhi Wang 			       bool trigger_interrupt_later)
1278453d674SZhi Wang {
1288453d674SZhi Wang 	struct intel_vgpu *vgpu = execlist->vgpu;
1298453d674SZhi Wang 	struct execlist_context_status_pointer_format ctx_status_ptr;
1308453d674SZhi Wang 	u32 write_pointer;
1318453d674SZhi Wang 	u32 ctx_status_ptr_reg, ctx_status_buf_reg, offset;
132a2ae95afSWeinan Li 	unsigned long hwsp_gpa;
1338453d674SZhi Wang 
1348fde4107SChris Wilson 	ctx_status_ptr_reg =
1358fde4107SChris Wilson 		execlist_ring_mmio(execlist->engine, _EL_OFFSET_STATUS_PTR);
1368fde4107SChris Wilson 	ctx_status_buf_reg =
1378fde4107SChris Wilson 		execlist_ring_mmio(execlist->engine, _EL_OFFSET_STATUS_BUF);
1388453d674SZhi Wang 
1398453d674SZhi Wang 	ctx_status_ptr.dw = vgpu_vreg(vgpu, ctx_status_ptr_reg);
1408453d674SZhi Wang 
1418453d674SZhi Wang 	write_pointer = ctx_status_ptr.write_ptr;
1428453d674SZhi Wang 
1438453d674SZhi Wang 	if (write_pointer == 0x7)
1448453d674SZhi Wang 		write_pointer = 0;
1458453d674SZhi Wang 	else {
1468453d674SZhi Wang 		++write_pointer;
1478453d674SZhi Wang 		write_pointer %= 0x6;
1488453d674SZhi Wang 	}
1498453d674SZhi Wang 
1508453d674SZhi Wang 	offset = ctx_status_buf_reg + write_pointer * 8;
1518453d674SZhi Wang 
1528453d674SZhi Wang 	vgpu_vreg(vgpu, offset) = status->ldw;
1538453d674SZhi Wang 	vgpu_vreg(vgpu, offset + 4) = status->udw;
1548453d674SZhi Wang 
1558453d674SZhi Wang 	ctx_status_ptr.write_ptr = write_pointer;
1568453d674SZhi Wang 	vgpu_vreg(vgpu, ctx_status_ptr_reg) = ctx_status_ptr.dw;
1578453d674SZhi Wang 
158a2ae95afSWeinan Li 	/* Update the CSB and CSB write pointer in HWSP */
159a2ae95afSWeinan Li 	hwsp_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm,
1608fde4107SChris Wilson 					 vgpu->hws_pga[execlist->engine->id]);
161a2ae95afSWeinan Li 	if (hwsp_gpa != INTEL_GVT_INVALID_ADDR) {
162*e3d7640eSChristoph Hellwig 		intel_gvt_write_gpa(vgpu,
1638fde4107SChris Wilson 			hwsp_gpa + I915_HWS_CSB_BUF0_INDEX * 4 + write_pointer * 8,
164a2ae95afSWeinan Li 			status, 8);
165*e3d7640eSChristoph Hellwig 		intel_gvt_write_gpa(vgpu,
166df62ae6fSJani Nikula 			hwsp_gpa + INTEL_HWS_CSB_WRITE_INDEX(execlist->engine->i915) * 4,
167a2ae95afSWeinan Li 			&write_pointer, 4);
168a2ae95afSWeinan Li 	}
169a2ae95afSWeinan Li 
1708453d674SZhi Wang 	gvt_dbg_el("vgpu%d: w pointer %u reg %x csb l %x csb h %x\n",
1718453d674SZhi Wang 		   vgpu->id, write_pointer, offset, status->ldw, status->udw);
1728453d674SZhi Wang 
1738453d674SZhi Wang 	if (trigger_interrupt_later)
1748453d674SZhi Wang 		return;
1758453d674SZhi Wang 
1768453d674SZhi Wang 	intel_vgpu_trigger_virtual_event(vgpu,
1778fde4107SChris Wilson 					 to_context_switch_event(execlist->engine));
1788453d674SZhi Wang }
1798453d674SZhi Wang 
emulate_execlist_ctx_schedule_out(struct intel_vgpu_execlist * execlist,struct execlist_ctx_descriptor_format * ctx)18028c4c6caSZhi Wang static int emulate_execlist_ctx_schedule_out(
1818453d674SZhi Wang 		struct intel_vgpu_execlist *execlist,
1828453d674SZhi Wang 		struct execlist_ctx_descriptor_format *ctx)
1838453d674SZhi Wang {
184695fbc08STina Zhang 	struct intel_vgpu *vgpu = execlist->vgpu;
1858453d674SZhi Wang 	struct intel_vgpu_execlist_slot *running = execlist->running_slot;
1868453d674SZhi Wang 	struct intel_vgpu_execlist_slot *pending = execlist->pending_slot;
1878453d674SZhi Wang 	struct execlist_ctx_descriptor_format *ctx0 = &running->ctx[0];
1888453d674SZhi Wang 	struct execlist_ctx_descriptor_format *ctx1 = &running->ctx[1];
1898453d674SZhi Wang 	struct execlist_context_status_format status;
1908453d674SZhi Wang 
1918453d674SZhi Wang 	memset(&status, 0, sizeof(status));
1928453d674SZhi Wang 
1938453d674SZhi Wang 	gvt_dbg_el("schedule out context id %x\n", ctx->context_id);
1948453d674SZhi Wang 
1958453d674SZhi Wang 	if (WARN_ON(!same_context(ctx, execlist->running_context))) {
196695fbc08STina Zhang 		gvt_vgpu_err("schedule out context is not running context,"
1978453d674SZhi Wang 				"ctx id %x running ctx id %x\n",
1988453d674SZhi Wang 				ctx->context_id,
1998453d674SZhi Wang 				execlist->running_context->context_id);
2008453d674SZhi Wang 		return -EINVAL;
2018453d674SZhi Wang 	}
2028453d674SZhi Wang 
2038453d674SZhi Wang 	/* ctx1 is valid, ctx0/ctx is scheduled-out -> element switch */
2048453d674SZhi Wang 	if (valid_context(ctx1) && same_context(ctx0, ctx)) {
2058453d674SZhi Wang 		gvt_dbg_el("ctx 1 valid, ctx/ctx 0 is scheduled-out\n");
2068453d674SZhi Wang 
2078453d674SZhi Wang 		execlist->running_context = ctx1;
2088453d674SZhi Wang 
2098453d674SZhi Wang 		emulate_execlist_status(execlist);
2108453d674SZhi Wang 
2118453d674SZhi Wang 		status.context_complete = status.element_switch = 1;
2128453d674SZhi Wang 		status.context_id = ctx->context_id;
2138453d674SZhi Wang 
2148453d674SZhi Wang 		emulate_csb_update(execlist, &status, false);
2158453d674SZhi Wang 		/*
2168453d674SZhi Wang 		 * ctx1 is not valid, ctx == ctx0
2178453d674SZhi Wang 		 * ctx1 is valid, ctx1 == ctx
2188453d674SZhi Wang 		 *	--> last element is finished
2198453d674SZhi Wang 		 * emulate:
2208453d674SZhi Wang 		 *	active-to-idle if there is *no* pending execlist
2218453d674SZhi Wang 		 *	context-complete if there *is* pending execlist
2228453d674SZhi Wang 		 */
2238453d674SZhi Wang 	} else if ((!valid_context(ctx1) && same_context(ctx0, ctx))
2248453d674SZhi Wang 			|| (valid_context(ctx1) && same_context(ctx1, ctx))) {
2258453d674SZhi Wang 		gvt_dbg_el("need to switch virtual execlist slot\n");
2268453d674SZhi Wang 
2278453d674SZhi Wang 		switch_virtual_execlist_slot(execlist);
2288453d674SZhi Wang 
2298453d674SZhi Wang 		emulate_execlist_status(execlist);
2308453d674SZhi Wang 
2318453d674SZhi Wang 		status.context_complete = status.active_to_idle = 1;
2328453d674SZhi Wang 		status.context_id = ctx->context_id;
2338453d674SZhi Wang 
2348453d674SZhi Wang 		if (!pending) {
2358453d674SZhi Wang 			emulate_csb_update(execlist, &status, false);
2368453d674SZhi Wang 		} else {
2378453d674SZhi Wang 			emulate_csb_update(execlist, &status, true);
2388453d674SZhi Wang 
2398453d674SZhi Wang 			memset(&status, 0, sizeof(status));
2408453d674SZhi Wang 
2418453d674SZhi Wang 			status.idle_to_active = 1;
2428453d674SZhi Wang 			status.context_id = 0;
2438453d674SZhi Wang 
2448453d674SZhi Wang 			emulate_csb_update(execlist, &status, false);
2458453d674SZhi Wang 		}
2468453d674SZhi Wang 	} else {
2478453d674SZhi Wang 		WARN_ON(1);
2488453d674SZhi Wang 		return -EINVAL;
2498453d674SZhi Wang 	}
2508453d674SZhi Wang 
2518453d674SZhi Wang 	return 0;
2528453d674SZhi Wang }
2538453d674SZhi Wang 
get_next_execlist_slot(struct intel_vgpu_execlist * execlist)2548453d674SZhi Wang static struct intel_vgpu_execlist_slot *get_next_execlist_slot(
2558453d674SZhi Wang 		struct intel_vgpu_execlist *execlist)
2568453d674SZhi Wang {
2578453d674SZhi Wang 	struct intel_vgpu *vgpu = execlist->vgpu;
2588fde4107SChris Wilson 	u32 status_reg =
2598fde4107SChris Wilson 		execlist_ring_mmio(execlist->engine, _EL_OFFSET_STATUS);
2608453d674SZhi Wang 	struct execlist_status_format status;
2618453d674SZhi Wang 
2628453d674SZhi Wang 	status.ldw = vgpu_vreg(vgpu, status_reg);
2638453d674SZhi Wang 	status.udw = vgpu_vreg(vgpu, status_reg + 4);
2648453d674SZhi Wang 
2658453d674SZhi Wang 	if (status.execlist_queue_full) {
266695fbc08STina Zhang 		gvt_vgpu_err("virtual execlist slots are full\n");
2678453d674SZhi Wang 		return NULL;
2688453d674SZhi Wang 	}
2698453d674SZhi Wang 
2708453d674SZhi Wang 	return &execlist->slot[status.execlist_write_pointer];
2718453d674SZhi Wang }
2728453d674SZhi Wang 
emulate_execlist_schedule_in(struct intel_vgpu_execlist * execlist,struct execlist_ctx_descriptor_format ctx[2])27328c4c6caSZhi Wang static int emulate_execlist_schedule_in(struct intel_vgpu_execlist *execlist,
2748453d674SZhi Wang 		struct execlist_ctx_descriptor_format ctx[2])
2758453d674SZhi Wang {
2768453d674SZhi Wang 	struct intel_vgpu_execlist_slot *running = execlist->running_slot;
2778453d674SZhi Wang 	struct intel_vgpu_execlist_slot *slot =
2788453d674SZhi Wang 		get_next_execlist_slot(execlist);
2798453d674SZhi Wang 
2808453d674SZhi Wang 	struct execlist_ctx_descriptor_format *ctx0, *ctx1;
2818453d674SZhi Wang 	struct execlist_context_status_format status;
282695fbc08STina Zhang 	struct intel_vgpu *vgpu = execlist->vgpu;
2838453d674SZhi Wang 
2848453d674SZhi Wang 	gvt_dbg_el("emulate schedule-in\n");
2858453d674SZhi Wang 
2868453d674SZhi Wang 	if (!slot) {
287695fbc08STina Zhang 		gvt_vgpu_err("no available execlist slot\n");
2888453d674SZhi Wang 		return -EINVAL;
2898453d674SZhi Wang 	}
2908453d674SZhi Wang 
2918453d674SZhi Wang 	memset(&status, 0, sizeof(status));
2928453d674SZhi Wang 	memset(slot->ctx, 0, sizeof(slot->ctx));
2938453d674SZhi Wang 
2948453d674SZhi Wang 	slot->ctx[0] = ctx[0];
2958453d674SZhi Wang 	slot->ctx[1] = ctx[1];
2968453d674SZhi Wang 
2978453d674SZhi Wang 	gvt_dbg_el("alloc slot index %d ctx 0 %x ctx 1 %x\n",
2988453d674SZhi Wang 			slot->index, ctx[0].context_id,
2998453d674SZhi Wang 			ctx[1].context_id);
3008453d674SZhi Wang 
3018453d674SZhi Wang 	/*
3028453d674SZhi Wang 	 * no running execlist, make this write bundle as running execlist
3038453d674SZhi Wang 	 * -> idle-to-active
3048453d674SZhi Wang 	 */
3058453d674SZhi Wang 	if (!running) {
3068453d674SZhi Wang 		gvt_dbg_el("no current running execlist\n");
3078453d674SZhi Wang 
3088453d674SZhi Wang 		execlist->running_slot = slot;
3098453d674SZhi Wang 		execlist->pending_slot = NULL;
3108453d674SZhi Wang 		execlist->running_context = &slot->ctx[0];
3118453d674SZhi Wang 
3128453d674SZhi Wang 		gvt_dbg_el("running slot index %d running context %x\n",
3138453d674SZhi Wang 				execlist->running_slot->index,
3148453d674SZhi Wang 				execlist->running_context->context_id);
3158453d674SZhi Wang 
3168453d674SZhi Wang 		emulate_execlist_status(execlist);
3178453d674SZhi Wang 
3188453d674SZhi Wang 		status.idle_to_active = 1;
3198453d674SZhi Wang 		status.context_id = 0;
3208453d674SZhi Wang 
3218453d674SZhi Wang 		emulate_csb_update(execlist, &status, false);
3228453d674SZhi Wang 		return 0;
3238453d674SZhi Wang 	}
3248453d674SZhi Wang 
3258453d674SZhi Wang 	ctx0 = &running->ctx[0];
3268453d674SZhi Wang 	ctx1 = &running->ctx[1];
3278453d674SZhi Wang 
3288453d674SZhi Wang 	gvt_dbg_el("current running slot index %d ctx 0 %x ctx 1 %x\n",
3298453d674SZhi Wang 		running->index, ctx0->context_id, ctx1->context_id);
3308453d674SZhi Wang 
3318453d674SZhi Wang 	/*
3328453d674SZhi Wang 	 * already has an running execlist
3338453d674SZhi Wang 	 *	a. running ctx1 is valid,
3348453d674SZhi Wang 	 *	   ctx0 is finished, and running ctx1 == new execlist ctx[0]
3358453d674SZhi Wang 	 *	b. running ctx1 is not valid,
3368453d674SZhi Wang 	 *	   ctx0 == new execlist ctx[0]
3378453d674SZhi Wang 	 * ----> lite-restore + preempted
3388453d674SZhi Wang 	 */
3398453d674SZhi Wang 	if ((valid_context(ctx1) && same_context(ctx1, &slot->ctx[0]) &&
3408453d674SZhi Wang 		/* condition a */
3418453d674SZhi Wang 		(!same_context(ctx0, execlist->running_context))) ||
3428453d674SZhi Wang 			(!valid_context(ctx1) &&
3438453d674SZhi Wang 			 same_context(ctx0, &slot->ctx[0]))) { /* condition b */
3448453d674SZhi Wang 		gvt_dbg_el("need to switch virtual execlist slot\n");
3458453d674SZhi Wang 
3468453d674SZhi Wang 		execlist->pending_slot = slot;
3478453d674SZhi Wang 		switch_virtual_execlist_slot(execlist);
3488453d674SZhi Wang 
3498453d674SZhi Wang 		emulate_execlist_status(execlist);
3508453d674SZhi Wang 
3518453d674SZhi Wang 		status.lite_restore = status.preempted = 1;
3528453d674SZhi Wang 		status.context_id = ctx[0].context_id;
3538453d674SZhi Wang 
3548453d674SZhi Wang 		emulate_csb_update(execlist, &status, false);
3558453d674SZhi Wang 	} else {
3568453d674SZhi Wang 		gvt_dbg_el("emulate as pending slot\n");
3578453d674SZhi Wang 		/*
3588453d674SZhi Wang 		 * otherwise
3598453d674SZhi Wang 		 * --> emulate pending execlist exist + but no preemption case
3608453d674SZhi Wang 		 */
3618453d674SZhi Wang 		execlist->pending_slot = slot;
3628453d674SZhi Wang 		emulate_execlist_status(execlist);
3638453d674SZhi Wang 	}
3648453d674SZhi Wang 	return 0;
3658453d674SZhi Wang }
3668453d674SZhi Wang 
36728c4c6caSZhi Wang #define get_desc_from_elsp_dwords(ed, i) \
36828c4c6caSZhi Wang 	((struct execlist_ctx_descriptor_format *)&((ed)->data[i * 2]))
36928c4c6caSZhi Wang 
prepare_execlist_workload(struct intel_vgpu_workload * workload)3700cce2823Sfred gao static int prepare_execlist_workload(struct intel_vgpu_workload *workload)
3710cce2823Sfred gao {
3720cce2823Sfred gao 	struct intel_vgpu *vgpu = workload->vgpu;
3731406a14bSZhi Wang 	struct intel_vgpu_submission *s = &vgpu->submission;
3740cce2823Sfred gao 	struct execlist_ctx_descriptor_format ctx[2];
3750cce2823Sfred gao 	int ret;
3760cce2823Sfred gao 
3770cce2823Sfred gao 	if (!workload->emulate_schedule_in)
3780cce2823Sfred gao 		return 0;
3790cce2823Sfred gao 
38054cff647SZhi Wang 	ctx[0] = *get_desc_from_elsp_dwords(&workload->elsp_dwords, 0);
38154cff647SZhi Wang 	ctx[1] = *get_desc_from_elsp_dwords(&workload->elsp_dwords, 1);
3820cce2823Sfred gao 
3838fde4107SChris Wilson 	ret = emulate_execlist_schedule_in(&s->execlist[workload->engine->id],
3848fde4107SChris Wilson 					   ctx);
385d8235b5eSZhi Wang 	if (ret) {
3860cce2823Sfred gao 		gvt_vgpu_err("fail to emulate execlist schedule in\n");
3870cce2823Sfred gao 		return ret;
3880cce2823Sfred gao 	}
389d8235b5eSZhi Wang 	return 0;
390d8235b5eSZhi Wang }
3910cce2823Sfred gao 
complete_execlist_workload(struct intel_vgpu_workload * workload)39228c4c6caSZhi Wang static int complete_execlist_workload(struct intel_vgpu_workload *workload)
39328c4c6caSZhi Wang {
39428c4c6caSZhi Wang 	struct intel_vgpu *vgpu = workload->vgpu;
3951406a14bSZhi Wang 	struct intel_vgpu_submission *s = &vgpu->submission;
3968fde4107SChris Wilson 	struct intel_vgpu_execlist *execlist =
3978fde4107SChris Wilson 		&s->execlist[workload->engine->id];
39828c4c6caSZhi Wang 	struct intel_vgpu_workload *next_workload;
3998fde4107SChris Wilson 	struct list_head *next = workload_q_head(vgpu, workload->engine)->next;
40028c4c6caSZhi Wang 	bool lite_restore = false;
401c9214008Sfred gao 	int ret = 0;
40228c4c6caSZhi Wang 
4038fde4107SChris Wilson 	gvt_dbg_el("complete workload %p status %d\n",
4048fde4107SChris Wilson 		   workload, workload->status);
40528c4c6caSZhi Wang 
4068fde4107SChris Wilson 	if (workload->status || vgpu->resetting_eng & workload->engine->mask)
40728c4c6caSZhi Wang 		goto out;
40828c4c6caSZhi Wang 
4098fde4107SChris Wilson 	if (!list_empty(workload_q_head(vgpu, workload->engine))) {
41028c4c6caSZhi Wang 		struct execlist_ctx_descriptor_format *this_desc, *next_desc;
41128c4c6caSZhi Wang 
41228c4c6caSZhi Wang 		next_workload = container_of(next,
41328c4c6caSZhi Wang 				struct intel_vgpu_workload, list);
41428c4c6caSZhi Wang 		this_desc = &workload->ctx_desc;
41528c4c6caSZhi Wang 		next_desc = &next_workload->ctx_desc;
41628c4c6caSZhi Wang 
41728c4c6caSZhi Wang 		lite_restore = same_context(this_desc, next_desc);
41828c4c6caSZhi Wang 	}
41928c4c6caSZhi Wang 
42028c4c6caSZhi Wang 	if (lite_restore) {
42128c4c6caSZhi Wang 		gvt_dbg_el("next context == current - no schedule-out\n");
422c9214008Sfred gao 		goto out;
42328c4c6caSZhi Wang 	}
42428c4c6caSZhi Wang 
42528c4c6caSZhi Wang 	ret = emulate_execlist_ctx_schedule_out(execlist, &workload->ctx_desc);
42628c4c6caSZhi Wang out:
42728c4c6caSZhi Wang 	return ret;
42828c4c6caSZhi Wang }
42928c4c6caSZhi Wang 
submit_context(struct intel_vgpu * vgpu,const struct intel_engine_cs * engine,struct execlist_ctx_descriptor_format * desc,bool emulate_schedule_in)4308fde4107SChris Wilson static int submit_context(struct intel_vgpu *vgpu,
4318fde4107SChris Wilson 			  const struct intel_engine_cs *engine,
43228c4c6caSZhi Wang 			  struct execlist_ctx_descriptor_format *desc,
43328c4c6caSZhi Wang 			  bool emulate_schedule_in)
43428c4c6caSZhi Wang {
4351406a14bSZhi Wang 	struct intel_vgpu_submission *s = &vgpu->submission;
43628c4c6caSZhi Wang 	struct intel_vgpu_workload *workload = NULL;
43728c4c6caSZhi Wang 
4388fde4107SChris Wilson 	workload = intel_vgpu_create_workload(vgpu, engine, desc);
43921527a8dSZhi Wang 	if (IS_ERR(workload))
44021527a8dSZhi Wang 		return PTR_ERR(workload);
44128c4c6caSZhi Wang 
44228c4c6caSZhi Wang 	workload->prepare = prepare_execlist_workload;
44328c4c6caSZhi Wang 	workload->complete = complete_execlist_workload;
44428c4c6caSZhi Wang 	workload->emulate_schedule_in = emulate_schedule_in;
44528c4c6caSZhi Wang 
44628c4c6caSZhi Wang 	if (emulate_schedule_in)
4478fde4107SChris Wilson 		workload->elsp_dwords = s->execlist[engine->id].elsp_dwords;
44828c4c6caSZhi Wang 
44928c4c6caSZhi Wang 	gvt_dbg_el("workload %p emulate schedule_in %d\n", workload,
45028c4c6caSZhi Wang 		   emulate_schedule_in);
45128c4c6caSZhi Wang 
45259a716c6SChangbin Du 	intel_vgpu_queue_workload(workload);
4536d763035SZhi Wang 	return 0;
45428c4c6caSZhi Wang }
45528c4c6caSZhi Wang 
intel_vgpu_submit_execlist(struct intel_vgpu * vgpu,const struct intel_engine_cs * engine)4568fde4107SChris Wilson int intel_vgpu_submit_execlist(struct intel_vgpu *vgpu,
4578fde4107SChris Wilson 			       const struct intel_engine_cs *engine)
45828c4c6caSZhi Wang {
4591406a14bSZhi Wang 	struct intel_vgpu_submission *s = &vgpu->submission;
4608fde4107SChris Wilson 	struct intel_vgpu_execlist *execlist = &s->execlist[engine->id];
46154cff647SZhi Wang 	struct execlist_ctx_descriptor_format *desc[2];
4625d0f5de1SChangbin Du 	int i, ret;
46328c4c6caSZhi Wang 
46454cff647SZhi Wang 	desc[0] = get_desc_from_elsp_dwords(&execlist->elsp_dwords, 0);
46554cff647SZhi Wang 	desc[1] = get_desc_from_elsp_dwords(&execlist->elsp_dwords, 1);
46628c4c6caSZhi Wang 
46754cff647SZhi Wang 	if (!desc[0]->valid) {
4685d0f5de1SChangbin Du 		gvt_vgpu_err("invalid elsp submission, desc0 is invalid\n");
4695d0f5de1SChangbin Du 		goto inv_desc;
4705d0f5de1SChangbin Du 	}
47128c4c6caSZhi Wang 
4725d0f5de1SChangbin Du 	for (i = 0; i < ARRAY_SIZE(desc); i++) {
47354cff647SZhi Wang 		if (!desc[i]->valid)
47428c4c6caSZhi Wang 			continue;
47554cff647SZhi Wang 		if (!desc[i]->privilege_access) {
476695fbc08STina Zhang 			gvt_vgpu_err("unexpected GGTT elsp submission\n");
4775d0f5de1SChangbin Du 			goto inv_desc;
47828c4c6caSZhi Wang 		}
47928c4c6caSZhi Wang 	}
48028c4c6caSZhi Wang 
48128c4c6caSZhi Wang 	/* submit workload */
4825d0f5de1SChangbin Du 	for (i = 0; i < ARRAY_SIZE(desc); i++) {
48354cff647SZhi Wang 		if (!desc[i]->valid)
4845d0f5de1SChangbin Du 			continue;
4858fde4107SChris Wilson 		ret = submit_context(vgpu, engine, desc[i], i == 0);
48628c4c6caSZhi Wang 		if (ret) {
4875d0f5de1SChangbin Du 			gvt_vgpu_err("failed to submit desc %d\n", i);
48828c4c6caSZhi Wang 			return ret;
48928c4c6caSZhi Wang 		}
49028c4c6caSZhi Wang 	}
4915d0f5de1SChangbin Du 
49228c4c6caSZhi Wang 	return 0;
4935d0f5de1SChangbin Du 
4945d0f5de1SChangbin Du inv_desc:
4955d0f5de1SChangbin Du 	gvt_vgpu_err("descriptors content: desc0 %08x %08x desc1 %08x %08x\n",
49654cff647SZhi Wang 		     desc[0]->udw, desc[0]->ldw, desc[1]->udw, desc[1]->ldw);
4975d0f5de1SChangbin Du 	return -EINVAL;
49828c4c6caSZhi Wang }
49928c4c6caSZhi Wang 
init_vgpu_execlist(struct intel_vgpu * vgpu,const struct intel_engine_cs * engine)5008fde4107SChris Wilson static void init_vgpu_execlist(struct intel_vgpu *vgpu,
5018fde4107SChris Wilson 			       const struct intel_engine_cs *engine)
5028453d674SZhi Wang {
5031406a14bSZhi Wang 	struct intel_vgpu_submission *s = &vgpu->submission;
5048fde4107SChris Wilson 	struct intel_vgpu_execlist *execlist = &s->execlist[engine->id];
5058453d674SZhi Wang 	struct execlist_context_status_pointer_format ctx_status_ptr;
5068453d674SZhi Wang 	u32 ctx_status_ptr_reg;
5078453d674SZhi Wang 
5088453d674SZhi Wang 	memset(execlist, 0, sizeof(*execlist));
5098453d674SZhi Wang 
5108453d674SZhi Wang 	execlist->vgpu = vgpu;
5118fde4107SChris Wilson 	execlist->engine = engine;
5128453d674SZhi Wang 	execlist->slot[0].index = 0;
5138453d674SZhi Wang 	execlist->slot[1].index = 1;
5148453d674SZhi Wang 
5158fde4107SChris Wilson 	ctx_status_ptr_reg = execlist_ring_mmio(engine, _EL_OFFSET_STATUS_PTR);
5168453d674SZhi Wang 	ctx_status_ptr.dw = vgpu_vreg(vgpu, ctx_status_ptr_reg);
517a34f8363SMin He 	ctx_status_ptr.read_ptr = 0;
518a34f8363SMin He 	ctx_status_ptr.write_ptr = 0x7;
5198453d674SZhi Wang 	vgpu_vreg(vgpu, ctx_status_ptr_reg) = ctx_status_ptr.dw;
5208453d674SZhi Wang }
5218453d674SZhi Wang 
clean_execlist(struct intel_vgpu * vgpu,intel_engine_mask_t engine_mask)5223a891a62SChris Wilson static void clean_execlist(struct intel_vgpu *vgpu,
5233a891a62SChris Wilson 			   intel_engine_mask_t engine_mask)
52428c4c6caSZhi Wang {
525325eb94aSZhi Wang 	struct intel_vgpu_submission *s = &vgpu->submission;
526d18ac1a7SChris Wilson 	struct intel_engine_cs *engine;
5273a891a62SChris Wilson 	intel_engine_mask_t tmp;
528325eb94aSZhi Wang 
529d18ac1a7SChris Wilson 	for_each_engine_masked(engine, vgpu->gvt->gt, engine_mask, tmp) {
5307569a06dSWeinan Li 		kfree(s->ring_scan_buffer[engine->id]);
5317569a06dSWeinan Li 		s->ring_scan_buffer[engine->id] = NULL;
5327569a06dSWeinan Li 		s->ring_scan_buffer_size[engine->id] = 0;
53328c4c6caSZhi Wang 	}
5340a53bc07Sfred gao }
5350a53bc07Sfred gao 
reset_execlist(struct intel_vgpu * vgpu,intel_engine_mask_t engine_mask)5367b302556SChris Wilson static void reset_execlist(struct intel_vgpu *vgpu,
5373a891a62SChris Wilson 			   intel_engine_mask_t engine_mask)
538e4734057SZhi Wang {
5390427f06aSDu, Changbin 	struct intel_engine_cs *engine;
5403a891a62SChris Wilson 	intel_engine_mask_t tmp;
541e4734057SZhi Wang 
542d18ac1a7SChris Wilson 	for_each_engine_masked(engine, vgpu->gvt->gt, engine_mask, tmp)
5438fde4107SChris Wilson 		init_vgpu_execlist(vgpu, engine);
544e4734057SZhi Wang }
545ad1d3636SZhi Wang 
init_execlist(struct intel_vgpu * vgpu,intel_engine_mask_t engine_mask)5467569a06dSWeinan Li static int init_execlist(struct intel_vgpu *vgpu,
5473a891a62SChris Wilson 			 intel_engine_mask_t engine_mask)
54806bb372fSZhi Wang {
5497569a06dSWeinan Li 	reset_execlist(vgpu, engine_mask);
55006bb372fSZhi Wang 	return 0;
55106bb372fSZhi Wang }
55206bb372fSZhi Wang 
553ad1d3636SZhi Wang const struct intel_vgpu_submission_ops intel_vgpu_execlist_submission_ops = {
554ad1d3636SZhi Wang 	.name = "execlist",
555ad1d3636SZhi Wang 	.init = init_execlist,
55606bb372fSZhi Wang 	.reset = reset_execlist,
557ad1d3636SZhi Wang 	.clean = clean_execlist,
558ad1d3636SZhi Wang };
559