WIP FPC-III support
[linux/fpc-iii.git] / drivers / gpu / drm / i915 / gt / selftest_gt_pm.c
blob6180a47c1b5114850edd34a10c15e73f85330a40
2 /*
3 * SPDX-License-Identifier: MIT
5 * Copyright © 2019 Intel Corporation
6 */
8 #include <linux/sort.h>
10 #include "intel_gt_clock_utils.h"
12 #include "selftest_llc.h"
13 #include "selftest_rc6.h"
14 #include "selftest_rps.h"
16 static int cmp_u64(const void *A, const void *B)
18 const u64 *a = A, *b = B;
20 if (a < b)
21 return -1;
22 else if (a > b)
23 return 1;
24 else
25 return 0;
28 static int cmp_u32(const void *A, const void *B)
30 const u32 *a = A, *b = B;
32 if (a < b)
33 return -1;
34 else if (a > b)
35 return 1;
36 else
37 return 0;
40 static void measure_clocks(struct intel_engine_cs *engine,
41 u32 *out_cycles, ktime_t *out_dt)
43 ktime_t dt[5];
44 u32 cycles[5];
45 int i;
47 for (i = 0; i < 5; i++) {
48 preempt_disable();
49 cycles[i] = -ENGINE_READ_FW(engine, RING_TIMESTAMP);
50 dt[i] = ktime_get();
52 udelay(1000);
54 dt[i] = ktime_sub(ktime_get(), dt[i]);
55 cycles[i] += ENGINE_READ_FW(engine, RING_TIMESTAMP);
56 preempt_enable();
59 /* Use the median of both cycle/dt; close enough */
60 sort(cycles, 5, sizeof(*cycles), cmp_u32, NULL);
61 *out_cycles = (cycles[1] + 2 * cycles[2] + cycles[3]) / 4;
63 sort(dt, 5, sizeof(*dt), cmp_u64, NULL);
64 *out_dt = div_u64(dt[1] + 2 * dt[2] + dt[3], 4);
67 static int live_gt_clocks(void *arg)
69 struct intel_gt *gt = arg;
70 struct intel_engine_cs *engine;
71 enum intel_engine_id id;
72 int err = 0;
74 if (!RUNTIME_INFO(gt->i915)->cs_timestamp_frequency_hz) { /* unknown */
75 pr_info("CS_TIMESTAMP frequency unknown\n");
76 return 0;
79 if (INTEL_GEN(gt->i915) < 4) /* Any CS_TIMESTAMP? */
80 return 0;
82 if (IS_GEN(gt->i915, 5))
84 * XXX CS_TIMESTAMP low dword is dysfunctional?
86 * Ville's experiments indicate the high dword still works,
87 * but at a correspondingly reduced frequency.
89 return 0;
91 if (IS_GEN(gt->i915, 4))
93 * XXX CS_TIMESTAMP appears gibberish
95 * Ville's experiments indicate that it mostly appears 'stuck'
96 * in that we see the register report the same cycle count
97 * for a couple of reads.
99 return 0;
101 intel_gt_pm_get(gt);
102 intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL);
104 for_each_engine(engine, gt, id) {
105 u32 cycles;
106 u32 expected;
107 u64 time;
108 u64 dt;
110 if (INTEL_GEN(engine->i915) < 7 && engine->id != RCS0)
111 continue;
113 measure_clocks(engine, &cycles, &dt);
115 time = i915_cs_timestamp_ticks_to_ns(engine->i915, cycles);
116 expected = i915_cs_timestamp_ns_to_ticks(engine->i915, dt);
118 pr_info("%s: TIMESTAMP %d cycles [%lldns] in %lldns [%d cycles], using CS clock frequency of %uKHz\n",
119 engine->name, cycles, time, dt, expected,
120 RUNTIME_INFO(engine->i915)->cs_timestamp_frequency_hz / 1000);
122 if (9 * time < 8 * dt || 8 * time > 9 * dt) {
123 pr_err("%s: CS ticks did not match walltime!\n",
124 engine->name);
125 err = -EINVAL;
126 break;
129 if (9 * expected < 8 * cycles || 8 * expected > 9 * cycles) {
130 pr_err("%s: walltime did not match CS ticks!\n",
131 engine->name);
132 err = -EINVAL;
133 break;
137 intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL);
138 intel_gt_pm_put(gt);
140 return err;
143 static int live_gt_resume(void *arg)
145 struct intel_gt *gt = arg;
146 IGT_TIMEOUT(end_time);
147 int err;
149 /* Do several suspend/resume cycles to check we don't explode! */
150 do {
151 intel_gt_suspend_prepare(gt);
152 intel_gt_suspend_late(gt);
154 if (gt->rc6.enabled) {
155 pr_err("rc6 still enabled after suspend!\n");
156 intel_gt_set_wedged_on_init(gt);
157 err = -EINVAL;
158 break;
161 err = intel_gt_resume(gt);
162 if (err)
163 break;
165 if (gt->rc6.supported && !gt->rc6.enabled) {
166 pr_err("rc6 not enabled upon resume!\n");
167 intel_gt_set_wedged_on_init(gt);
168 err = -EINVAL;
169 break;
172 err = st_llc_verify(&gt->llc);
173 if (err) {
174 pr_err("llc state not restored upon resume!\n");
175 intel_gt_set_wedged_on_init(gt);
176 break;
178 } while (!__igt_timeout(end_time, NULL));
180 return err;
183 int intel_gt_pm_live_selftests(struct drm_i915_private *i915)
185 static const struct i915_subtest tests[] = {
186 SUBTEST(live_gt_clocks),
187 SUBTEST(live_rc6_manual),
188 SUBTEST(live_rps_clock_interval),
189 SUBTEST(live_rps_control),
190 SUBTEST(live_rps_frequency_cs),
191 SUBTEST(live_rps_frequency_srm),
192 SUBTEST(live_rps_power),
193 SUBTEST(live_rps_interrupt),
194 SUBTEST(live_rps_dynamic),
195 SUBTEST(live_gt_resume),
198 if (intel_gt_is_wedged(&i915->gt))
199 return 0;
201 return intel_gt_live_subtests(tests, &i915->gt);
204 int intel_gt_pm_late_selftests(struct drm_i915_private *i915)
206 static const struct i915_subtest tests[] = {
208 * These tests may leave the system in an undesirable state.
209 * They are intended to be run last in CI and the system
210 * rebooted afterwards.
212 SUBTEST(live_rc6_ctx_wa),
215 if (intel_gt_is_wedged(&i915->gt))
216 return 0;
218 return intel_gt_live_subtests(tests, &i915->gt);