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 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 66 static 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 142 static 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(>->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 182 int 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 203 int 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 } 219