]> Git Repo - linux.git/blob - drivers/gpu/drm/i915/intel_wakeref.h
Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
[linux.git] / drivers / gpu / drm / i915 / intel_wakeref.h
1 /*
2  * SPDX-License-Identifier: MIT
3  *
4  * Copyright © 2019 Intel Corporation
5  */
6
7 #ifndef INTEL_WAKEREF_H
8 #define INTEL_WAKEREF_H
9
10 #include <linux/atomic.h>
11 #include <linux/bits.h>
12 #include <linux/lockdep.h>
13 #include <linux/mutex.h>
14 #include <linux/refcount.h>
15 #include <linux/stackdepot.h>
16 #include <linux/timer.h>
17 #include <linux/workqueue.h>
18
19 #if IS_ENABLED(CONFIG_DRM_I915_DEBUG)
20 #define INTEL_WAKEREF_BUG_ON(expr) BUG_ON(expr)
21 #else
22 #define INTEL_WAKEREF_BUG_ON(expr) BUILD_BUG_ON_INVALID(expr)
23 #endif
24
25 struct intel_runtime_pm;
26 struct intel_wakeref;
27
28 typedef depot_stack_handle_t intel_wakeref_t;
29
30 struct intel_wakeref_ops {
31         int (*get)(struct intel_wakeref *wf);
32         int (*put)(struct intel_wakeref *wf);
33 };
34
35 struct intel_wakeref {
36         atomic_t count;
37         struct mutex mutex;
38
39         intel_wakeref_t wakeref;
40
41         struct intel_runtime_pm *rpm;
42         const struct intel_wakeref_ops *ops;
43
44         struct work_struct work;
45 };
46
47 void __intel_wakeref_init(struct intel_wakeref *wf,
48                           struct intel_runtime_pm *rpm,
49                           const struct intel_wakeref_ops *ops,
50                           struct lock_class_key *key);
51 #define intel_wakeref_init(wf, rpm, ops) do {                           \
52         static struct lock_class_key __key;                             \
53                                                                         \
54         __intel_wakeref_init((wf), (rpm), (ops), &__key);               \
55 } while (0)
56
57 int __intel_wakeref_get_first(struct intel_wakeref *wf);
58 void __intel_wakeref_put_last(struct intel_wakeref *wf, unsigned long flags);
59
60 /**
61  * intel_wakeref_get: Acquire the wakeref
62  * @i915: the drm_i915_private device
63  * @wf: the wakeref
64  * @fn: callback for acquired the wakeref, called only on first acquire.
65  *
66  * Acquire a hold on the wakeref. The first user to do so, will acquire
67  * the runtime pm wakeref and then call the @fn underneath the wakeref
68  * mutex.
69  *
70  * Note that @fn is allowed to fail, in which case the runtime-pm wakeref
71  * will be released and the acquisition unwound, and an error reported.
72  *
73  * Returns: 0 if the wakeref was acquired successfully, or a negative error
74  * code otherwise.
75  */
76 static inline int
77 intel_wakeref_get(struct intel_wakeref *wf)
78 {
79         if (unlikely(!atomic_inc_not_zero(&wf->count)))
80                 return __intel_wakeref_get_first(wf);
81
82         return 0;
83 }
84
85 /**
86  * intel_wakeref_get_if_in_use: Acquire the wakeref
87  * @wf: the wakeref
88  *
89  * Acquire a hold on the wakeref, but only if the wakeref is already
90  * active.
91  *
92  * Returns: true if the wakeref was acquired, false otherwise.
93  */
94 static inline bool
95 intel_wakeref_get_if_active(struct intel_wakeref *wf)
96 {
97         return atomic_inc_not_zero(&wf->count);
98 }
99
100 /**
101  * intel_wakeref_put_flags: Release the wakeref
102  * @wf: the wakeref
103  * @flags: control flags
104  *
105  * Release our hold on the wakeref. When there are no more users,
106  * the runtime pm wakeref will be released after the @fn callback is called
107  * underneath the wakeref mutex.
108  *
109  * Note that @fn is allowed to fail, in which case the runtime-pm wakeref
110  * is retained and an error reported.
111  *
112  * Returns: 0 if the wakeref was released successfully, or a negative error
113  * code otherwise.
114  */
115 static inline void
116 __intel_wakeref_put(struct intel_wakeref *wf, unsigned long flags)
117 #define INTEL_WAKEREF_PUT_ASYNC BIT(0)
118 {
119         INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count) <= 0);
120         if (unlikely(!atomic_add_unless(&wf->count, -1, 1)))
121                 __intel_wakeref_put_last(wf, flags);
122 }
123
124 static inline void
125 intel_wakeref_put(struct intel_wakeref *wf)
126 {
127         might_sleep();
128         __intel_wakeref_put(wf, 0);
129 }
130
131 static inline void
132 intel_wakeref_put_async(struct intel_wakeref *wf)
133 {
134         __intel_wakeref_put(wf, INTEL_WAKEREF_PUT_ASYNC);
135 }
136
137 /**
138  * intel_wakeref_lock: Lock the wakeref (mutex)
139  * @wf: the wakeref
140  *
141  * Locks the wakeref to prevent it being acquired or released. New users
142  * can still adjust the counter, but the wakeref itself (and callback)
143  * cannot be acquired or released.
144  */
145 static inline void
146 intel_wakeref_lock(struct intel_wakeref *wf)
147         __acquires(wf->mutex)
148 {
149         mutex_lock(&wf->mutex);
150 }
151
152 /**
153  * intel_wakeref_unlock: Unlock the wakeref
154  * @wf: the wakeref
155  *
156  * Releases a previously acquired intel_wakeref_lock().
157  */
158 static inline void
159 intel_wakeref_unlock(struct intel_wakeref *wf)
160         __releases(wf->mutex)
161 {
162         mutex_unlock(&wf->mutex);
163 }
164
165 /**
166  * intel_wakeref_unlock_wait: Wait until the active callback is complete
167  * @wf: the wakeref
168  *
169  * Waits for the active callback (under the @wf->mutex or another CPU) is
170  * complete.
171  */
172 static inline void
173 intel_wakeref_unlock_wait(struct intel_wakeref *wf)
174 {
175         mutex_lock(&wf->mutex);
176         mutex_unlock(&wf->mutex);
177         flush_work(&wf->work);
178 }
179
180 /**
181  * intel_wakeref_is_active: Query whether the wakeref is currently held
182  * @wf: the wakeref
183  *
184  * Returns: true if the wakeref is currently held.
185  */
186 static inline bool
187 intel_wakeref_is_active(const struct intel_wakeref *wf)
188 {
189         return READ_ONCE(wf->wakeref);
190 }
191
192 /**
193  * __intel_wakeref_defer_park: Defer the current park callback
194  * @wf: the wakeref
195  */
196 static inline void
197 __intel_wakeref_defer_park(struct intel_wakeref *wf)
198 {
199         lockdep_assert_held(&wf->mutex);
200         INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count));
201         atomic_set_release(&wf->count, 1);
202 }
203
204 /**
205  * intel_wakeref_wait_for_idle: Wait until the wakeref is idle
206  * @wf: the wakeref
207  *
208  * Wait for the earlier asynchronous release of the wakeref. Note
209  * this will wait for any third party as well, so make sure you only wait
210  * when you have control over the wakeref and trust no one else is acquiring
211  * it.
212  *
213  * Return: 0 on success, error code if killed.
214  */
215 int intel_wakeref_wait_for_idle(struct intel_wakeref *wf);
216
217 struct intel_wakeref_auto {
218         struct intel_runtime_pm *rpm;
219         struct timer_list timer;
220         intel_wakeref_t wakeref;
221         spinlock_t lock;
222         refcount_t count;
223 };
224
225 /**
226  * intel_wakeref_auto: Delay the runtime-pm autosuspend
227  * @wf: the wakeref
228  * @timeout: relative timeout in jiffies
229  *
230  * The runtime-pm core uses a suspend delay after the last wakeref
231  * is released before triggering runtime suspend of the device. That
232  * delay is configurable via sysfs with little regard to the device
233  * characteristics. Instead, we want to tune the autosuspend based on our
234  * HW knowledge. intel_wakeref_auto() delays the sleep by the supplied
235  * timeout.
236  *
237  * Pass @timeout = 0 to cancel a previous autosuspend by executing the
238  * suspend immediately.
239  */
240 void intel_wakeref_auto(struct intel_wakeref_auto *wf, unsigned long timeout);
241
242 void intel_wakeref_auto_init(struct intel_wakeref_auto *wf,
243                              struct intel_runtime_pm *rpm);
244 void intel_wakeref_auto_fini(struct intel_wakeref_auto *wf);
245
246 #endif /* INTEL_WAKEREF_H */
This page took 0.047678 seconds and 4 git commands to generate.