1 /*
2  * SPDX-License-Identifier: MIT
3  *
4  * Copyright © 2018 Intel Corporation
5  */
6 
7 #include "../i915_drv.h"
8 
9 #include "../i915_selftest.h"
10 #include "igt_flush_test.h"
11 
12 struct wedge_me {
13 	struct delayed_work work;
14 	struct drm_i915_private *i915;
15 	const void *symbol;
16 };
17 
18 static void wedge_me(struct work_struct *work)
19 {
20 	struct wedge_me *w = container_of(work, typeof(*w), work.work);
21 
22 	pr_err("%pS timed out, cancelling all further testing.\n", w->symbol);
23 
24 	GEM_TRACE("%pS timed out.\n", w->symbol);
25 	GEM_TRACE_DUMP();
26 
27 	i915_gem_set_wedged(w->i915);
28 }
29 
30 static void __init_wedge(struct wedge_me *w,
31 			 struct drm_i915_private *i915,
32 			 long timeout,
33 			 const void *symbol)
34 {
35 	w->i915 = i915;
36 	w->symbol = symbol;
37 
38 	INIT_DELAYED_WORK_ONSTACK(&w->work, wedge_me);
39 	schedule_delayed_work(&w->work, timeout);
40 }
41 
42 static void __fini_wedge(struct wedge_me *w)
43 {
44 	cancel_delayed_work_sync(&w->work);
45 	destroy_delayed_work_on_stack(&w->work);
46 	w->i915 = NULL;
47 }
48 
49 #define wedge_on_timeout(W, DEV, TIMEOUT)				\
50 	for (__init_wedge((W), (DEV), (TIMEOUT), __builtin_return_address(0)); \
51 	     (W)->i915;							\
52 	     __fini_wedge((W)))
53 
54 int igt_flush_test(struct drm_i915_private *i915, unsigned int flags)
55 {
56 	struct wedge_me w;
57 
58 	cond_resched();
59 
60 	if (flags & I915_WAIT_LOCKED &&
61 	    i915_gem_switch_to_kernel_context(i915)) {
62 		pr_err("Failed to switch back to kernel context; declaring wedged\n");
63 		i915_gem_set_wedged(i915);
64 	}
65 
66 	wedge_on_timeout(&w, i915, HZ)
67 		i915_gem_wait_for_idle(i915, flags);
68 
69 	return i915_terminally_wedged(&i915->gpu_error) ? -EIO : 0;
70 }
71