1 // SPDX-License-Identifier: MIT
3 * Copyright © 2020 Intel Corporation
6 #include <linux/sort.h>
8 #include "intel_engine_pm.h"
9 #include "intel_gt_pm.h"
10 #include "intel_rc6.h"
11 #include "selftest_rps.h"
12 #include "selftests/igt_flush_test.h"
13 #include "selftests/igt_spinner.h"
14 #include "selftests/librapl.h"
16 static void dummy_rps_work(struct work_struct *wrk)
20 static void sleep_for_ei(struct intel_rps *rps, int timeout_us)
22 /* Flush any previous EI */
23 usleep_range(timeout_us, 2 * timeout_us);
25 /* Reset the interrupt status */
26 rps_disable_interrupts(rps);
27 GEM_BUG_ON(rps->pm_iir);
28 rps_enable_interrupts(rps);
30 /* And then wait for the timeout, for real this time */
31 usleep_range(2 * timeout_us, 3 * timeout_us);
34 static int __rps_up_interrupt(struct intel_rps *rps,
35 struct intel_engine_cs *engine,
36 struct igt_spinner *spin)
38 struct intel_uncore *uncore = engine->uncore;
39 struct i915_request *rq;
42 if (!intel_engine_can_store_dword(engine))
45 mutex_lock(&rps->lock);
46 GEM_BUG_ON(!rps->active);
47 intel_rps_set(rps, rps->min_freq);
48 mutex_unlock(&rps->lock);
50 rq = igt_spinner_create_request(spin, engine->kernel_context, MI_NOOP);
57 if (!igt_wait_for_spinner(spin, rq)) {
58 pr_err("%s: RPS spinner did not start\n",
61 intel_gt_set_wedged(engine->gt);
66 pr_err("%s: RPS not enabled on starting spinner\n",
68 igt_spinner_end(spin);
73 if (!(rps->pm_events & GEN6_PM_RP_UP_THRESHOLD)) {
74 pr_err("%s: RPS did not register UP interrupt\n",
80 if (rps->last_freq != rps->min_freq) {
81 pr_err("%s: RPS did not program min frequency\n",
87 timeout = intel_uncore_read(uncore, GEN6_RP_UP_EI);
88 timeout = GT_PM_INTERVAL_TO_US(engine->i915, timeout);
90 sleep_for_ei(rps, timeout);
91 GEM_BUG_ON(i915_request_completed(rq));
93 igt_spinner_end(spin);
96 if (rps->cur_freq != rps->min_freq) {
97 pr_err("%s: Frequency unexpectedly changed [up], now %d!\n",
98 engine->name, intel_rps_read_actual_frequency(rps));
102 if (!(rps->pm_iir & GEN6_PM_RP_UP_THRESHOLD)) {
103 pr_err("%s: UP interrupt not recorded for spinner, pm_iir:%x, prev_up:%x, up_threshold:%x, up_ei:%x\n",
104 engine->name, rps->pm_iir,
105 intel_uncore_read(uncore, GEN6_RP_PREV_UP),
106 intel_uncore_read(uncore, GEN6_RP_UP_THRESHOLD),
107 intel_uncore_read(uncore, GEN6_RP_UP_EI));
114 static int __rps_down_interrupt(struct intel_rps *rps,
115 struct intel_engine_cs *engine)
117 struct intel_uncore *uncore = engine->uncore;
120 mutex_lock(&rps->lock);
121 GEM_BUG_ON(!rps->active);
122 intel_rps_set(rps, rps->max_freq);
123 mutex_unlock(&rps->lock);
125 if (!(rps->pm_events & GEN6_PM_RP_DOWN_THRESHOLD)) {
126 pr_err("%s: RPS did not register DOWN interrupt\n",
131 if (rps->last_freq != rps->max_freq) {
132 pr_err("%s: RPS did not program max frequency\n",
137 timeout = intel_uncore_read(uncore, GEN6_RP_DOWN_EI);
138 timeout = GT_PM_INTERVAL_TO_US(engine->i915, timeout);
140 sleep_for_ei(rps, timeout);
142 if (rps->cur_freq != rps->max_freq) {
143 pr_err("%s: Frequency unexpectedly changed [down], now %d!\n",
145 intel_rps_read_actual_frequency(rps));
149 if (!(rps->pm_iir & (GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT))) {
150 pr_err("%s: DOWN interrupt not recorded for idle, pm_iir:%x, prev_down:%x, down_threshold:%x, down_ei:%x [prev_up:%x, up_threshold:%x, up_ei:%x]\n",
151 engine->name, rps->pm_iir,
152 intel_uncore_read(uncore, GEN6_RP_PREV_DOWN),
153 intel_uncore_read(uncore, GEN6_RP_DOWN_THRESHOLD),
154 intel_uncore_read(uncore, GEN6_RP_DOWN_EI),
155 intel_uncore_read(uncore, GEN6_RP_PREV_UP),
156 intel_uncore_read(uncore, GEN6_RP_UP_THRESHOLD),
157 intel_uncore_read(uncore, GEN6_RP_UP_EI));
164 int live_rps_interrupt(void *arg)
166 struct intel_gt *gt = arg;
167 struct intel_rps *rps = >->rps;
168 void (*saved_work)(struct work_struct *wrk);
169 struct intel_engine_cs *engine;
170 enum intel_engine_id id;
171 struct igt_spinner spin;
176 * First, let's check whether or not we are receiving interrupts.
179 if (!rps->enabled || rps->max_freq <= rps->min_freq)
183 pm_events = rps->pm_events;
186 pr_err("No RPS PM events registered, but RPS is enabled?\n");
190 if (igt_spinner_init(&spin, gt))
193 intel_gt_pm_wait_for_idle(gt);
194 saved_work = rps->work.func;
195 rps->work.func = dummy_rps_work;
197 for_each_engine(engine, gt, id) {
198 /* Keep the engine busy with a spinner; expect an UP! */
199 if (pm_events & GEN6_PM_RP_UP_THRESHOLD) {
200 intel_gt_pm_wait_for_idle(engine->gt);
201 GEM_BUG_ON(rps->active);
203 intel_engine_pm_get(engine);
204 err = __rps_up_interrupt(rps, engine, &spin);
205 intel_engine_pm_put(engine);
209 intel_gt_pm_wait_for_idle(engine->gt);
212 /* Keep the engine awake but idle and check for DOWN */
213 if (pm_events & GEN6_PM_RP_DOWN_THRESHOLD) {
214 intel_engine_pm_get(engine);
215 intel_rc6_disable(>->rc6);
217 err = __rps_down_interrupt(rps, engine);
219 intel_rc6_enable(>->rc6);
220 intel_engine_pm_put(engine);
227 if (igt_flush_test(gt->i915))
230 igt_spinner_fini(&spin);
232 intel_gt_pm_wait_for_idle(gt);
233 rps->work.func = saved_work;
238 static u64 __measure_power(int duration_ms)
243 dE = librapl_energy_uJ();
244 usleep_range(1000 * duration_ms, 2000 * duration_ms);
245 dE = librapl_energy_uJ() - dE;
246 dt = ktime_get() - dt;
248 return div64_u64(1000 * 1000 * dE, dt);
251 static int cmp_u64(const void *A, const void *B)
253 const u64 *a = A, *b = B;
263 static u64 measure_power_at(struct intel_rps *rps, int freq)
268 mutex_lock(&rps->lock);
269 GEM_BUG_ON(!rps->active);
270 intel_rps_set(rps, freq);
271 mutex_unlock(&rps->lock);
273 msleep(20); /* more than enough time to stabilise! */
277 pr_notice("Running at %x [%uMHz], not target %x [%uMHz]\n",
278 i, intel_gpu_freq(rps, i),
279 freq, intel_gpu_freq(rps, freq));
281 for (i = 0; i < 5; i++)
282 x[i] = __measure_power(5);
284 /* A simple triangle filter for better result stability */
285 sort(x, 5, sizeof(*x), cmp_u64, NULL);
286 return div_u64(x[1] + 2 * x[2] + x[3], 4);
289 int live_rps_power(void *arg)
291 struct intel_gt *gt = arg;
292 struct intel_rps *rps = >->rps;
293 void (*saved_work)(struct work_struct *wrk);
294 struct intel_engine_cs *engine;
295 enum intel_engine_id id;
296 struct igt_spinner spin;
300 * Our fundamental assumption is that running at lower frequency
301 * actually saves power. Let's see if our RAPL measurement support
305 if (!rps->enabled || rps->max_freq <= rps->min_freq)
308 if (!librapl_energy_uJ())
311 if (igt_spinner_init(&spin, gt))
314 intel_gt_pm_wait_for_idle(gt);
315 saved_work = rps->work.func;
316 rps->work.func = dummy_rps_work;
318 for_each_engine(engine, gt, id) {
319 struct i915_request *rq;
322 if (!intel_engine_can_store_dword(engine))
325 rq = igt_spinner_create_request(&spin,
326 engine->kernel_context,
333 i915_request_add(rq);
335 if (!igt_wait_for_spinner(&spin, rq)) {
336 pr_err("%s: RPS spinner did not start\n",
338 intel_gt_set_wedged(engine->gt);
343 max = measure_power_at(rps, rps->max_freq);
344 min = measure_power_at(rps, rps->min_freq);
346 igt_spinner_end(&spin);
348 pr_info("%s: min:%llumW @ %uMHz, max:%llumW @ %uMHz\n",
350 min, intel_gpu_freq(rps, rps->min_freq),
351 max, intel_gpu_freq(rps, rps->max_freq));
352 if (11 * min > 10 * max) {
353 pr_err("%s: did not conserve power when setting lower frequency!\n",
359 if (igt_flush_test(gt->i915)) {
365 igt_spinner_fini(&spin);
367 intel_gt_pm_wait_for_idle(gt);
368 rps->work.func = saved_work;