2 * SPDX-License-Identifier: MIT
4 * Copyright © 2019 Intel Corporation
7 #include "intel_context.h"
8 #include "intel_engine_pm.h"
9 #include "intel_gt_requests.h"
10 #include "intel_ring.h"
11 #include "selftest_rc6.h"
13 #include "selftests/i915_random.h"
14 #include "selftests/librapl.h"
16 static u64
rc6_residency(struct intel_rc6
*rc6
)
20 /* XXX VLV_GT_MEDIA_RC6? */
22 result
= intel_rc6_residency_ns(rc6
, GEN6_GT_GFX_RC6
);
23 if (HAS_RC6p(rc6_to_i915(rc6
)))
24 result
+= intel_rc6_residency_ns(rc6
, GEN6_GT_GFX_RC6p
);
25 if (HAS_RC6pp(rc6_to_i915(rc6
)))
26 result
+= intel_rc6_residency_ns(rc6
, GEN6_GT_GFX_RC6pp
);
31 int live_rc6_manual(void *arg
)
33 struct intel_gt
*gt
= arg
;
34 struct intel_rc6
*rc6
= >
->rc6
;
35 u64 rc0_power
, rc6_power
;
36 intel_wakeref_t wakeref
;
42 * Our claim is that we can "encourage" the GPU to enter rc6 at will.
49 /* bsw/byt use a PCU and decouple RC6 from our manual control */
50 if (IS_VALLEYVIEW(gt
->i915
) || IS_CHERRYVIEW(gt
->i915
))
53 wakeref
= intel_runtime_pm_get(gt
->uncore
->rpm
);
55 /* Force RC6 off for starters */
56 __intel_rc6_disable(rc6
);
57 msleep(1); /* wakeup is not immediate, takes about 100us on icl */
59 res
[0] = rc6_residency(rc6
);
62 rc0_power
= librapl_energy_uJ();
64 rc0_power
= librapl_energy_uJ() - rc0_power
;
65 dt
= ktime_sub(ktime_get(), dt
);
66 res
[1] = rc6_residency(rc6
);
67 if ((res
[1] - res
[0]) >> 10) {
68 pr_err("RC6 residency increased by %lldus while disabled for 250ms!\n",
69 (res
[1] - res
[0]) >> 10);
74 rc0_power
= div64_u64(NSEC_PER_SEC
* rc0_power
, ktime_to_ns(dt
));
76 pr_err("No power measured while in RC0\n");
81 /* Manually enter RC6 */
84 res
[0] = rc6_residency(rc6
);
85 intel_uncore_forcewake_flush(rc6_to_uncore(rc6
), FORCEWAKE_ALL
);
87 rc6_power
= librapl_energy_uJ();
89 rc6_power
= librapl_energy_uJ() - rc6_power
;
90 dt
= ktime_sub(ktime_get(), dt
);
91 res
[1] = rc6_residency(rc6
);
92 if (res
[1] == res
[0]) {
93 pr_err("Did not enter RC6! RC6_STATE=%08x, RC6_CONTROL=%08x, residency=%lld\n",
94 intel_uncore_read_fw(gt
->uncore
, GEN6_RC_STATE
),
95 intel_uncore_read_fw(gt
->uncore
, GEN6_RC_CONTROL
),
100 rc6_power
= div64_u64(NSEC_PER_SEC
* rc6_power
, ktime_to_ns(dt
));
101 pr_info("GPU consumed %llduW in RC0 and %llduW in RC6\n",
102 rc0_power
, rc6_power
);
103 if (2 * rc6_power
> rc0_power
) {
104 pr_err("GPU leaked energy while in RC6!\n");
109 /* Restore what should have been the original state! */
110 intel_rc6_unpark(rc6
);
113 intel_runtime_pm_put(gt
->uncore
->rpm
, wakeref
);
117 static const u32
*__live_rc6_ctx(struct intel_context
*ce
)
119 struct i915_request
*rq
;
124 rq
= intel_context_create_request(ce
);
128 cs
= intel_ring_begin(rq
, 4);
130 i915_request_add(rq
);
134 cmd
= MI_STORE_REGISTER_MEM
| MI_USE_GGTT
;
135 if (INTEL_GEN(rq
->engine
->i915
) >= 8)
139 *cs
++ = i915_mmio_reg_offset(GEN8_RC6_CTX_INFO
);
140 *cs
++ = ce
->timeline
->hwsp_offset
+ 8;
142 intel_ring_advance(rq
, cs
);
144 result
= rq
->hwsp_seqno
+ 2;
145 i915_request_add(rq
);
150 static struct intel_engine_cs
**
151 randomised_engines(struct intel_gt
*gt
,
152 struct rnd_state
*prng
,
155 struct intel_engine_cs
*engine
, **engines
;
156 enum intel_engine_id id
;
160 for_each_engine(engine
, gt
, id
)
165 engines
= kmalloc_array(n
, sizeof(*engines
), GFP_KERNEL
);
170 for_each_engine(engine
, gt
, id
)
171 engines
[n
++] = engine
;
173 i915_prandom_shuffle(engines
, sizeof(*engines
), n
, prng
);
179 int live_rc6_ctx_wa(void *arg
)
181 struct intel_gt
*gt
= arg
;
182 struct intel_engine_cs
**engines
;
183 unsigned int n
, count
;
184 I915_RND_STATE(prng
);
187 /* A read of CTX_INFO upsets rc6. Poke the bear! */
188 if (INTEL_GEN(gt
->i915
) < 8)
191 engines
= randomised_engines(gt
, &prng
, &count
);
195 for (n
= 0; n
< count
; n
++) {
196 struct intel_engine_cs
*engine
= engines
[n
];
199 for (pass
= 0; pass
< 2; pass
++) {
200 struct i915_gpu_error
*error
= >
->i915
->gpu_error
;
201 struct intel_context
*ce
;
202 unsigned int resets
=
203 i915_reset_engine_count(error
, engine
);
206 /* Use a sacrifical context */
207 ce
= intel_context_create(engine
);
213 intel_engine_pm_get(engine
);
214 res
= __live_rc6_ctx(ce
);
215 intel_engine_pm_put(engine
);
216 intel_context_put(ce
);
222 if (intel_gt_wait_for_idle(gt
, HZ
/ 5) == -ETIME
) {
223 intel_gt_set_wedged(gt
);
228 intel_gt_pm_wait_for_idle(gt
);
229 pr_debug("%s: CTX_INFO=%0x\n",
230 engine
->name
, READ_ONCE(*res
));
233 i915_reset_engine_count(error
, engine
)) {
234 pr_err("%s: GPU reset required\n",
236 add_taint_for_CI(gt
->i915
, TAINT_WARN
);