Linux-libre 5.4.48-gnu
[librecmc/linux-libre.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 <linux/kref.h>
8
9 #include "gem/i915_gem_pm.h"
10 #include "gt/intel_gt.h"
11
12 #include "i915_selftest.h"
13
14 #include "igt_flush_test.h"
15 #include "lib_sw_fence.h"
16
17 struct live_active {
18         struct i915_active base;
19         struct kref ref;
20         bool retired;
21 };
22
23 static void __live_get(struct live_active *active)
24 {
25         kref_get(&active->ref);
26 }
27
28 static void __live_free(struct live_active *active)
29 {
30         i915_active_fini(&active->base);
31         kfree(active);
32 }
33
34 static void __live_release(struct kref *ref)
35 {
36         struct live_active *active = container_of(ref, typeof(*active), ref);
37
38         __live_free(active);
39 }
40
41 static void __live_put(struct live_active *active)
42 {
43         kref_put(&active->ref, __live_release);
44 }
45
46 static int __live_active(struct i915_active *base)
47 {
48         struct live_active *active = container_of(base, typeof(*active), base);
49
50         __live_get(active);
51         return 0;
52 }
53
54 static void __live_retire(struct i915_active *base)
55 {
56         struct live_active *active = container_of(base, typeof(*active), base);
57
58         active->retired = true;
59         __live_put(active);
60 }
61
62 static struct live_active *__live_alloc(struct drm_i915_private *i915)
63 {
64         struct live_active *active;
65
66         active = kzalloc(sizeof(*active), GFP_KERNEL);
67         if (!active)
68                 return NULL;
69
70         kref_init(&active->ref);
71         i915_active_init(i915, &active->base, __live_active, __live_retire);
72
73         return active;
74 }
75
76 static struct live_active *
77 __live_active_setup(struct drm_i915_private *i915)
78 {
79         struct intel_engine_cs *engine;
80         struct i915_sw_fence *submit;
81         struct live_active *active;
82         enum intel_engine_id id;
83         unsigned int count = 0;
84         int err = 0;
85
86         active = __live_alloc(i915);
87         if (!active)
88                 return ERR_PTR(-ENOMEM);
89
90         submit = heap_fence_create(GFP_KERNEL);
91         if (!submit) {
92                 kfree(active);
93                 return ERR_PTR(-ENOMEM);
94         }
95
96         err = i915_active_acquire(&active->base);
97         if (err)
98                 goto out;
99
100         for_each_engine(engine, i915, id) {
101                 struct i915_request *rq;
102
103                 rq = i915_request_create(engine->kernel_context);
104                 if (IS_ERR(rq)) {
105                         err = PTR_ERR(rq);
106                         break;
107                 }
108
109                 err = i915_sw_fence_await_sw_fence_gfp(&rq->submit,
110                                                        submit,
111                                                        GFP_KERNEL);
112                 if (err >= 0)
113                         err = i915_active_ref(&active->base, rq->timeline, rq);
114                 i915_request_add(rq);
115                 if (err) {
116                         pr_err("Failed to track active ref!\n");
117                         break;
118                 }
119
120                 count++;
121         }
122
123         i915_active_release(&active->base);
124         if (active->retired && count) {
125                 pr_err("i915_active retired before submission!\n");
126                 err = -EINVAL;
127         }
128         if (atomic_read(&active->base.count) != count) {
129                 pr_err("i915_active not tracking all requests, found %d, expected %d\n",
130                        atomic_read(&active->base.count), count);
131                 err = -EINVAL;
132         }
133
134 out:
135         i915_sw_fence_commit(submit);
136         heap_fence_put(submit);
137         if (err) {
138                 __live_put(active);
139                 active = ERR_PTR(err);
140         }
141
142         return active;
143 }
144
145 static int live_active_wait(void *arg)
146 {
147         struct drm_i915_private *i915 = arg;
148         struct live_active *active;
149         intel_wakeref_t wakeref;
150         int err = 0;
151
152         /* Check that we get a callback when requests retire upon waiting */
153
154         mutex_lock(&i915->drm.struct_mutex);
155         wakeref = intel_runtime_pm_get(&i915->runtime_pm);
156
157         active = __live_active_setup(i915);
158         if (IS_ERR(active)) {
159                 err = PTR_ERR(active);
160                 goto err;
161         }
162
163         i915_active_wait(&active->base);
164         if (!active->retired) {
165                 pr_err("i915_active not retired after waiting!\n");
166                 err = -EINVAL;
167         }
168
169         __live_put(active);
170
171         if (igt_flush_test(i915, I915_WAIT_LOCKED))
172                 err = -EIO;
173
174 err:
175         intel_runtime_pm_put(&i915->runtime_pm, wakeref);
176         mutex_unlock(&i915->drm.struct_mutex);
177
178         return err;
179 }
180
181 static int live_active_retire(void *arg)
182 {
183         struct drm_i915_private *i915 = arg;
184         struct live_active *active;
185         intel_wakeref_t wakeref;
186         int err = 0;
187
188         /* Check that we get a callback when requests are indirectly retired */
189
190         mutex_lock(&i915->drm.struct_mutex);
191         wakeref = intel_runtime_pm_get(&i915->runtime_pm);
192
193         active = __live_active_setup(i915);
194         if (IS_ERR(active)) {
195                 err = PTR_ERR(active);
196                 goto err;
197         }
198
199         /* waits for & retires all requests */
200         if (igt_flush_test(i915, I915_WAIT_LOCKED))
201                 err = -EIO;
202
203         if (!active->retired) {
204                 pr_err("i915_active not retired after flushing!\n");
205                 err = -EINVAL;
206         }
207
208         __live_put(active);
209
210 err:
211         intel_runtime_pm_put(&i915->runtime_pm, wakeref);
212         mutex_unlock(&i915->drm.struct_mutex);
213
214         return err;
215 }
216
217 int i915_active_live_selftests(struct drm_i915_private *i915)
218 {
219         static const struct i915_subtest tests[] = {
220                 SUBTEST(live_active_wait),
221                 SUBTEST(live_active_retire),
222         };
223
224         if (intel_gt_is_wedged(&i915->gt))
225                 return 0;
226
227         return i915_subtests(tests, i915);
228 }