cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

selftest_gt_pm.c (4779B)


      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
     15static 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
     27static 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
     39static void measure_clocks(struct intel_engine_cs *engine,
     40			   u32 *out_cycles, ktime_t *out_dt)
     41{
     42	ktime_t dt[5];
     43	u32 cycles[5];
     44	int i;
     45
     46	for (i = 0; i < 5; i++) {
     47		local_irq_disable();
     48		cycles[i] = -ENGINE_READ_FW(engine, RING_TIMESTAMP);
     49		dt[i] = ktime_get();
     50
     51		udelay(1000);
     52
     53		dt[i] = ktime_sub(ktime_get(), dt[i]);
     54		cycles[i] += ENGINE_READ_FW(engine, RING_TIMESTAMP);
     55		local_irq_enable();
     56	}
     57
     58	/* Use the median of both cycle/dt; close enough */
     59	sort(cycles, 5, sizeof(*cycles), cmp_u32, NULL);
     60	*out_cycles = (cycles[1] + 2 * cycles[2] + cycles[3]) / 4;
     61
     62	sort(dt, 5, sizeof(*dt), cmp_u64, NULL);
     63	*out_dt = div_u64(dt[1] + 2 * dt[2] + dt[3], 4);
     64}
     65
     66static int live_gt_clocks(void *arg)
     67{
     68	struct intel_gt *gt = arg;
     69	struct intel_engine_cs *engine;
     70	enum intel_engine_id id;
     71	int err = 0;
     72
     73	if (!gt->clock_frequency) { /* unknown */
     74		pr_info("CS_TIMESTAMP frequency unknown\n");
     75		return 0;
     76	}
     77
     78	if (GRAPHICS_VER(gt->i915) < 4) /* Any CS_TIMESTAMP? */
     79		return 0;
     80
     81	if (GRAPHICS_VER(gt->i915) == 5)
     82		/*
     83		 * XXX CS_TIMESTAMP low dword is dysfunctional?
     84		 *
     85		 * Ville's experiments indicate the high dword still works,
     86		 * but at a correspondingly reduced frequency.
     87		 */
     88		return 0;
     89
     90	if (GRAPHICS_VER(gt->i915) == 4)
     91		/*
     92		 * XXX CS_TIMESTAMP appears gibberish
     93		 *
     94		 * Ville's experiments indicate that it mostly appears 'stuck'
     95		 * in that we see the register report the same cycle count
     96		 * for a couple of reads.
     97		 */
     98		return 0;
     99
    100	intel_gt_pm_get(gt);
    101	intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL);
    102
    103	for_each_engine(engine, gt, id) {
    104		u32 cycles;
    105		u32 expected;
    106		u64 time;
    107		u64 dt;
    108
    109		if (GRAPHICS_VER(engine->i915) < 7 && engine->id != RCS0)
    110			continue;
    111
    112		measure_clocks(engine, &cycles, &dt);
    113
    114		time = intel_gt_clock_interval_to_ns(engine->gt, cycles);
    115		expected = intel_gt_ns_to_clock_interval(engine->gt, dt);
    116
    117		pr_info("%s: TIMESTAMP %d cycles [%lldns] in %lldns [%d cycles], using CS clock frequency of %uKHz\n",
    118			engine->name, cycles, time, dt, expected,
    119			engine->gt->clock_frequency / 1000);
    120
    121		if (9 * time < 8 * dt || 8 * time > 9 * dt) {
    122			pr_err("%s: CS ticks did not match walltime!\n",
    123			       engine->name);
    124			err = -EINVAL;
    125			break;
    126		}
    127
    128		if (9 * expected < 8 * cycles || 8 * expected > 9 * cycles) {
    129			pr_err("%s: walltime did not match CS ticks!\n",
    130			       engine->name);
    131			err = -EINVAL;
    132			break;
    133		}
    134	}
    135
    136	intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL);
    137	intel_gt_pm_put(gt);
    138
    139	return err;
    140}
    141
    142static int live_gt_resume(void *arg)
    143{
    144	struct intel_gt *gt = arg;
    145	IGT_TIMEOUT(end_time);
    146	int err;
    147
    148	/* Do several suspend/resume cycles to check we don't explode! */
    149	do {
    150		intel_gt_suspend_prepare(gt);
    151		intel_gt_suspend_late(gt);
    152
    153		if (gt->rc6.enabled) {
    154			pr_err("rc6 still enabled after suspend!\n");
    155			intel_gt_set_wedged_on_init(gt);
    156			err = -EINVAL;
    157			break;
    158		}
    159
    160		err = intel_gt_resume(gt);
    161		if (err)
    162			break;
    163
    164		if (gt->rc6.supported && !gt->rc6.enabled) {
    165			pr_err("rc6 not enabled upon resume!\n");
    166			intel_gt_set_wedged_on_init(gt);
    167			err = -EINVAL;
    168			break;
    169		}
    170
    171		err = st_llc_verify(&gt->llc);
    172		if (err) {
    173			pr_err("llc state not restored upon resume!\n");
    174			intel_gt_set_wedged_on_init(gt);
    175			break;
    176		}
    177	} while (!__igt_timeout(end_time, NULL));
    178
    179	return err;
    180}
    181
    182int intel_gt_pm_live_selftests(struct drm_i915_private *i915)
    183{
    184	static const struct i915_subtest tests[] = {
    185		SUBTEST(live_gt_clocks),
    186		SUBTEST(live_rc6_manual),
    187		SUBTEST(live_rps_clock_interval),
    188		SUBTEST(live_rps_control),
    189		SUBTEST(live_rps_frequency_cs),
    190		SUBTEST(live_rps_frequency_srm),
    191		SUBTEST(live_rps_power),
    192		SUBTEST(live_rps_interrupt),
    193		SUBTEST(live_rps_dynamic),
    194		SUBTEST(live_gt_resume),
    195	};
    196
    197	if (intel_gt_is_wedged(to_gt(i915)))
    198		return 0;
    199
    200	return intel_gt_live_subtests(tests, to_gt(i915));
    201}
    202
    203int intel_gt_pm_late_selftests(struct drm_i915_private *i915)
    204{
    205	static const struct i915_subtest tests[] = {
    206		/*
    207		 * These tests may leave the system in an undesirable state.
    208		 * They are intended to be run last in CI and the system
    209		 * rebooted afterwards.
    210		 */
    211		SUBTEST(live_rc6_ctx_wa),
    212	};
    213
    214	if (intel_gt_is_wedged(to_gt(i915)))
    215		return 0;
    216
    217	return intel_gt_live_subtests(tests, to_gt(i915));
    218}