drm/i915: Prevent lock-cycles between GPU waits and GPU resets
[linux-2.6-microblaze.git] / drivers / gpu / drm / i915 / selftests / i915_active.c
1 /*
2  * SPDX-License-Identifier: MIT
3  *
4  * Copyright © 2018 Intel Corporation
5  */
6
7 #include "gem/i915_gem_pm.h"
8
9 #include "i915_selftest.h"
10
11 #include "igt_flush_test.h"
12 #include "lib_sw_fence.h"
13
14 struct live_active {
15         struct i915_active base;
16         bool retired;
17 };
18
19 static void __live_active_retire(struct i915_active *base)
20 {
21         struct live_active *active = container_of(base, typeof(*active), base);
22
23         active->retired = true;
24 }
25
26 static int __live_active_setup(struct drm_i915_private *i915,
27                                struct live_active *active)
28 {
29         struct intel_engine_cs *engine;
30         struct i915_sw_fence *submit;
31         enum intel_engine_id id;
32         unsigned int count = 0;
33         int err = 0;
34
35         submit = heap_fence_create(GFP_KERNEL);
36         if (!submit)
37                 return -ENOMEM;
38
39         i915_active_init(i915, &active->base, __live_active_retire);
40         active->retired = false;
41
42         if (!i915_active_acquire(&active->base)) {
43                 pr_err("First i915_active_acquire should report being idle\n");
44                 err = -EINVAL;
45                 goto out;
46         }
47
48         for_each_engine(engine, i915, id) {
49                 struct i915_request *rq;
50
51                 rq = i915_request_create(engine->kernel_context);
52                 if (IS_ERR(rq)) {
53                         err = PTR_ERR(rq);
54                         break;
55                 }
56
57                 err = i915_sw_fence_await_sw_fence_gfp(&rq->submit,
58                                                        submit,
59                                                        GFP_KERNEL);
60                 if (err >= 0)
61                         err = i915_active_ref(&active->base,
62                                               rq->fence.context, rq);
63                 i915_request_add(rq);
64                 if (err) {
65                         pr_err("Failed to track active ref!\n");
66                         break;
67                 }
68
69                 count++;
70         }
71
72         i915_active_release(&active->base);
73         if (active->retired && count) {
74                 pr_err("i915_active retired before submission!\n");
75                 err = -EINVAL;
76         }
77         if (active->base.count != count) {
78                 pr_err("i915_active not tracking all requests, found %d, expected %d\n",
79                        active->base.count, count);
80                 err = -EINVAL;
81         }
82
83 out:
84         i915_sw_fence_commit(submit);
85         heap_fence_put(submit);
86
87         return err;
88 }
89
90 static int live_active_wait(void *arg)
91 {
92         struct drm_i915_private *i915 = arg;
93         struct live_active active;
94         intel_wakeref_t wakeref;
95         int err;
96
97         /* Check that we get a callback when requests retire upon waiting */
98
99         mutex_lock(&i915->drm.struct_mutex);
100         wakeref = intel_runtime_pm_get(i915);
101
102         err = __live_active_setup(i915, &active);
103
104         i915_active_wait(&active.base);
105         if (!active.retired) {
106                 pr_err("i915_active not retired after waiting!\n");
107                 err = -EINVAL;
108         }
109
110         i915_active_fini(&active.base);
111         if (igt_flush_test(i915, I915_WAIT_LOCKED))
112                 err = -EIO;
113
114         intel_runtime_pm_put(i915, wakeref);
115         mutex_unlock(&i915->drm.struct_mutex);
116         return err;
117 }
118
119 static int live_active_retire(void *arg)
120 {
121         struct drm_i915_private *i915 = arg;
122         struct live_active active;
123         intel_wakeref_t wakeref;
124         int err;
125
126         /* Check that we get a callback when requests are indirectly retired */
127
128         mutex_lock(&i915->drm.struct_mutex);
129         wakeref = intel_runtime_pm_get(i915);
130
131         err = __live_active_setup(i915, &active);
132
133         /* waits for & retires all requests */
134         if (igt_flush_test(i915, I915_WAIT_LOCKED))
135                 err = -EIO;
136
137         if (!active.retired) {
138                 pr_err("i915_active not retired after flushing!\n");
139                 err = -EINVAL;
140         }
141
142         i915_active_fini(&active.base);
143         intel_runtime_pm_put(i915, wakeref);
144         mutex_unlock(&i915->drm.struct_mutex);
145         return err;
146 }
147
148 int i915_active_live_selftests(struct drm_i915_private *i915)
149 {
150         static const struct i915_subtest tests[] = {
151                 SUBTEST(live_active_wait),
152                 SUBTEST(live_active_retire),
153         };
154
155         if (i915_terminally_wedged(i915))
156                 return 0;
157
158         return i915_subtests(tests, i915);
159 }