Commit | Line | Data |
---|---|---|
0d5adc5f JN |
1 | /* SPDX-License-Identifier: MIT */ |
2 | /* | |
3 | * Copyright © 2019 Intel Corporation | |
4 | */ | |
5 | ||
6 | #ifndef __INTEL_RUNTIME_PM_H__ | |
7 | #define __INTEL_RUNTIME_PM_H__ | |
8 | ||
0d5adc5f JN |
9 | #include <linux/types.h> |
10 | ||
df0566a6 JN |
11 | #include "display/intel_display.h" |
12 | ||
09a93ef3 | 13 | #include "intel_wakeref.h" |
0d5adc5f | 14 | |
1bf676cc DCS |
15 | #include "i915_utils.h" |
16 | ||
17 | struct device; | |
09a93ef3 JN |
18 | struct drm_i915_private; |
19 | struct drm_printer; | |
0d5adc5f JN |
20 | |
21 | enum i915_drm_suspend_mode { | |
22 | I915_DRM_SUSPEND_IDLE, | |
23 | I915_DRM_SUSPEND_MEM, | |
24 | I915_DRM_SUSPEND_HIBERNATE, | |
25 | }; | |
26 | ||
1bf676cc DCS |
27 | /* |
28 | * This struct helps tracking the state needed for runtime PM, which puts the | |
29 | * device in PCI D3 state. Notice that when this happens, nothing on the | |
30 | * graphics device works, even register access, so we don't get interrupts nor | |
31 | * anything else. | |
32 | * | |
33 | * Every piece of our code that needs to actually touch the hardware needs to | |
34 | * either call intel_runtime_pm_get or call intel_display_power_get with the | |
35 | * appropriate power domain. | |
36 | * | |
37 | * Our driver uses the autosuspend delay feature, which means we'll only really | |
38 | * suspend if we stay with zero refcount for a certain amount of time. The | |
39 | * default value is currently very conservative (see intel_runtime_pm_enable), but | |
40 | * it can be changed with the standard runtime PM files from sysfs. | |
41 | * | |
42 | * The irqs_disabled variable becomes true exactly after we disable the IRQs and | |
43 | * goes back to false exactly before we reenable the IRQs. We use this variable | |
44 | * to check if someone is trying to enable/disable IRQs while they're supposed | |
45 | * to be disabled. This shouldn't happen and we'll print some error messages in | |
46 | * case it happens. | |
47 | * | |
fb4da215 | 48 | * For more, read the Documentation/power/runtime_pm.rst. |
1bf676cc DCS |
49 | */ |
50 | struct intel_runtime_pm { | |
51 | atomic_t wakeref_count; | |
52 | struct device *kdev; /* points to i915->drm.pdev->dev */ | |
53 | bool available; | |
54 | bool suspended; | |
55 | bool irqs_enabled; | |
56 | ||
57 | #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) | |
58 | /* | |
59 | * To aide detection of wakeref leaks and general misuse, we | |
60 | * track all wakeref holders. With manual markup (i.e. returning | |
61 | * a cookie to each rpm_get caller which they then supply to their | |
62 | * paired rpm_put) we can remove corresponding pairs of and keep | |
63 | * the array trimmed to active wakerefs. | |
64 | */ | |
65 | struct intel_runtime_pm_debug { | |
66 | spinlock_t lock; | |
67 | ||
68 | depot_stack_handle_t last_acquire; | |
69 | depot_stack_handle_t last_release; | |
70 | ||
71 | depot_stack_handle_t *owners; | |
72 | unsigned long count; | |
73 | } debug; | |
74 | #endif | |
75 | }; | |
76 | ||
77 | #define BITS_PER_WAKEREF \ | |
78 | BITS_PER_TYPE(struct_member(struct intel_runtime_pm, wakeref_count)) | |
79 | #define INTEL_RPM_WAKELOCK_SHIFT (BITS_PER_WAKEREF / 2) | |
80 | #define INTEL_RPM_WAKELOCK_BIAS (1 << INTEL_RPM_WAKELOCK_SHIFT) | |
81 | #define INTEL_RPM_RAW_WAKEREF_MASK (INTEL_RPM_WAKELOCK_BIAS - 1) | |
82 | ||
83 | static inline int | |
84 | intel_rpm_raw_wakeref_count(int wakeref_count) | |
85 | { | |
86 | return wakeref_count & INTEL_RPM_RAW_WAKEREF_MASK; | |
87 | } | |
88 | ||
89 | static inline int | |
90 | intel_rpm_wakelock_count(int wakeref_count) | |
91 | { | |
92 | return wakeref_count >> INTEL_RPM_WAKELOCK_SHIFT; | |
93 | } | |
94 | ||
95 | static inline void | |
96 | assert_rpm_device_not_suspended(struct intel_runtime_pm *rpm) | |
97 | { | |
98 | WARN_ONCE(rpm->suspended, | |
99 | "Device suspended during HW access\n"); | |
100 | } | |
101 | ||
102 | static inline void | |
103 | __assert_rpm_raw_wakeref_held(struct intel_runtime_pm *rpm, int wakeref_count) | |
104 | { | |
105 | assert_rpm_device_not_suspended(rpm); | |
106 | WARN_ONCE(!intel_rpm_raw_wakeref_count(wakeref_count), | |
107 | "RPM raw-wakeref not held\n"); | |
108 | } | |
109 | ||
110 | static inline void | |
111 | __assert_rpm_wakelock_held(struct intel_runtime_pm *rpm, int wakeref_count) | |
112 | { | |
113 | __assert_rpm_raw_wakeref_held(rpm, wakeref_count); | |
114 | WARN_ONCE(!intel_rpm_wakelock_count(wakeref_count), | |
115 | "RPM wakelock ref not held during HW access\n"); | |
116 | } | |
117 | ||
118 | static inline void | |
119 | assert_rpm_raw_wakeref_held(struct intel_runtime_pm *rpm) | |
120 | { | |
121 | __assert_rpm_raw_wakeref_held(rpm, atomic_read(&rpm->wakeref_count)); | |
122 | } | |
123 | ||
124 | static inline void | |
125 | assert_rpm_wakelock_held(struct intel_runtime_pm *rpm) | |
126 | { | |
127 | __assert_rpm_wakelock_held(rpm, atomic_read(&rpm->wakeref_count)); | |
128 | } | |
129 | ||
130 | /** | |
131 | * disable_rpm_wakeref_asserts - disable the RPM assert checks | |
132 | * @rpm: the intel_runtime_pm structure | |
133 | * | |
134 | * This function disable asserts that check if we hold an RPM wakelock | |
135 | * reference, while keeping the device-not-suspended checks still enabled. | |
136 | * It's meant to be used only in special circumstances where our rule about | |
137 | * the wakelock refcount wrt. the device power state doesn't hold. According | |
138 | * to this rule at any point where we access the HW or want to keep the HW in | |
139 | * an active state we must hold an RPM wakelock reference acquired via one of | |
140 | * the intel_runtime_pm_get() helpers. Currently there are a few special spots | |
141 | * where this rule doesn't hold: the IRQ and suspend/resume handlers, the | |
142 | * forcewake release timer, and the GPU RPS and hangcheck works. All other | |
143 | * users should avoid using this function. | |
144 | * | |
145 | * Any calls to this function must have a symmetric call to | |
146 | * enable_rpm_wakeref_asserts(). | |
147 | */ | |
148 | static inline void | |
149 | disable_rpm_wakeref_asserts(struct intel_runtime_pm *rpm) | |
150 | { | |
151 | atomic_add(INTEL_RPM_WAKELOCK_BIAS + 1, | |
152 | &rpm->wakeref_count); | |
153 | } | |
154 | ||
155 | /** | |
156 | * enable_rpm_wakeref_asserts - re-enable the RPM assert checks | |
157 | * @rpm: the intel_runtime_pm structure | |
158 | * | |
159 | * This function re-enables the RPM assert checks after disabling them with | |
160 | * disable_rpm_wakeref_asserts. It's meant to be used only in special | |
161 | * circumstances otherwise its use should be avoided. | |
162 | * | |
163 | * Any calls to this function must have a symmetric call to | |
164 | * disable_rpm_wakeref_asserts(). | |
165 | */ | |
166 | static inline void | |
167 | enable_rpm_wakeref_asserts(struct intel_runtime_pm *rpm) | |
168 | { | |
169 | atomic_sub(INTEL_RPM_WAKELOCK_BIAS + 1, | |
170 | &rpm->wakeref_count); | |
171 | } | |
172 | ||
69c66355 DCS |
173 | void intel_runtime_pm_init_early(struct intel_runtime_pm *rpm); |
174 | void intel_runtime_pm_enable(struct intel_runtime_pm *rpm); | |
175 | void intel_runtime_pm_disable(struct intel_runtime_pm *rpm); | |
3b58a945 | 176 | void intel_runtime_pm_driver_release(struct intel_runtime_pm *rpm); |
0d5adc5f | 177 | |
d858d569 DCS |
178 | intel_wakeref_t intel_runtime_pm_get(struct intel_runtime_pm *rpm); |
179 | intel_wakeref_t intel_runtime_pm_get_if_in_use(struct intel_runtime_pm *rpm); | |
180 | intel_wakeref_t intel_runtime_pm_get_noresume(struct intel_runtime_pm *rpm); | |
181 | intel_wakeref_t intel_runtime_pm_get_raw(struct intel_runtime_pm *rpm); | |
0d5adc5f | 182 | |
c447ff7d DCS |
183 | #define with_intel_runtime_pm(rpm, wf) \ |
184 | for ((wf) = intel_runtime_pm_get(rpm); (wf); \ | |
185 | intel_runtime_pm_put((rpm), (wf)), (wf) = 0) | |
0d5adc5f | 186 | |
c447ff7d DCS |
187 | #define with_intel_runtime_pm_if_in_use(rpm, wf) \ |
188 | for ((wf) = intel_runtime_pm_get_if_in_use(rpm); (wf); \ | |
189 | intel_runtime_pm_put((rpm), (wf)), (wf) = 0) | |
0d5adc5f | 190 | |
d858d569 | 191 | void intel_runtime_pm_put_unchecked(struct intel_runtime_pm *rpm); |
0d5adc5f | 192 | #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) |
d858d569 | 193 | void intel_runtime_pm_put(struct intel_runtime_pm *rpm, intel_wakeref_t wref); |
0d5adc5f | 194 | #else |
e0da2d63 | 195 | static inline void |
d858d569 | 196 | intel_runtime_pm_put(struct intel_runtime_pm *rpm, intel_wakeref_t wref) |
e0da2d63 | 197 | { |
d858d569 | 198 | intel_runtime_pm_put_unchecked(rpm); |
e0da2d63 | 199 | } |
0d5adc5f | 200 | #endif |
d858d569 | 201 | void intel_runtime_pm_put_raw(struct intel_runtime_pm *rpm, intel_wakeref_t wref); |
0d5adc5f JN |
202 | |
203 | #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) | |
69c66355 | 204 | void print_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, |
0d5adc5f JN |
205 | struct drm_printer *p); |
206 | #else | |
69c66355 | 207 | static inline void print_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, |
0d5adc5f JN |
208 | struct drm_printer *p) |
209 | { | |
210 | } | |
211 | #endif | |
212 | ||
0d5adc5f | 213 | #endif /* __INTEL_RUNTIME_PM_H__ */ |