brintos

brintos / linux-shallow public Read only

0
0
Text · 8.5 KiB · 2cfc23c Raw
395 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2018 Intel Corporation4 */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 int18__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.stolen;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_gem_get_pat_index(gt->i915,90							    I915_CACHE_NONE),91				     0);92		mb();93 94		s = io_mapping_map_wc(&ggtt->iomap,95				      ggtt->error_capture.start,96				      PAGE_SIZE);97 98		if (!__drm_mm_interval_first(&gt->i915->mm.stolen,99					     page << PAGE_SHIFT,100					     ((page + 1) << PAGE_SHIFT) - 1))101			memset_io(s, STACK_MAGIC, PAGE_SIZE);102 103		in = (void __force *)s;104		if (i915_memcpy_from_wc(tmp, in, PAGE_SIZE))105			in = tmp;106		crc[page] = crc32_le(0, in, PAGE_SIZE);107 108		io_mapping_unmap(s);109	}110	mb();111	ggtt->vm.clear_range(&ggtt->vm, ggtt->error_capture.start, PAGE_SIZE);112 113	if (mask == ALL_ENGINES) {114		intel_gt_reset(gt, mask, NULL);115	} else {116		for_each_engine(engine, gt, id) {117			if (mask & engine->mask)118				intel_engine_reset(engine, NULL);119		}120	}121 122	max = -1;123	count = 0;124	for (page = 0; page < num_pages; page++) {125		dma_addr_t dma = (dma_addr_t)dsm->start + (page << PAGE_SHIFT);126		void __iomem *s;127		void *in;128		u32 x;129 130		ggtt->vm.insert_page(&ggtt->vm, dma,131				     ggtt->error_capture.start,132				     i915_gem_get_pat_index(gt->i915,133							    I915_CACHE_NONE),134				     0);135		mb();136 137		s = io_mapping_map_wc(&ggtt->iomap,138				      ggtt->error_capture.start,139				      PAGE_SIZE);140 141		in = (void __force *)s;142		if (i915_memcpy_from_wc(tmp, in, PAGE_SIZE))143			in = tmp;144		x = crc32_le(0, in, PAGE_SIZE);145 146		if (x != crc[page] &&147		    !__drm_mm_interval_first(&gt->i915->mm.stolen,148					     page << PAGE_SHIFT,149					     ((page + 1) << PAGE_SHIFT) - 1)) {150			pr_debug("unused stolen page %pa modified by GPU reset\n",151				 &page);152			if (count++ == 0)153				igt_hexdump(in, PAGE_SIZE);154			max = page;155		}156 157		io_mapping_unmap(s);158	}159	mb();160	ggtt->vm.clear_range(&ggtt->vm, ggtt->error_capture.start, PAGE_SIZE);161 162	if (count > 0) {163		pr_info("%s reset clobbered %ld pages of stolen, last clobber at page %ld\n",164			msg, count, max);165	}166	if (max >= I915_GEM_STOLEN_BIAS >> PAGE_SHIFT) {167		pr_err("%s reset clobbered unreserved area [above %x] of stolen; may cause severe faults\n",168		       msg, I915_GEM_STOLEN_BIAS);169		err = -EINVAL;170	}171 172err_spin:173	igt_spinner_fini(&spin);174 175err_lock:176	intel_runtime_pm_put(gt->uncore->rpm, wakeref);177	igt_global_reset_unlock(gt);178 179	kfree(tmp);180err_crc:181	kfree(crc);182	return err;183}184 185static int igt_reset_device_stolen(void *arg)186{187	return __igt_reset_stolen(arg, ALL_ENGINES, "device");188}189 190static int igt_reset_engines_stolen(void *arg)191{192	struct intel_gt *gt = arg;193	struct intel_engine_cs *engine;194	enum intel_engine_id id;195	int err;196 197	if (!intel_has_reset_engine(gt))198		return 0;199 200	for_each_engine(engine, gt, id) {201		err = __igt_reset_stolen(gt, engine->mask, engine->name);202		if (err)203			return err;204	}205 206	return 0;207}208 209static int igt_global_reset(void *arg)210{211	struct intel_gt *gt = arg;212	unsigned int reset_count;213	intel_wakeref_t wakeref;214	int err = 0;215 216	/* Check that we can issue a global GPU reset */217 218	igt_global_reset_lock(gt);219	wakeref = intel_runtime_pm_get(gt->uncore->rpm);220 221	reset_count = i915_reset_count(&gt->i915->gpu_error);222 223	intel_gt_reset(gt, ALL_ENGINES, NULL);224 225	if (i915_reset_count(&gt->i915->gpu_error) == reset_count) {226		pr_err("No GPU reset recorded!\n");227		err = -EINVAL;228	}229 230	intel_runtime_pm_put(gt->uncore->rpm, wakeref);231	igt_global_reset_unlock(gt);232 233	if (intel_gt_is_wedged(gt))234		err = -EIO;235 236	return err;237}238 239static int igt_wedged_reset(void *arg)240{241	struct intel_gt *gt = arg;242	intel_wakeref_t wakeref;243 244	/* Check that we can recover a wedged device with a GPU reset */245 246	igt_global_reset_lock(gt);247	wakeref = intel_runtime_pm_get(gt->uncore->rpm);248 249	intel_gt_set_wedged(gt);250 251	GEM_BUG_ON(!intel_gt_is_wedged(gt));252	intel_gt_reset(gt, ALL_ENGINES, NULL);253 254	intel_runtime_pm_put(gt->uncore->rpm, wakeref);255	igt_global_reset_unlock(gt);256 257	return intel_gt_is_wedged(gt) ? -EIO : 0;258}259 260static int igt_atomic_reset(void *arg)261{262	struct intel_gt *gt = arg;263	const typeof(*igt_atomic_phases) *p;264	intel_wakeref_t wakeref;265	int err = 0;266 267	/* Check that the resets are usable from atomic context */268 269	wakeref = intel_gt_pm_get(gt);270	igt_global_reset_lock(gt);271 272	/* Flush any requests before we get started and check basics */273	if (!igt_force_reset(gt))274		goto unlock;275 276	for (p = igt_atomic_phases; p->name; p++) {277		intel_engine_mask_t awake;278 279		GEM_TRACE("__intel_gt_reset under %s\n", p->name);280 281		awake = reset_prepare(gt);282		p->critical_section_begin();283 284		err = intel_gt_reset_all_engines(gt);285 286		p->critical_section_end();287		reset_finish(gt, awake);288 289		if (err) {290			pr_err("__intel_gt_reset failed under %s\n", p->name);291			break;292		}293	}294 295	/* As we poke around the guts, do a full reset before continuing. */296	igt_force_reset(gt);297 298unlock:299	igt_global_reset_unlock(gt);300	intel_gt_pm_put(gt, wakeref);301 302	return err;303}304 305static int igt_atomic_engine_reset(void *arg)306{307	struct intel_gt *gt = arg;308	const typeof(*igt_atomic_phases) *p;309	struct intel_engine_cs *engine;310	enum intel_engine_id id;311	intel_wakeref_t wakeref;312	int err = 0;313 314	/* Check that the resets are usable from atomic context */315 316	if (!intel_has_reset_engine(gt))317		return 0;318 319	if (intel_uc_uses_guc_submission(&gt->uc))320		return 0;321 322	wakeref = intel_gt_pm_get(gt);323	igt_global_reset_lock(gt);324 325	/* Flush any requests before we get started and check basics */326	if (!igt_force_reset(gt))327		goto out_unlock;328 329	for_each_engine(engine, gt, id) {330		struct tasklet_struct *t = &engine->sched_engine->tasklet;331 332		if (t->func)333			tasklet_disable(t);334		intel_engine_pm_get(engine);335 336		for (p = igt_atomic_phases; p->name; p++) {337			GEM_TRACE("intel_engine_reset(%s) under %s\n",338				  engine->name, p->name);339			if (strcmp(p->name, "softirq"))340				local_bh_disable();341 342			p->critical_section_begin();343			err = __intel_engine_reset_bh(engine, NULL);344			p->critical_section_end();345 346			if (strcmp(p->name, "softirq"))347				local_bh_enable();348 349			if (err) {350				pr_err("intel_engine_reset(%s) failed under %s\n",351				       engine->name, p->name);352				break;353			}354		}355 356		intel_engine_pm_put(engine);357		if (t->func) {358			tasklet_enable(t);359			tasklet_hi_schedule(t);360		}361		if (err)362			break;363	}364 365	/* As we poke around the guts, do a full reset before continuing. */366	igt_force_reset(gt);367 368out_unlock:369	igt_global_reset_unlock(gt);370	intel_gt_pm_put(gt, wakeref);371 372	return err;373}374 375int intel_reset_live_selftests(struct drm_i915_private *i915)376{377	static const struct i915_subtest tests[] = {378		SUBTEST(igt_global_reset), /* attempt to recover GPU first */379		SUBTEST(igt_reset_device_stolen),380		SUBTEST(igt_reset_engines_stolen),381		SUBTEST(igt_wedged_reset),382		SUBTEST(igt_atomic_reset),383		SUBTEST(igt_atomic_engine_reset),384	};385	struct intel_gt *gt = to_gt(i915);386 387	if (!intel_has_gpu_reset(gt))388		return 0;389 390	if (intel_gt_is_wedged(gt))391		return -EIO; /* we're long past hope of a successful reset */392 393	return intel_gt_live_subtests(tests, gt);394}395