162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * SPDX-License-Identifier: MIT 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright © 2019 Intel Corporation 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#ifndef INTEL_WAKEREF_H 862306a36Sopenharmony_ci#define INTEL_WAKEREF_H 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/atomic.h> 1162306a36Sopenharmony_ci#include <linux/bitfield.h> 1262306a36Sopenharmony_ci#include <linux/bits.h> 1362306a36Sopenharmony_ci#include <linux/lockdep.h> 1462306a36Sopenharmony_ci#include <linux/mutex.h> 1562306a36Sopenharmony_ci#include <linux/refcount.h> 1662306a36Sopenharmony_ci#include <linux/stackdepot.h> 1762306a36Sopenharmony_ci#include <linux/timer.h> 1862306a36Sopenharmony_ci#include <linux/workqueue.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) 2162306a36Sopenharmony_ci#define INTEL_WAKEREF_BUG_ON(expr) BUG_ON(expr) 2262306a36Sopenharmony_ci#else 2362306a36Sopenharmony_ci#define INTEL_WAKEREF_BUG_ON(expr) BUILD_BUG_ON_INVALID(expr) 2462306a36Sopenharmony_ci#endif 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct intel_runtime_pm; 2762306a36Sopenharmony_cistruct intel_wakeref; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_citypedef depot_stack_handle_t intel_wakeref_t; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistruct intel_wakeref_ops { 3262306a36Sopenharmony_ci int (*get)(struct intel_wakeref *wf); 3362306a36Sopenharmony_ci int (*put)(struct intel_wakeref *wf); 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistruct intel_wakeref { 3762306a36Sopenharmony_ci atomic_t count; 3862306a36Sopenharmony_ci struct mutex mutex; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci intel_wakeref_t wakeref; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci struct drm_i915_private *i915; 4362306a36Sopenharmony_ci const struct intel_wakeref_ops *ops; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci struct delayed_work work; 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistruct intel_wakeref_lockclass { 4962306a36Sopenharmony_ci struct lock_class_key mutex; 5062306a36Sopenharmony_ci struct lock_class_key work; 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_civoid __intel_wakeref_init(struct intel_wakeref *wf, 5462306a36Sopenharmony_ci struct drm_i915_private *i915, 5562306a36Sopenharmony_ci const struct intel_wakeref_ops *ops, 5662306a36Sopenharmony_ci struct intel_wakeref_lockclass *key); 5762306a36Sopenharmony_ci#define intel_wakeref_init(wf, i915, ops) do { \ 5862306a36Sopenharmony_ci static struct intel_wakeref_lockclass __key; \ 5962306a36Sopenharmony_ci \ 6062306a36Sopenharmony_ci __intel_wakeref_init((wf), (i915), (ops), &__key); \ 6162306a36Sopenharmony_ci} while (0) 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ciint __intel_wakeref_get_first(struct intel_wakeref *wf); 6462306a36Sopenharmony_civoid __intel_wakeref_put_last(struct intel_wakeref *wf, unsigned long flags); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/** 6762306a36Sopenharmony_ci * intel_wakeref_get: Acquire the wakeref 6862306a36Sopenharmony_ci * @wf: the wakeref 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * Acquire a hold on the wakeref. The first user to do so, will acquire 7162306a36Sopenharmony_ci * the runtime pm wakeref and then call the intel_wakeref_ops->get() 7262306a36Sopenharmony_ci * underneath the wakeref mutex. 7362306a36Sopenharmony_ci * 7462306a36Sopenharmony_ci * Note that intel_wakeref_ops->get() is allowed to fail, in which case 7562306a36Sopenharmony_ci * the runtime-pm wakeref will be released and the acquisition unwound, 7662306a36Sopenharmony_ci * and an error reported. 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * Returns: 0 if the wakeref was acquired successfully, or a negative error 7962306a36Sopenharmony_ci * code otherwise. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_cistatic inline int 8262306a36Sopenharmony_ciintel_wakeref_get(struct intel_wakeref *wf) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci might_sleep(); 8562306a36Sopenharmony_ci if (unlikely(!atomic_inc_not_zero(&wf->count))) 8662306a36Sopenharmony_ci return __intel_wakeref_get_first(wf); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci return 0; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/** 9262306a36Sopenharmony_ci * __intel_wakeref_get: Acquire the wakeref, again 9362306a36Sopenharmony_ci * @wf: the wakeref 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci * Increment the wakeref counter, only valid if it is already held by 9662306a36Sopenharmony_ci * the caller. 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci * See intel_wakeref_get(). 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_cistatic inline void 10162306a36Sopenharmony_ci__intel_wakeref_get(struct intel_wakeref *wf) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count) <= 0); 10462306a36Sopenharmony_ci atomic_inc(&wf->count); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/** 10862306a36Sopenharmony_ci * intel_wakeref_get_if_active: Acquire the wakeref 10962306a36Sopenharmony_ci * @wf: the wakeref 11062306a36Sopenharmony_ci * 11162306a36Sopenharmony_ci * Acquire a hold on the wakeref, but only if the wakeref is already 11262306a36Sopenharmony_ci * active. 11362306a36Sopenharmony_ci * 11462306a36Sopenharmony_ci * Returns: true if the wakeref was acquired, false otherwise. 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_cistatic inline bool 11762306a36Sopenharmony_ciintel_wakeref_get_if_active(struct intel_wakeref *wf) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci return atomic_inc_not_zero(&wf->count); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cienum { 12362306a36Sopenharmony_ci INTEL_WAKEREF_PUT_ASYNC_BIT = 0, 12462306a36Sopenharmony_ci __INTEL_WAKEREF_PUT_LAST_BIT__ 12562306a36Sopenharmony_ci}; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic inline void 12862306a36Sopenharmony_ciintel_wakeref_might_get(struct intel_wakeref *wf) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci might_lock(&wf->mutex); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/** 13462306a36Sopenharmony_ci * __intel_wakeref_put: Release the wakeref 13562306a36Sopenharmony_ci * @wf: the wakeref 13662306a36Sopenharmony_ci * @flags: control flags 13762306a36Sopenharmony_ci * 13862306a36Sopenharmony_ci * Release our hold on the wakeref. When there are no more users, 13962306a36Sopenharmony_ci * the runtime pm wakeref will be released after the intel_wakeref_ops->put() 14062306a36Sopenharmony_ci * callback is called underneath the wakeref mutex. 14162306a36Sopenharmony_ci * 14262306a36Sopenharmony_ci * Note that intel_wakeref_ops->put() is allowed to fail, in which case the 14362306a36Sopenharmony_ci * runtime-pm wakeref is retained. 14462306a36Sopenharmony_ci * 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_cistatic inline void 14762306a36Sopenharmony_ci__intel_wakeref_put(struct intel_wakeref *wf, unsigned long flags) 14862306a36Sopenharmony_ci#define INTEL_WAKEREF_PUT_ASYNC BIT(INTEL_WAKEREF_PUT_ASYNC_BIT) 14962306a36Sopenharmony_ci#define INTEL_WAKEREF_PUT_DELAY \ 15062306a36Sopenharmony_ci GENMASK(BITS_PER_LONG - 1, __INTEL_WAKEREF_PUT_LAST_BIT__) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count) <= 0); 15362306a36Sopenharmony_ci if (unlikely(!atomic_add_unless(&wf->count, -1, 1))) 15462306a36Sopenharmony_ci __intel_wakeref_put_last(wf, flags); 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic inline void 15862306a36Sopenharmony_ciintel_wakeref_put(struct intel_wakeref *wf) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci might_sleep(); 16162306a36Sopenharmony_ci __intel_wakeref_put(wf, 0); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic inline void 16562306a36Sopenharmony_ciintel_wakeref_put_async(struct intel_wakeref *wf) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci __intel_wakeref_put(wf, INTEL_WAKEREF_PUT_ASYNC); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic inline void 17162306a36Sopenharmony_ciintel_wakeref_put_delay(struct intel_wakeref *wf, unsigned long delay) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci __intel_wakeref_put(wf, 17462306a36Sopenharmony_ci INTEL_WAKEREF_PUT_ASYNC | 17562306a36Sopenharmony_ci FIELD_PREP(INTEL_WAKEREF_PUT_DELAY, delay)); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic inline void 17962306a36Sopenharmony_ciintel_wakeref_might_put(struct intel_wakeref *wf) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci might_lock(&wf->mutex); 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/** 18562306a36Sopenharmony_ci * intel_wakeref_lock: Lock the wakeref (mutex) 18662306a36Sopenharmony_ci * @wf: the wakeref 18762306a36Sopenharmony_ci * 18862306a36Sopenharmony_ci * Locks the wakeref to prevent it being acquired or released. New users 18962306a36Sopenharmony_ci * can still adjust the counter, but the wakeref itself (and callback) 19062306a36Sopenharmony_ci * cannot be acquired or released. 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_cistatic inline void 19362306a36Sopenharmony_ciintel_wakeref_lock(struct intel_wakeref *wf) 19462306a36Sopenharmony_ci __acquires(wf->mutex) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci mutex_lock(&wf->mutex); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci/** 20062306a36Sopenharmony_ci * intel_wakeref_unlock: Unlock the wakeref 20162306a36Sopenharmony_ci * @wf: the wakeref 20262306a36Sopenharmony_ci * 20362306a36Sopenharmony_ci * Releases a previously acquired intel_wakeref_lock(). 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_cistatic inline void 20662306a36Sopenharmony_ciintel_wakeref_unlock(struct intel_wakeref *wf) 20762306a36Sopenharmony_ci __releases(wf->mutex) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci mutex_unlock(&wf->mutex); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/** 21362306a36Sopenharmony_ci * intel_wakeref_unlock_wait: Wait until the active callback is complete 21462306a36Sopenharmony_ci * @wf: the wakeref 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * Waits for the active callback (under the @wf->mutex or another CPU) is 21762306a36Sopenharmony_ci * complete. 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_cistatic inline void 22062306a36Sopenharmony_ciintel_wakeref_unlock_wait(struct intel_wakeref *wf) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci mutex_lock(&wf->mutex); 22362306a36Sopenharmony_ci mutex_unlock(&wf->mutex); 22462306a36Sopenharmony_ci flush_delayed_work(&wf->work); 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/** 22862306a36Sopenharmony_ci * intel_wakeref_is_active: Query whether the wakeref is currently held 22962306a36Sopenharmony_ci * @wf: the wakeref 23062306a36Sopenharmony_ci * 23162306a36Sopenharmony_ci * Returns: true if the wakeref is currently held. 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_cistatic inline bool 23462306a36Sopenharmony_ciintel_wakeref_is_active(const struct intel_wakeref *wf) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci return READ_ONCE(wf->wakeref); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci/** 24062306a36Sopenharmony_ci * __intel_wakeref_defer_park: Defer the current park callback 24162306a36Sopenharmony_ci * @wf: the wakeref 24262306a36Sopenharmony_ci */ 24362306a36Sopenharmony_cistatic inline void 24462306a36Sopenharmony_ci__intel_wakeref_defer_park(struct intel_wakeref *wf) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci lockdep_assert_held(&wf->mutex); 24762306a36Sopenharmony_ci INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count)); 24862306a36Sopenharmony_ci atomic_set_release(&wf->count, 1); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci/** 25262306a36Sopenharmony_ci * intel_wakeref_wait_for_idle: Wait until the wakeref is idle 25362306a36Sopenharmony_ci * @wf: the wakeref 25462306a36Sopenharmony_ci * 25562306a36Sopenharmony_ci * Wait for the earlier asynchronous release of the wakeref. Note 25662306a36Sopenharmony_ci * this will wait for any third party as well, so make sure you only wait 25762306a36Sopenharmony_ci * when you have control over the wakeref and trust no one else is acquiring 25862306a36Sopenharmony_ci * it. 25962306a36Sopenharmony_ci * 26062306a36Sopenharmony_ci * Return: 0 on success, error code if killed. 26162306a36Sopenharmony_ci */ 26262306a36Sopenharmony_ciint intel_wakeref_wait_for_idle(struct intel_wakeref *wf); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistruct intel_wakeref_auto { 26562306a36Sopenharmony_ci struct drm_i915_private *i915; 26662306a36Sopenharmony_ci struct timer_list timer; 26762306a36Sopenharmony_ci intel_wakeref_t wakeref; 26862306a36Sopenharmony_ci spinlock_t lock; 26962306a36Sopenharmony_ci refcount_t count; 27062306a36Sopenharmony_ci}; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/** 27362306a36Sopenharmony_ci * intel_wakeref_auto: Delay the runtime-pm autosuspend 27462306a36Sopenharmony_ci * @wf: the wakeref 27562306a36Sopenharmony_ci * @timeout: relative timeout in jiffies 27662306a36Sopenharmony_ci * 27762306a36Sopenharmony_ci * The runtime-pm core uses a suspend delay after the last wakeref 27862306a36Sopenharmony_ci * is released before triggering runtime suspend of the device. That 27962306a36Sopenharmony_ci * delay is configurable via sysfs with little regard to the device 28062306a36Sopenharmony_ci * characteristics. Instead, we want to tune the autosuspend based on our 28162306a36Sopenharmony_ci * HW knowledge. intel_wakeref_auto() delays the sleep by the supplied 28262306a36Sopenharmony_ci * timeout. 28362306a36Sopenharmony_ci * 28462306a36Sopenharmony_ci * Pass @timeout = 0 to cancel a previous autosuspend by executing the 28562306a36Sopenharmony_ci * suspend immediately. 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_civoid intel_wakeref_auto(struct intel_wakeref_auto *wf, unsigned long timeout); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_civoid intel_wakeref_auto_init(struct intel_wakeref_auto *wf, 29062306a36Sopenharmony_ci struct drm_i915_private *i915); 29162306a36Sopenharmony_civoid intel_wakeref_auto_fini(struct intel_wakeref_auto *wf); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci#endif /* INTEL_WAKEREF_H */ 294