GNU Linux-libre 5.10.215-gnu1
[releases.git] / drivers / gpu / drm / i915 / gt / selftest_engine_pm.c
1 /*
2  * SPDX-License-Identifier: GPL-2.0
3  *
4  * Copyright © 2018 Intel Corporation
5  */
6
7 #include "i915_selftest.h"
8 #include "selftest_engine.h"
9 #include "selftest_engine_heartbeat.h"
10 #include "selftests/igt_atomic.h"
11 #include "selftests/igt_flush_test.h"
12 #include "selftests/igt_spinner.h"
13
14 static int live_engine_busy_stats(void *arg)
15 {
16         struct intel_gt *gt = arg;
17         struct intel_engine_cs *engine;
18         enum intel_engine_id id;
19         struct igt_spinner spin;
20         int err = 0;
21
22         /*
23          * Check that if an engine supports busy-stats, they tell the truth.
24          */
25
26         if (igt_spinner_init(&spin, gt))
27                 return -ENOMEM;
28
29         GEM_BUG_ON(intel_gt_pm_is_awake(gt));
30         for_each_engine(engine, gt, id) {
31                 struct i915_request *rq;
32                 ktime_t de, dt;
33                 ktime_t t[2];
34
35                 if (!intel_engine_supports_stats(engine))
36                         continue;
37
38                 if (!intel_engine_can_store_dword(engine))
39                         continue;
40
41                 if (intel_gt_pm_wait_for_idle(gt)) {
42                         err = -EBUSY;
43                         break;
44                 }
45
46                 st_engine_heartbeat_disable(engine);
47
48                 ENGINE_TRACE(engine, "measuring idle time\n");
49                 preempt_disable();
50                 de = intel_engine_get_busy_time(engine, &t[0]);
51                 udelay(100);
52                 de = ktime_sub(intel_engine_get_busy_time(engine, &t[1]), de);
53                 preempt_enable();
54                 dt = ktime_sub(t[1], t[0]);
55                 if (de < 0 || de > 10) {
56                         pr_err("%s: reported %lldns [%d%%] busyness while sleeping [for %lldns]\n",
57                                engine->name,
58                                de, (int)div64_u64(100 * de, dt), dt);
59                         GEM_TRACE_DUMP();
60                         err = -EINVAL;
61                         goto end;
62                 }
63
64                 /* 100% busy */
65                 rq = igt_spinner_create_request(&spin,
66                                                 engine->kernel_context,
67                                                 MI_NOOP);
68                 if (IS_ERR(rq)) {
69                         err = PTR_ERR(rq);
70                         goto end;
71                 }
72                 i915_request_add(rq);
73
74                 if (!igt_wait_for_spinner(&spin, rq)) {
75                         intel_gt_set_wedged(engine->gt);
76                         err = -ETIME;
77                         goto end;
78                 }
79
80                 ENGINE_TRACE(engine, "measuring busy time\n");
81                 preempt_disable();
82                 de = intel_engine_get_busy_time(engine, &t[0]);
83                 udelay(100);
84                 de = ktime_sub(intel_engine_get_busy_time(engine, &t[1]), de);
85                 preempt_enable();
86                 dt = ktime_sub(t[1], t[0]);
87                 if (100 * de < 95 * dt || 95 * de > 100 * dt) {
88                         pr_err("%s: reported %lldns [%d%%] busyness while spinning [for %lldns]\n",
89                                engine->name,
90                                de, (int)div64_u64(100 * de, dt), dt);
91                         GEM_TRACE_DUMP();
92                         err = -EINVAL;
93                         goto end;
94                 }
95
96 end:
97                 st_engine_heartbeat_enable(engine);
98                 igt_spinner_end(&spin);
99                 if (igt_flush_test(gt->i915))
100                         err = -EIO;
101                 if (err)
102                         break;
103         }
104
105         igt_spinner_fini(&spin);
106         if (igt_flush_test(gt->i915))
107                 err = -EIO;
108         return err;
109 }
110
111 static int live_engine_pm(void *arg)
112 {
113         struct intel_gt *gt = arg;
114         struct intel_engine_cs *engine;
115         enum intel_engine_id id;
116
117         /*
118          * Check we can call intel_engine_pm_put from any context. No
119          * failures are reported directly, but if we mess up lockdep should
120          * tell us.
121          */
122         if (intel_gt_pm_wait_for_idle(gt)) {
123                 pr_err("Unable to flush GT pm before test\n");
124                 return -EBUSY;
125         }
126
127         GEM_BUG_ON(intel_gt_pm_is_awake(gt));
128         for_each_engine(engine, gt, id) {
129                 const typeof(*igt_atomic_phases) *p;
130
131                 for (p = igt_atomic_phases; p->name; p++) {
132                         /*
133                          * Acquisition is always synchronous, except if we
134                          * know that the engine is already awake, in which
135                          * case we should use intel_engine_pm_get_if_awake()
136                          * to atomically grab the wakeref.
137                          *
138                          * In practice,
139                          *    intel_engine_pm_get();
140                          *    intel_engine_pm_put();
141                          * occurs in one thread, while simultaneously
142                          *    intel_engine_pm_get_if_awake();
143                          *    intel_engine_pm_put();
144                          * occurs from atomic context in another.
145                          */
146                         GEM_BUG_ON(intel_engine_pm_is_awake(engine));
147                         intel_engine_pm_get(engine);
148
149                         p->critical_section_begin();
150                         if (!intel_engine_pm_get_if_awake(engine))
151                                 pr_err("intel_engine_pm_get_if_awake(%s) failed under %s\n",
152                                        engine->name, p->name);
153                         else
154                                 intel_engine_pm_put_async(engine);
155                         intel_engine_pm_put_async(engine);
156                         p->critical_section_end();
157
158                         intel_engine_pm_flush(engine);
159
160                         if (intel_engine_pm_is_awake(engine)) {
161                                 pr_err("%s is still awake after flushing pm\n",
162                                        engine->name);
163                                 return -EINVAL;
164                         }
165
166                         /* gt wakeref is async (deferred to workqueue) */
167                         if (intel_gt_pm_wait_for_idle(gt)) {
168                                 pr_err("GT failed to idle\n");
169                                 return -EINVAL;
170                         }
171                 }
172         }
173
174         return 0;
175 }
176
177 int live_engine_pm_selftests(struct intel_gt *gt)
178 {
179         static const struct i915_subtest tests[] = {
180                 SUBTEST(live_engine_busy_stats),
181                 SUBTEST(live_engine_pm),
182         };
183
184         return intel_gt_live_subtests(tests, gt);
185 }