treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / drivers / gpu / drm / i915 / gt / selftest_engine_heartbeat.c
blob43d4d589749fbc748f15636fe560ef38e1c917d3
1 /*
2 * SPDX-License-Identifier: MIT
4 * Copyright © 2018 Intel Corporation
5 */
7 #include <linux/sort.h>
9 #include "i915_drv.h"
11 #include "intel_gt_requests.h"
12 #include "i915_selftest.h"
14 static int timeline_sync(struct intel_timeline *tl)
16 struct dma_fence *fence;
17 long timeout;
19 fence = i915_active_fence_get(&tl->last_request);
20 if (!fence)
21 return 0;
23 timeout = dma_fence_wait_timeout(fence, true, HZ / 2);
24 dma_fence_put(fence);
25 if (timeout < 0)
26 return timeout;
28 return 0;
31 static int engine_sync_barrier(struct intel_engine_cs *engine)
33 return timeline_sync(engine->kernel_context->timeline);
36 struct pulse {
37 struct i915_active active;
38 struct kref kref;
41 static int pulse_active(struct i915_active *active)
43 kref_get(&container_of(active, struct pulse, active)->kref);
44 return 0;
47 static void pulse_free(struct kref *kref)
49 kfree(container_of(kref, struct pulse, kref));
52 static void pulse_put(struct pulse *p)
54 kref_put(&p->kref, pulse_free);
57 static void pulse_retire(struct i915_active *active)
59 pulse_put(container_of(active, struct pulse, active));
62 static struct pulse *pulse_create(void)
64 struct pulse *p;
66 p = kmalloc(sizeof(*p), GFP_KERNEL);
67 if (!p)
68 return p;
70 kref_init(&p->kref);
71 i915_active_init(&p->active, pulse_active, pulse_retire);
73 return p;
76 static void pulse_unlock_wait(struct pulse *p)
78 i915_active_unlock_wait(&p->active);
81 static int __live_idle_pulse(struct intel_engine_cs *engine,
82 int (*fn)(struct intel_engine_cs *cs))
84 struct pulse *p;
85 int err;
87 GEM_BUG_ON(!intel_engine_pm_is_awake(engine));
89 p = pulse_create();
90 if (!p)
91 return -ENOMEM;
93 err = i915_active_acquire(&p->active);
94 if (err)
95 goto out;
97 err = i915_active_acquire_preallocate_barrier(&p->active, engine);
98 if (err) {
99 i915_active_release(&p->active);
100 goto out;
103 i915_active_acquire_barrier(&p->active);
104 i915_active_release(&p->active);
106 GEM_BUG_ON(i915_active_is_idle(&p->active));
107 GEM_BUG_ON(llist_empty(&engine->barrier_tasks));
109 err = fn(engine);
110 if (err)
111 goto out;
113 GEM_BUG_ON(!llist_empty(&engine->barrier_tasks));
115 if (engine_sync_barrier(engine)) {
116 struct drm_printer m = drm_err_printer("pulse");
118 pr_err("%s: no heartbeat pulse?\n", engine->name);
119 intel_engine_dump(engine, &m, "%s", engine->name);
121 err = -ETIME;
122 goto out;
125 GEM_BUG_ON(READ_ONCE(engine->serial) != engine->wakeref_serial);
127 pulse_unlock_wait(p); /* synchronize with the retirement callback */
129 if (!i915_active_is_idle(&p->active)) {
130 struct drm_printer m = drm_err_printer("pulse");
132 pr_err("%s: heartbeat pulse did not flush idle tasks\n",
133 engine->name);
134 i915_active_print(&p->active, &m);
136 err = -EINVAL;
137 goto out;
140 out:
141 pulse_put(p);
142 return err;
145 static int live_idle_flush(void *arg)
147 struct intel_gt *gt = arg;
148 struct intel_engine_cs *engine;
149 enum intel_engine_id id;
150 int err = 0;
152 /* Check that we can flush the idle barriers */
154 for_each_engine(engine, gt, id) {
155 intel_engine_pm_get(engine);
156 err = __live_idle_pulse(engine, intel_engine_flush_barriers);
157 intel_engine_pm_put(engine);
158 if (err)
159 break;
162 return err;
165 static int live_idle_pulse(void *arg)
167 struct intel_gt *gt = arg;
168 struct intel_engine_cs *engine;
169 enum intel_engine_id id;
170 int err = 0;
172 /* Check that heartbeat pulses flush the idle barriers */
174 for_each_engine(engine, gt, id) {
175 intel_engine_pm_get(engine);
176 err = __live_idle_pulse(engine, intel_engine_pulse);
177 intel_engine_pm_put(engine);
178 if (err && err != -ENODEV)
179 break;
181 err = 0;
184 return err;
187 static int cmp_u32(const void *_a, const void *_b)
189 const u32 *a = _a, *b = _b;
191 return *a - *b;
194 static int __live_heartbeat_fast(struct intel_engine_cs *engine)
196 struct intel_context *ce;
197 struct i915_request *rq;
198 ktime_t t0, t1;
199 u32 times[5];
200 int err;
201 int i;
203 ce = intel_context_create(engine);
204 if (IS_ERR(ce))
205 return PTR_ERR(ce);
207 intel_engine_pm_get(engine);
209 err = intel_engine_set_heartbeat(engine, 1);
210 if (err)
211 goto err_pm;
213 for (i = 0; i < ARRAY_SIZE(times); i++) {
214 /* Manufacture a tick */
215 do {
216 while (READ_ONCE(engine->heartbeat.systole))
217 flush_delayed_work(&engine->heartbeat.work);
219 engine->serial++; /* quick, pretend we are not idle! */
220 flush_delayed_work(&engine->heartbeat.work);
221 if (!delayed_work_pending(&engine->heartbeat.work)) {
222 pr_err("%s: heartbeat did not start\n",
223 engine->name);
224 err = -EINVAL;
225 goto err_pm;
228 rcu_read_lock();
229 rq = READ_ONCE(engine->heartbeat.systole);
230 if (rq)
231 rq = i915_request_get_rcu(rq);
232 rcu_read_unlock();
233 } while (!rq);
235 t0 = ktime_get();
236 while (rq == READ_ONCE(engine->heartbeat.systole))
237 yield(); /* work is on the local cpu! */
238 t1 = ktime_get();
240 i915_request_put(rq);
241 times[i] = ktime_us_delta(t1, t0);
244 sort(times, ARRAY_SIZE(times), sizeof(times[0]), cmp_u32, NULL);
246 pr_info("%s: Heartbeat delay: %uus [%u, %u]\n",
247 engine->name,
248 times[ARRAY_SIZE(times) / 2],
249 times[0],
250 times[ARRAY_SIZE(times) - 1]);
252 /* Min work delay is 2 * 2 (worst), +1 for scheduling, +1 for slack */
253 if (times[ARRAY_SIZE(times) / 2] > jiffies_to_usecs(6)) {
254 pr_err("%s: Heartbeat delay was %uus, expected less than %dus\n",
255 engine->name,
256 times[ARRAY_SIZE(times) / 2],
257 jiffies_to_usecs(6));
258 err = -EINVAL;
261 intel_engine_set_heartbeat(engine, CONFIG_DRM_I915_HEARTBEAT_INTERVAL);
262 err_pm:
263 intel_engine_pm_put(engine);
264 intel_context_put(ce);
265 return err;
268 static int live_heartbeat_fast(void *arg)
270 struct intel_gt *gt = arg;
271 struct intel_engine_cs *engine;
272 enum intel_engine_id id;
273 int err = 0;
275 /* Check that the heartbeat ticks at the desired rate. */
276 if (!CONFIG_DRM_I915_HEARTBEAT_INTERVAL)
277 return 0;
279 for_each_engine(engine, gt, id) {
280 err = __live_heartbeat_fast(engine);
281 if (err)
282 break;
285 return err;
288 static int __live_heartbeat_off(struct intel_engine_cs *engine)
290 int err;
292 intel_engine_pm_get(engine);
294 engine->serial++;
295 flush_delayed_work(&engine->heartbeat.work);
296 if (!delayed_work_pending(&engine->heartbeat.work)) {
297 pr_err("%s: heartbeat not running\n",
298 engine->name);
299 err = -EINVAL;
300 goto err_pm;
303 err = intel_engine_set_heartbeat(engine, 0);
304 if (err)
305 goto err_pm;
307 engine->serial++;
308 flush_delayed_work(&engine->heartbeat.work);
309 if (delayed_work_pending(&engine->heartbeat.work)) {
310 pr_err("%s: heartbeat still running\n",
311 engine->name);
312 err = -EINVAL;
313 goto err_beat;
316 if (READ_ONCE(engine->heartbeat.systole)) {
317 pr_err("%s: heartbeat still allocated\n",
318 engine->name);
319 err = -EINVAL;
320 goto err_beat;
323 err_beat:
324 intel_engine_set_heartbeat(engine, CONFIG_DRM_I915_HEARTBEAT_INTERVAL);
325 err_pm:
326 intel_engine_pm_put(engine);
327 return err;
330 static int live_heartbeat_off(void *arg)
332 struct intel_gt *gt = arg;
333 struct intel_engine_cs *engine;
334 enum intel_engine_id id;
335 int err = 0;
337 /* Check that we can turn off heartbeat and not interrupt VIP */
338 if (!CONFIG_DRM_I915_HEARTBEAT_INTERVAL)
339 return 0;
341 for_each_engine(engine, gt, id) {
342 if (!intel_engine_has_preemption(engine))
343 continue;
345 err = __live_heartbeat_off(engine);
346 if (err)
347 break;
350 return err;
353 int intel_heartbeat_live_selftests(struct drm_i915_private *i915)
355 static const struct i915_subtest tests[] = {
356 SUBTEST(live_idle_flush),
357 SUBTEST(live_idle_pulse),
358 SUBTEST(live_heartbeat_fast),
359 SUBTEST(live_heartbeat_off),
361 int saved_hangcheck;
362 int err;
364 if (intel_gt_is_wedged(&i915->gt))
365 return 0;
367 saved_hangcheck = i915_modparams.enable_hangcheck;
368 i915_modparams.enable_hangcheck = INT_MAX;
370 err = intel_gt_live_subtests(tests, &i915->gt);
372 i915_modparams.enable_hangcheck = saved_hangcheck;
373 return err;