xref: /openbsd-src/sys/dev/pci/drm/i915/gt/intel_engine_heartbeat.c (revision f005ef32267c16bdb134f0e9fa4477dbe07c263a)
15ca02815Sjsg // SPDX-License-Identifier: MIT
2c349dbc7Sjsg /*
3c349dbc7Sjsg  * Copyright © 2019 Intel Corporation
4c349dbc7Sjsg  */
5c349dbc7Sjsg 
6ad8b1aafSjsg #include "i915_drv.h"
7c349dbc7Sjsg #include "i915_request.h"
8c349dbc7Sjsg 
9c349dbc7Sjsg #include "intel_context.h"
10c349dbc7Sjsg #include "intel_engine_heartbeat.h"
11c349dbc7Sjsg #include "intel_engine_pm.h"
12c349dbc7Sjsg #include "intel_engine.h"
13c349dbc7Sjsg #include "intel_gt.h"
14c349dbc7Sjsg #include "intel_reset.h"
15c349dbc7Sjsg 
16c349dbc7Sjsg /*
17c349dbc7Sjsg  * While the engine is active, we send a periodic pulse along the engine
18c349dbc7Sjsg  * to check on its health and to flush any idle-barriers. If that request
19c349dbc7Sjsg  * is stuck, and we fail to preempt it, we declare the engine hung and
20c349dbc7Sjsg  * issue a reset -- in the hope that restores progress.
21c349dbc7Sjsg  */
22c349dbc7Sjsg 
next_heartbeat(struct intel_engine_cs * engine)23c349dbc7Sjsg static bool next_heartbeat(struct intel_engine_cs *engine)
24c349dbc7Sjsg {
25*f005ef32Sjsg 	struct i915_request *rq;
26c349dbc7Sjsg 	long delay;
27c349dbc7Sjsg 
28c349dbc7Sjsg 	delay = READ_ONCE(engine->props.heartbeat_interval_ms);
29*f005ef32Sjsg 
30*f005ef32Sjsg 	rq = engine->heartbeat.systole;
31*f005ef32Sjsg 
32*f005ef32Sjsg 	/*
33*f005ef32Sjsg 	 * FIXME: The final period extension is disabled if the period has been
34*f005ef32Sjsg 	 * modified from the default. This is to prevent issues with certain
35*f005ef32Sjsg 	 * selftests which override the value and expect specific behaviour.
36*f005ef32Sjsg 	 * Once the selftests have been updated to either cope with variable
37*f005ef32Sjsg 	 * heartbeat periods (or to override the pre-emption timeout as well,
38*f005ef32Sjsg 	 * or just to add a selftest specific override of the extension), the
39*f005ef32Sjsg 	 * generic override can be removed.
40*f005ef32Sjsg 	 */
41*f005ef32Sjsg 	if (rq && rq->sched.attr.priority >= I915_PRIORITY_BARRIER &&
42*f005ef32Sjsg 	    delay == engine->defaults.heartbeat_interval_ms) {
43*f005ef32Sjsg 		long longer;
44*f005ef32Sjsg 
45*f005ef32Sjsg 		/*
46*f005ef32Sjsg 		 * The final try is at the highest priority possible. Up until now
47*f005ef32Sjsg 		 * a pre-emption might not even have been attempted. So make sure
48*f005ef32Sjsg 		 * this last attempt allows enough time for a pre-emption to occur.
49*f005ef32Sjsg 		 */
50*f005ef32Sjsg 		longer = READ_ONCE(engine->props.preempt_timeout_ms) * 2;
51*f005ef32Sjsg 		longer = intel_clamp_heartbeat_interval_ms(engine, longer);
52*f005ef32Sjsg 		if (longer > delay)
53*f005ef32Sjsg 			delay = longer;
54*f005ef32Sjsg 	}
55*f005ef32Sjsg 
56c349dbc7Sjsg 	if (!delay)
57c349dbc7Sjsg 		return false;
58c349dbc7Sjsg 
59c349dbc7Sjsg 	delay = msecs_to_jiffies_timeout(delay);
60c349dbc7Sjsg 	if (delay >= HZ)
61c349dbc7Sjsg 		delay = round_jiffies_up_relative(delay);
625ca02815Sjsg 	mod_delayed_work(system_highpri_wq, &engine->heartbeat.work, delay + 1);
63c349dbc7Sjsg 
64c349dbc7Sjsg 	return true;
65c349dbc7Sjsg }
66c349dbc7Sjsg 
675ca02815Sjsg static struct i915_request *
heartbeat_create(struct intel_context * ce,gfp_t gfp)685ca02815Sjsg heartbeat_create(struct intel_context *ce, gfp_t gfp)
695ca02815Sjsg {
705ca02815Sjsg 	struct i915_request *rq;
715ca02815Sjsg 
725ca02815Sjsg 	intel_context_enter(ce);
735ca02815Sjsg 	rq = __i915_request_create(ce, gfp);
745ca02815Sjsg 	intel_context_exit(ce);
755ca02815Sjsg 
765ca02815Sjsg 	return rq;
775ca02815Sjsg }
785ca02815Sjsg 
idle_pulse(struct intel_engine_cs * engine,struct i915_request * rq)79c349dbc7Sjsg static void idle_pulse(struct intel_engine_cs *engine, struct i915_request *rq)
80c349dbc7Sjsg {
81c349dbc7Sjsg 	engine->wakeref_serial = READ_ONCE(engine->serial) + 1;
82c349dbc7Sjsg 	i915_request_add_active_barriers(rq);
835ca02815Sjsg 	if (!engine->heartbeat.systole && intel_engine_has_heartbeat(engine))
845ca02815Sjsg 		engine->heartbeat.systole = i915_request_get(rq);
855ca02815Sjsg }
865ca02815Sjsg 
heartbeat_commit(struct i915_request * rq,const struct i915_sched_attr * attr)875ca02815Sjsg static void heartbeat_commit(struct i915_request *rq,
885ca02815Sjsg 			     const struct i915_sched_attr *attr)
895ca02815Sjsg {
905ca02815Sjsg 	idle_pulse(rq->engine, rq);
915ca02815Sjsg 
925ca02815Sjsg 	__i915_request_commit(rq);
935ca02815Sjsg 	__i915_request_queue(rq, attr);
94c349dbc7Sjsg }
95c349dbc7Sjsg 
show_heartbeat(const struct i915_request * rq,struct intel_engine_cs * engine)96c349dbc7Sjsg static void show_heartbeat(const struct i915_request *rq,
97c349dbc7Sjsg 			   struct intel_engine_cs *engine)
98c349dbc7Sjsg {
99c349dbc7Sjsg 	struct drm_printer p = drm_debug_printer("heartbeat");
100c349dbc7Sjsg 
1015ca02815Sjsg 	if (!rq) {
1025ca02815Sjsg 		intel_engine_dump(engine, &p,
1035ca02815Sjsg 				  "%s heartbeat not ticking\n",
1045ca02815Sjsg 				  engine->name);
1055ca02815Sjsg 	} else {
106c349dbc7Sjsg 		intel_engine_dump(engine, &p,
107ad8b1aafSjsg 				  "%s heartbeat {seqno:%llx:%lld, prio:%d} not ticking\n",
108c349dbc7Sjsg 				  engine->name,
109ad8b1aafSjsg 				  rq->fence.context,
110ad8b1aafSjsg 				  rq->fence.seqno,
111c349dbc7Sjsg 				  rq->sched.attr.priority);
112c349dbc7Sjsg 	}
1135ca02815Sjsg }
1145ca02815Sjsg 
1155ca02815Sjsg static void
reset_engine(struct intel_engine_cs * engine,struct i915_request * rq)1165ca02815Sjsg reset_engine(struct intel_engine_cs *engine, struct i915_request *rq)
1175ca02815Sjsg {
1185ca02815Sjsg 	if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM))
1195ca02815Sjsg 		show_heartbeat(rq, engine);
1205ca02815Sjsg 
1215ca02815Sjsg 	if (intel_engine_uses_guc(engine))
1225ca02815Sjsg 		/*
1235ca02815Sjsg 		 * GuC itself is toast or GuC's hang detection
1245ca02815Sjsg 		 * is disabled. Either way, need to find the
1255ca02815Sjsg 		 * hang culprit manually.
1265ca02815Sjsg 		 */
1275ca02815Sjsg 		intel_guc_find_hung_context(engine);
1285ca02815Sjsg 
1295ca02815Sjsg 	intel_gt_handle_error(engine->gt, engine->mask,
1305ca02815Sjsg 			      I915_ERROR_CAPTURE,
1315ca02815Sjsg 			      "stopped heartbeat on %s",
1325ca02815Sjsg 			      engine->name);
1335ca02815Sjsg }
134c349dbc7Sjsg 
heartbeat(struct work_struct * wrk)135c349dbc7Sjsg static void heartbeat(struct work_struct *wrk)
136c349dbc7Sjsg {
1375ca02815Sjsg 	struct i915_sched_attr attr = { .priority = I915_PRIORITY_MIN };
138c349dbc7Sjsg 	struct intel_engine_cs *engine =
139c349dbc7Sjsg 		container_of(wrk, typeof(*engine), heartbeat.work.work);
140c349dbc7Sjsg 	struct intel_context *ce = engine->kernel_context;
141c349dbc7Sjsg 	struct i915_request *rq;
142ad8b1aafSjsg 	unsigned long serial;
143ad8b1aafSjsg 
144ad8b1aafSjsg 	/* Just in case everything has gone horribly wrong, give it a kick */
145ad8b1aafSjsg 	intel_engine_flush_submission(engine);
146c349dbc7Sjsg 
147c349dbc7Sjsg 	rq = engine->heartbeat.systole;
148c349dbc7Sjsg 	if (rq && i915_request_completed(rq)) {
149c349dbc7Sjsg 		i915_request_put(rq);
150c349dbc7Sjsg 		engine->heartbeat.systole = NULL;
151c349dbc7Sjsg 	}
152c349dbc7Sjsg 
153c349dbc7Sjsg 	if (!intel_engine_pm_get_if_awake(engine))
154c349dbc7Sjsg 		return;
155c349dbc7Sjsg 
156c349dbc7Sjsg 	if (intel_gt_is_wedged(engine->gt))
157c349dbc7Sjsg 		goto out;
158c349dbc7Sjsg 
1595ca02815Sjsg 	if (i915_sched_engine_disabled(engine->sched_engine)) {
1605ca02815Sjsg 		reset_engine(engine, engine->heartbeat.systole);
1615ca02815Sjsg 		goto out;
1625ca02815Sjsg 	}
1635ca02815Sjsg 
164c349dbc7Sjsg 	if (engine->heartbeat.systole) {
1655ca02815Sjsg 		long delay = READ_ONCE(engine->props.heartbeat_interval_ms);
1665ca02815Sjsg 
1675ca02815Sjsg 		/* Safeguard against too-fast worker invocations */
1685ca02815Sjsg 		if (!time_after(jiffies,
1695ca02815Sjsg 				rq->emitted_jiffies + msecs_to_jiffies(delay)))
1705ca02815Sjsg 			goto out;
1715ca02815Sjsg 
172ad8b1aafSjsg 		if (!i915_sw_fence_signaled(&rq->submit)) {
173ad8b1aafSjsg 			/*
174ad8b1aafSjsg 			 * Not yet submitted, system is stalled.
175ad8b1aafSjsg 			 *
176ad8b1aafSjsg 			 * This more often happens for ring submission,
177ad8b1aafSjsg 			 * where all contexts are funnelled into a common
178ad8b1aafSjsg 			 * ringbuffer. If one context is blocked on an
179ad8b1aafSjsg 			 * external fence, not only is it not submitted,
180ad8b1aafSjsg 			 * but all other contexts, including the kernel
181ad8b1aafSjsg 			 * context are stuck waiting for the signal.
182ad8b1aafSjsg 			 */
1835ca02815Sjsg 		} else if (engine->sched_engine->schedule &&
184c349dbc7Sjsg 			   rq->sched.attr.priority < I915_PRIORITY_BARRIER) {
185c349dbc7Sjsg 			/*
186c349dbc7Sjsg 			 * Gradually raise the priority of the heartbeat to
187c349dbc7Sjsg 			 * give high priority work [which presumably desires
188c349dbc7Sjsg 			 * low latency and no jitter] the chance to naturally
189c349dbc7Sjsg 			 * complete before being preempted.
190c349dbc7Sjsg 			 */
1915ca02815Sjsg 			attr.priority = 0;
192c349dbc7Sjsg 			if (rq->sched.attr.priority >= attr.priority)
1935ca02815Sjsg 				attr.priority = I915_PRIORITY_HEARTBEAT;
194c349dbc7Sjsg 			if (rq->sched.attr.priority >= attr.priority)
195c349dbc7Sjsg 				attr.priority = I915_PRIORITY_BARRIER;
196c349dbc7Sjsg 
197c349dbc7Sjsg 			local_bh_disable();
1985ca02815Sjsg 			engine->sched_engine->schedule(rq, &attr);
199c349dbc7Sjsg 			local_bh_enable();
200c349dbc7Sjsg 		} else {
2015ca02815Sjsg 			reset_engine(engine, rq);
202c349dbc7Sjsg 		}
2035ca02815Sjsg 
2045ca02815Sjsg 		rq->emitted_jiffies = jiffies;
205c349dbc7Sjsg 		goto out;
206c349dbc7Sjsg 	}
207c349dbc7Sjsg 
208ad8b1aafSjsg 	serial = READ_ONCE(engine->serial);
209ad8b1aafSjsg 	if (engine->wakeref_serial == serial)
210c349dbc7Sjsg 		goto out;
211c349dbc7Sjsg 
212ad8b1aafSjsg 	if (!mutex_trylock(&ce->timeline->mutex)) {
213ad8b1aafSjsg 		/* Unable to lock the kernel timeline, is the engine stuck? */
214ad8b1aafSjsg 		if (xchg(&engine->heartbeat.blocked, serial) == serial)
215ad8b1aafSjsg 			intel_gt_handle_error(engine->gt, engine->mask,
216ad8b1aafSjsg 					      I915_ERROR_CAPTURE,
217ad8b1aafSjsg 					      "no heartbeat on %s",
218ad8b1aafSjsg 					      engine->name);
219ad8b1aafSjsg 		goto out;
220ad8b1aafSjsg 	}
221c349dbc7Sjsg 
2225ca02815Sjsg 	rq = heartbeat_create(ce, GFP_NOWAIT | __GFP_NOWARN);
223c349dbc7Sjsg 	if (IS_ERR(rq))
224c349dbc7Sjsg 		goto unlock;
225c349dbc7Sjsg 
2265ca02815Sjsg 	heartbeat_commit(rq, &attr);
227c349dbc7Sjsg 
228c349dbc7Sjsg unlock:
229c349dbc7Sjsg 	mutex_unlock(&ce->timeline->mutex);
230c349dbc7Sjsg out:
2315ca02815Sjsg 	if (!engine->i915->params.enable_hangcheck || !next_heartbeat(engine))
232c349dbc7Sjsg 		i915_request_put(fetch_and_zero(&engine->heartbeat.systole));
233c349dbc7Sjsg 	intel_engine_pm_put(engine);
234c349dbc7Sjsg }
235c349dbc7Sjsg 
intel_engine_unpark_heartbeat(struct intel_engine_cs * engine)236c349dbc7Sjsg void intel_engine_unpark_heartbeat(struct intel_engine_cs *engine)
237c349dbc7Sjsg {
2381bb76ff1Sjsg 	if (!CONFIG_DRM_I915_HEARTBEAT_INTERVAL)
239c349dbc7Sjsg 		return;
240c349dbc7Sjsg 
241c349dbc7Sjsg 	next_heartbeat(engine);
242c349dbc7Sjsg }
243c349dbc7Sjsg 
intel_engine_park_heartbeat(struct intel_engine_cs * engine)244c349dbc7Sjsg void intel_engine_park_heartbeat(struct intel_engine_cs *engine)
245c349dbc7Sjsg {
246c349dbc7Sjsg 	if (cancel_delayed_work(&engine->heartbeat.work))
247c349dbc7Sjsg 		i915_request_put(fetch_and_zero(&engine->heartbeat.systole));
248c349dbc7Sjsg }
249c349dbc7Sjsg 
intel_gt_unpark_heartbeats(struct intel_gt * gt)2505ca02815Sjsg void intel_gt_unpark_heartbeats(struct intel_gt *gt)
2515ca02815Sjsg {
2525ca02815Sjsg 	struct intel_engine_cs *engine;
2535ca02815Sjsg 	enum intel_engine_id id;
2545ca02815Sjsg 
2555ca02815Sjsg 	for_each_engine(engine, gt, id)
2565ca02815Sjsg 		if (intel_engine_pm_is_awake(engine))
2575ca02815Sjsg 			intel_engine_unpark_heartbeat(engine);
2585ca02815Sjsg }
2595ca02815Sjsg 
intel_gt_park_heartbeats(struct intel_gt * gt)2605ca02815Sjsg void intel_gt_park_heartbeats(struct intel_gt *gt)
2615ca02815Sjsg {
2625ca02815Sjsg 	struct intel_engine_cs *engine;
2635ca02815Sjsg 	enum intel_engine_id id;
2645ca02815Sjsg 
2655ca02815Sjsg 	for_each_engine(engine, gt, id)
2665ca02815Sjsg 		intel_engine_park_heartbeat(engine);
2675ca02815Sjsg }
2685ca02815Sjsg 
intel_engine_init_heartbeat(struct intel_engine_cs * engine)269c349dbc7Sjsg void intel_engine_init_heartbeat(struct intel_engine_cs *engine)
270c349dbc7Sjsg {
271c349dbc7Sjsg 	INIT_DELAYED_WORK(&engine->heartbeat.work, heartbeat);
272c349dbc7Sjsg }
273c349dbc7Sjsg 
__intel_engine_pulse(struct intel_engine_cs * engine)274ad8b1aafSjsg static int __intel_engine_pulse(struct intel_engine_cs *engine)
275c349dbc7Sjsg {
276c349dbc7Sjsg 	struct i915_sched_attr attr = { .priority = I915_PRIORITY_BARRIER };
277c349dbc7Sjsg 	struct intel_context *ce = engine->kernel_context;
278c349dbc7Sjsg 	struct i915_request *rq;
279ad8b1aafSjsg 
280ad8b1aafSjsg 	lockdep_assert_held(&ce->timeline->mutex);
281ad8b1aafSjsg 	GEM_BUG_ON(!intel_engine_has_preemption(engine));
282ad8b1aafSjsg 	GEM_BUG_ON(!intel_engine_pm_is_awake(engine));
283ad8b1aafSjsg 
2845ca02815Sjsg 	rq = heartbeat_create(ce, GFP_NOWAIT | __GFP_NOWARN);
285ad8b1aafSjsg 	if (IS_ERR(rq))
286ad8b1aafSjsg 		return PTR_ERR(rq);
287ad8b1aafSjsg 
288ad8b1aafSjsg 	__set_bit(I915_FENCE_FLAG_SENTINEL, &rq->fence.flags);
289ad8b1aafSjsg 
2905ca02815Sjsg 	heartbeat_commit(rq, &attr);
291ad8b1aafSjsg 	GEM_BUG_ON(rq->sched.attr.priority < I915_PRIORITY_BARRIER);
292ad8b1aafSjsg 
293ad8b1aafSjsg 	return 0;
294ad8b1aafSjsg }
295ad8b1aafSjsg 
set_heartbeat(struct intel_engine_cs * engine,unsigned long delay)296ad8b1aafSjsg static unsigned long set_heartbeat(struct intel_engine_cs *engine,
297ad8b1aafSjsg 				   unsigned long delay)
298ad8b1aafSjsg {
299ad8b1aafSjsg 	unsigned long old;
300ad8b1aafSjsg 
301ad8b1aafSjsg 	old = xchg(&engine->props.heartbeat_interval_ms, delay);
302ad8b1aafSjsg 	if (delay)
303ad8b1aafSjsg 		intel_engine_unpark_heartbeat(engine);
304ad8b1aafSjsg 	else
305ad8b1aafSjsg 		intel_engine_park_heartbeat(engine);
306ad8b1aafSjsg 
307ad8b1aafSjsg 	return old;
308ad8b1aafSjsg }
309ad8b1aafSjsg 
intel_engine_set_heartbeat(struct intel_engine_cs * engine,unsigned long delay)310ad8b1aafSjsg int intel_engine_set_heartbeat(struct intel_engine_cs *engine,
311ad8b1aafSjsg 			       unsigned long delay)
312ad8b1aafSjsg {
313ad8b1aafSjsg 	struct intel_context *ce = engine->kernel_context;
314ad8b1aafSjsg 	int err = 0;
315ad8b1aafSjsg 
316ad8b1aafSjsg 	if (!delay && !intel_engine_has_preempt_reset(engine))
317ad8b1aafSjsg 		return -ENODEV;
318ad8b1aafSjsg 
319*f005ef32Sjsg 	/* FIXME: Remove together with equally marked hack in next_heartbeat. */
320*f005ef32Sjsg 	if (delay != engine->defaults.heartbeat_interval_ms &&
321*f005ef32Sjsg 	    delay < 2 * engine->props.preempt_timeout_ms) {
322*f005ef32Sjsg 		if (intel_engine_uses_guc(engine))
323*f005ef32Sjsg 			drm_notice(&engine->i915->drm, "%s heartbeat interval adjusted to a non-default value which may downgrade individual engine resets to full GPU resets!\n",
324*f005ef32Sjsg 				   engine->name);
325*f005ef32Sjsg 		else
326*f005ef32Sjsg 			drm_notice(&engine->i915->drm, "%s heartbeat interval adjusted to a non-default value which may cause engine resets to target innocent contexts!\n",
327*f005ef32Sjsg 				   engine->name);
328*f005ef32Sjsg 	}
329*f005ef32Sjsg 
330ad8b1aafSjsg 	intel_engine_pm_get(engine);
331ad8b1aafSjsg 
332ad8b1aafSjsg 	err = mutex_lock_interruptible(&ce->timeline->mutex);
333ad8b1aafSjsg 	if (err)
334ad8b1aafSjsg 		goto out_rpm;
335ad8b1aafSjsg 
336ad8b1aafSjsg 	if (delay != engine->props.heartbeat_interval_ms) {
337ad8b1aafSjsg 		unsigned long saved = set_heartbeat(engine, delay);
338ad8b1aafSjsg 
339ad8b1aafSjsg 		/* recheck current execution */
340ad8b1aafSjsg 		if (intel_engine_has_preemption(engine)) {
341ad8b1aafSjsg 			err = __intel_engine_pulse(engine);
342ad8b1aafSjsg 			if (err)
343ad8b1aafSjsg 				set_heartbeat(engine, saved);
344ad8b1aafSjsg 		}
345ad8b1aafSjsg 	}
346ad8b1aafSjsg 
347ad8b1aafSjsg 	mutex_unlock(&ce->timeline->mutex);
348ad8b1aafSjsg 
349ad8b1aafSjsg out_rpm:
350ad8b1aafSjsg 	intel_engine_pm_put(engine);
351ad8b1aafSjsg 	return err;
352ad8b1aafSjsg }
353ad8b1aafSjsg 
intel_engine_pulse(struct intel_engine_cs * engine)354ad8b1aafSjsg int intel_engine_pulse(struct intel_engine_cs *engine)
355ad8b1aafSjsg {
356ad8b1aafSjsg 	struct intel_context *ce = engine->kernel_context;
357c349dbc7Sjsg 	int err;
358c349dbc7Sjsg 
359c349dbc7Sjsg 	if (!intel_engine_has_preemption(engine))
360c349dbc7Sjsg 		return -ENODEV;
361c349dbc7Sjsg 
362c349dbc7Sjsg 	if (!intel_engine_pm_get_if_awake(engine))
363c349dbc7Sjsg 		return 0;
364c349dbc7Sjsg 
365c349dbc7Sjsg 	err = -EINTR;
366ad8b1aafSjsg 	if (!mutex_lock_interruptible(&ce->timeline->mutex)) {
367ad8b1aafSjsg 		err = __intel_engine_pulse(engine);
368c349dbc7Sjsg 		mutex_unlock(&ce->timeline->mutex);
369ad8b1aafSjsg 	}
370ad8b1aafSjsg 
3715ca02815Sjsg 	intel_engine_flush_submission(engine);
372c349dbc7Sjsg 	intel_engine_pm_put(engine);
373c349dbc7Sjsg 	return err;
374c349dbc7Sjsg }
375c349dbc7Sjsg 
intel_engine_flush_barriers(struct intel_engine_cs * engine)376c349dbc7Sjsg int intel_engine_flush_barriers(struct intel_engine_cs *engine)
377c349dbc7Sjsg {
3785ca02815Sjsg 	struct i915_sched_attr attr = { .priority = I915_PRIORITY_MIN };
3795ca02815Sjsg 	struct intel_context *ce = engine->kernel_context;
380c349dbc7Sjsg 	struct i915_request *rq;
3815ca02815Sjsg 	int err;
382c349dbc7Sjsg 
383c349dbc7Sjsg 	if (llist_empty(&engine->barrier_tasks))
384c349dbc7Sjsg 		return 0;
385c349dbc7Sjsg 
386c349dbc7Sjsg 	if (!intel_engine_pm_get_if_awake(engine))
387c349dbc7Sjsg 		return 0;
388c349dbc7Sjsg 
3895ca02815Sjsg 	if (mutex_lock_interruptible(&ce->timeline->mutex)) {
3905ca02815Sjsg 		err = -EINTR;
391c349dbc7Sjsg 		goto out_rpm;
392c349dbc7Sjsg 	}
393c349dbc7Sjsg 
3945ca02815Sjsg 	rq = heartbeat_create(ce, GFP_KERNEL);
3955ca02815Sjsg 	if (IS_ERR(rq)) {
3965ca02815Sjsg 		err = PTR_ERR(rq);
3975ca02815Sjsg 		goto out_unlock;
3985ca02815Sjsg 	}
399c349dbc7Sjsg 
4005ca02815Sjsg 	heartbeat_commit(rq, &attr);
4015ca02815Sjsg 
4025ca02815Sjsg 	err = 0;
4035ca02815Sjsg out_unlock:
4045ca02815Sjsg 	mutex_unlock(&ce->timeline->mutex);
405c349dbc7Sjsg out_rpm:
406c349dbc7Sjsg 	intel_engine_pm_put(engine);
407c349dbc7Sjsg 	return err;
408c349dbc7Sjsg }
409c349dbc7Sjsg 
410c349dbc7Sjsg #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
411c349dbc7Sjsg #include "selftest_engine_heartbeat.c"
412c349dbc7Sjsg #endif
413