brintos

brintos / linux-shallow public Read only

0
0
Text · 6.6 KiB · 9e4f0e4 Raw
320 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2018 Intel Corporation4 */5 6#include <linux/sort.h>7 8#include "i915_drv.h"9 10#include "intel_gt_requests.h"11#include "i915_selftest.h"12#include "selftest_engine_heartbeat.h"13 14static void reset_heartbeat(struct intel_engine_cs *engine)15{16	intel_engine_set_heartbeat(engine,17				   engine->defaults.heartbeat_interval_ms);18}19 20static int timeline_sync(struct intel_timeline *tl)21{22	struct dma_fence *fence;23	long timeout;24 25	fence = i915_active_fence_get(&tl->last_request);26	if (!fence)27		return 0;28 29	timeout = dma_fence_wait_timeout(fence, true, HZ / 2);30	dma_fence_put(fence);31	if (timeout < 0)32		return timeout;33 34	return 0;35}36 37static int engine_sync_barrier(struct intel_engine_cs *engine)38{39	return timeline_sync(engine->kernel_context->timeline);40}41 42struct pulse {43	struct i915_active active;44	struct kref kref;45};46 47static int pulse_active(struct i915_active *active)48{49	kref_get(&container_of(active, struct pulse, active)->kref);50	return 0;51}52 53static void pulse_free(struct kref *kref)54{55	struct pulse *p = container_of(kref, typeof(*p), kref);56 57	i915_active_fini(&p->active);58	kfree(p);59}60 61static void pulse_put(struct pulse *p)62{63	kref_put(&p->kref, pulse_free);64}65 66static void pulse_retire(struct i915_active *active)67{68	pulse_put(container_of(active, struct pulse, active));69}70 71static struct pulse *pulse_create(void)72{73	struct pulse *p;74 75	p = kmalloc(sizeof(*p), GFP_KERNEL);76	if (!p)77		return p;78 79	kref_init(&p->kref);80	i915_active_init(&p->active, pulse_active, pulse_retire, 0);81 82	return p;83}84 85static void pulse_unlock_wait(struct pulse *p)86{87	wait_var_event_timeout(&p->active, i915_active_is_idle(&p->active), HZ);88}89 90static int __live_idle_pulse(struct intel_engine_cs *engine,91			     int (*fn)(struct intel_engine_cs *cs))92{93	struct pulse *p;94	int err;95 96	GEM_BUG_ON(!intel_engine_pm_is_awake(engine));97 98	p = pulse_create();99	if (!p)100		return -ENOMEM;101 102	err = i915_active_acquire(&p->active);103	if (err)104		goto out;105 106	err = i915_active_acquire_preallocate_barrier(&p->active, engine);107	if (err) {108		i915_active_release(&p->active);109		goto out;110	}111 112	i915_active_acquire_barrier(&p->active);113	i915_active_release(&p->active);114 115	GEM_BUG_ON(i915_active_is_idle(&p->active));116	GEM_BUG_ON(llist_empty(&engine->barrier_tasks));117 118	err = fn(engine);119	if (err)120		goto out;121 122	GEM_BUG_ON(!llist_empty(&engine->barrier_tasks));123 124	if (engine_sync_barrier(engine)) {125		struct drm_printer m = drm_err_printer(&engine->i915->drm, "pulse");126 127		drm_printf(&m, "%s: no heartbeat pulse?\n", engine->name);128		intel_engine_dump(engine, &m, "%s", engine->name);129 130		err = -ETIME;131		goto out;132	}133 134	GEM_BUG_ON(READ_ONCE(engine->serial) != engine->wakeref_serial);135 136	pulse_unlock_wait(p); /* synchronize with the retirement callback */137 138	if (!i915_active_is_idle(&p->active)) {139		struct drm_printer m = drm_err_printer(&engine->i915->drm, "pulse");140 141		drm_printf(&m, "%s: heartbeat pulse did not flush idle tasks\n",142			   engine->name);143		i915_active_print(&p->active, &m);144 145		err = -EINVAL;146		goto out;147	}148 149out:150	pulse_put(p);151	return err;152}153 154static int live_idle_flush(void *arg)155{156	struct intel_gt *gt = arg;157	struct intel_engine_cs *engine;158	enum intel_engine_id id;159	int err = 0;160 161	/* Check that we can flush the idle barriers */162 163	for_each_engine(engine, gt, id) {164		st_engine_heartbeat_disable(engine);165		err = __live_idle_pulse(engine, intel_engine_flush_barriers);166		st_engine_heartbeat_enable(engine);167		if (err)168			break;169	}170 171	return err;172}173 174static int live_idle_pulse(void *arg)175{176	struct intel_gt *gt = arg;177	struct intel_engine_cs *engine;178	enum intel_engine_id id;179	int err = 0;180 181	/* Check that heartbeat pulses flush the idle barriers */182 183	for_each_engine(engine, gt, id) {184		st_engine_heartbeat_disable(engine);185		err = __live_idle_pulse(engine, intel_engine_pulse);186		st_engine_heartbeat_enable(engine);187		if (err && err != -ENODEV)188			break;189 190		err = 0;191	}192 193	return err;194}195 196static int __live_heartbeat_off(struct intel_engine_cs *engine)197{198	int err;199 200	intel_engine_pm_get(engine);201 202	engine->serial++;203	flush_delayed_work(&engine->heartbeat.work);204	if (!delayed_work_pending(&engine->heartbeat.work)) {205		pr_err("%s: heartbeat not running\n",206		       engine->name);207		err = -EINVAL;208		goto err_pm;209	}210 211	err = intel_engine_set_heartbeat(engine, 0);212	if (err)213		goto err_pm;214 215	engine->serial++;216	flush_delayed_work(&engine->heartbeat.work);217	if (delayed_work_pending(&engine->heartbeat.work)) {218		pr_err("%s: heartbeat still running\n",219		       engine->name);220		err = -EINVAL;221		goto err_beat;222	}223 224	if (READ_ONCE(engine->heartbeat.systole)) {225		pr_err("%s: heartbeat still allocated\n",226		       engine->name);227		err = -EINVAL;228		goto err_beat;229	}230 231err_beat:232	reset_heartbeat(engine);233err_pm:234	intel_engine_pm_put(engine);235	return err;236}237 238static int live_heartbeat_off(void *arg)239{240	struct intel_gt *gt = arg;241	struct intel_engine_cs *engine;242	enum intel_engine_id id;243	int err = 0;244 245	/* Check that we can turn off heartbeat and not interrupt VIP */246	if (!CONFIG_DRM_I915_HEARTBEAT_INTERVAL)247		return 0;248 249	for_each_engine(engine, gt, id) {250		if (!intel_engine_has_preemption(engine))251			continue;252 253		err = __live_heartbeat_off(engine);254		if (err)255			break;256	}257 258	return err;259}260 261int intel_heartbeat_live_selftests(struct drm_i915_private *i915)262{263	static const struct i915_subtest tests[] = {264		SUBTEST(live_idle_flush),265		SUBTEST(live_idle_pulse),266		SUBTEST(live_heartbeat_off),267	};268	int saved_hangcheck;269	int err;270 271	if (intel_gt_is_wedged(to_gt(i915)))272		return 0;273 274	saved_hangcheck = i915->params.enable_hangcheck;275	i915->params.enable_hangcheck = INT_MAX;276 277	err = intel_gt_live_subtests(tests, to_gt(i915));278 279	i915->params.enable_hangcheck = saved_hangcheck;280	return err;281}282 283void st_engine_heartbeat_disable(struct intel_engine_cs *engine)284{285	engine->props.heartbeat_interval_ms = 0;286 287	intel_engine_pm_get(engine);288	intel_engine_park_heartbeat(engine);289}290 291void st_engine_heartbeat_enable(struct intel_engine_cs *engine)292{293	intel_engine_pm_put(engine);294 295	engine->props.heartbeat_interval_ms =296		engine->defaults.heartbeat_interval_ms;297}298 299void st_engine_heartbeat_disable_no_pm(struct intel_engine_cs *engine)300{301	engine->props.heartbeat_interval_ms = 0;302 303	/*304	 * Park the heartbeat but without holding the PM lock as that305	 * makes the engines appear not-idle. Note that if/when unpark306	 * is called due to the PM lock being acquired later the307	 * heartbeat still won't be enabled because of the above = 0.308	 */309	if (intel_engine_pm_get_if_awake(engine)) {310		intel_engine_park_heartbeat(engine);311		intel_engine_pm_put(engine);312	}313}314 315void st_engine_heartbeat_enable_no_pm(struct intel_engine_cs *engine)316{317	engine->props.heartbeat_interval_ms =318		engine->defaults.heartbeat_interval_ms;319}320