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