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