cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

selftest_reset.c (8459B)


      1// SPDX-License-Identifier: MIT
      2/*
      3 * Copyright © 2018 Intel Corporation
      4 */
      5
      6#include <linux/crc32.h>
      7
      8#include "gem/i915_gem_stolen.h"
      9
     10#include "i915_memcpy.h"
     11#include "i915_selftest.h"
     12#include "intel_gpu_commands.h"
     13#include "selftests/igt_reset.h"
     14#include "selftests/igt_atomic.h"
     15#include "selftests/igt_spinner.h"
     16
     17static int
     18__igt_reset_stolen(struct intel_gt *gt,
     19		   intel_engine_mask_t mask,
     20		   const char *msg)
     21{
     22	struct i915_ggtt *ggtt = gt->ggtt;
     23	const struct resource *dsm = &gt->i915->dsm;
     24	resource_size_t num_pages, page;
     25	struct intel_engine_cs *engine;
     26	intel_wakeref_t wakeref;
     27	enum intel_engine_id id;
     28	struct igt_spinner spin;
     29	long max, count;
     30	void *tmp;
     31	u32 *crc;
     32	int err;
     33
     34	if (!drm_mm_node_allocated(&ggtt->error_capture))
     35		return 0;
     36
     37	num_pages = resource_size(dsm) >> PAGE_SHIFT;
     38	if (!num_pages)
     39		return 0;
     40
     41	crc = kmalloc_array(num_pages, sizeof(u32), GFP_KERNEL);
     42	if (!crc)
     43		return -ENOMEM;
     44
     45	tmp = kmalloc(PAGE_SIZE, GFP_KERNEL);
     46	if (!tmp) {
     47		err = -ENOMEM;
     48		goto err_crc;
     49	}
     50
     51	igt_global_reset_lock(gt);
     52	wakeref = intel_runtime_pm_get(gt->uncore->rpm);
     53
     54	err = igt_spinner_init(&spin, gt);
     55	if (err)
     56		goto err_lock;
     57
     58	for_each_engine(engine, gt, id) {
     59		struct intel_context *ce;
     60		struct i915_request *rq;
     61
     62		if (!(mask & engine->mask))
     63			continue;
     64
     65		if (!intel_engine_can_store_dword(engine))
     66			continue;
     67
     68		ce = intel_context_create(engine);
     69		if (IS_ERR(ce)) {
     70			err = PTR_ERR(ce);
     71			goto err_spin;
     72		}
     73		rq = igt_spinner_create_request(&spin, ce, MI_ARB_CHECK);
     74		intel_context_put(ce);
     75		if (IS_ERR(rq)) {
     76			err = PTR_ERR(rq);
     77			goto err_spin;
     78		}
     79		i915_request_add(rq);
     80	}
     81
     82	for (page = 0; page < num_pages; page++) {
     83		dma_addr_t dma = (dma_addr_t)dsm->start + (page << PAGE_SHIFT);
     84		void __iomem *s;
     85		void *in;
     86
     87		ggtt->vm.insert_page(&ggtt->vm, dma,
     88				     ggtt->error_capture.start,
     89				     I915_CACHE_NONE, 0);
     90		mb();
     91
     92		s = io_mapping_map_wc(&ggtt->iomap,
     93				      ggtt->error_capture.start,
     94				      PAGE_SIZE);
     95
     96		if (!__drm_mm_interval_first(&gt->i915->mm.stolen,
     97					     page << PAGE_SHIFT,
     98					     ((page + 1) << PAGE_SHIFT) - 1))
     99			memset_io(s, STACK_MAGIC, PAGE_SIZE);
    100
    101		in = (void __force *)s;
    102		if (i915_memcpy_from_wc(tmp, in, PAGE_SIZE))
    103			in = tmp;
    104		crc[page] = crc32_le(0, in, PAGE_SIZE);
    105
    106		io_mapping_unmap(s);
    107	}
    108	mb();
    109	ggtt->vm.clear_range(&ggtt->vm, ggtt->error_capture.start, PAGE_SIZE);
    110
    111	if (mask == ALL_ENGINES) {
    112		intel_gt_reset(gt, mask, NULL);
    113	} else {
    114		for_each_engine(engine, gt, id) {
    115			if (mask & engine->mask)
    116				intel_engine_reset(engine, NULL);
    117		}
    118	}
    119
    120	max = -1;
    121	count = 0;
    122	for (page = 0; page < num_pages; page++) {
    123		dma_addr_t dma = (dma_addr_t)dsm->start + (page << PAGE_SHIFT);
    124		void __iomem *s;
    125		void *in;
    126		u32 x;
    127
    128		ggtt->vm.insert_page(&ggtt->vm, dma,
    129				     ggtt->error_capture.start,
    130				     I915_CACHE_NONE, 0);
    131		mb();
    132
    133		s = io_mapping_map_wc(&ggtt->iomap,
    134				      ggtt->error_capture.start,
    135				      PAGE_SIZE);
    136
    137		in = (void __force *)s;
    138		if (i915_memcpy_from_wc(tmp, in, PAGE_SIZE))
    139			in = tmp;
    140		x = crc32_le(0, in, PAGE_SIZE);
    141
    142		if (x != crc[page] &&
    143		    !__drm_mm_interval_first(&gt->i915->mm.stolen,
    144					     page << PAGE_SHIFT,
    145					     ((page + 1) << PAGE_SHIFT) - 1)) {
    146			pr_debug("unused stolen page %pa modified by GPU reset\n",
    147				 &page);
    148			if (count++ == 0)
    149				igt_hexdump(in, PAGE_SIZE);
    150			max = page;
    151		}
    152
    153		io_mapping_unmap(s);
    154	}
    155	mb();
    156	ggtt->vm.clear_range(&ggtt->vm, ggtt->error_capture.start, PAGE_SIZE);
    157
    158	if (count > 0) {
    159		pr_info("%s reset clobbered %ld pages of stolen, last clobber at page %ld\n",
    160			msg, count, max);
    161	}
    162	if (max >= I915_GEM_STOLEN_BIAS >> PAGE_SHIFT) {
    163		pr_err("%s reset clobbered unreserved area [above %x] of stolen; may cause severe faults\n",
    164		       msg, I915_GEM_STOLEN_BIAS);
    165		err = -EINVAL;
    166	}
    167
    168err_spin:
    169	igt_spinner_fini(&spin);
    170
    171err_lock:
    172	intel_runtime_pm_put(gt->uncore->rpm, wakeref);
    173	igt_global_reset_unlock(gt);
    174
    175	kfree(tmp);
    176err_crc:
    177	kfree(crc);
    178	return err;
    179}
    180
    181static int igt_reset_device_stolen(void *arg)
    182{
    183	return __igt_reset_stolen(arg, ALL_ENGINES, "device");
    184}
    185
    186static int igt_reset_engines_stolen(void *arg)
    187{
    188	struct intel_gt *gt = arg;
    189	struct intel_engine_cs *engine;
    190	enum intel_engine_id id;
    191	int err;
    192
    193	if (!intel_has_reset_engine(gt))
    194		return 0;
    195
    196	for_each_engine(engine, gt, id) {
    197		err = __igt_reset_stolen(gt, engine->mask, engine->name);
    198		if (err)
    199			return err;
    200	}
    201
    202	return 0;
    203}
    204
    205static int igt_global_reset(void *arg)
    206{
    207	struct intel_gt *gt = arg;
    208	unsigned int reset_count;
    209	intel_wakeref_t wakeref;
    210	int err = 0;
    211
    212	/* Check that we can issue a global GPU reset */
    213
    214	igt_global_reset_lock(gt);
    215	wakeref = intel_runtime_pm_get(gt->uncore->rpm);
    216
    217	reset_count = i915_reset_count(&gt->i915->gpu_error);
    218
    219	intel_gt_reset(gt, ALL_ENGINES, NULL);
    220
    221	if (i915_reset_count(&gt->i915->gpu_error) == reset_count) {
    222		pr_err("No GPU reset recorded!\n");
    223		err = -EINVAL;
    224	}
    225
    226	intel_runtime_pm_put(gt->uncore->rpm, wakeref);
    227	igt_global_reset_unlock(gt);
    228
    229	if (intel_gt_is_wedged(gt))
    230		err = -EIO;
    231
    232	return err;
    233}
    234
    235static int igt_wedged_reset(void *arg)
    236{
    237	struct intel_gt *gt = arg;
    238	intel_wakeref_t wakeref;
    239
    240	/* Check that we can recover a wedged device with a GPU reset */
    241
    242	igt_global_reset_lock(gt);
    243	wakeref = intel_runtime_pm_get(gt->uncore->rpm);
    244
    245	intel_gt_set_wedged(gt);
    246
    247	GEM_BUG_ON(!intel_gt_is_wedged(gt));
    248	intel_gt_reset(gt, ALL_ENGINES, NULL);
    249
    250	intel_runtime_pm_put(gt->uncore->rpm, wakeref);
    251	igt_global_reset_unlock(gt);
    252
    253	return intel_gt_is_wedged(gt) ? -EIO : 0;
    254}
    255
    256static int igt_atomic_reset(void *arg)
    257{
    258	struct intel_gt *gt = arg;
    259	const typeof(*igt_atomic_phases) *p;
    260	int err = 0;
    261
    262	/* Check that the resets are usable from atomic context */
    263
    264	intel_gt_pm_get(gt);
    265	igt_global_reset_lock(gt);
    266
    267	/* Flush any requests before we get started and check basics */
    268	if (!igt_force_reset(gt))
    269		goto unlock;
    270
    271	for (p = igt_atomic_phases; p->name; p++) {
    272		intel_engine_mask_t awake;
    273
    274		GEM_TRACE("__intel_gt_reset under %s\n", p->name);
    275
    276		awake = reset_prepare(gt);
    277		p->critical_section_begin();
    278
    279		err = __intel_gt_reset(gt, ALL_ENGINES);
    280
    281		p->critical_section_end();
    282		reset_finish(gt, awake);
    283
    284		if (err) {
    285			pr_err("__intel_gt_reset failed under %s\n", p->name);
    286			break;
    287		}
    288	}
    289
    290	/* As we poke around the guts, do a full reset before continuing. */
    291	igt_force_reset(gt);
    292
    293unlock:
    294	igt_global_reset_unlock(gt);
    295	intel_gt_pm_put(gt);
    296
    297	return err;
    298}
    299
    300static int igt_atomic_engine_reset(void *arg)
    301{
    302	struct intel_gt *gt = arg;
    303	const typeof(*igt_atomic_phases) *p;
    304	struct intel_engine_cs *engine;
    305	enum intel_engine_id id;
    306	int err = 0;
    307
    308	/* Check that the resets are usable from atomic context */
    309
    310	if (!intel_has_reset_engine(gt))
    311		return 0;
    312
    313	if (intel_uc_uses_guc_submission(&gt->uc))
    314		return 0;
    315
    316	intel_gt_pm_get(gt);
    317	igt_global_reset_lock(gt);
    318
    319	/* Flush any requests before we get started and check basics */
    320	if (!igt_force_reset(gt))
    321		goto out_unlock;
    322
    323	for_each_engine(engine, gt, id) {
    324		struct tasklet_struct *t = &engine->sched_engine->tasklet;
    325
    326		if (t->func)
    327			tasklet_disable(t);
    328		intel_engine_pm_get(engine);
    329
    330		for (p = igt_atomic_phases; p->name; p++) {
    331			GEM_TRACE("intel_engine_reset(%s) under %s\n",
    332				  engine->name, p->name);
    333			if (strcmp(p->name, "softirq"))
    334				local_bh_disable();
    335
    336			p->critical_section_begin();
    337			err = __intel_engine_reset_bh(engine, NULL);
    338			p->critical_section_end();
    339
    340			if (strcmp(p->name, "softirq"))
    341				local_bh_enable();
    342
    343			if (err) {
    344				pr_err("intel_engine_reset(%s) failed under %s\n",
    345				       engine->name, p->name);
    346				break;
    347			}
    348		}
    349
    350		intel_engine_pm_put(engine);
    351		if (t->func) {
    352			tasklet_enable(t);
    353			tasklet_hi_schedule(t);
    354		}
    355		if (err)
    356			break;
    357	}
    358
    359	/* As we poke around the guts, do a full reset before continuing. */
    360	igt_force_reset(gt);
    361
    362out_unlock:
    363	igt_global_reset_unlock(gt);
    364	intel_gt_pm_put(gt);
    365
    366	return err;
    367}
    368
    369int intel_reset_live_selftests(struct drm_i915_private *i915)
    370{
    371	static const struct i915_subtest tests[] = {
    372		SUBTEST(igt_global_reset), /* attempt to recover GPU first */
    373		SUBTEST(igt_reset_device_stolen),
    374		SUBTEST(igt_reset_engines_stolen),
    375		SUBTEST(igt_wedged_reset),
    376		SUBTEST(igt_atomic_reset),
    377		SUBTEST(igt_atomic_engine_reset),
    378	};
    379	struct intel_gt *gt = to_gt(i915);
    380
    381	if (!intel_has_gpu_reset(gt))
    382		return 0;
    383
    384	if (intel_gt_is_wedged(gt))
    385		return -EIO; /* we're long past hope of a successful reset */
    386
    387	return intel_gt_live_subtests(tests, gt);
    388}