1d91e6578SChris Wilson /*
2d91e6578SChris Wilson  * SPDX-License-Identifier: MIT
3d91e6578SChris Wilson  *
4d91e6578SChris Wilson  * Copyright © 2019 Intel Corporation
5d91e6578SChris Wilson  */
6d91e6578SChris Wilson 
7d91e6578SChris Wilson #ifndef INTEL_WAKEREF_H
8d91e6578SChris Wilson #define INTEL_WAKEREF_H
9d91e6578SChris Wilson 
10d91e6578SChris Wilson #include <linux/atomic.h>
11e9037e7fSChris Wilson #include <linux/bitfield.h>
12c7302f20SChris Wilson #include <linux/bits.h>
1307779a76SChris Wilson #include <linux/lockdep.h>
14d91e6578SChris Wilson #include <linux/mutex.h>
15b27e35aeSChris Wilson #include <linux/refcount.h>
16d91e6578SChris Wilson #include <linux/stackdepot.h>
17b27e35aeSChris Wilson #include <linux/timer.h>
18c7302f20SChris Wilson #include <linux/workqueue.h>
19d91e6578SChris Wilson 
20fb993aa7SChris Wilson #if IS_ENABLED(CONFIG_DRM_I915_DEBUG)
21fb993aa7SChris Wilson #define INTEL_WAKEREF_BUG_ON(expr) BUG_ON(expr)
22fb993aa7SChris Wilson #else
23fb993aa7SChris Wilson #define INTEL_WAKEREF_BUG_ON(expr) BUILD_BUG_ON_INVALID(expr)
24fb993aa7SChris Wilson #endif
25fb993aa7SChris Wilson 
2658a111f0SDaniele Ceraolo Spurio struct intel_runtime_pm;
27c7302f20SChris Wilson struct intel_wakeref;
28d91e6578SChris Wilson 
29d91e6578SChris Wilson typedef depot_stack_handle_t intel_wakeref_t;
30d91e6578SChris Wilson 
31c7302f20SChris Wilson struct intel_wakeref_ops {
32c7302f20SChris Wilson 	int (*get)(struct intel_wakeref *wf);
33c7302f20SChris Wilson 	int (*put)(struct intel_wakeref *wf);
34c7302f20SChris Wilson };
35c7302f20SChris Wilson 
36d91e6578SChris Wilson struct intel_wakeref {
37d91e6578SChris Wilson 	atomic_t count;
38d91e6578SChris Wilson 	struct mutex mutex;
39c7302f20SChris Wilson 
40d91e6578SChris Wilson 	intel_wakeref_t wakeref;
41c7302f20SChris Wilson 
42*8d208a5eSLuca Coelho 	struct drm_i915_private *i915;
43c7302f20SChris Wilson 	const struct intel_wakeref_ops *ops;
44c7302f20SChris Wilson 
45e9037e7fSChris Wilson 	struct delayed_work work;
46d91e6578SChris Wilson };
47d91e6578SChris Wilson 
48cdd280b1SChris Wilson struct intel_wakeref_lockclass {
49cdd280b1SChris Wilson 	struct lock_class_key mutex;
50cdd280b1SChris Wilson 	struct lock_class_key work;
51cdd280b1SChris Wilson };
52cdd280b1SChris Wilson 
53d91e6578SChris Wilson void __intel_wakeref_init(struct intel_wakeref *wf,
54*8d208a5eSLuca Coelho 			  struct drm_i915_private *i915,
55c7302f20SChris Wilson 			  const struct intel_wakeref_ops *ops,
56cdd280b1SChris Wilson 			  struct intel_wakeref_lockclass *key);
57*8d208a5eSLuca Coelho #define intel_wakeref_init(wf, i915, ops) do {				\
58cdd280b1SChris Wilson 	static struct intel_wakeref_lockclass __key;			\
59d91e6578SChris Wilson 									\
60*8d208a5eSLuca Coelho 	__intel_wakeref_init((wf), (i915), (ops), &__key);		\
61d91e6578SChris Wilson } while (0)
62d91e6578SChris Wilson 
63c7302f20SChris Wilson int __intel_wakeref_get_first(struct intel_wakeref *wf);
6407779a76SChris Wilson void __intel_wakeref_put_last(struct intel_wakeref *wf, unsigned long flags);
65d91e6578SChris Wilson 
66d91e6578SChris Wilson /**
67d91e6578SChris Wilson  * intel_wakeref_get: Acquire the wakeref
68d91e6578SChris Wilson  * @wf: the wakeref
69d91e6578SChris Wilson  *
70d91e6578SChris Wilson  * Acquire a hold on the wakeref. The first user to do so, will acquire
717e095a4cSNirmoy Das  * the runtime pm wakeref and then call the intel_wakeref_ops->get()
727e095a4cSNirmoy Das  * underneath the wakeref mutex.
73d91e6578SChris Wilson  *
747e095a4cSNirmoy Das  * Note that intel_wakeref_ops->get() is allowed to fail, in which case
757e095a4cSNirmoy Das  * the runtime-pm wakeref will be released and the acquisition unwound,
767e095a4cSNirmoy Das  * and an error reported.
77d91e6578SChris Wilson  *
78d91e6578SChris Wilson  * Returns: 0 if the wakeref was acquired successfully, or a negative error
79d91e6578SChris Wilson  * code otherwise.
80d91e6578SChris Wilson  */
81d91e6578SChris Wilson static inline int
intel_wakeref_get(struct intel_wakeref * wf)82c7302f20SChris Wilson intel_wakeref_get(struct intel_wakeref *wf)
83d91e6578SChris Wilson {
8493b0e8feSChris Wilson 	might_sleep();
85d91e6578SChris Wilson 	if (unlikely(!atomic_inc_not_zero(&wf->count)))
86c7302f20SChris Wilson 		return __intel_wakeref_get_first(wf);
87d91e6578SChris Wilson 
88d91e6578SChris Wilson 	return 0;
89d91e6578SChris Wilson }
90d91e6578SChris Wilson 
91d91e6578SChris Wilson /**
9293b0e8feSChris Wilson  * __intel_wakeref_get: Acquire the wakeref, again
9393b0e8feSChris Wilson  * @wf: the wakeref
9493b0e8feSChris Wilson  *
9593b0e8feSChris Wilson  * Increment the wakeref counter, only valid if it is already held by
9693b0e8feSChris Wilson  * the caller.
9793b0e8feSChris Wilson  *
9893b0e8feSChris Wilson  * See intel_wakeref_get().
9993b0e8feSChris Wilson  */
10093b0e8feSChris Wilson static inline void
__intel_wakeref_get(struct intel_wakeref * wf)10193b0e8feSChris Wilson __intel_wakeref_get(struct intel_wakeref *wf)
10293b0e8feSChris Wilson {
10393b0e8feSChris Wilson 	INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count) <= 0);
10493b0e8feSChris Wilson 	atomic_inc(&wf->count);
10593b0e8feSChris Wilson }
10693b0e8feSChris Wilson 
10793b0e8feSChris Wilson /**
108b358793cSJani Nikula  * intel_wakeref_get_if_active: Acquire the wakeref
109de5147b8SChris Wilson  * @wf: the wakeref
110de5147b8SChris Wilson  *
111de5147b8SChris Wilson  * Acquire a hold on the wakeref, but only if the wakeref is already
112de5147b8SChris Wilson  * active.
113de5147b8SChris Wilson  *
114de5147b8SChris Wilson  * Returns: true if the wakeref was acquired, false otherwise.
115de5147b8SChris Wilson  */
116de5147b8SChris Wilson static inline bool
intel_wakeref_get_if_active(struct intel_wakeref * wf)117de5147b8SChris Wilson intel_wakeref_get_if_active(struct intel_wakeref *wf)
118de5147b8SChris Wilson {
119de5147b8SChris Wilson 	return atomic_inc_not_zero(&wf->count);
120de5147b8SChris Wilson }
121de5147b8SChris Wilson 
122e9037e7fSChris Wilson enum {
123e9037e7fSChris Wilson 	INTEL_WAKEREF_PUT_ASYNC_BIT = 0,
124e9037e7fSChris Wilson 	__INTEL_WAKEREF_PUT_LAST_BIT__
125e9037e7fSChris Wilson };
126e9037e7fSChris Wilson 
127f61eae18SMatthew Brost static inline void
intel_wakeref_might_get(struct intel_wakeref * wf)128f61eae18SMatthew Brost intel_wakeref_might_get(struct intel_wakeref *wf)
129f61eae18SMatthew Brost {
130f61eae18SMatthew Brost 	might_lock(&wf->mutex);
131f61eae18SMatthew Brost }
132f61eae18SMatthew Brost 
133de5147b8SChris Wilson /**
1347e095a4cSNirmoy Das  * __intel_wakeref_put: Release the wakeref
135d91e6578SChris Wilson  * @wf: the wakeref
13607779a76SChris Wilson  * @flags: control flags
137d91e6578SChris Wilson  *
138d91e6578SChris Wilson  * Release our hold on the wakeref. When there are no more users,
1397e095a4cSNirmoy Das  * the runtime pm wakeref will be released after the intel_wakeref_ops->put()
1407e095a4cSNirmoy Das  * callback is called underneath the wakeref mutex.
141d91e6578SChris Wilson  *
1427e095a4cSNirmoy Das  * Note that intel_wakeref_ops->put() is allowed to fail, in which case the
1437e095a4cSNirmoy Das  * runtime-pm wakeref is retained.
144d91e6578SChris Wilson  *
145d91e6578SChris Wilson  */
146c7302f20SChris Wilson static inline void
__intel_wakeref_put(struct intel_wakeref * wf,unsigned long flags)14707779a76SChris Wilson __intel_wakeref_put(struct intel_wakeref *wf, unsigned long flags)
148e9037e7fSChris Wilson #define INTEL_WAKEREF_PUT_ASYNC BIT(INTEL_WAKEREF_PUT_ASYNC_BIT)
149e9037e7fSChris Wilson #define INTEL_WAKEREF_PUT_DELAY \
150e9037e7fSChris Wilson 	GENMASK(BITS_PER_LONG - 1, __INTEL_WAKEREF_PUT_LAST_BIT__)
151d91e6578SChris Wilson {
152fb993aa7SChris Wilson 	INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count) <= 0);
153c7302f20SChris Wilson 	if (unlikely(!atomic_add_unless(&wf->count, -1, 1)))
15407779a76SChris Wilson 		__intel_wakeref_put_last(wf, flags);
15507779a76SChris Wilson }
15607779a76SChris Wilson 
15707779a76SChris Wilson static inline void
intel_wakeref_put(struct intel_wakeref * wf)15807779a76SChris Wilson intel_wakeref_put(struct intel_wakeref *wf)
15907779a76SChris Wilson {
16007779a76SChris Wilson 	might_sleep();
16107779a76SChris Wilson 	__intel_wakeref_put(wf, 0);
16207779a76SChris Wilson }
16307779a76SChris Wilson 
16407779a76SChris Wilson static inline void
intel_wakeref_put_async(struct intel_wakeref * wf)16507779a76SChris Wilson intel_wakeref_put_async(struct intel_wakeref *wf)
16607779a76SChris Wilson {
16707779a76SChris Wilson 	__intel_wakeref_put(wf, INTEL_WAKEREF_PUT_ASYNC);
168d91e6578SChris Wilson }
169d91e6578SChris Wilson 
170e9037e7fSChris Wilson static inline void
intel_wakeref_put_delay(struct intel_wakeref * wf,unsigned long delay)171e9037e7fSChris Wilson intel_wakeref_put_delay(struct intel_wakeref *wf, unsigned long delay)
172e9037e7fSChris Wilson {
173e9037e7fSChris Wilson 	__intel_wakeref_put(wf,
174e9037e7fSChris Wilson 			    INTEL_WAKEREF_PUT_ASYNC |
175e9037e7fSChris Wilson 			    FIELD_PREP(INTEL_WAKEREF_PUT_DELAY, delay));
176e9037e7fSChris Wilson }
177e9037e7fSChris Wilson 
178f61eae18SMatthew Brost static inline void
intel_wakeref_might_put(struct intel_wakeref * wf)179f61eae18SMatthew Brost intel_wakeref_might_put(struct intel_wakeref *wf)
180f61eae18SMatthew Brost {
181f61eae18SMatthew Brost 	might_lock(&wf->mutex);
182f61eae18SMatthew Brost }
183f61eae18SMatthew Brost 
184d91e6578SChris Wilson /**
185d91e6578SChris Wilson  * intel_wakeref_lock: Lock the wakeref (mutex)
186d91e6578SChris Wilson  * @wf: the wakeref
187d91e6578SChris Wilson  *
188d91e6578SChris Wilson  * Locks the wakeref to prevent it being acquired or released. New users
189d91e6578SChris Wilson  * can still adjust the counter, but the wakeref itself (and callback)
190d91e6578SChris Wilson  * cannot be acquired or released.
191d91e6578SChris Wilson  */
192d91e6578SChris Wilson static inline void
intel_wakeref_lock(struct intel_wakeref * wf)193d91e6578SChris Wilson intel_wakeref_lock(struct intel_wakeref *wf)
194d91e6578SChris Wilson 	__acquires(wf->mutex)
195d91e6578SChris Wilson {
196d91e6578SChris Wilson 	mutex_lock(&wf->mutex);
197d91e6578SChris Wilson }
198d91e6578SChris Wilson 
199d91e6578SChris Wilson /**
200d91e6578SChris Wilson  * intel_wakeref_unlock: Unlock the wakeref
201d91e6578SChris Wilson  * @wf: the wakeref
202d91e6578SChris Wilson  *
203d91e6578SChris Wilson  * Releases a previously acquired intel_wakeref_lock().
204d91e6578SChris Wilson  */
205d91e6578SChris Wilson static inline void
intel_wakeref_unlock(struct intel_wakeref * wf)206d91e6578SChris Wilson intel_wakeref_unlock(struct intel_wakeref *wf)
207d91e6578SChris Wilson 	__releases(wf->mutex)
208d91e6578SChris Wilson {
209d91e6578SChris Wilson 	mutex_unlock(&wf->mutex);
210d91e6578SChris Wilson }
211d91e6578SChris Wilson 
212d91e6578SChris Wilson /**
213f4ba0707SChris Wilson  * intel_wakeref_unlock_wait: Wait until the active callback is complete
214f4ba0707SChris Wilson  * @wf: the wakeref
215f4ba0707SChris Wilson  *
216f4ba0707SChris Wilson  * Waits for the active callback (under the @wf->mutex or another CPU) is
217f4ba0707SChris Wilson  * complete.
218f4ba0707SChris Wilson  */
219f4ba0707SChris Wilson static inline void
intel_wakeref_unlock_wait(struct intel_wakeref * wf)220f4ba0707SChris Wilson intel_wakeref_unlock_wait(struct intel_wakeref *wf)
221f4ba0707SChris Wilson {
222f4ba0707SChris Wilson 	mutex_lock(&wf->mutex);
223f4ba0707SChris Wilson 	mutex_unlock(&wf->mutex);
224e9037e7fSChris Wilson 	flush_delayed_work(&wf->work);
225f4ba0707SChris Wilson }
226f4ba0707SChris Wilson 
227f4ba0707SChris Wilson /**
2285f22e5b3SChris Wilson  * intel_wakeref_is_active: Query whether the wakeref is currently held
229d91e6578SChris Wilson  * @wf: the wakeref
230d91e6578SChris Wilson  *
231d91e6578SChris Wilson  * Returns: true if the wakeref is currently held.
232d91e6578SChris Wilson  */
233d91e6578SChris Wilson static inline bool
intel_wakeref_is_active(const struct intel_wakeref * wf)2345f22e5b3SChris Wilson intel_wakeref_is_active(const struct intel_wakeref *wf)
235d91e6578SChris Wilson {
2367ee280a7SChris Wilson 	return READ_ONCE(wf->wakeref);
237d91e6578SChris Wilson }
238d91e6578SChris Wilson 
239c7302f20SChris Wilson /**
240a79ca656SChris Wilson  * __intel_wakeref_defer_park: Defer the current park callback
241a79ca656SChris Wilson  * @wf: the wakeref
242a79ca656SChris Wilson  */
243a79ca656SChris Wilson static inline void
__intel_wakeref_defer_park(struct intel_wakeref * wf)244a79ca656SChris Wilson __intel_wakeref_defer_park(struct intel_wakeref *wf)
245a79ca656SChris Wilson {
24607779a76SChris Wilson 	lockdep_assert_held(&wf->mutex);
247a79ca656SChris Wilson 	INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count));
248a79ca656SChris Wilson 	atomic_set_release(&wf->count, 1);
249a79ca656SChris Wilson }
250a79ca656SChris Wilson 
251a79ca656SChris Wilson /**
252c7302f20SChris Wilson  * intel_wakeref_wait_for_idle: Wait until the wakeref is idle
253c7302f20SChris Wilson  * @wf: the wakeref
254c7302f20SChris Wilson  *
255c7302f20SChris Wilson  * Wait for the earlier asynchronous release of the wakeref. Note
256c7302f20SChris Wilson  * this will wait for any third party as well, so make sure you only wait
257c7302f20SChris Wilson  * when you have control over the wakeref and trust no one else is acquiring
258c7302f20SChris Wilson  * it.
259c7302f20SChris Wilson  *
260c7302f20SChris Wilson  * Return: 0 on success, error code if killed.
261c7302f20SChris Wilson  */
262c7302f20SChris Wilson int intel_wakeref_wait_for_idle(struct intel_wakeref *wf);
263c7302f20SChris Wilson 
264b27e35aeSChris Wilson struct intel_wakeref_auto {
265*8d208a5eSLuca Coelho 	struct drm_i915_private *i915;
266b27e35aeSChris Wilson 	struct timer_list timer;
267b27e35aeSChris Wilson 	intel_wakeref_t wakeref;
268b27e35aeSChris Wilson 	spinlock_t lock;
269b27e35aeSChris Wilson 	refcount_t count;
270b27e35aeSChris Wilson };
271b27e35aeSChris Wilson 
272b27e35aeSChris Wilson /**
273b27e35aeSChris Wilson  * intel_wakeref_auto: Delay the runtime-pm autosuspend
274b27e35aeSChris Wilson  * @wf: the wakeref
275b27e35aeSChris Wilson  * @timeout: relative timeout in jiffies
276b27e35aeSChris Wilson  *
277b27e35aeSChris Wilson  * The runtime-pm core uses a suspend delay after the last wakeref
278b27e35aeSChris Wilson  * is released before triggering runtime suspend of the device. That
279b27e35aeSChris Wilson  * delay is configurable via sysfs with little regard to the device
280b27e35aeSChris Wilson  * characteristics. Instead, we want to tune the autosuspend based on our
281b27e35aeSChris Wilson  * HW knowledge. intel_wakeref_auto() delays the sleep by the supplied
282b27e35aeSChris Wilson  * timeout.
283b27e35aeSChris Wilson  *
284b27e35aeSChris Wilson  * Pass @timeout = 0 to cancel a previous autosuspend by executing the
285b27e35aeSChris Wilson  * suspend immediately.
286b27e35aeSChris Wilson  */
287b27e35aeSChris Wilson void intel_wakeref_auto(struct intel_wakeref_auto *wf, unsigned long timeout);
288b27e35aeSChris Wilson 
289b27e35aeSChris Wilson void intel_wakeref_auto_init(struct intel_wakeref_auto *wf,
290*8d208a5eSLuca Coelho 			     struct drm_i915_private *i915);
291b27e35aeSChris Wilson void intel_wakeref_auto_fini(struct intel_wakeref_auto *wf);
292b27e35aeSChris Wilson 
293d91e6578SChris Wilson #endif /* INTEL_WAKEREF_H */
294