FILE
intel_wakeref.h
File preview with syntax highlighting.
linux-6.19.14/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/bitfield.h> 12#include <linux/bits.h> 13#include <linux/lockdep.h> 14#include <linux/mutex.h> 15#include <linux/refcount.h> 16#include <linux/ref_tracker.h> 17#include <linux/timer.h> 18#include <linux/workqueue.h> 19 20struct drm_printer; 21struct intel_runtime_pm; 22struct intel_wakeref; 23 24typedef struct ref_tracker *intel_wakeref_t; 25 26#define INTEL_REFTRACK_DEAD_COUNT 16 27#define INTEL_REFTRACK_PRINT_LIMIT 16 28 29#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) 30#define INTEL_WAKEREF_BUG_ON(expr) BUG_ON(expr) 31#else 32#define INTEL_WAKEREF_BUG_ON(expr) BUILD_BUG_ON_INVALID(expr) 33#endif 34 35struct intel_wakeref_ops { 36 int (*get)(struct intel_wakeref *wf); 37 int (*put)(struct intel_wakeref *wf); 38}; 39 40struct intel_wakeref { 41 atomic_t count; 42 struct mutex mutex; 43 44 intel_wakeref_t wakeref; 45 46 struct drm_i915_private *i915; 47 const struct intel_wakeref_ops *ops; 48 49 struct delayed_work work; 50 51#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) 52 struct ref_tracker_dir debug; 53#endif 54}; 55 56struct intel_wakeref_lockclass { 57 struct lock_class_key mutex; 58 struct lock_class_key work; 59}; 60 61void __intel_wakeref_init(struct intel_wakeref *wf, 62 struct drm_i915_private *i915, 63 const struct intel_wakeref_ops *ops, 64 struct intel_wakeref_lockclass *key, 65 const char *name); 66#define intel_wakeref_init(wf, i915, ops, name) do { \ 67 static struct intel_wakeref_lockclass __key; \ 68 \ 69 __intel_wakeref_init((wf), (i915), (ops), &__key, name); \ 70} while (0) 71 72int __intel_wakeref_get_first(struct intel_wakeref *wf); 73void __intel_wakeref_put_last(struct intel_wakeref *wf, unsigned long flags); 74 75/** 76 * intel_wakeref_get: Acquire the wakeref 77 * @wf: the wakeref 78 * 79 * Acquire a hold on the wakeref. The first user to do so, will acquire 80 * the runtime pm wakeref and then call the intel_wakeref_ops->get() 81 * underneath the wakeref mutex. 82 * 83 * Note that intel_wakeref_ops->get() is allowed to fail, in which case 84 * the runtime-pm wakeref will be released and the acquisition unwound, 85 * and an error reported. 86 * 87 * Returns: 0 if the wakeref was acquired successfully, or a negative error 88 * code otherwise. 89 */ 90static inline int 91intel_wakeref_get(struct intel_wakeref *wf) 92{ 93 might_sleep(); 94 if (unlikely(!atomic_inc_not_zero(&wf->count))) 95 return __intel_wakeref_get_first(wf); 96 97 return 0; 98} 99 100/** 101 * __intel_wakeref_get: Acquire the wakeref, again 102 * @wf: the wakeref 103 * 104 * Increment the wakeref counter, only valid if it is already held by 105 * the caller. 106 * 107 * See intel_wakeref_get(). 108 */ 109static inline void 110__intel_wakeref_get(struct intel_wakeref *wf) 111{ 112 INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count) <= 0); 113 atomic_inc(&wf->count); 114} 115 116/** 117 * intel_wakeref_get_if_active: Acquire the wakeref 118 * @wf: the wakeref 119 * 120 * Acquire a hold on the wakeref, but only if the wakeref is already 121 * active. 122 * 123 * Returns: true if the wakeref was acquired, false otherwise. 124 */ 125static inline bool 126intel_wakeref_get_if_active(struct intel_wakeref *wf) 127{ 128 return atomic_inc_not_zero(&wf->count); 129} 130 131static inline void 132intel_wakeref_might_get(struct intel_wakeref *wf) 133{ 134 might_lock(&wf->mutex); 135} 136 137/* flags for __intel_wakeref_put() and __intel_wakeref_put_last */ 138#define INTEL_WAKEREF_PUT_ASYNC BIT(0) 139#define INTEL_WAKEREF_PUT_DELAY_MASK GENMASK(BITS_PER_LONG - 1, 1) 140 141/** 142 * __intel_wakeref_put: Release the wakeref 143 * @wf: the wakeref 144 * @flags: control flags 145 * 146 * Release our hold on the wakeref. When there are no more users, 147 * the runtime pm wakeref will be released after the intel_wakeref_ops->put() 148 * callback is called underneath the wakeref mutex. 149 * 150 * Note that intel_wakeref_ops->put() is allowed to fail, in which case the 151 * runtime-pm wakeref is retained. 152 * 153 */ 154static inline void 155__intel_wakeref_put(struct intel_wakeref *wf, unsigned long flags) 156{ 157 INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count) <= 0); 158 if (unlikely(!atomic_add_unless(&wf->count, -1, 1))) 159 __intel_wakeref_put_last(wf, flags); 160} 161 162static inline void 163intel_wakeref_put(struct intel_wakeref *wf) 164{ 165 might_sleep(); 166 __intel_wakeref_put(wf, 0); 167} 168 169static inline void 170intel_wakeref_put_async(struct intel_wakeref *wf) 171{ 172 __intel_wakeref_put(wf, INTEL_WAKEREF_PUT_ASYNC); 173} 174 175static inline void 176intel_wakeref_put_delay(struct intel_wakeref *wf, unsigned long delay) 177{ 178 __intel_wakeref_put(wf, 179 INTEL_WAKEREF_PUT_ASYNC | 180 FIELD_PREP(INTEL_WAKEREF_PUT_DELAY_MASK, delay)); 181} 182 183static inline void 184intel_wakeref_might_put(struct intel_wakeref *wf) 185{ 186 might_lock(&wf->mutex); 187} 188 189/** 190 * intel_wakeref_lock: Lock the wakeref (mutex) 191 * @wf: the wakeref 192 * 193 * Locks the wakeref to prevent it being acquired or released. New users 194 * can still adjust the counter, but the wakeref itself (and callback) 195 * cannot be acquired or released. 196 */ 197static inline void 198intel_wakeref_lock(struct intel_wakeref *wf) 199 __acquires(wf->mutex) 200{ 201 mutex_lock(&wf->mutex); 202} 203 204/** 205 * intel_wakeref_unlock: Unlock the wakeref 206 * @wf: the wakeref 207 * 208 * Releases a previously acquired intel_wakeref_lock(). 209 */ 210static inline void 211intel_wakeref_unlock(struct intel_wakeref *wf) 212 __releases(wf->mutex) 213{ 214 mutex_unlock(&wf->mutex); 215} 216 217/** 218 * intel_wakeref_unlock_wait: Wait until the active callback is complete 219 * @wf: the wakeref 220 * 221 * Waits for the active callback (under the @wf->mutex or another CPU) is 222 * complete. 223 */ 224static inline void 225intel_wakeref_unlock_wait(struct intel_wakeref *wf) 226{ 227 mutex_lock(&wf->mutex); 228 mutex_unlock(&wf->mutex); 229 flush_delayed_work(&wf->work); 230} 231 232/** 233 * intel_wakeref_is_active: Query whether the wakeref is currently held 234 * @wf: the wakeref 235 * 236 * Returns: true if the wakeref is currently held. 237 */ 238static inline bool 239intel_wakeref_is_active(const struct intel_wakeref *wf) 240{ 241 return READ_ONCE(wf->wakeref); 242} 243 244/** 245 * __intel_wakeref_defer_park: Defer the current park callback 246 * @wf: the wakeref 247 */ 248static inline void 249__intel_wakeref_defer_park(struct intel_wakeref *wf) 250{ 251 lockdep_assert_held(&wf->mutex); 252 INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count)); 253 atomic_set_release(&wf->count, 1); 254} 255 256/** 257 * intel_wakeref_wait_for_idle: Wait until the wakeref is idle 258 * @wf: the wakeref 259 * 260 * Wait for the earlier asynchronous release of the wakeref. Note 261 * this will wait for any third party as well, so make sure you only wait 262 * when you have control over the wakeref and trust no one else is acquiring 263 * it. 264 * 265 * Return: 0 on success, error code if killed. 266 */ 267int intel_wakeref_wait_for_idle(struct intel_wakeref *wf); 268 269#define INTEL_WAKEREF_DEF ERR_PTR(-ENOENT) 270 271static inline intel_wakeref_t intel_ref_tracker_alloc(struct ref_tracker_dir *dir) 272{ 273 struct ref_tracker *user = NULL; 274 275 ref_tracker_alloc(dir, &user, GFP_NOWAIT); 276 277 return user ?: INTEL_WAKEREF_DEF; 278} 279 280static inline void intel_ref_tracker_free(struct ref_tracker_dir *dir, 281 intel_wakeref_t wakeref) 282{ 283 if (wakeref == INTEL_WAKEREF_DEF) 284 wakeref = NULL; 285 286 if (WARN_ON(IS_ERR(wakeref))) 287 return; 288 289 ref_tracker_free(dir, &wakeref); 290} 291 292void intel_ref_tracker_show(struct ref_tracker_dir *dir, 293 struct drm_printer *p); 294 295#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) 296 297static inline intel_wakeref_t intel_wakeref_track(struct intel_wakeref *wf) 298{ 299 return intel_ref_tracker_alloc(&wf->debug); 300} 301 302static inline void intel_wakeref_untrack(struct intel_wakeref *wf, 303 intel_wakeref_t handle) 304{ 305 intel_ref_tracker_free(&wf->debug, handle); 306} 307 308#else 309 310static inline intel_wakeref_t intel_wakeref_track(struct intel_wakeref *wf) 311{ 312 return INTEL_WAKEREF_DEF; 313} 314 315static inline void intel_wakeref_untrack(struct intel_wakeref *wf, 316 intel_wakeref_t handle) 317{ 318} 319 320#endif 321 322struct intel_wakeref_auto { 323 struct drm_i915_private *i915; 324 struct timer_list timer; 325 intel_wakeref_t wakeref; 326 spinlock_t lock; 327 refcount_t count; 328}; 329 330/** 331 * intel_wakeref_auto: Delay the runtime-pm autosuspend 332 * @wf: the wakeref 333 * @timeout: relative timeout in jiffies 334 * 335 * The runtime-pm core uses a suspend delay after the last wakeref 336 * is released before triggering runtime suspend of the device. That 337 * delay is configurable via sysfs with little regard to the device 338 * characteristics. Instead, we want to tune the autosuspend based on our 339 * HW knowledge. intel_wakeref_auto() delays the sleep by the supplied 340 * timeout. 341 * 342 * Pass @timeout = 0 to cancel a previous autosuspend by executing the 343 * suspend immediately. 344 */ 345void intel_wakeref_auto(struct intel_wakeref_auto *wf, unsigned long timeout); 346 347void intel_wakeref_auto_init(struct intel_wakeref_auto *wf, 348 struct drm_i915_private *i915); 349void intel_wakeref_auto_fini(struct intel_wakeref_auto *wf); 350 351#endif /* INTEL_WAKEREF_H */
~/
Read-only file preview.