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