brintos

brintos / linux-shallow public Read only

0
0
Text · 10.0 KiB · 5eb4670 Raw
454 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright © 2019 Intel Corporation4 */5 6#include "i915_selftest.h"7#include "intel_engine_heartbeat.h"8#include "intel_engine_pm.h"9#include "intel_gt.h"10 11#include "gem/selftests/mock_context.h"12#include "selftests/igt_flush_test.h"13#include "selftests/mock_drm.h"14 15static int request_sync(struct i915_request *rq)16{17	struct intel_timeline *tl = i915_request_timeline(rq);18	long timeout;19	int err = 0;20 21	intel_timeline_get(tl);22	i915_request_get(rq);23 24	/* Opencode i915_request_add() so we can keep the timeline locked. */25	__i915_request_commit(rq);26	rq->sched.attr.priority = I915_PRIORITY_BARRIER;27	__i915_request_queue_bh(rq);28 29	timeout = i915_request_wait(rq, 0, HZ / 10);30	if (timeout < 0)31		err = timeout;32	else33		i915_request_retire_upto(rq);34 35	lockdep_unpin_lock(&tl->mutex, rq->cookie);36	mutex_unlock(&tl->mutex);37 38	i915_request_put(rq);39	intel_timeline_put(tl);40 41	return err;42}43 44static int context_sync(struct intel_context *ce)45{46	struct intel_timeline *tl = ce->timeline;47	int err = 0;48 49	mutex_lock(&tl->mutex);50	do {51		struct i915_request *rq;52		long timeout;53 54		if (list_empty(&tl->requests))55			break;56 57		rq = list_last_entry(&tl->requests, typeof(*rq), link);58		i915_request_get(rq);59 60		timeout = i915_request_wait(rq, 0, HZ / 10);61		if (timeout < 0)62			err = timeout;63		else64			i915_request_retire_upto(rq);65 66		i915_request_put(rq);67	} while (!err);68	mutex_unlock(&tl->mutex);69 70	/* Wait for all barriers to complete (remote CPU) before we check */71	i915_active_unlock_wait(&ce->active);72	return err;73}74 75static int __live_context_size(struct intel_engine_cs *engine)76{77	struct intel_context *ce;78	struct i915_request *rq;79	void *vaddr;80	int err;81 82	ce = intel_context_create(engine);83	if (IS_ERR(ce))84		return PTR_ERR(ce);85 86	err = intel_context_pin(ce);87	if (err)88		goto err;89 90	vaddr = i915_gem_object_pin_map_unlocked(ce->state->obj,91						 intel_gt_coherent_map_type(engine->gt,92									    ce->state->obj,93									    false));94	if (IS_ERR(vaddr)) {95		err = PTR_ERR(vaddr);96		intel_context_unpin(ce);97		goto err;98	}99 100	/*101	 * Note that execlists also applies a redzone which it checks on102	 * context unpin when debugging. We are using the same location103	 * and same poison value so that our checks overlap. Despite the104	 * redundancy, we want to keep this little selftest so that we105	 * get coverage of any and all submission backends, and we can106	 * always extend this test to ensure we trick the HW into a107	 * compromising position wrt to the various sections that need108	 * to be written into the context state.109	 *110	 * TLDR; this overlaps with the execlists redzone.111	 */112	vaddr += engine->context_size - I915_GTT_PAGE_SIZE;113	memset(vaddr, POISON_INUSE, I915_GTT_PAGE_SIZE);114 115	rq = intel_context_create_request(ce);116	intel_context_unpin(ce);117	if (IS_ERR(rq)) {118		err = PTR_ERR(rq);119		goto err_unpin;120	}121 122	err = request_sync(rq);123	if (err)124		goto err_unpin;125 126	/* Force the context switch */127	rq = intel_engine_create_kernel_request(engine);128	if (IS_ERR(rq)) {129		err = PTR_ERR(rq);130		goto err_unpin;131	}132	err = request_sync(rq);133	if (err)134		goto err_unpin;135 136	if (memchr_inv(vaddr, POISON_INUSE, I915_GTT_PAGE_SIZE)) {137		pr_err("%s context overwrote trailing red-zone!", engine->name);138		err = -EINVAL;139	}140 141err_unpin:142	i915_gem_object_unpin_map(ce->state->obj);143err:144	intel_context_put(ce);145	return err;146}147 148static int live_context_size(void *arg)149{150	struct intel_gt *gt = arg;151	struct intel_engine_cs *engine;152	enum intel_engine_id id;153	int err = 0;154 155	/*156	 * Check that our context sizes are correct by seeing if the157	 * HW tries to write past the end of one.158	 */159 160	for_each_engine(engine, gt, id) {161		struct file *saved;162 163		if (!engine->context_size)164			continue;165 166		intel_engine_pm_get(engine);167 168		/*169		 * Hide the old default state -- we lie about the context size170		 * and get confused when the default state is smaller than171		 * expected. For our do nothing request, inheriting the172		 * active state is sufficient, we are only checking that we173		 * don't use more than we planned.174		 */175		saved = fetch_and_zero(&engine->default_state);176 177		/* Overlaps with the execlists redzone */178		engine->context_size += I915_GTT_PAGE_SIZE;179 180		err = __live_context_size(engine);181 182		engine->context_size -= I915_GTT_PAGE_SIZE;183 184		engine->default_state = saved;185 186		intel_engine_pm_put(engine);187 188		if (err)189			break;190	}191 192	return err;193}194 195static int __live_active_context(struct intel_engine_cs *engine)196{197	unsigned long saved_heartbeat;198	struct intel_context *ce;199	int pass;200	int err;201 202	/*203	 * We keep active contexts alive until after a subsequent context204	 * switch as the final write from the context-save will be after205	 * we retire the final request. We track when we unpin the context,206	 * under the presumption that the final pin is from the last request,207	 * and instead of immediately unpinning the context, we add a task208	 * to unpin the context from the next idle-barrier.209	 *210	 * This test makes sure that the context is kept alive until a211	 * subsequent idle-barrier (emitted when the engine wakeref hits 0212	 * with no more outstanding requests).213	 *214	 * In GuC submission mode we don't use idle barriers and we instead215	 * get a message from the GuC to signal that it is safe to unpin the216	 * context from memory.217	 */218	if (intel_engine_uses_guc(engine))219		return 0;220 221	if (intel_engine_pm_is_awake(engine)) {222		pr_err("%s is awake before starting %s!\n",223		       engine->name, __func__);224		return -EINVAL;225	}226 227	ce = intel_context_create(engine);228	if (IS_ERR(ce))229		return PTR_ERR(ce);230 231	saved_heartbeat = engine->props.heartbeat_interval_ms;232	engine->props.heartbeat_interval_ms = 0;233 234	for (pass = 0; pass <= 2; pass++) {235		struct i915_request *rq;236 237		intel_engine_pm_get(engine);238 239		rq = intel_context_create_request(ce);240		if (IS_ERR(rq)) {241			err = PTR_ERR(rq);242			goto out_engine;243		}244 245		err = request_sync(rq);246		if (err)247			goto out_engine;248 249		/* Context will be kept active until after an idle-barrier. */250		if (i915_active_is_idle(&ce->active)) {251			pr_err("context is not active; expected idle-barrier (%s pass %d)\n",252			       engine->name, pass);253			err = -EINVAL;254			goto out_engine;255		}256 257		if (!intel_engine_pm_is_awake(engine)) {258			pr_err("%s is asleep before idle-barrier\n",259			       engine->name);260			err = -EINVAL;261			goto out_engine;262		}263 264out_engine:265		intel_engine_pm_put(engine);266		if (err)267			goto err;268	}269 270	/* Now make sure our idle-barriers are flushed */271	err = intel_engine_flush_barriers(engine);272	if (err)273		goto err;274 275	/* Wait for the barrier and in the process wait for engine to park */276	err = context_sync(engine->kernel_context);277	if (err)278		goto err;279 280	if (!i915_active_is_idle(&ce->active)) {281		pr_err("context is still active!");282		err = -EINVAL;283	}284 285	intel_engine_pm_flush(engine);286 287	if (intel_engine_pm_is_awake(engine)) {288		struct drm_printer p = drm_dbg_printer(&engine->i915->drm,289						       DRM_UT_DRIVER, NULL);290 291		intel_engine_dump(engine, &p,292				  "%s is still awake:%d after idle-barriers\n",293				  engine->name,294				  atomic_read(&engine->wakeref.count));295		GEM_TRACE_DUMP();296 297		err = -EINVAL;298		goto err;299	}300 301err:302	engine->props.heartbeat_interval_ms = saved_heartbeat;303	intel_context_put(ce);304	return err;305}306 307static int live_active_context(void *arg)308{309	struct intel_gt *gt = arg;310	struct intel_engine_cs *engine;311	enum intel_engine_id id;312	int err = 0;313 314	for_each_engine(engine, gt, id) {315		err = __live_active_context(engine);316		if (err)317			break;318 319		err = igt_flush_test(gt->i915);320		if (err)321			break;322	}323 324	return err;325}326 327static int __remote_sync(struct intel_context *ce, struct intel_context *remote)328{329	struct i915_request *rq;330	int err;331 332	err = intel_context_pin(remote);333	if (err)334		return err;335 336	rq = intel_context_create_request(ce);337	if (IS_ERR(rq)) {338		err = PTR_ERR(rq);339		goto unpin;340	}341 342	err = intel_context_prepare_remote_request(remote, rq);343	if (err) {344		i915_request_add(rq);345		goto unpin;346	}347 348	err = request_sync(rq);349 350unpin:351	intel_context_unpin(remote);352	return err;353}354 355static int __live_remote_context(struct intel_engine_cs *engine)356{357	struct intel_context *local, *remote;358	unsigned long saved_heartbeat;359	int pass;360	int err;361 362	/*363	 * Check that our idle barriers do not interfere with normal364	 * activity tracking. In particular, check that operating365	 * on the context image remotely (intel_context_prepare_remote_request),366	 * which inserts foreign fences into intel_context.active, does not367	 * clobber the idle-barrier.368	 *369	 * In GuC submission mode we don't use idle barriers.370	 */371	if (intel_engine_uses_guc(engine))372		return 0;373 374	if (intel_engine_pm_is_awake(engine)) {375		pr_err("%s is awake before starting %s!\n",376		       engine->name, __func__);377		return -EINVAL;378	}379 380	remote = intel_context_create(engine);381	if (IS_ERR(remote))382		return PTR_ERR(remote);383 384	local = intel_context_create(engine);385	if (IS_ERR(local)) {386		err = PTR_ERR(local);387		goto err_remote;388	}389 390	saved_heartbeat = engine->props.heartbeat_interval_ms;391	engine->props.heartbeat_interval_ms = 0;392	intel_engine_pm_get(engine);393 394	for (pass = 0; pass <= 2; pass++) {395		err = __remote_sync(local, remote);396		if (err)397			break;398 399		err = __remote_sync(engine->kernel_context, remote);400		if (err)401			break;402 403		if (i915_active_is_idle(&remote->active)) {404			pr_err("remote context is not active; expected idle-barrier (%s pass %d)\n",405			       engine->name, pass);406			err = -EINVAL;407			break;408		}409	}410 411	intel_engine_pm_put(engine);412	engine->props.heartbeat_interval_ms = saved_heartbeat;413 414	intel_context_put(local);415err_remote:416	intel_context_put(remote);417	return err;418}419 420static int live_remote_context(void *arg)421{422	struct intel_gt *gt = arg;423	struct intel_engine_cs *engine;424	enum intel_engine_id id;425	int err = 0;426 427	for_each_engine(engine, gt, id) {428		err = __live_remote_context(engine);429		if (err)430			break;431 432		err = igt_flush_test(gt->i915);433		if (err)434			break;435	}436 437	return err;438}439 440int intel_context_live_selftests(struct drm_i915_private *i915)441{442	static const struct i915_subtest tests[] = {443		SUBTEST(live_context_size),444		SUBTEST(live_active_context),445		SUBTEST(live_remote_context),446	};447	struct intel_gt *gt = to_gt(i915);448 449	if (intel_gt_is_wedged(gt))450		return 0;451 452	return intel_gt_live_subtests(tests, gt);453}454