]> Git Repo - linux.git/blob - drivers/gpu/drm/i915/gt/selftest_gt_pm.c
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[linux.git] / drivers / gpu / drm / i915 / gt / selftest_gt_pm.c
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2019 Intel Corporation
4  */
5
6 #include <linux/sort.h>
7
8 #include "intel_gt_clock_utils.h"
9
10 #include "selftest_llc.h"
11 #include "selftest_rc6.h"
12 #include "selftest_rps.h"
13
14 static int cmp_u64(const void *A, const void *B)
15 {
16         const u64 *a = A, *b = B;
17
18         if (a < b)
19                 return -1;
20         else if (a > b)
21                 return 1;
22         else
23                 return 0;
24 }
25
26 static int cmp_u32(const void *A, const void *B)
27 {
28         const u32 *a = A, *b = B;
29
30         if (a < b)
31                 return -1;
32         else if (a > b)
33                 return 1;
34         else
35                 return 0;
36 }
37
38 static void measure_clocks(struct intel_engine_cs *engine,
39                            u32 *out_cycles, ktime_t *out_dt)
40 {
41         ktime_t dt[5];
42         u32 cycles[5];
43         int i;
44
45         for (i = 0; i < 5; i++) {
46                 preempt_disable();
47                 cycles[i] = -ENGINE_READ_FW(engine, RING_TIMESTAMP);
48                 dt[i] = ktime_get();
49
50                 udelay(1000);
51
52                 dt[i] = ktime_sub(ktime_get(), dt[i]);
53                 cycles[i] += ENGINE_READ_FW(engine, RING_TIMESTAMP);
54                 preempt_enable();
55         }
56
57         /* Use the median of both cycle/dt; close enough */
58         sort(cycles, 5, sizeof(*cycles), cmp_u32, NULL);
59         *out_cycles = (cycles[1] + 2 * cycles[2] + cycles[3]) / 4;
60
61         sort(dt, 5, sizeof(*dt), cmp_u64, NULL);
62         *out_dt = div_u64(dt[1] + 2 * dt[2] + dt[3], 4);
63 }
64
65 static int live_gt_clocks(void *arg)
66 {
67         struct intel_gt *gt = arg;
68         struct intel_engine_cs *engine;
69         enum intel_engine_id id;
70         int err = 0;
71
72         if (!gt->clock_frequency) { /* unknown */
73                 pr_info("CS_TIMESTAMP frequency unknown\n");
74                 return 0;
75         }
76
77         if (GRAPHICS_VER(gt->i915) < 4) /* Any CS_TIMESTAMP? */
78                 return 0;
79
80         if (GRAPHICS_VER(gt->i915) == 5)
81                 /*
82                  * XXX CS_TIMESTAMP low dword is dysfunctional?
83                  *
84                  * Ville's experiments indicate the high dword still works,
85                  * but at a correspondingly reduced frequency.
86                  */
87                 return 0;
88
89         if (GRAPHICS_VER(gt->i915) == 4)
90                 /*
91                  * XXX CS_TIMESTAMP appears gibberish
92                  *
93                  * Ville's experiments indicate that it mostly appears 'stuck'
94                  * in that we see the register report the same cycle count
95                  * for a couple of reads.
96                  */
97                 return 0;
98
99         intel_gt_pm_get(gt);
100         intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL);
101
102         for_each_engine(engine, gt, id) {
103                 u32 cycles;
104                 u32 expected;
105                 u64 time;
106                 u64 dt;
107
108                 if (GRAPHICS_VER(engine->i915) < 7 && engine->id != RCS0)
109                         continue;
110
111                 measure_clocks(engine, &cycles, &dt);
112
113                 time = intel_gt_clock_interval_to_ns(engine->gt, cycles);
114                 expected = intel_gt_ns_to_clock_interval(engine->gt, dt);
115
116                 pr_info("%s: TIMESTAMP %d cycles [%lldns] in %lldns [%d cycles], using CS clock frequency of %uKHz\n",
117                         engine->name, cycles, time, dt, expected,
118                         engine->gt->clock_frequency / 1000);
119
120                 if (9 * time < 8 * dt || 8 * time > 9 * dt) {
121                         pr_err("%s: CS ticks did not match walltime!\n",
122                                engine->name);
123                         err = -EINVAL;
124                         break;
125                 }
126
127                 if (9 * expected < 8 * cycles || 8 * expected > 9 * cycles) {
128                         pr_err("%s: walltime did not match CS ticks!\n",
129                                engine->name);
130                         err = -EINVAL;
131                         break;
132                 }
133         }
134
135         intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL);
136         intel_gt_pm_put(gt);
137
138         return err;
139 }
140
141 static int live_gt_resume(void *arg)
142 {
143         struct intel_gt *gt = arg;
144         IGT_TIMEOUT(end_time);
145         int err;
146
147         /* Do several suspend/resume cycles to check we don't explode! */
148         do {
149                 intel_gt_suspend_prepare(gt);
150                 intel_gt_suspend_late(gt);
151
152                 if (gt->rc6.enabled) {
153                         pr_err("rc6 still enabled after suspend!\n");
154                         intel_gt_set_wedged_on_init(gt);
155                         err = -EINVAL;
156                         break;
157                 }
158
159                 err = intel_gt_resume(gt);
160                 if (err)
161                         break;
162
163                 if (gt->rc6.supported && !gt->rc6.enabled) {
164                         pr_err("rc6 not enabled upon resume!\n");
165                         intel_gt_set_wedged_on_init(gt);
166                         err = -EINVAL;
167                         break;
168                 }
169
170                 err = st_llc_verify(&gt->llc);
171                 if (err) {
172                         pr_err("llc state not restored upon resume!\n");
173                         intel_gt_set_wedged_on_init(gt);
174                         break;
175                 }
176         } while (!__igt_timeout(end_time, NULL));
177
178         return err;
179 }
180
181 int intel_gt_pm_live_selftests(struct drm_i915_private *i915)
182 {
183         static const struct i915_subtest tests[] = {
184                 SUBTEST(live_gt_clocks),
185                 SUBTEST(live_rc6_manual),
186                 SUBTEST(live_rps_clock_interval),
187                 SUBTEST(live_rps_control),
188                 SUBTEST(live_rps_frequency_cs),
189                 SUBTEST(live_rps_frequency_srm),
190                 SUBTEST(live_rps_power),
191                 SUBTEST(live_rps_interrupt),
192                 SUBTEST(live_rps_dynamic),
193                 SUBTEST(live_gt_resume),
194         };
195
196         if (intel_gt_is_wedged(&i915->gt))
197                 return 0;
198
199         return intel_gt_live_subtests(tests, &i915->gt);
200 }
201
202 int intel_gt_pm_late_selftests(struct drm_i915_private *i915)
203 {
204         static const struct i915_subtest tests[] = {
205                 /*
206                  * These tests may leave the system in an undesirable state.
207                  * They are intended to be run last in CI and the system
208                  * rebooted afterwards.
209                  */
210                 SUBTEST(live_rc6_ctx_wa),
211         };
212
213         if (intel_gt_is_wedged(&i915->gt))
214                 return 0;
215
216         return intel_gt_live_subtests(tests, &i915->gt);
217 }
This page took 0.048603 seconds and 4 git commands to generate.