WIP FPC-III support
[linux/fpc-iii.git] / drivers / gpu / drm / i915 / gt / selftest_engine_heartbeat.c
blobb88aa35ad75b6bbdaef192b565b125753b125939
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"
13 #include "selftest_engine_heartbeat.h"
15 static int timeline_sync(struct intel_timeline *tl)
17 struct dma_fence *fence;
18 long timeout;
20 fence = i915_active_fence_get(&tl->last_request);
21 if (!fence)
22 return 0;
24 timeout = dma_fence_wait_timeout(fence, true, HZ / 2);
25 dma_fence_put(fence);
26 if (timeout < 0)
27 return timeout;
29 return 0;
32 static int engine_sync_barrier(struct intel_engine_cs *engine)
34 return timeline_sync(engine->kernel_context->timeline);
37 struct pulse {
38 struct i915_active active;
39 struct kref kref;
42 static int pulse_active(struct i915_active *active)
44 kref_get(&container_of(active, struct pulse, active)->kref);
45 return 0;
48 static void pulse_free(struct kref *kref)
50 struct pulse *p = container_of(kref, typeof(*p), kref);
52 i915_active_fini(&p->active);
53 kfree(p);
56 static void pulse_put(struct pulse *p)
58 kref_put(&p->kref, pulse_free);
61 static void pulse_retire(struct i915_active *active)
63 pulse_put(container_of(active, struct pulse, active));
66 static struct pulse *pulse_create(void)
68 struct pulse *p;
70 p = kmalloc(sizeof(*p), GFP_KERNEL);
71 if (!p)
72 return p;
74 kref_init(&p->kref);
75 i915_active_init(&p->active, pulse_active, pulse_retire);
77 return p;
80 static void pulse_unlock_wait(struct pulse *p)
82 i915_active_unlock_wait(&p->active);
85 static int __live_idle_pulse(struct intel_engine_cs *engine,
86 int (*fn)(struct intel_engine_cs *cs))
88 struct pulse *p;
89 int err;
91 GEM_BUG_ON(!intel_engine_pm_is_awake(engine));
93 p = pulse_create();
94 if (!p)
95 return -ENOMEM;
97 err = i915_active_acquire(&p->active);
98 if (err)
99 goto out;
101 err = i915_active_acquire_preallocate_barrier(&p->active, engine);
102 if (err) {
103 i915_active_release(&p->active);
104 goto out;
107 i915_active_acquire_barrier(&p->active);
108 i915_active_release(&p->active);
110 GEM_BUG_ON(i915_active_is_idle(&p->active));
111 GEM_BUG_ON(llist_empty(&engine->barrier_tasks));
113 err = fn(engine);
114 if (err)
115 goto out;
117 GEM_BUG_ON(!llist_empty(&engine->barrier_tasks));
119 if (engine_sync_barrier(engine)) {
120 struct drm_printer m = drm_err_printer("pulse");
122 pr_err("%s: no heartbeat pulse?\n", engine->name);
123 intel_engine_dump(engine, &m, "%s", engine->name);
125 err = -ETIME;
126 goto out;
129 GEM_BUG_ON(READ_ONCE(engine->serial) != engine->wakeref_serial);
131 pulse_unlock_wait(p); /* synchronize with the retirement callback */
133 if (!i915_active_is_idle(&p->active)) {
134 struct drm_printer m = drm_err_printer("pulse");
136 pr_err("%s: heartbeat pulse did not flush idle tasks\n",
137 engine->name);
138 i915_active_print(&p->active, &m);
140 err = -EINVAL;
141 goto out;
144 out:
145 pulse_put(p);
146 return err;
149 static int live_idle_flush(void *arg)
151 struct intel_gt *gt = arg;
152 struct intel_engine_cs *engine;
153 enum intel_engine_id id;
154 int err = 0;
156 /* Check that we can flush the idle barriers */
158 for_each_engine(engine, gt, id) {
159 st_engine_heartbeat_disable(engine);
160 err = __live_idle_pulse(engine, intel_engine_flush_barriers);
161 st_engine_heartbeat_enable(engine);
162 if (err)
163 break;
166 return err;
169 static int live_idle_pulse(void *arg)
171 struct intel_gt *gt = arg;
172 struct intel_engine_cs *engine;
173 enum intel_engine_id id;
174 int err = 0;
176 /* Check that heartbeat pulses flush the idle barriers */
178 for_each_engine(engine, gt, id) {
179 st_engine_heartbeat_disable(engine);
180 err = __live_idle_pulse(engine, intel_engine_pulse);
181 st_engine_heartbeat_enable(engine);
182 if (err && err != -ENODEV)
183 break;
185 err = 0;
188 return err;
191 static int cmp_u32(const void *_a, const void *_b)
193 const u32 *a = _a, *b = _b;
195 return *a - *b;
198 static int __live_heartbeat_fast(struct intel_engine_cs *engine)
200 struct intel_context *ce;
201 struct i915_request *rq;
202 ktime_t t0, t1;
203 u32 times[5];
204 int err;
205 int i;
207 ce = intel_context_create(engine);
208 if (IS_ERR(ce))
209 return PTR_ERR(ce);
211 intel_engine_pm_get(engine);
213 err = intel_engine_set_heartbeat(engine, 1);
214 if (err)
215 goto err_pm;
217 for (i = 0; i < ARRAY_SIZE(times); i++) {
218 do {
219 /* Manufacture a tick */
220 intel_engine_park_heartbeat(engine);
221 GEM_BUG_ON(engine->heartbeat.systole);
222 engine->serial++; /* pretend we are not idle! */
223 intel_engine_unpark_heartbeat(engine);
225 flush_delayed_work(&engine->heartbeat.work);
226 if (!delayed_work_pending(&engine->heartbeat.work)) {
227 pr_err("%s: heartbeat %d did not start\n",
228 engine->name, i);
229 err = -EINVAL;
230 goto err_pm;
233 rcu_read_lock();
234 rq = READ_ONCE(engine->heartbeat.systole);
235 if (rq)
236 rq = i915_request_get_rcu(rq);
237 rcu_read_unlock();
238 } while (!rq);
240 t0 = ktime_get();
241 while (rq == READ_ONCE(engine->heartbeat.systole))
242 yield(); /* work is on the local cpu! */
243 t1 = ktime_get();
245 i915_request_put(rq);
246 times[i] = ktime_us_delta(t1, t0);
249 sort(times, ARRAY_SIZE(times), sizeof(times[0]), cmp_u32, NULL);
251 pr_info("%s: Heartbeat delay: %uus [%u, %u]\n",
252 engine->name,
253 times[ARRAY_SIZE(times) / 2],
254 times[0],
255 times[ARRAY_SIZE(times) - 1]);
257 /* Min work delay is 2 * 2 (worst), +1 for scheduling, +1 for slack */
258 if (times[ARRAY_SIZE(times) / 2] > jiffies_to_usecs(6)) {
259 pr_err("%s: Heartbeat delay was %uus, expected less than %dus\n",
260 engine->name,
261 times[ARRAY_SIZE(times) / 2],
262 jiffies_to_usecs(6));
263 err = -EINVAL;
266 intel_engine_set_heartbeat(engine, CONFIG_DRM_I915_HEARTBEAT_INTERVAL);
267 err_pm:
268 intel_engine_pm_put(engine);
269 intel_context_put(ce);
270 return err;
273 static int live_heartbeat_fast(void *arg)
275 struct intel_gt *gt = arg;
276 struct intel_engine_cs *engine;
277 enum intel_engine_id id;
278 int err = 0;
280 /* Check that the heartbeat ticks at the desired rate. */
281 if (!CONFIG_DRM_I915_HEARTBEAT_INTERVAL)
282 return 0;
284 for_each_engine(engine, gt, id) {
285 err = __live_heartbeat_fast(engine);
286 if (err)
287 break;
290 return err;
293 static int __live_heartbeat_off(struct intel_engine_cs *engine)
295 int err;
297 intel_engine_pm_get(engine);
299 engine->serial++;
300 flush_delayed_work(&engine->heartbeat.work);
301 if (!delayed_work_pending(&engine->heartbeat.work)) {
302 pr_err("%s: heartbeat not running\n",
303 engine->name);
304 err = -EINVAL;
305 goto err_pm;
308 err = intel_engine_set_heartbeat(engine, 0);
309 if (err)
310 goto err_pm;
312 engine->serial++;
313 flush_delayed_work(&engine->heartbeat.work);
314 if (delayed_work_pending(&engine->heartbeat.work)) {
315 pr_err("%s: heartbeat still running\n",
316 engine->name);
317 err = -EINVAL;
318 goto err_beat;
321 if (READ_ONCE(engine->heartbeat.systole)) {
322 pr_err("%s: heartbeat still allocated\n",
323 engine->name);
324 err = -EINVAL;
325 goto err_beat;
328 err_beat:
329 intel_engine_set_heartbeat(engine, CONFIG_DRM_I915_HEARTBEAT_INTERVAL);
330 err_pm:
331 intel_engine_pm_put(engine);
332 return err;
335 static int live_heartbeat_off(void *arg)
337 struct intel_gt *gt = arg;
338 struct intel_engine_cs *engine;
339 enum intel_engine_id id;
340 int err = 0;
342 /* Check that we can turn off heartbeat and not interrupt VIP */
343 if (!CONFIG_DRM_I915_HEARTBEAT_INTERVAL)
344 return 0;
346 for_each_engine(engine, gt, id) {
347 if (!intel_engine_has_preemption(engine))
348 continue;
350 err = __live_heartbeat_off(engine);
351 if (err)
352 break;
355 return err;
358 int intel_heartbeat_live_selftests(struct drm_i915_private *i915)
360 static const struct i915_subtest tests[] = {
361 SUBTEST(live_idle_flush),
362 SUBTEST(live_idle_pulse),
363 SUBTEST(live_heartbeat_fast),
364 SUBTEST(live_heartbeat_off),
366 int saved_hangcheck;
367 int err;
369 if (intel_gt_is_wedged(&i915->gt))
370 return 0;
372 saved_hangcheck = i915->params.enable_hangcheck;
373 i915->params.enable_hangcheck = INT_MAX;
375 err = intel_gt_live_subtests(tests, &i915->gt);
377 i915->params.enable_hangcheck = saved_hangcheck;
378 return err;
381 void st_engine_heartbeat_disable(struct intel_engine_cs *engine)
383 engine->props.heartbeat_interval_ms = 0;
385 intel_engine_pm_get(engine);
386 intel_engine_park_heartbeat(engine);
389 void st_engine_heartbeat_enable(struct intel_engine_cs *engine)
391 intel_engine_pm_put(engine);
393 engine->props.heartbeat_interval_ms =
394 engine->defaults.heartbeat_interval_ms;