162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright © 2019 Intel Corporation
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "gt/intel_engine_pm.h"
762306a36Sopenharmony_ci#include "gt/intel_gpu_commands.h"
862306a36Sopenharmony_ci#include "i915_selftest.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "gem/selftests/igt_gem_utils.h"
1162306a36Sopenharmony_ci#include "gem/selftests/mock_context.h"
1262306a36Sopenharmony_ci#include "selftests/igt_reset.h"
1362306a36Sopenharmony_ci#include "selftests/igt_spinner.h"
1462306a36Sopenharmony_ci#include "selftests/intel_scheduler_helpers.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistruct live_mocs {
1762306a36Sopenharmony_ci	struct drm_i915_mocs_table table;
1862306a36Sopenharmony_ci	struct drm_i915_mocs_table *mocs;
1962306a36Sopenharmony_ci	struct drm_i915_mocs_table *l3cc;
2062306a36Sopenharmony_ci	struct i915_vma *scratch;
2162306a36Sopenharmony_ci	void *vaddr;
2262306a36Sopenharmony_ci};
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic struct intel_context *mocs_context_create(struct intel_engine_cs *engine)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	struct intel_context *ce;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	ce = intel_context_create(engine);
2962306a36Sopenharmony_ci	if (IS_ERR(ce))
3062306a36Sopenharmony_ci		return ce;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	/* We build large requests to read the registers from the ring */
3362306a36Sopenharmony_ci	ce->ring_size = SZ_16K;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	return ce;
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic int request_add_sync(struct i915_request *rq, int err)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	i915_request_get(rq);
4162306a36Sopenharmony_ci	i915_request_add(rq);
4262306a36Sopenharmony_ci	if (i915_request_wait(rq, 0, HZ / 5) < 0)
4362306a36Sopenharmony_ci		err = -ETIME;
4462306a36Sopenharmony_ci	i915_request_put(rq);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	return err;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic int request_add_spin(struct i915_request *rq, struct igt_spinner *spin)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	int err = 0;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	i915_request_get(rq);
5462306a36Sopenharmony_ci	i915_request_add(rq);
5562306a36Sopenharmony_ci	if (spin && !igt_wait_for_spinner(spin, rq))
5662306a36Sopenharmony_ci		err = -ETIME;
5762306a36Sopenharmony_ci	i915_request_put(rq);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	return err;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic int live_mocs_init(struct live_mocs *arg, struct intel_gt *gt)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	unsigned int flags;
6562306a36Sopenharmony_ci	int err;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	memset(arg, 0, sizeof(*arg));
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	flags = get_mocs_settings(gt->i915, &arg->table);
7062306a36Sopenharmony_ci	if (!flags)
7162306a36Sopenharmony_ci		return -EINVAL;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (flags & HAS_RENDER_L3CC)
7462306a36Sopenharmony_ci		arg->l3cc = &arg->table;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (flags & (HAS_GLOBAL_MOCS | HAS_ENGINE_MOCS))
7762306a36Sopenharmony_ci		arg->mocs = &arg->table;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	arg->scratch =
8062306a36Sopenharmony_ci		__vm_create_scratch_for_read_pinned(&gt->ggtt->vm, PAGE_SIZE);
8162306a36Sopenharmony_ci	if (IS_ERR(arg->scratch))
8262306a36Sopenharmony_ci		return PTR_ERR(arg->scratch);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	arg->vaddr = i915_gem_object_pin_map_unlocked(arg->scratch->obj, I915_MAP_WB);
8562306a36Sopenharmony_ci	if (IS_ERR(arg->vaddr)) {
8662306a36Sopenharmony_ci		err = PTR_ERR(arg->vaddr);
8762306a36Sopenharmony_ci		goto err_scratch;
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	return 0;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cierr_scratch:
9362306a36Sopenharmony_ci	i915_vma_unpin_and_release(&arg->scratch, 0);
9462306a36Sopenharmony_ci	return err;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic void live_mocs_fini(struct live_mocs *arg)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	i915_vma_unpin_and_release(&arg->scratch, I915_VMA_RELEASE_MAP);
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic int read_regs(struct i915_request *rq,
10362306a36Sopenharmony_ci		     u32 addr, unsigned int count,
10462306a36Sopenharmony_ci		     u32 *offset)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	unsigned int i;
10762306a36Sopenharmony_ci	u32 *cs;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	GEM_BUG_ON(!IS_ALIGNED(*offset, sizeof(u32)));
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	cs = intel_ring_begin(rq, 4 * count);
11262306a36Sopenharmony_ci	if (IS_ERR(cs))
11362306a36Sopenharmony_ci		return PTR_ERR(cs);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
11662306a36Sopenharmony_ci		*cs++ = MI_STORE_REGISTER_MEM_GEN8 | MI_USE_GGTT;
11762306a36Sopenharmony_ci		*cs++ = addr;
11862306a36Sopenharmony_ci		*cs++ = *offset;
11962306a36Sopenharmony_ci		*cs++ = 0;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci		addr += sizeof(u32);
12262306a36Sopenharmony_ci		*offset += sizeof(u32);
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	intel_ring_advance(rq, cs);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	return 0;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic int read_mocs_table(struct i915_request *rq,
13162306a36Sopenharmony_ci			   const struct drm_i915_mocs_table *table,
13262306a36Sopenharmony_ci			   u32 *offset)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	struct intel_gt *gt = rq->engine->gt;
13562306a36Sopenharmony_ci	u32 addr;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	if (!table)
13862306a36Sopenharmony_ci		return 0;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	if (HAS_GLOBAL_MOCS_REGISTERS(rq->i915))
14162306a36Sopenharmony_ci		addr = global_mocs_offset() + gt->uncore->gsi_offset;
14262306a36Sopenharmony_ci	else
14362306a36Sopenharmony_ci		addr = mocs_offset(rq->engine);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	return read_regs(rq, addr, table->n_entries, offset);
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic int read_l3cc_table(struct i915_request *rq,
14962306a36Sopenharmony_ci			   const struct drm_i915_mocs_table *table,
15062306a36Sopenharmony_ci			   u32 *offset)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	u32 addr = i915_mmio_reg_offset(GEN9_LNCFCMOCS(0));
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	if (!table)
15562306a36Sopenharmony_ci		return 0;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	return read_regs(rq, addr, (table->n_entries + 1) / 2, offset);
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic int check_mocs_table(struct intel_engine_cs *engine,
16162306a36Sopenharmony_ci			    const struct drm_i915_mocs_table *table,
16262306a36Sopenharmony_ci			    u32 **vaddr)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	unsigned int i;
16562306a36Sopenharmony_ci	u32 expect;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	if (!table)
16862306a36Sopenharmony_ci		return 0;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	for_each_mocs(expect, table, i) {
17162306a36Sopenharmony_ci		if (**vaddr != expect) {
17262306a36Sopenharmony_ci			pr_err("%s: Invalid MOCS[%d] entry, found %08x, expected %08x\n",
17362306a36Sopenharmony_ci			       engine->name, i, **vaddr, expect);
17462306a36Sopenharmony_ci			return -EINVAL;
17562306a36Sopenharmony_ci		}
17662306a36Sopenharmony_ci		++*vaddr;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	return 0;
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic bool mcr_range(struct drm_i915_private *i915, u32 offset)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	/*
18562306a36Sopenharmony_ci	 * Registers in this range are affected by the MCR selector
18662306a36Sopenharmony_ci	 * which only controls CPU initiated MMIO. Routing does not
18762306a36Sopenharmony_ci	 * work for CS access so we cannot verify them on this path.
18862306a36Sopenharmony_ci	 */
18962306a36Sopenharmony_ci	return GRAPHICS_VER(i915) >= 8 && offset >= 0xb000 && offset <= 0xb4ff;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic int check_l3cc_table(struct intel_engine_cs *engine,
19362306a36Sopenharmony_ci			    const struct drm_i915_mocs_table *table,
19462306a36Sopenharmony_ci			    u32 **vaddr)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	/* Can we read the MCR range 0xb00 directly? See intel_workarounds! */
19762306a36Sopenharmony_ci	u32 reg = i915_mmio_reg_offset(GEN9_LNCFCMOCS(0));
19862306a36Sopenharmony_ci	unsigned int i;
19962306a36Sopenharmony_ci	u32 expect;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (!table)
20262306a36Sopenharmony_ci		return 0;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	for_each_l3cc(expect, table, i) {
20562306a36Sopenharmony_ci		if (!mcr_range(engine->i915, reg) && **vaddr != expect) {
20662306a36Sopenharmony_ci			pr_err("%s: Invalid L3CC[%d] entry, found %08x, expected %08x\n",
20762306a36Sopenharmony_ci			       engine->name, i, **vaddr, expect);
20862306a36Sopenharmony_ci			return -EINVAL;
20962306a36Sopenharmony_ci		}
21062306a36Sopenharmony_ci		++*vaddr;
21162306a36Sopenharmony_ci		reg += 4;
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	return 0;
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic int check_mocs_engine(struct live_mocs *arg,
21862306a36Sopenharmony_ci			     struct intel_context *ce)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	struct i915_vma *vma = arg->scratch;
22162306a36Sopenharmony_ci	struct i915_request *rq;
22262306a36Sopenharmony_ci	u32 offset;
22362306a36Sopenharmony_ci	u32 *vaddr;
22462306a36Sopenharmony_ci	int err;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	memset32(arg->vaddr, STACK_MAGIC, PAGE_SIZE / sizeof(u32));
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	rq = intel_context_create_request(ce);
22962306a36Sopenharmony_ci	if (IS_ERR(rq))
23062306a36Sopenharmony_ci		return PTR_ERR(rq);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	err = igt_vma_move_to_active_unlocked(vma, rq, EXEC_OBJECT_WRITE);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	/* Read the mocs tables back using SRM */
23562306a36Sopenharmony_ci	offset = i915_ggtt_offset(vma);
23662306a36Sopenharmony_ci	if (!err)
23762306a36Sopenharmony_ci		err = read_mocs_table(rq, arg->mocs, &offset);
23862306a36Sopenharmony_ci	if (!err && ce->engine->class == RENDER_CLASS)
23962306a36Sopenharmony_ci		err = read_l3cc_table(rq, arg->l3cc, &offset);
24062306a36Sopenharmony_ci	offset -= i915_ggtt_offset(vma);
24162306a36Sopenharmony_ci	GEM_BUG_ON(offset > PAGE_SIZE);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	err = request_add_sync(rq, err);
24462306a36Sopenharmony_ci	if (err)
24562306a36Sopenharmony_ci		return err;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	/* Compare the results against the expected tables */
24862306a36Sopenharmony_ci	vaddr = arg->vaddr;
24962306a36Sopenharmony_ci	if (!err)
25062306a36Sopenharmony_ci		err = check_mocs_table(ce->engine, arg->mocs, &vaddr);
25162306a36Sopenharmony_ci	if (!err && ce->engine->class == RENDER_CLASS)
25262306a36Sopenharmony_ci		err = check_l3cc_table(ce->engine, arg->l3cc, &vaddr);
25362306a36Sopenharmony_ci	if (err)
25462306a36Sopenharmony_ci		return err;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	GEM_BUG_ON(arg->vaddr + offset != vaddr);
25762306a36Sopenharmony_ci	return 0;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic int live_mocs_kernel(void *arg)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	struct intel_gt *gt = arg;
26362306a36Sopenharmony_ci	struct intel_engine_cs *engine;
26462306a36Sopenharmony_ci	enum intel_engine_id id;
26562306a36Sopenharmony_ci	struct live_mocs mocs;
26662306a36Sopenharmony_ci	int err;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	/* Basic check the system is configured with the expected mocs table */
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	err = live_mocs_init(&mocs, gt);
27162306a36Sopenharmony_ci	if (err)
27262306a36Sopenharmony_ci		return err;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	for_each_engine(engine, gt, id) {
27562306a36Sopenharmony_ci		intel_engine_pm_get(engine);
27662306a36Sopenharmony_ci		err = check_mocs_engine(&mocs, engine->kernel_context);
27762306a36Sopenharmony_ci		intel_engine_pm_put(engine);
27862306a36Sopenharmony_ci		if (err)
27962306a36Sopenharmony_ci			break;
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	live_mocs_fini(&mocs);
28362306a36Sopenharmony_ci	return err;
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic int live_mocs_clean(void *arg)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	struct intel_gt *gt = arg;
28962306a36Sopenharmony_ci	struct intel_engine_cs *engine;
29062306a36Sopenharmony_ci	enum intel_engine_id id;
29162306a36Sopenharmony_ci	struct live_mocs mocs;
29262306a36Sopenharmony_ci	int err;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	/* Every new context should see the same mocs table */
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	err = live_mocs_init(&mocs, gt);
29762306a36Sopenharmony_ci	if (err)
29862306a36Sopenharmony_ci		return err;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	for_each_engine(engine, gt, id) {
30162306a36Sopenharmony_ci		struct intel_context *ce;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci		ce = mocs_context_create(engine);
30462306a36Sopenharmony_ci		if (IS_ERR(ce)) {
30562306a36Sopenharmony_ci			err = PTR_ERR(ce);
30662306a36Sopenharmony_ci			break;
30762306a36Sopenharmony_ci		}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci		err = check_mocs_engine(&mocs, ce);
31062306a36Sopenharmony_ci		intel_context_put(ce);
31162306a36Sopenharmony_ci		if (err)
31262306a36Sopenharmony_ci			break;
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	live_mocs_fini(&mocs);
31662306a36Sopenharmony_ci	return err;
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic int active_engine_reset(struct intel_context *ce,
32062306a36Sopenharmony_ci			       const char *reason,
32162306a36Sopenharmony_ci			       bool using_guc)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct igt_spinner spin;
32462306a36Sopenharmony_ci	struct i915_request *rq;
32562306a36Sopenharmony_ci	int err;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	err = igt_spinner_init(&spin, ce->engine->gt);
32862306a36Sopenharmony_ci	if (err)
32962306a36Sopenharmony_ci		return err;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	rq = igt_spinner_create_request(&spin, ce, MI_NOOP);
33262306a36Sopenharmony_ci	if (IS_ERR(rq)) {
33362306a36Sopenharmony_ci		igt_spinner_fini(&spin);
33462306a36Sopenharmony_ci		return PTR_ERR(rq);
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	err = request_add_spin(rq, &spin);
33862306a36Sopenharmony_ci	if (err == 0 && !using_guc)
33962306a36Sopenharmony_ci		err = intel_engine_reset(ce->engine, reason);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	/* Ensure the reset happens and kills the engine */
34262306a36Sopenharmony_ci	if (err == 0)
34362306a36Sopenharmony_ci		err = intel_selftest_wait_for_rq(rq);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	igt_spinner_end(&spin);
34662306a36Sopenharmony_ci	igt_spinner_fini(&spin);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	return err;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic int __live_mocs_reset(struct live_mocs *mocs,
35262306a36Sopenharmony_ci			     struct intel_context *ce, bool using_guc)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	struct intel_gt *gt = ce->engine->gt;
35562306a36Sopenharmony_ci	int err;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	if (intel_has_reset_engine(gt)) {
35862306a36Sopenharmony_ci		if (!using_guc) {
35962306a36Sopenharmony_ci			err = intel_engine_reset(ce->engine, "mocs");
36062306a36Sopenharmony_ci			if (err)
36162306a36Sopenharmony_ci				return err;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci			err = check_mocs_engine(mocs, ce);
36462306a36Sopenharmony_ci			if (err)
36562306a36Sopenharmony_ci				return err;
36662306a36Sopenharmony_ci		}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci		err = active_engine_reset(ce, "mocs", using_guc);
36962306a36Sopenharmony_ci		if (err)
37062306a36Sopenharmony_ci			return err;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci		err = check_mocs_engine(mocs, ce);
37362306a36Sopenharmony_ci		if (err)
37462306a36Sopenharmony_ci			return err;
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	if (intel_has_gpu_reset(gt)) {
37862306a36Sopenharmony_ci		intel_gt_reset(gt, ce->engine->mask, "mocs");
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci		err = check_mocs_engine(mocs, ce);
38162306a36Sopenharmony_ci		if (err)
38262306a36Sopenharmony_ci			return err;
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	return 0;
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_cistatic int live_mocs_reset(void *arg)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	struct intel_gt *gt = arg;
39162306a36Sopenharmony_ci	struct intel_engine_cs *engine;
39262306a36Sopenharmony_ci	enum intel_engine_id id;
39362306a36Sopenharmony_ci	struct live_mocs mocs;
39462306a36Sopenharmony_ci	int err = 0;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* Check the mocs setup is retained over per-engine and global resets */
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	err = live_mocs_init(&mocs, gt);
39962306a36Sopenharmony_ci	if (err)
40062306a36Sopenharmony_ci		return err;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	igt_global_reset_lock(gt);
40362306a36Sopenharmony_ci	for_each_engine(engine, gt, id) {
40462306a36Sopenharmony_ci		bool using_guc = intel_engine_uses_guc(engine);
40562306a36Sopenharmony_ci		struct intel_selftest_saved_policy saved;
40662306a36Sopenharmony_ci		struct intel_context *ce;
40762306a36Sopenharmony_ci		int err2;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci		err = intel_selftest_modify_policy(engine, &saved,
41062306a36Sopenharmony_ci						   SELFTEST_SCHEDULER_MODIFY_FAST_RESET);
41162306a36Sopenharmony_ci		if (err)
41262306a36Sopenharmony_ci			break;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci		ce = mocs_context_create(engine);
41562306a36Sopenharmony_ci		if (IS_ERR(ce)) {
41662306a36Sopenharmony_ci			err = PTR_ERR(ce);
41762306a36Sopenharmony_ci			goto restore;
41862306a36Sopenharmony_ci		}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci		intel_engine_pm_get(engine);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci		err = __live_mocs_reset(&mocs, ce, using_guc);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci		intel_engine_pm_put(engine);
42562306a36Sopenharmony_ci		intel_context_put(ce);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cirestore:
42862306a36Sopenharmony_ci		err2 = intel_selftest_restore_policy(engine, &saved);
42962306a36Sopenharmony_ci		if (err == 0)
43062306a36Sopenharmony_ci			err = err2;
43162306a36Sopenharmony_ci		if (err)
43262306a36Sopenharmony_ci			break;
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci	igt_global_reset_unlock(gt);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	live_mocs_fini(&mocs);
43762306a36Sopenharmony_ci	return err;
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ciint intel_mocs_live_selftests(struct drm_i915_private *i915)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	static const struct i915_subtest tests[] = {
44362306a36Sopenharmony_ci		SUBTEST(live_mocs_kernel),
44462306a36Sopenharmony_ci		SUBTEST(live_mocs_clean),
44562306a36Sopenharmony_ci		SUBTEST(live_mocs_reset),
44662306a36Sopenharmony_ci	};
44762306a36Sopenharmony_ci	struct drm_i915_mocs_table table;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	if (!get_mocs_settings(i915, &table))
45062306a36Sopenharmony_ci		return 0;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	return intel_gt_live_subtests(tests, to_gt(i915));
45362306a36Sopenharmony_ci}
454