xref: /linux/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2018 Intel Corporation
4  */
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 
reset_heartbeat(struct intel_engine_cs * engine)14 static void reset_heartbeat(struct intel_engine_cs *engine)
15 {
16 	intel_engine_set_heartbeat(engine,
17 				   engine->defaults.heartbeat_interval_ms);
18 }
19 
timeline_sync(struct intel_timeline * tl)20 static 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 
engine_sync_barrier(struct intel_engine_cs * engine)37 static int engine_sync_barrier(struct intel_engine_cs *engine)
38 {
39 	return timeline_sync(engine->kernel_context->timeline);
40 }
41 
42 struct pulse {
43 	struct i915_active active;
44 	struct kref kref;
45 };
46 
pulse_active(struct i915_active * active)47 static int pulse_active(struct i915_active *active)
48 {
49 	kref_get(&container_of(active, struct pulse, active)->kref);
50 	return 0;
51 }
52 
pulse_free(struct kref * kref)53 static 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 
pulse_put(struct pulse * p)61 static void pulse_put(struct pulse *p)
62 {
63 	kref_put(&p->kref, pulse_free);
64 }
65 
pulse_retire(struct i915_active * active)66 static void pulse_retire(struct i915_active *active)
67 {
68 	pulse_put(container_of(active, struct pulse, active));
69 }
70 
pulse_create(void)71 static 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 
pulse_unlock_wait(struct pulse * p)85 static void pulse_unlock_wait(struct pulse *p)
86 {
87 	wait_var_event_timeout(&p->active, i915_active_is_idle(&p->active), HZ);
88 }
89 
__live_idle_pulse(struct intel_engine_cs * engine,int (* fn)(struct intel_engine_cs * cs))90 static 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 
149 out:
150 	pulse_put(p);
151 	return err;
152 }
153 
live_idle_flush(void * arg)154 static 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 
live_idle_pulse(void * arg)174 static 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 
__live_heartbeat_off(struct intel_engine_cs * engine)196 static 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 
231 err_beat:
232 	reset_heartbeat(engine);
233 err_pm:
234 	intel_engine_pm_put(engine);
235 	return err;
236 }
237 
live_heartbeat_off(void * arg)238 static 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 
intel_heartbeat_live_selftests(struct drm_i915_private * i915)261 int 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 
st_engine_heartbeat_disable(struct intel_engine_cs * engine)283 void 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 
st_engine_heartbeat_enable(struct intel_engine_cs * engine)291 void 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 
st_engine_heartbeat_disable_no_pm(struct intel_engine_cs * engine)299 void 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 that
305 	 * makes the engines appear not-idle. Note that if/when unpark
306 	 * is called due to the PM lock being acquired later the
307 	 * 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 
st_engine_heartbeat_enable_no_pm(struct intel_engine_cs * engine)315 void 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