1 /* 2 * SPDX-License-Identifier: MIT 3 * 4 * Copyright © 2019 Intel Corporation 5 */ 6 7 #include "intel_drv.h" 8 #include "intel_wakeref.h" 9 10 static void rpm_get(struct drm_i915_private *i915, struct intel_wakeref *wf) 11 { 12 wf->wakeref = intel_runtime_pm_get(i915); 13 } 14 15 static void rpm_put(struct drm_i915_private *i915, struct intel_wakeref *wf) 16 { 17 intel_wakeref_t wakeref = fetch_and_zero(&wf->wakeref); 18 19 intel_runtime_pm_put(i915, wakeref); 20 GEM_BUG_ON(!wakeref); 21 } 22 23 int __intel_wakeref_get_first(struct drm_i915_private *i915, 24 struct intel_wakeref *wf, 25 int (*fn)(struct intel_wakeref *wf)) 26 { 27 /* 28 * Treat get/put as different subclasses, as we may need to run 29 * the put callback from under the shrinker and do not want to 30 * cross-contanimate that callback with any extra work performed 31 * upon acquiring the wakeref. 32 */ 33 mutex_lock_nested(&wf->mutex, SINGLE_DEPTH_NESTING); 34 if (!atomic_read(&wf->count)) { 35 int err; 36 37 rpm_get(i915, wf); 38 39 err = fn(wf); 40 if (unlikely(err)) { 41 rpm_put(i915, wf); 42 mutex_unlock(&wf->mutex); 43 return err; 44 } 45 46 smp_mb__before_atomic(); /* release wf->count */ 47 } 48 atomic_inc(&wf->count); 49 mutex_unlock(&wf->mutex); 50 51 return 0; 52 } 53 54 int __intel_wakeref_put_last(struct drm_i915_private *i915, 55 struct intel_wakeref *wf, 56 int (*fn)(struct intel_wakeref *wf)) 57 { 58 int err; 59 60 err = fn(wf); 61 if (likely(!err)) 62 rpm_put(i915, wf); 63 else 64 atomic_inc(&wf->count); 65 mutex_unlock(&wf->mutex); 66 67 return err; 68 } 69 70 void __intel_wakeref_init(struct intel_wakeref *wf, struct lock_class_key *key) 71 { 72 __mutex_init(&wf->mutex, "wakeref", key); 73 atomic_set(&wf->count, 0); 74 wf->wakeref = 0; 75 } 76