Commit | Line | Data |
---|---|---|
9c065a7d DV |
1 | /* |
2 | * Copyright © 2012-2014 Intel Corporation | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice (including the next | |
12 | * paragraph) shall be included in all copies or substantial portions of the | |
13 | * Software. | |
14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
21 | * IN THE SOFTWARE. | |
22 | * | |
23 | * Authors: | |
24 | * Eugeni Dodonov <eugeni.dodonov@intel.com> | |
25 | * Daniel Vetter <daniel.vetter@ffwll.ch> | |
26 | * | |
27 | */ | |
28 | ||
29 | #include <linux/pm_runtime.h> | |
9c065a7d | 30 | |
bd780f37 CW |
31 | #include <drm/drm_print.h> |
32 | ||
9c065a7d | 33 | #include "i915_drv.h" |
a09d9a80 | 34 | #include "i915_trace.h" |
9c065a7d | 35 | |
e4e7684f DV |
36 | /** |
37 | * DOC: runtime pm | |
38 | * | |
39 | * The i915 driver supports dynamic enabling and disabling of entire hardware | |
40 | * blocks at runtime. This is especially important on the display side where | |
41 | * software is supposed to control many power gates manually on recent hardware, | |
42 | * since on the GT side a lot of the power management is done by the hardware. | |
43 | * But even there some manual control at the device level is required. | |
44 | * | |
45 | * Since i915 supports a diverse set of platforms with a unified codebase and | |
46 | * hardware engineers just love to shuffle functionality around between power | |
47 | * domains there's a sizeable amount of indirection required. This file provides | |
48 | * generic functions to the driver for grabbing and releasing references for | |
49 | * abstract power domains. It then maps those to the actual power wells | |
50 | * present for a given platform. | |
51 | */ | |
52 | ||
261200eb JN |
53 | static struct drm_i915_private *rpm_to_i915(struct intel_runtime_pm *rpm) |
54 | { | |
55 | return container_of(rpm, struct drm_i915_private, runtime_pm); | |
56 | } | |
57 | ||
bd780f37 CW |
58 | #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) |
59 | ||
1bf676cc | 60 | static void init_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) |
bd780f37 | 61 | { |
b49e894c | 62 | ref_tracker_dir_init(&rpm->debug, INTEL_REFTRACK_DEAD_COUNT, dev_name(rpm->kdev)); |
bd780f37 CW |
63 | } |
64 | ||
b49e894c | 65 | static intel_wakeref_t |
1bf676cc | 66 | track_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) |
bd780f37 | 67 | { |
b49e894c | 68 | if (!rpm->available || rpm->no_wakeref_tracking) |
985a0256 VS |
69 | return -1; |
70 | ||
b49e894c | 71 | return intel_ref_tracker_alloc(&rpm->debug); |
16e4dd03 CW |
72 | } |
73 | ||
1bf676cc | 74 | static void untrack_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, |
b49e894c | 75 | intel_wakeref_t wakeref) |
bd780f37 | 76 | { |
b49e894c | 77 | if (!rpm->available || rpm->no_wakeref_tracking) |
bd780f37 CW |
78 | return; |
79 | ||
b49e894c | 80 | intel_ref_tracker_free(&rpm->debug, wakeref); |
dbf99c1f ID |
81 | } |
82 | ||
b49e894c | 83 | static void untrack_all_intel_runtime_pm_wakerefs(struct intel_runtime_pm *rpm) |
dbf99c1f | 84 | { |
b49e894c | 85 | ref_tracker_dir_exit(&rpm->debug); |
dbf99c1f ID |
86 | } |
87 | ||
bd780f37 | 88 | static noinline void |
1bf676cc | 89 | __intel_wakeref_dec_and_check_tracking(struct intel_runtime_pm *rpm) |
bd780f37 | 90 | { |
bd780f37 CW |
91 | unsigned long flags; |
92 | ||
dbf99c1f ID |
93 | if (!atomic_dec_and_lock_irqsave(&rpm->wakeref_count, |
94 | &rpm->debug.lock, | |
95 | flags)) | |
96 | return; | |
bd780f37 | 97 | |
b49e894c | 98 | ref_tracker_dir_print_locked(&rpm->debug, INTEL_REFTRACK_PRINT_LIMIT); |
dbf99c1f | 99 | spin_unlock_irqrestore(&rpm->debug.lock, flags); |
bd780f37 CW |
100 | } |
101 | ||
69c66355 | 102 | void print_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, |
bd780f37 CW |
103 | struct drm_printer *p) |
104 | { | |
b49e894c | 105 | intel_ref_tracker_show(&rpm->debug, p); |
bd780f37 CW |
106 | } |
107 | ||
108 | #else | |
109 | ||
1bf676cc | 110 | static void init_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) |
bd780f37 CW |
111 | { |
112 | } | |
113 | ||
b49e894c | 114 | static intel_wakeref_t |
1bf676cc | 115 | track_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) |
bd780f37 | 116 | { |
16e4dd03 | 117 | return -1; |
bd780f37 CW |
118 | } |
119 | ||
1bf676cc | 120 | static void untrack_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, |
b49e894c | 121 | intel_wakeref_t wakeref) |
4547c255 ID |
122 | { |
123 | } | |
124 | ||
125 | static void | |
1bf676cc | 126 | __intel_wakeref_dec_and_check_tracking(struct intel_runtime_pm *rpm) |
bd780f37 | 127 | { |
d5b6c275 | 128 | atomic_dec(&rpm->wakeref_count); |
bd780f37 CW |
129 | } |
130 | ||
dbf99c1f | 131 | static void |
1bf676cc | 132 | untrack_all_intel_runtime_pm_wakerefs(struct intel_runtime_pm *rpm) |
dbf99c1f ID |
133 | { |
134 | } | |
135 | ||
bd780f37 CW |
136 | #endif |
137 | ||
4547c255 | 138 | static void |
1bf676cc | 139 | intel_runtime_pm_acquire(struct intel_runtime_pm *rpm, bool wakelock) |
4547c255 | 140 | { |
4547c255 ID |
141 | if (wakelock) { |
142 | atomic_add(1 + INTEL_RPM_WAKELOCK_BIAS, &rpm->wakeref_count); | |
87b391b9 | 143 | assert_rpm_wakelock_held(rpm); |
4547c255 ID |
144 | } else { |
145 | atomic_inc(&rpm->wakeref_count); | |
87b391b9 | 146 | assert_rpm_raw_wakeref_held(rpm); |
4547c255 ID |
147 | } |
148 | } | |
149 | ||
150 | static void | |
1bf676cc | 151 | intel_runtime_pm_release(struct intel_runtime_pm *rpm, int wakelock) |
4547c255 | 152 | { |
4547c255 | 153 | if (wakelock) { |
87b391b9 | 154 | assert_rpm_wakelock_held(rpm); |
4547c255 ID |
155 | atomic_sub(INTEL_RPM_WAKELOCK_BIAS, &rpm->wakeref_count); |
156 | } else { | |
87b391b9 | 157 | assert_rpm_raw_wakeref_held(rpm); |
4547c255 ID |
158 | } |
159 | ||
d5b6c275 | 160 | __intel_wakeref_dec_and_check_tracking(rpm); |
4547c255 ID |
161 | } |
162 | ||
1bf676cc | 163 | static intel_wakeref_t __intel_runtime_pm_get(struct intel_runtime_pm *rpm, |
7645b19d | 164 | bool wakelock) |
dcddab3a | 165 | { |
261200eb | 166 | struct drm_i915_private *i915 = rpm_to_i915(rpm); |
7645b19d | 167 | int ret; |
dcddab3a | 168 | |
d5b6c275 | 169 | ret = pm_runtime_get_sync(rpm->kdev); |
649c10ff PB |
170 | drm_WARN_ONCE(&i915->drm, ret < 0, |
171 | "pm_runtime_get_sync() failed: %d\n", ret); | |
b409ca95 | 172 | |
d5b6c275 | 173 | intel_runtime_pm_acquire(rpm, wakelock); |
b409ca95 | 174 | |
d5b6c275 | 175 | return track_intel_runtime_pm_wakeref(rpm); |
b409ca95 ID |
176 | } |
177 | ||
e4e7684f | 178 | /** |
7645b19d | 179 | * intel_runtime_pm_get_raw - grab a raw runtime pm reference |
d858d569 | 180 | * @rpm: the intel_runtime_pm structure |
e4e7684f DV |
181 | * |
182 | * This is the unlocked version of intel_display_power_is_enabled() and should | |
183 | * only be used from error capture and recovery code where deadlocks are | |
184 | * possible. | |
7645b19d DCS |
185 | * This function grabs a device-level runtime pm reference (mostly used for |
186 | * asynchronous PM management from display code) and ensures that it is powered | |
187 | * up. Raw references are not considered during wakelock assert checks. | |
e4e7684f | 188 | * |
7645b19d DCS |
189 | * Any runtime pm reference obtained by this function must have a symmetric |
190 | * call to intel_runtime_pm_put_raw() to release the reference again. | |
191 | * | |
192 | * Returns: the wakeref cookie to pass to intel_runtime_pm_put_raw(), evaluates | |
193 | * as True if the wakeref was acquired, or False otherwise. | |
e4e7684f | 194 | */ |
d858d569 | 195 | intel_wakeref_t intel_runtime_pm_get_raw(struct intel_runtime_pm *rpm) |
7645b19d | 196 | { |
d858d569 | 197 | return __intel_runtime_pm_get(rpm, false); |
9c065a7d DV |
198 | } |
199 | ||
e4e7684f | 200 | /** |
7645b19d | 201 | * intel_runtime_pm_get - grab a runtime pm reference |
d858d569 | 202 | * @rpm: the intel_runtime_pm structure |
e4e7684f | 203 | * |
7645b19d DCS |
204 | * This function grabs a device-level runtime pm reference (mostly used for GEM |
205 | * code to ensure the GTT or GT is on) and ensures that it is powered up. | |
e4e7684f | 206 | * |
7645b19d DCS |
207 | * Any runtime pm reference obtained by this function must have a symmetric |
208 | * call to intel_runtime_pm_put() to release the reference again. | |
e4e7684f | 209 | * |
7645b19d | 210 | * Returns: the wakeref cookie to pass to intel_runtime_pm_put() |
e4e7684f | 211 | */ |
d858d569 | 212 | intel_wakeref_t intel_runtime_pm_get(struct intel_runtime_pm *rpm) |
9c065a7d | 213 | { |
d858d569 | 214 | return __intel_runtime_pm_get(rpm, true); |
9c065a7d DV |
215 | } |
216 | ||
7645b19d | 217 | /** |
9d58aa46 | 218 | * __intel_runtime_pm_get_if_active - grab a runtime pm reference if device is active |
d858d569 | 219 | * @rpm: the intel_runtime_pm structure |
9d58aa46 | 220 | * @ignore_usecount: get a ref even if dev->power.usage_count is 0 |
7645b19d DCS |
221 | * |
222 | * This function grabs a device-level runtime pm reference if the device is | |
9d58aa46 ID |
223 | * already active and ensures that it is powered up. It is illegal to try |
224 | * and access the HW should intel_runtime_pm_get_if_active() report failure. | |
225 | * | |
81f1f8f1 | 226 | * If @ignore_usecount is true, a reference will be acquired even if there is no |
9d58aa46 ID |
227 | * user requiring the device to be powered up (dev->power.usage_count == 0). |
228 | * If the function returns false in this case then it's guaranteed that the | |
229 | * device's runtime suspend hook has been called already or that it will be | |
230 | * called (and hence it's also guaranteed that the device's runtime resume | |
231 | * hook will be called eventually). | |
7645b19d DCS |
232 | * |
233 | * Any runtime pm reference obtained by this function must have a symmetric | |
234 | * call to intel_runtime_pm_put() to release the reference again. | |
235 | * | |
236 | * Returns: the wakeref cookie to pass to intel_runtime_pm_put(), evaluates | |
237 | * as True if the wakeref was acquired, or False otherwise. | |
9c065a7d | 238 | */ |
9d58aa46 ID |
239 | static intel_wakeref_t __intel_runtime_pm_get_if_active(struct intel_runtime_pm *rpm, |
240 | bool ignore_usecount) | |
9c065a7d | 241 | { |
d5b6c275 | 242 | if (IS_ENABLED(CONFIG_PM)) { |
b2891eb2 | 243 | /* |
7645b19d DCS |
244 | * In cases runtime PM is disabled by the RPM core and we get |
245 | * an -EINVAL return value we are not supposed to call this | |
246 | * function, since the power state is undefined. This applies | |
247 | * atm to the late/early system suspend/resume handlers. | |
b2891eb2 | 248 | */ |
c0ef3df8 SA |
249 | if ((ignore_usecount && |
250 | pm_runtime_get_if_active(rpm->kdev) <= 0) || | |
251 | (!ignore_usecount && | |
252 | pm_runtime_get_if_in_use(rpm->kdev) <= 0)) | |
7645b19d | 253 | return 0; |
ffd7e32d | 254 | } |
664326f8 | 255 | |
d5b6c275 | 256 | intel_runtime_pm_acquire(rpm, true); |
da2f41d1 | 257 | |
d5b6c275 | 258 | return track_intel_runtime_pm_wakeref(rpm); |
da2f41d1 ID |
259 | } |
260 | ||
9d58aa46 ID |
261 | intel_wakeref_t intel_runtime_pm_get_if_in_use(struct intel_runtime_pm *rpm) |
262 | { | |
263 | return __intel_runtime_pm_get_if_active(rpm, false); | |
264 | } | |
265 | ||
266 | intel_wakeref_t intel_runtime_pm_get_if_active(struct intel_runtime_pm *rpm) | |
267 | { | |
268 | return __intel_runtime_pm_get_if_active(rpm, true); | |
269 | } | |
270 | ||
13e1592f | 271 | /** |
7645b19d | 272 | * intel_runtime_pm_get_noresume - grab a runtime pm reference |
d858d569 | 273 | * @rpm: the intel_runtime_pm structure |
7645b19d | 274 | * |
7af6b116 | 275 | * This function grabs a device-level runtime pm reference. |
7645b19d | 276 | * |
7af6b116 RV |
277 | * It will _not_ resume the device but instead only get an extra wakeref. |
278 | * Therefore it is only valid to call this functions from contexts where | |
279 | * the device is known to be active and with another wakeref previously hold. | |
13e1592f | 280 | * |
7645b19d DCS |
281 | * Any runtime pm reference obtained by this function must have a symmetric |
282 | * call to intel_runtime_pm_put() to release the reference again. | |
13e1592f | 283 | * |
7645b19d | 284 | * Returns: the wakeref cookie to pass to intel_runtime_pm_put() |
13e1592f | 285 | */ |
d858d569 | 286 | intel_wakeref_t intel_runtime_pm_get_noresume(struct intel_runtime_pm *rpm) |
dc174300 | 287 | { |
7af6b116 | 288 | assert_rpm_raw_wakeref_held(rpm); |
d5b6c275 | 289 | pm_runtime_get_noresume(rpm->kdev); |
5aefb239 | 290 | |
d5b6c275 | 291 | intel_runtime_pm_acquire(rpm, true); |
5aefb239 | 292 | |
d5b6c275 | 293 | return track_intel_runtime_pm_wakeref(rpm); |
5aefb239 SS |
294 | } |
295 | ||
1bf676cc | 296 | static void __intel_runtime_pm_put(struct intel_runtime_pm *rpm, |
7645b19d DCS |
297 | intel_wakeref_t wref, |
298 | bool wakelock) | |
5aefb239 | 299 | { |
d5b6c275 | 300 | struct device *kdev = rpm->kdev; |
53421c2f | 301 | |
d5b6c275 | 302 | untrack_intel_runtime_pm_wakeref(rpm, wref); |
dc174300 | 303 | |
d5b6c275 | 304 | intel_runtime_pm_release(rpm, wakelock); |
93c7cb6c | 305 | |
7645b19d DCS |
306 | pm_runtime_mark_last_busy(kdev); |
307 | pm_runtime_put_autosuspend(kdev); | |
93c7cb6c SS |
308 | } |
309 | ||
7645b19d DCS |
310 | /** |
311 | * intel_runtime_pm_put_raw - release a raw runtime pm reference | |
d858d569 | 312 | * @rpm: the intel_runtime_pm structure |
7645b19d DCS |
313 | * @wref: wakeref acquired for the reference that is being released |
314 | * | |
315 | * This function drops the device-level runtime pm reference obtained by | |
316 | * intel_runtime_pm_get_raw() and might power down the corresponding | |
317 | * hardware block right away if this is the last reference. | |
318 | */ | |
319 | void | |
d858d569 | 320 | intel_runtime_pm_put_raw(struct intel_runtime_pm *rpm, intel_wakeref_t wref) |
93c7cb6c | 321 | { |
d858d569 | 322 | __intel_runtime_pm_put(rpm, wref, false); |
f75a1985 SS |
323 | } |
324 | ||
e4e7684f | 325 | /** |
4547c255 | 326 | * intel_runtime_pm_put_unchecked - release an unchecked runtime pm reference |
d858d569 | 327 | * @rpm: the intel_runtime_pm structure |
e4e7684f DV |
328 | * |
329 | * This function drops the device-level runtime pm reference obtained by | |
330 | * intel_runtime_pm_get() and might power down the corresponding | |
331 | * hardware block right away if this is the last reference. | |
4547c255 ID |
332 | * |
333 | * This function exists only for historical reasons and should be avoided in | |
334 | * new code, as the correctness of its use cannot be checked. Always use | |
335 | * intel_runtime_pm_put() instead. | |
e4e7684f | 336 | */ |
d858d569 | 337 | void intel_runtime_pm_put_unchecked(struct intel_runtime_pm *rpm) |
9c065a7d | 338 | { |
d858d569 | 339 | __intel_runtime_pm_put(rpm, -1, true); |
9c065a7d DV |
340 | } |
341 | ||
16e4dd03 | 342 | #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) |
4547c255 ID |
343 | /** |
344 | * intel_runtime_pm_put - release a runtime pm reference | |
d858d569 | 345 | * @rpm: the intel_runtime_pm structure |
4547c255 ID |
346 | * @wref: wakeref acquired for the reference that is being released |
347 | * | |
348 | * This function drops the device-level runtime pm reference obtained by | |
349 | * intel_runtime_pm_get() and might power down the corresponding | |
350 | * hardware block right away if this is the last reference. | |
351 | */ | |
d858d569 | 352 | void intel_runtime_pm_put(struct intel_runtime_pm *rpm, intel_wakeref_t wref) |
16e4dd03 | 353 | { |
d858d569 | 354 | __intel_runtime_pm_put(rpm, wref, true); |
16e4dd03 CW |
355 | } |
356 | #endif | |
357 | ||
e4e7684f DV |
358 | /** |
359 | * intel_runtime_pm_enable - enable runtime pm | |
69c66355 | 360 | * @rpm: the intel_runtime_pm structure |
e4e7684f DV |
361 | * |
362 | * This function enables runtime pm at the end of the driver load sequence. | |
363 | * | |
364 | * Note that this function does currently not enable runtime pm for the | |
2cd9a689 ID |
365 | * subordinate display power domains. That is done by |
366 | * intel_power_domains_enable(). | |
e4e7684f | 367 | */ |
69c66355 | 368 | void intel_runtime_pm_enable(struct intel_runtime_pm *rpm) |
9c065a7d | 369 | { |
261200eb | 370 | struct drm_i915_private *i915 = rpm_to_i915(rpm); |
d5b6c275 | 371 | struct device *kdev = rpm->kdev; |
9c065a7d | 372 | |
07d80572 CW |
373 | /* |
374 | * Disable the system suspend direct complete optimization, which can | |
375 | * leave the device suspended skipping the driver's suspend handlers | |
376 | * if the device was already runtime suspended. This is needed due to | |
377 | * the difference in our runtime and system suspend sequence and | |
378 | * becaue the HDA driver may require us to enable the audio power | |
379 | * domain during system suspend. | |
380 | */ | |
e0751556 | 381 | dev_pm_set_driver_flags(kdev, DPM_FLAG_NO_DIRECT_COMPLETE); |
07d80572 | 382 | |
c49d13ee DW |
383 | pm_runtime_set_autosuspend_delay(kdev, 10000); /* 10s */ |
384 | pm_runtime_mark_last_busy(kdev); | |
cbc68dc9 | 385 | |
25b181b4 ID |
386 | /* |
387 | * Take a permanent reference to disable the RPM functionality and drop | |
388 | * it only when unloading the driver. Use the low level get/put helpers, | |
389 | * so the driver's own RPM reference tracking asserts also work on | |
390 | * platforms without RPM support. | |
391 | */ | |
d5b6c275 | 392 | if (!rpm->available) { |
f5073824 ID |
393 | int ret; |
394 | ||
c49d13ee | 395 | pm_runtime_dont_use_autosuspend(kdev); |
f5073824 | 396 | ret = pm_runtime_get_sync(kdev); |
649c10ff PB |
397 | drm_WARN(&i915->drm, ret < 0, |
398 | "pm_runtime_get_sync() failed: %d\n", ret); | |
cbc68dc9 | 399 | } else { |
c49d13ee | 400 | pm_runtime_use_autosuspend(kdev); |
cbc68dc9 | 401 | } |
9c065a7d | 402 | |
66eb93e7 AG |
403 | /* |
404 | * FIXME: Temp hammer to keep autosupend disable on lmem supported platforms. | |
405 | * As per PCIe specs 5.3.1.4.1, all iomem read write request over a PCIe | |
406 | * function will be unsupported in case PCIe endpoint function is in D3. | |
407 | * Let's keep i915 autosuspend control 'on' till we fix all known issue | |
408 | * with lmem access in D3. | |
409 | */ | |
410 | if (!IS_DGFX(i915)) | |
411 | pm_runtime_allow(kdev); | |
527bab04 | 412 | |
aabee1bb ID |
413 | /* |
414 | * The core calls the driver load handler with an RPM reference held. | |
415 | * We drop that here and will reacquire it during unloading in | |
416 | * intel_power_domains_fini(). | |
417 | */ | |
c49d13ee | 418 | pm_runtime_put_autosuspend(kdev); |
9c065a7d | 419 | } |
07d80572 | 420 | |
69c66355 | 421 | void intel_runtime_pm_disable(struct intel_runtime_pm *rpm) |
07d80572 | 422 | { |
261200eb | 423 | struct drm_i915_private *i915 = rpm_to_i915(rpm); |
d5b6c275 | 424 | struct device *kdev = rpm->kdev; |
07d80572 CW |
425 | |
426 | /* Transfer rpm ownership back to core */ | |
649c10ff PB |
427 | drm_WARN(&i915->drm, pm_runtime_get_sync(kdev) < 0, |
428 | "Failed to pass rpm ownership back to core\n"); | |
07d80572 CW |
429 | |
430 | pm_runtime_dont_use_autosuspend(kdev); | |
431 | ||
d5b6c275 | 432 | if (!rpm->available) |
07d80572 CW |
433 | pm_runtime_put(kdev); |
434 | } | |
bd780f37 | 435 | |
3b58a945 | 436 | void intel_runtime_pm_driver_release(struct intel_runtime_pm *rpm) |
bd780f37 | 437 | { |
261200eb | 438 | struct drm_i915_private *i915 = rpm_to_i915(rpm); |
dbf99c1f | 439 | int count = atomic_read(&rpm->wakeref_count); |
bd780f37 | 440 | |
e66c8dcf AG |
441 | intel_wakeref_auto_fini(&rpm->userfault_wakeref); |
442 | ||
649c10ff PB |
443 | drm_WARN(&i915->drm, count, |
444 | "i915 raw-wakerefs=%d wakelocks=%d on cleanup\n", | |
445 | intel_rpm_raw_wakeref_count(count), | |
446 | intel_rpm_wakelock_count(count)); | |
b49e894c | 447 | } |
bd780f37 | 448 | |
b49e894c AH |
449 | void intel_runtime_pm_driver_last_release(struct intel_runtime_pm *rpm) |
450 | { | |
451 | intel_runtime_pm_driver_release(rpm); | |
d5b6c275 | 452 | untrack_all_intel_runtime_pm_wakerefs(rpm); |
bd780f37 CW |
453 | } |
454 | ||
69c66355 | 455 | void intel_runtime_pm_init_early(struct intel_runtime_pm *rpm) |
bd780f37 | 456 | { |
261200eb | 457 | struct drm_i915_private *i915 = rpm_to_i915(rpm); |
8ff5446a | 458 | struct pci_dev *pdev = to_pci_dev(i915->drm.dev); |
d5b6c275 DCS |
459 | struct device *kdev = &pdev->dev; |
460 | ||
461 | rpm->kdev = kdev; | |
462 | rpm->available = HAS_RUNTIME_PM(i915); | |
d3708182 | 463 | atomic_set(&rpm->wakeref_count, 0); |
d5b6c275 DCS |
464 | |
465 | init_intel_runtime_pm_wakeref(rpm); | |
e66c8dcf | 466 | INIT_LIST_HEAD(&rpm->lmem_userfault_list); |
1cacd689 | 467 | spin_lock_init(&rpm->lmem_userfault_lock); |
8d208a5e | 468 | intel_wakeref_auto_init(&rpm->userfault_wakeref, i915); |
bd780f37 | 469 | } |