xref: /openbsd-src/sys/dev/pci/drm/i915/gt/intel_gt_pm.c (revision fc405d53b73a2d73393cb97f684863d17b583e38)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2019 Intel Corporation
4  */
5 
6 #include <linux/string_helpers.h>
7 #include <linux/suspend.h>
8 
9 #include "i915_drv.h"
10 #include "i915_params.h"
11 #include "intel_context.h"
12 #include "intel_engine_pm.h"
13 #include "intel_gt.h"
14 #include "intel_gt_clock_utils.h"
15 #include "intel_gt_pm.h"
16 #include "intel_gt_requests.h"
17 #include "intel_llc.h"
18 #include "intel_pm.h"
19 #include "intel_rc6.h"
20 #include "intel_rps.h"
21 #include "intel_wakeref.h"
22 #include "pxp/intel_pxp_pm.h"
23 
24 #define I915_GT_SUSPEND_IDLE_TIMEOUT (HZ / 2)
25 
26 static void user_forcewake(struct intel_gt *gt, bool suspend)
27 {
28 	int count = atomic_read(&gt->user_wakeref);
29 
30 	/* Inside suspend/resume so single threaded, no races to worry about. */
31 	if (likely(!count))
32 		return;
33 
34 	intel_gt_pm_get(gt);
35 	if (suspend) {
36 		GEM_BUG_ON(count > atomic_read(&gt->wakeref.count));
37 		atomic_sub(count, &gt->wakeref.count);
38 	} else {
39 		atomic_add(count, &gt->wakeref.count);
40 	}
41 	intel_gt_pm_put(gt);
42 }
43 
44 static void runtime_begin(struct intel_gt *gt)
45 {
46 	local_irq_disable();
47 #ifdef notyet
48 	write_seqcount_begin(&gt->stats.lock);
49 #else
50 	write_seqcount_begin((seqcount_t *)&gt->stats.lock);
51 #endif
52 	gt->stats.start = ktime_get();
53 	gt->stats.active = true;
54 #ifdef notyet
55 	write_seqcount_end(&gt->stats.lock);
56 #else
57 	write_seqcount_end((seqcount_t *)&gt->stats.lock);
58 #endif
59 	local_irq_enable();
60 }
61 
62 static void runtime_end(struct intel_gt *gt)
63 {
64 	local_irq_disable();
65 #ifdef notyet
66 	write_seqcount_begin(&gt->stats.lock);
67 #else
68 	write_seqcount_begin((seqcount_t *)&gt->stats.lock);
69 #endif
70 	gt->stats.active = false;
71 	gt->stats.total =
72 		ktime_add(gt->stats.total,
73 			  ktime_sub(ktime_get(), gt->stats.start));
74 #ifdef notyet
75 	write_seqcount_end(&gt->stats.lock);
76 #else
77 	write_seqcount_end((seqcount_t *)&gt->stats.lock);
78 #endif
79 	local_irq_enable();
80 }
81 
82 static int __gt_unpark(struct intel_wakeref *wf)
83 {
84 	struct intel_gt *gt = container_of(wf, typeof(*gt), wakeref);
85 	struct drm_i915_private *i915 = gt->i915;
86 
87 	GT_TRACE(gt, "\n");
88 
89 	/*
90 	 * It seems that the DMC likes to transition between the DC states a lot
91 	 * when there are no connected displays (no active power domains) during
92 	 * command submission.
93 	 *
94 	 * This activity has negative impact on the performance of the chip with
95 	 * huge latencies observed in the interrupt handler and elsewhere.
96 	 *
97 	 * Work around it by grabbing a GT IRQ power domain whilst there is any
98 	 * GT activity, preventing any DC state transitions.
99 	 */
100 	gt->awake = intel_display_power_get(i915, POWER_DOMAIN_GT_IRQ);
101 	GEM_BUG_ON(!gt->awake);
102 
103 	intel_rc6_unpark(&gt->rc6);
104 	intel_rps_unpark(&gt->rps);
105 	i915_pmu_gt_unparked(i915);
106 	intel_guc_busyness_unpark(gt);
107 
108 	intel_gt_unpark_requests(gt);
109 	runtime_begin(gt);
110 
111 	return 0;
112 }
113 
114 static int __gt_park(struct intel_wakeref *wf)
115 {
116 	struct intel_gt *gt = container_of(wf, typeof(*gt), wakeref);
117 	intel_wakeref_t wakeref = fetch_and_zero(&gt->awake);
118 	struct drm_i915_private *i915 = gt->i915;
119 
120 	GT_TRACE(gt, "\n");
121 
122 	runtime_end(gt);
123 	intel_gt_park_requests(gt);
124 
125 	intel_guc_busyness_park(gt);
126 	i915_vma_parked(gt);
127 	i915_pmu_gt_parked(i915);
128 	intel_rps_park(&gt->rps);
129 	intel_rc6_park(&gt->rc6);
130 
131 	/* Everything switched off, flush any residual interrupt just in case */
132 	intel_synchronize_irq(i915);
133 
134 	/* Defer dropping the display power well for 100ms, it's slow! */
135 	GEM_BUG_ON(!wakeref);
136 	intel_display_power_put_async(i915, POWER_DOMAIN_GT_IRQ, wakeref);
137 
138 	return 0;
139 }
140 
141 static const struct intel_wakeref_ops wf_ops = {
142 	.get = __gt_unpark,
143 	.put = __gt_park,
144 };
145 
146 void intel_gt_pm_init_early(struct intel_gt *gt)
147 {
148 	/*
149 	 * We access the runtime_pm structure via gt->i915 here rather than
150 	 * gt->uncore as we do elsewhere in the file because gt->uncore is not
151 	 * yet initialized for all tiles at this point in the driver startup.
152 	 * runtime_pm is per-device rather than per-tile, so this is still the
153 	 * correct structure.
154 	 */
155 	intel_wakeref_init(&gt->wakeref, &gt->i915->runtime_pm, &wf_ops);
156 	seqcount_mutex_init(&gt->stats.lock, &gt->wakeref.mutex);
157 }
158 
159 void intel_gt_pm_init(struct intel_gt *gt)
160 {
161 	/*
162 	 * Enabling power-management should be "self-healing". If we cannot
163 	 * enable a feature, simply leave it disabled with a notice to the
164 	 * user.
165 	 */
166 	intel_rc6_init(&gt->rc6);
167 	intel_rps_init(&gt->rps);
168 }
169 
170 static bool reset_engines(struct intel_gt *gt)
171 {
172 	if (INTEL_INFO(gt->i915)->gpu_reset_clobbers_display)
173 		return false;
174 
175 	return __intel_gt_reset(gt, ALL_ENGINES) == 0;
176 }
177 
178 static void gt_sanitize(struct intel_gt *gt, bool force)
179 {
180 	struct intel_engine_cs *engine;
181 	enum intel_engine_id id;
182 	intel_wakeref_t wakeref;
183 
184 	GT_TRACE(gt, "force:%s", str_yes_no(force));
185 
186 	/* Use a raw wakeref to avoid calling intel_display_power_get early */
187 	wakeref = intel_runtime_pm_get(gt->uncore->rpm);
188 	intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL);
189 
190 	intel_gt_check_clock_frequency(gt);
191 
192 	/*
193 	 * As we have just resumed the machine and woken the device up from
194 	 * deep PCI sleep (presumably D3_cold), assume the HW has been reset
195 	 * back to defaults, recovering from whatever wedged state we left it
196 	 * in and so worth trying to use the device once more.
197 	 */
198 	if (intel_gt_is_wedged(gt))
199 		intel_gt_unset_wedged(gt);
200 
201 	/* For GuC mode, ensure submission is disabled before stopping ring */
202 	intel_uc_reset_prepare(&gt->uc);
203 
204 	for_each_engine(engine, gt, id) {
205 		if (engine->reset.prepare)
206 			engine->reset.prepare(engine);
207 
208 		if (engine->sanitize)
209 			engine->sanitize(engine);
210 	}
211 
212 	if (reset_engines(gt) || force) {
213 		for_each_engine(engine, gt, id)
214 			__intel_engine_reset(engine, false);
215 	}
216 
217 	intel_uc_reset(&gt->uc, false);
218 
219 	for_each_engine(engine, gt, id)
220 		if (engine->reset.finish)
221 			engine->reset.finish(engine);
222 
223 	intel_rps_sanitize(&gt->rps);
224 
225 	intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL);
226 	intel_runtime_pm_put(gt->uncore->rpm, wakeref);
227 }
228 
229 void intel_gt_pm_fini(struct intel_gt *gt)
230 {
231 	intel_rc6_fini(&gt->rc6);
232 }
233 
234 int intel_gt_resume(struct intel_gt *gt)
235 {
236 	struct intel_engine_cs *engine;
237 	enum intel_engine_id id;
238 	int err;
239 
240 	err = intel_gt_has_unrecoverable_error(gt);
241 	if (err)
242 		return err;
243 
244 	GT_TRACE(gt, "\n");
245 
246 	/*
247 	 * After resume, we may need to poke into the pinned kernel
248 	 * contexts to paper over any damage caused by the sudden suspend.
249 	 * Only the kernel contexts should remain pinned over suspend,
250 	 * allowing us to fixup the user contexts on their first pin.
251 	 */
252 	gt_sanitize(gt, true);
253 
254 	intel_gt_pm_get(gt);
255 
256 	intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL);
257 	intel_rc6_sanitize(&gt->rc6);
258 	if (intel_gt_is_wedged(gt)) {
259 		err = -EIO;
260 		goto out_fw;
261 	}
262 
263 	/* Only when the HW is re-initialised, can we replay the requests */
264 	err = intel_gt_init_hw(gt);
265 	if (err) {
266 		i915_probe_error(gt->i915,
267 				 "Failed to initialize GPU, declaring it wedged!\n");
268 		goto err_wedged;
269 	}
270 
271 	intel_uc_reset_finish(&gt->uc);
272 
273 	intel_rps_enable(&gt->rps);
274 	intel_llc_enable(&gt->llc);
275 
276 	for_each_engine(engine, gt, id) {
277 		intel_engine_pm_get(engine);
278 
279 		engine->serial++; /* kernel context lost */
280 		err = intel_engine_resume(engine);
281 
282 		intel_engine_pm_put(engine);
283 		if (err) {
284 			drm_err(&gt->i915->drm,
285 				"Failed to restart %s (%d)\n",
286 				engine->name, err);
287 			goto err_wedged;
288 		}
289 	}
290 
291 	intel_rc6_enable(&gt->rc6);
292 
293 	intel_uc_resume(&gt->uc);
294 
295 	intel_pxp_resume(&gt->pxp);
296 
297 	user_forcewake(gt, false);
298 
299 out_fw:
300 	intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL);
301 	intel_gt_pm_put(gt);
302 	return err;
303 
304 err_wedged:
305 	intel_gt_set_wedged(gt);
306 	goto out_fw;
307 }
308 
309 static void wait_for_suspend(struct intel_gt *gt)
310 {
311 	if (!intel_gt_pm_is_awake(gt))
312 		return;
313 
314 	if (intel_gt_wait_for_idle(gt, I915_GT_SUSPEND_IDLE_TIMEOUT) == -ETIME) {
315 		/*
316 		 * Forcibly cancel outstanding work and leave
317 		 * the gpu quiet.
318 		 */
319 		intel_gt_set_wedged(gt);
320 		intel_gt_retire_requests(gt);
321 	}
322 
323 	intel_gt_pm_wait_for_idle(gt);
324 }
325 
326 void intel_gt_suspend_prepare(struct intel_gt *gt)
327 {
328 	user_forcewake(gt, true);
329 	wait_for_suspend(gt);
330 
331 	intel_pxp_suspend_prepare(&gt->pxp);
332 }
333 
334 #ifdef notyet
335 static suspend_state_t pm_suspend_target(void)
336 {
337 #if IS_ENABLED(CONFIG_SUSPEND) && IS_ENABLED(CONFIG_PM_SLEEP)
338 	return pm_suspend_target_state;
339 #else
340 	return PM_SUSPEND_TO_IDLE;
341 #endif
342 }
343 #endif
344 
345 void intel_gt_suspend_late(struct intel_gt *gt)
346 {
347 	intel_wakeref_t wakeref;
348 
349 	/* We expect to be idle already; but also want to be independent */
350 	wait_for_suspend(gt);
351 
352 	if (is_mock_gt(gt))
353 		return;
354 
355 	GEM_BUG_ON(gt->awake);
356 
357 	intel_uc_suspend(&gt->uc);
358 	intel_pxp_suspend(&gt->pxp);
359 
360 	/*
361 	 * On disabling the device, we want to turn off HW access to memory
362 	 * that we no longer own.
363 	 *
364 	 * However, not all suspend-states disable the device. S0 (s2idle)
365 	 * is effectively runtime-suspend, the device is left powered on
366 	 * but needs to be put into a low power state. We need to keep
367 	 * powermanagement enabled, but we also retain system state and so
368 	 * it remains safe to keep on using our allocated memory.
369 	 */
370 #ifdef notyet
371 	if (pm_suspend_target() == PM_SUSPEND_TO_IDLE)
372 		return;
373 #endif
374 
375 	with_intel_runtime_pm(gt->uncore->rpm, wakeref) {
376 		intel_rps_disable(&gt->rps);
377 		intel_rc6_disable(&gt->rc6);
378 		intel_llc_disable(&gt->llc);
379 	}
380 
381 	gt_sanitize(gt, false);
382 
383 	GT_TRACE(gt, "\n");
384 }
385 
386 void intel_gt_runtime_suspend(struct intel_gt *gt)
387 {
388 	intel_pxp_runtime_suspend(&gt->pxp);
389 	intel_uc_runtime_suspend(&gt->uc);
390 
391 	GT_TRACE(gt, "\n");
392 }
393 
394 int intel_gt_runtime_resume(struct intel_gt *gt)
395 {
396 	int ret;
397 
398 	GT_TRACE(gt, "\n");
399 	intel_gt_init_swizzling(gt);
400 	intel_ggtt_restore_fences(gt->ggtt);
401 
402 	ret = intel_uc_runtime_resume(&gt->uc);
403 	if (ret)
404 		return ret;
405 
406 	intel_pxp_runtime_resume(&gt->pxp);
407 
408 	return 0;
409 }
410 
411 static ktime_t __intel_gt_get_awake_time(const struct intel_gt *gt)
412 {
413 	ktime_t total = gt->stats.total;
414 
415 	if (gt->stats.active)
416 		total = ktime_add(total,
417 				  ktime_sub(ktime_get(), gt->stats.start));
418 
419 	return total;
420 }
421 
422 ktime_t intel_gt_get_awake_time(const struct intel_gt *gt)
423 {
424 	unsigned int seq;
425 	ktime_t total;
426 
427 #ifdef notyet
428 	do {
429 		seq = read_seqcount_begin(&gt->stats.lock);
430 		total = __intel_gt_get_awake_time(gt);
431 	} while (read_seqcount_retry(&gt->stats.lock, seq));
432 #else
433 	do {
434 		seq = read_seqcount_begin((seqcount_t *)&gt->stats.lock);
435 		total = __intel_gt_get_awake_time(gt);
436 	} while (read_seqcount_retry((seqcount_t *)&gt->stats.lock, seq));
437 #endif
438 
439 	return total;
440 }
441 
442 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
443 #include "selftest_gt_pm.c"
444 #endif
445