xref: /openbsd/sys/dev/pci/drm/i915/gt/selftest_gt_pm.c (revision f005ef32)
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(&gt->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