Home | History | Annotate | Line # | Download | only in gt
      1 /*	$NetBSD: selftest_mocs.c,v 1.2 2021/12/18 23:45:30 riastradh Exp $	*/
      2 
      3 /*
      4  * SPDX-License-Identifier: MIT
      5  *
      6  * Copyright  2019 Intel Corporation
      7  */
      8 
      9 #include <sys/cdefs.h>
     10 __KERNEL_RCSID(0, "$NetBSD: selftest_mocs.c,v 1.2 2021/12/18 23:45:30 riastradh Exp $");
     11 
     12 #include "gt/intel_engine_pm.h"
     13 #include "i915_selftest.h"
     14 
     15 #include "gem/selftests/mock_context.h"
     16 #include "selftests/igt_reset.h"
     17 #include "selftests/igt_spinner.h"
     18 
     19 struct live_mocs {
     20 	struct drm_i915_mocs_table table;
     21 	struct i915_vma *scratch;
     22 	void *vaddr;
     23 };
     24 
     25 static int request_add_sync(struct i915_request *rq, int err)
     26 {
     27 	i915_request_get(rq);
     28 	i915_request_add(rq);
     29 	if (i915_request_wait(rq, 0, HZ / 5) < 0)
     30 		err = -ETIME;
     31 	i915_request_put(rq);
     32 
     33 	return err;
     34 }
     35 
     36 static int request_add_spin(struct i915_request *rq, struct igt_spinner *spin)
     37 {
     38 	int err = 0;
     39 
     40 	i915_request_get(rq);
     41 	i915_request_add(rq);
     42 	if (spin && !igt_wait_for_spinner(spin, rq))
     43 		err = -ETIME;
     44 	i915_request_put(rq);
     45 
     46 	return err;
     47 }
     48 
     49 static struct i915_vma *create_scratch(struct intel_gt *gt)
     50 {
     51 	struct drm_i915_gem_object *obj;
     52 	struct i915_vma *vma;
     53 	int err;
     54 
     55 	obj = i915_gem_object_create_internal(gt->i915, PAGE_SIZE);
     56 	if (IS_ERR(obj))
     57 		return ERR_CAST(obj);
     58 
     59 	i915_gem_object_set_cache_coherency(obj, I915_CACHING_CACHED);
     60 
     61 	vma = i915_vma_instance(obj, &gt->ggtt->vm, NULL);
     62 	if (IS_ERR(vma)) {
     63 		i915_gem_object_put(obj);
     64 		return vma;
     65 	}
     66 
     67 	err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
     68 	if (err) {
     69 		i915_gem_object_put(obj);
     70 		return ERR_PTR(err);
     71 	}
     72 
     73 	return vma;
     74 }
     75 
     76 static int live_mocs_init(struct live_mocs *arg, struct intel_gt *gt)
     77 {
     78 	int err;
     79 
     80 	if (!get_mocs_settings(gt->i915, &arg->table))
     81 		return -EINVAL;
     82 
     83 	arg->scratch = create_scratch(gt);
     84 	if (IS_ERR(arg->scratch))
     85 		return PTR_ERR(arg->scratch);
     86 
     87 	arg->vaddr = i915_gem_object_pin_map(arg->scratch->obj, I915_MAP_WB);
     88 	if (IS_ERR(arg->vaddr)) {
     89 		err = PTR_ERR(arg->vaddr);
     90 		goto err_scratch;
     91 	}
     92 
     93 	return 0;
     94 
     95 err_scratch:
     96 	i915_vma_unpin_and_release(&arg->scratch, 0);
     97 	return err;
     98 }
     99 
    100 static void live_mocs_fini(struct live_mocs *arg)
    101 {
    102 	i915_vma_unpin_and_release(&arg->scratch, I915_VMA_RELEASE_MAP);
    103 }
    104 
    105 static int read_regs(struct i915_request *rq,
    106 		     u32 addr, unsigned int count,
    107 		     uint32_t *offset)
    108 {
    109 	unsigned int i;
    110 	u32 *cs;
    111 
    112 	GEM_BUG_ON(!IS_ALIGNED(*offset, sizeof(u32)));
    113 
    114 	cs = intel_ring_begin(rq, 4 * count);
    115 	if (IS_ERR(cs))
    116 		return PTR_ERR(cs);
    117 
    118 	for (i = 0; i < count; i++) {
    119 		*cs++ = MI_STORE_REGISTER_MEM_GEN8 | MI_USE_GGTT;
    120 		*cs++ = addr;
    121 		*cs++ = *offset;
    122 		*cs++ = 0;
    123 
    124 		addr += sizeof(u32);
    125 		*offset += sizeof(u32);
    126 	}
    127 
    128 	intel_ring_advance(rq, cs);
    129 
    130 	return 0;
    131 }
    132 
    133 static int read_mocs_table(struct i915_request *rq,
    134 			   const struct drm_i915_mocs_table *table,
    135 			   uint32_t *offset)
    136 {
    137 	u32 addr;
    138 
    139 	if (HAS_GLOBAL_MOCS_REGISTERS(rq->i915))
    140 		addr = global_mocs_offset();
    141 	else
    142 		addr = mocs_offset(rq->engine);
    143 
    144 	return read_regs(rq, addr, table->n_entries, offset);
    145 }
    146 
    147 static int read_l3cc_table(struct i915_request *rq,
    148 			   const struct drm_i915_mocs_table *table,
    149 			   uint32_t *offset)
    150 {
    151 	u32 addr = i915_mmio_reg_offset(GEN9_LNCFCMOCS(0));
    152 
    153 	return read_regs(rq, addr, (table->n_entries + 1) / 2, offset);
    154 }
    155 
    156 static int check_mocs_table(struct intel_engine_cs *engine,
    157 			    const struct drm_i915_mocs_table *table,
    158 			    uint32_t **vaddr)
    159 {
    160 	unsigned int i;
    161 	u32 expect;
    162 
    163 	for_each_mocs(expect, table, i) {
    164 		if (**vaddr != expect) {
    165 			pr_err("%s: Invalid MOCS[%d] entry, found %08x, expected %08x\n",
    166 			       engine->name, i, **vaddr, expect);
    167 			return -EINVAL;
    168 		}
    169 		++*vaddr;
    170 	}
    171 
    172 	return 0;
    173 }
    174 
    175 static bool mcr_range(struct drm_i915_private *i915, u32 offset)
    176 {
    177 	/*
    178 	 * Registers in this range are affected by the MCR selector
    179 	 * which only controls CPU initiated MMIO. Routing does not
    180 	 * work for CS access so we cannot verify them on this path.
    181 	 */
    182 	return INTEL_GEN(i915) >= 8 && offset >= 0xb000 && offset <= 0xb4ff;
    183 }
    184 
    185 static int check_l3cc_table(struct intel_engine_cs *engine,
    186 			    const struct drm_i915_mocs_table *table,
    187 			    uint32_t **vaddr)
    188 {
    189 	/* Can we read the MCR range 0xb00 directly? See intel_workarounds! */
    190 	u32 reg = i915_mmio_reg_offset(GEN9_LNCFCMOCS(0));
    191 	unsigned int i;
    192 	u32 expect;
    193 
    194 	for_each_l3cc(expect, table, i) {
    195 		if (!mcr_range(engine->i915, reg) && **vaddr != expect) {
    196 			pr_err("%s: Invalid L3CC[%d] entry, found %08x, expected %08x\n",
    197 			       engine->name, i, **vaddr, expect);
    198 			return -EINVAL;
    199 		}
    200 		++*vaddr;
    201 		reg += 4;
    202 	}
    203 
    204 	return 0;
    205 }
    206 
    207 static int check_mocs_engine(struct live_mocs *arg,
    208 			     struct intel_context *ce)
    209 {
    210 	struct i915_vma *vma = arg->scratch;
    211 	struct i915_request *rq;
    212 	u32 offset;
    213 	u32 *vaddr;
    214 	int err;
    215 
    216 	memset32(arg->vaddr, STACK_MAGIC, PAGE_SIZE / sizeof(u32));
    217 
    218 	rq = intel_context_create_request(ce);
    219 	if (IS_ERR(rq))
    220 		return PTR_ERR(rq);
    221 
    222 	i915_vma_lock(vma);
    223 	err = i915_request_await_object(rq, vma->obj, true);
    224 	if (!err)
    225 		err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
    226 	i915_vma_unlock(vma);
    227 
    228 	/* Read the mocs tables back using SRM */
    229 	offset = i915_ggtt_offset(vma);
    230 	if (!err)
    231 		err = read_mocs_table(rq, &arg->table, &offset);
    232 	if (!err && ce->engine->class == RENDER_CLASS)
    233 		err = read_l3cc_table(rq, &arg->table, &offset);
    234 	offset -= i915_ggtt_offset(vma);
    235 	GEM_BUG_ON(offset > PAGE_SIZE);
    236 
    237 	err = request_add_sync(rq, err);
    238 	if (err)
    239 		return err;
    240 
    241 	/* Compare the results against the expected tables */
    242 	vaddr = arg->vaddr;
    243 	if (!err)
    244 		err = check_mocs_table(ce->engine, &arg->table, &vaddr);
    245 	if (!err && ce->engine->class == RENDER_CLASS)
    246 		err = check_l3cc_table(ce->engine, &arg->table, &vaddr);
    247 	if (err)
    248 		return err;
    249 
    250 	GEM_BUG_ON(arg->vaddr + offset != vaddr);
    251 	return 0;
    252 }
    253 
    254 static int live_mocs_kernel(void *arg)
    255 {
    256 	struct intel_gt *gt = arg;
    257 	struct intel_engine_cs *engine;
    258 	enum intel_engine_id id;
    259 	struct live_mocs mocs;
    260 	int err;
    261 
    262 	/* Basic check the system is configured with the expected mocs table */
    263 
    264 	err = live_mocs_init(&mocs, gt);
    265 	if (err)
    266 		return err;
    267 
    268 	for_each_engine(engine, gt, id) {
    269 		intel_engine_pm_get(engine);
    270 		err = check_mocs_engine(&mocs, engine->kernel_context);
    271 		intel_engine_pm_put(engine);
    272 		if (err)
    273 			break;
    274 	}
    275 
    276 	live_mocs_fini(&mocs);
    277 	return err;
    278 }
    279 
    280 static int live_mocs_clean(void *arg)
    281 {
    282 	struct intel_gt *gt = arg;
    283 	struct intel_engine_cs *engine;
    284 	enum intel_engine_id id;
    285 	struct live_mocs mocs;
    286 	int err;
    287 
    288 	/* Every new context should see the same mocs table */
    289 
    290 	err = live_mocs_init(&mocs, gt);
    291 	if (err)
    292 		return err;
    293 
    294 	for_each_engine(engine, gt, id) {
    295 		struct intel_context *ce;
    296 
    297 		ce = intel_context_create(engine);
    298 		if (IS_ERR(ce)) {
    299 			err = PTR_ERR(ce);
    300 			break;
    301 		}
    302 
    303 		err = check_mocs_engine(&mocs, ce);
    304 		intel_context_put(ce);
    305 		if (err)
    306 			break;
    307 	}
    308 
    309 	live_mocs_fini(&mocs);
    310 	return err;
    311 }
    312 
    313 static int active_engine_reset(struct intel_context *ce,
    314 			       const char *reason)
    315 {
    316 	struct igt_spinner spin;
    317 	struct i915_request *rq;
    318 	int err;
    319 
    320 	err = igt_spinner_init(&spin, ce->engine->gt);
    321 	if (err)
    322 		return err;
    323 
    324 	rq = igt_spinner_create_request(&spin, ce, MI_NOOP);
    325 	if (IS_ERR(rq)) {
    326 		igt_spinner_fini(&spin);
    327 		return PTR_ERR(rq);
    328 	}
    329 
    330 	err = request_add_spin(rq, &spin);
    331 	if (err == 0)
    332 		err = intel_engine_reset(ce->engine, reason);
    333 
    334 	igt_spinner_end(&spin);
    335 	igt_spinner_fini(&spin);
    336 
    337 	return err;
    338 }
    339 
    340 static int __live_mocs_reset(struct live_mocs *mocs,
    341 			     struct intel_context *ce)
    342 {
    343 	int err;
    344 
    345 	err = intel_engine_reset(ce->engine, "mocs");
    346 	if (err)
    347 		return err;
    348 
    349 	err = check_mocs_engine(mocs, ce);
    350 	if (err)
    351 		return err;
    352 
    353 	err = active_engine_reset(ce, "mocs");
    354 	if (err)
    355 		return err;
    356 
    357 	err = check_mocs_engine(mocs, ce);
    358 	if (err)
    359 		return err;
    360 
    361 	intel_gt_reset(ce->engine->gt, ce->engine->mask, "mocs");
    362 
    363 	err = check_mocs_engine(mocs, ce);
    364 	if (err)
    365 		return err;
    366 
    367 	return 0;
    368 }
    369 
    370 static int live_mocs_reset(void *arg)
    371 {
    372 	struct intel_gt *gt = arg;
    373 	struct intel_engine_cs *engine;
    374 	enum intel_engine_id id;
    375 	struct live_mocs mocs;
    376 	int err = 0;
    377 
    378 	/* Check the mocs setup is retained over per-engine and global resets */
    379 
    380 	if (!intel_has_reset_engine(gt))
    381 		return 0;
    382 
    383 	err = live_mocs_init(&mocs, gt);
    384 	if (err)
    385 		return err;
    386 
    387 	igt_global_reset_lock(gt);
    388 	for_each_engine(engine, gt, id) {
    389 		struct intel_context *ce;
    390 
    391 		ce = intel_context_create(engine);
    392 		if (IS_ERR(ce)) {
    393 			err = PTR_ERR(ce);
    394 			break;
    395 		}
    396 
    397 		intel_engine_pm_get(engine);
    398 		err = __live_mocs_reset(&mocs, ce);
    399 		intel_engine_pm_put(engine);
    400 
    401 		intel_context_put(ce);
    402 		if (err)
    403 			break;
    404 	}
    405 	igt_global_reset_unlock(gt);
    406 
    407 	live_mocs_fini(&mocs);
    408 	return err;
    409 }
    410 
    411 int intel_mocs_live_selftests(struct drm_i915_private *i915)
    412 {
    413 	static const struct i915_subtest tests[] = {
    414 		SUBTEST(live_mocs_kernel),
    415 		SUBTEST(live_mocs_clean),
    416 		SUBTEST(live_mocs_reset),
    417 	};
    418 	struct drm_i915_mocs_table table;
    419 
    420 	if (!get_mocs_settings(i915, &table))
    421 		return 0;
    422 
    423 	return intel_gt_live_subtests(tests, &i915->gt);
    424 }
    425