162306a36Sopenharmony_ci/* SPDX-License-Identifier: MIT */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright © 2019 Intel Corporation 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#ifndef __INTEL_RUNTIME_PM_H__ 762306a36Sopenharmony_ci#define __INTEL_RUNTIME_PM_H__ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/types.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "intel_wakeref.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "i915_utils.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistruct device; 1662306a36Sopenharmony_cistruct drm_i915_private; 1762306a36Sopenharmony_cistruct drm_printer; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * This struct helps tracking the state needed for runtime PM, which puts the 2162306a36Sopenharmony_ci * device in PCI D3 state. Notice that when this happens, nothing on the 2262306a36Sopenharmony_ci * graphics device works, even register access, so we don't get interrupts nor 2362306a36Sopenharmony_ci * anything else. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * Every piece of our code that needs to actually touch the hardware needs to 2662306a36Sopenharmony_ci * either call intel_runtime_pm_get or call intel_display_power_get with the 2762306a36Sopenharmony_ci * appropriate power domain. 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * Our driver uses the autosuspend delay feature, which means we'll only really 3062306a36Sopenharmony_ci * suspend if we stay with zero refcount for a certain amount of time. The 3162306a36Sopenharmony_ci * default value is currently very conservative (see intel_runtime_pm_enable), but 3262306a36Sopenharmony_ci * it can be changed with the standard runtime PM files from sysfs. 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * The irqs_disabled variable becomes true exactly after we disable the IRQs and 3562306a36Sopenharmony_ci * goes back to false exactly before we reenable the IRQs. We use this variable 3662306a36Sopenharmony_ci * to check if someone is trying to enable/disable IRQs while they're supposed 3762306a36Sopenharmony_ci * to be disabled. This shouldn't happen and we'll print some error messages in 3862306a36Sopenharmony_ci * case it happens. 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * For more, read the Documentation/power/runtime_pm.rst. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_cistruct intel_runtime_pm { 4362306a36Sopenharmony_ci atomic_t wakeref_count; 4462306a36Sopenharmony_ci struct device *kdev; /* points to i915->drm.dev */ 4562306a36Sopenharmony_ci bool available; 4662306a36Sopenharmony_ci bool suspended; 4762306a36Sopenharmony_ci bool irqs_enabled; 4862306a36Sopenharmony_ci bool no_wakeref_tracking; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci /* 5162306a36Sopenharmony_ci * Protects access to lmem usefault list. 5262306a36Sopenharmony_ci * It is required, if we are outside of the runtime suspend path, 5362306a36Sopenharmony_ci * access to @lmem_userfault_list requires always first grabbing the 5462306a36Sopenharmony_ci * runtime pm, to ensure we can't race against runtime suspend. 5562306a36Sopenharmony_ci * Once we have that we also need to grab @lmem_userfault_lock, 5662306a36Sopenharmony_ci * at which point we have exclusive access. 5762306a36Sopenharmony_ci * The runtime suspend path is special since it doesn't really hold any locks, 5862306a36Sopenharmony_ci * but instead has exclusive access by virtue of all other accesses requiring 5962306a36Sopenharmony_ci * holding the runtime pm wakeref. 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_ci spinlock_t lmem_userfault_lock; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* 6462306a36Sopenharmony_ci * Keep list of userfaulted gem obj, which require to release their 6562306a36Sopenharmony_ci * mmap mappings at runtime suspend path. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci struct list_head lmem_userfault_list; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci /* Manual runtime pm autosuspend delay for user GGTT/lmem mmaps */ 7062306a36Sopenharmony_ci struct intel_wakeref_auto userfault_wakeref; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) 7362306a36Sopenharmony_ci /* 7462306a36Sopenharmony_ci * To aide detection of wakeref leaks and general misuse, we 7562306a36Sopenharmony_ci * track all wakeref holders. With manual markup (i.e. returning 7662306a36Sopenharmony_ci * a cookie to each rpm_get caller which they then supply to their 7762306a36Sopenharmony_ci * paired rpm_put) we can remove corresponding pairs of and keep 7862306a36Sopenharmony_ci * the array trimmed to active wakerefs. 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci struct intel_runtime_pm_debug { 8162306a36Sopenharmony_ci spinlock_t lock; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci depot_stack_handle_t last_acquire; 8462306a36Sopenharmony_ci depot_stack_handle_t last_release; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci depot_stack_handle_t *owners; 8762306a36Sopenharmony_ci unsigned long count; 8862306a36Sopenharmony_ci } debug; 8962306a36Sopenharmony_ci#endif 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci#define BITS_PER_WAKEREF \ 9362306a36Sopenharmony_ci BITS_PER_TYPE(typeof_member(struct intel_runtime_pm, wakeref_count)) 9462306a36Sopenharmony_ci#define INTEL_RPM_WAKELOCK_SHIFT (BITS_PER_WAKEREF / 2) 9562306a36Sopenharmony_ci#define INTEL_RPM_WAKELOCK_BIAS (1 << INTEL_RPM_WAKELOCK_SHIFT) 9662306a36Sopenharmony_ci#define INTEL_RPM_RAW_WAKEREF_MASK (INTEL_RPM_WAKELOCK_BIAS - 1) 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic inline int 9962306a36Sopenharmony_ciintel_rpm_raw_wakeref_count(int wakeref_count) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci return wakeref_count & INTEL_RPM_RAW_WAKEREF_MASK; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic inline int 10562306a36Sopenharmony_ciintel_rpm_wakelock_count(int wakeref_count) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci return wakeref_count >> INTEL_RPM_WAKELOCK_SHIFT; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic inline void 11162306a36Sopenharmony_ciassert_rpm_device_not_suspended(struct intel_runtime_pm *rpm) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci WARN_ONCE(rpm->suspended, 11462306a36Sopenharmony_ci "Device suspended during HW access\n"); 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic inline void 11862306a36Sopenharmony_ci__assert_rpm_raw_wakeref_held(struct intel_runtime_pm *rpm, int wakeref_count) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci assert_rpm_device_not_suspended(rpm); 12162306a36Sopenharmony_ci WARN_ONCE(!intel_rpm_raw_wakeref_count(wakeref_count), 12262306a36Sopenharmony_ci "RPM raw-wakeref not held\n"); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic inline void 12662306a36Sopenharmony_ci__assert_rpm_wakelock_held(struct intel_runtime_pm *rpm, int wakeref_count) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci __assert_rpm_raw_wakeref_held(rpm, wakeref_count); 12962306a36Sopenharmony_ci WARN_ONCE(!intel_rpm_wakelock_count(wakeref_count), 13062306a36Sopenharmony_ci "RPM wakelock ref not held during HW access\n"); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic inline void 13462306a36Sopenharmony_ciassert_rpm_raw_wakeref_held(struct intel_runtime_pm *rpm) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci __assert_rpm_raw_wakeref_held(rpm, atomic_read(&rpm->wakeref_count)); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic inline void 14062306a36Sopenharmony_ciassert_rpm_wakelock_held(struct intel_runtime_pm *rpm) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci __assert_rpm_wakelock_held(rpm, atomic_read(&rpm->wakeref_count)); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/** 14662306a36Sopenharmony_ci * disable_rpm_wakeref_asserts - disable the RPM assert checks 14762306a36Sopenharmony_ci * @rpm: the intel_runtime_pm structure 14862306a36Sopenharmony_ci * 14962306a36Sopenharmony_ci * This function disable asserts that check if we hold an RPM wakelock 15062306a36Sopenharmony_ci * reference, while keeping the device-not-suspended checks still enabled. 15162306a36Sopenharmony_ci * It's meant to be used only in special circumstances where our rule about 15262306a36Sopenharmony_ci * the wakelock refcount wrt. the device power state doesn't hold. According 15362306a36Sopenharmony_ci * to this rule at any point where we access the HW or want to keep the HW in 15462306a36Sopenharmony_ci * an active state we must hold an RPM wakelock reference acquired via one of 15562306a36Sopenharmony_ci * the intel_runtime_pm_get() helpers. Currently there are a few special spots 15662306a36Sopenharmony_ci * where this rule doesn't hold: the IRQ and suspend/resume handlers, the 15762306a36Sopenharmony_ci * forcewake release timer, and the GPU RPS and hangcheck works. All other 15862306a36Sopenharmony_ci * users should avoid using this function. 15962306a36Sopenharmony_ci * 16062306a36Sopenharmony_ci * Any calls to this function must have a symmetric call to 16162306a36Sopenharmony_ci * enable_rpm_wakeref_asserts(). 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_cistatic inline void 16462306a36Sopenharmony_cidisable_rpm_wakeref_asserts(struct intel_runtime_pm *rpm) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci atomic_add(INTEL_RPM_WAKELOCK_BIAS + 1, 16762306a36Sopenharmony_ci &rpm->wakeref_count); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/** 17162306a36Sopenharmony_ci * enable_rpm_wakeref_asserts - re-enable the RPM assert checks 17262306a36Sopenharmony_ci * @rpm: the intel_runtime_pm structure 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci * This function re-enables the RPM assert checks after disabling them with 17562306a36Sopenharmony_ci * disable_rpm_wakeref_asserts. It's meant to be used only in special 17662306a36Sopenharmony_ci * circumstances otherwise its use should be avoided. 17762306a36Sopenharmony_ci * 17862306a36Sopenharmony_ci * Any calls to this function must have a symmetric call to 17962306a36Sopenharmony_ci * disable_rpm_wakeref_asserts(). 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_cistatic inline void 18262306a36Sopenharmony_cienable_rpm_wakeref_asserts(struct intel_runtime_pm *rpm) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci atomic_sub(INTEL_RPM_WAKELOCK_BIAS + 1, 18562306a36Sopenharmony_ci &rpm->wakeref_count); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_civoid intel_runtime_pm_init_early(struct intel_runtime_pm *rpm); 18962306a36Sopenharmony_civoid intel_runtime_pm_enable(struct intel_runtime_pm *rpm); 19062306a36Sopenharmony_civoid intel_runtime_pm_disable(struct intel_runtime_pm *rpm); 19162306a36Sopenharmony_civoid intel_runtime_pm_driver_release(struct intel_runtime_pm *rpm); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ciintel_wakeref_t intel_runtime_pm_get(struct intel_runtime_pm *rpm); 19462306a36Sopenharmony_ciintel_wakeref_t intel_runtime_pm_get_if_in_use(struct intel_runtime_pm *rpm); 19562306a36Sopenharmony_ciintel_wakeref_t intel_runtime_pm_get_if_active(struct intel_runtime_pm *rpm); 19662306a36Sopenharmony_ciintel_wakeref_t intel_runtime_pm_get_noresume(struct intel_runtime_pm *rpm); 19762306a36Sopenharmony_ciintel_wakeref_t intel_runtime_pm_get_raw(struct intel_runtime_pm *rpm); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci#define with_intel_runtime_pm(rpm, wf) \ 20062306a36Sopenharmony_ci for ((wf) = intel_runtime_pm_get(rpm); (wf); \ 20162306a36Sopenharmony_ci intel_runtime_pm_put((rpm), (wf)), (wf) = 0) 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci#define with_intel_runtime_pm_if_in_use(rpm, wf) \ 20462306a36Sopenharmony_ci for ((wf) = intel_runtime_pm_get_if_in_use(rpm); (wf); \ 20562306a36Sopenharmony_ci intel_runtime_pm_put((rpm), (wf)), (wf) = 0) 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci#define with_intel_runtime_pm_if_active(rpm, wf) \ 20862306a36Sopenharmony_ci for ((wf) = intel_runtime_pm_get_if_active(rpm); (wf); \ 20962306a36Sopenharmony_ci intel_runtime_pm_put((rpm), (wf)), (wf) = 0) 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_civoid intel_runtime_pm_put_unchecked(struct intel_runtime_pm *rpm); 21262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) 21362306a36Sopenharmony_civoid intel_runtime_pm_put(struct intel_runtime_pm *rpm, intel_wakeref_t wref); 21462306a36Sopenharmony_ci#else 21562306a36Sopenharmony_cistatic inline void 21662306a36Sopenharmony_ciintel_runtime_pm_put(struct intel_runtime_pm *rpm, intel_wakeref_t wref) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci intel_runtime_pm_put_unchecked(rpm); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci#endif 22162306a36Sopenharmony_civoid intel_runtime_pm_put_raw(struct intel_runtime_pm *rpm, intel_wakeref_t wref); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) 22462306a36Sopenharmony_civoid print_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, 22562306a36Sopenharmony_ci struct drm_printer *p); 22662306a36Sopenharmony_ci#else 22762306a36Sopenharmony_cistatic inline void print_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, 22862306a36Sopenharmony_ci struct drm_printer *p) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci#endif 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci#endif /* __INTEL_RUNTIME_PM_H__ */ 234