Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  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
 14static 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
 26static 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
 38static 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
 65static 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
141static 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
181int 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
202int 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}