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