Branch data Line data Source code
1 : : /*
2 : : * SPDX-License-Identifier: MIT
3 : : *
4 : : * Copyright © 2019 Intel Corporation
5 : : */
6 : :
7 : : #include <linux/wait_bit.h>
8 : :
9 : : #include "intel_runtime_pm.h"
10 : : #include "intel_wakeref.h"
11 : :
12 : 0 : static void rpm_get(struct intel_wakeref *wf)
13 : : {
14 : 0 : wf->wakeref = intel_runtime_pm_get(wf->rpm);
15 : : }
16 : :
17 : 0 : static void rpm_put(struct intel_wakeref *wf)
18 : : {
19 : 0 : intel_wakeref_t wakeref = fetch_and_zero(&wf->wakeref);
20 : :
21 : 0 : intel_runtime_pm_put(wf->rpm, wakeref);
22 : 0 : INTEL_WAKEREF_BUG_ON(!wakeref);
23 : : }
24 : :
25 : 0 : int __intel_wakeref_get_first(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 : 0 : mutex_lock_nested(&wf->mutex, SINGLE_DEPTH_NESTING);
34 [ # # ]: 0 : if (!atomic_read(&wf->count)) {
35 : 0 : int err;
36 : :
37 : 0 : rpm_get(wf);
38 : :
39 : 0 : err = wf->ops->get(wf);
40 [ # # ]: 0 : if (unlikely(err)) {
41 : 0 : rpm_put(wf);
42 : 0 : mutex_unlock(&wf->mutex);
43 : 0 : return err;
44 : : }
45 : :
46 : 0 : smp_mb__before_atomic(); /* release wf->count */
47 : : }
48 : 0 : atomic_inc(&wf->count);
49 : 0 : mutex_unlock(&wf->mutex);
50 : :
51 : 0 : INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count) <= 0);
52 : 0 : return 0;
53 : : }
54 : :
55 : 0 : static void ____intel_wakeref_put_last(struct intel_wakeref *wf)
56 : : {
57 : 0 : INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count) <= 0);
58 [ # # ]: 0 : if (unlikely(!atomic_dec_and_test(&wf->count)))
59 : 0 : goto unlock;
60 : :
61 : : /* ops->put() must reschedule its own release on error/deferral */
62 [ # # ]: 0 : if (likely(!wf->ops->put(wf))) {
63 : 0 : rpm_put(wf);
64 : 0 : wake_up_var(&wf->wakeref);
65 : : }
66 : :
67 : 0 : unlock:
68 : 0 : mutex_unlock(&wf->mutex);
69 : 0 : }
70 : :
71 : 0 : void __intel_wakeref_put_last(struct intel_wakeref *wf, unsigned long flags)
72 : : {
73 : 0 : INTEL_WAKEREF_BUG_ON(work_pending(&wf->work));
74 : :
75 : : /* Assume we are not in process context and so cannot sleep. */
76 [ # # # # ]: 0 : if (flags & INTEL_WAKEREF_PUT_ASYNC || !mutex_trylock(&wf->mutex)) {
77 : 0 : schedule_work(&wf->work);
78 : 0 : return;
79 : : }
80 : :
81 : 0 : ____intel_wakeref_put_last(wf);
82 : : }
83 : :
84 : 0 : static void __intel_wakeref_put_work(struct work_struct *wrk)
85 : : {
86 : 0 : struct intel_wakeref *wf = container_of(wrk, typeof(*wf), work);
87 : :
88 [ # # ]: 0 : if (atomic_add_unless(&wf->count, -1, 1))
89 : : return;
90 : :
91 : 0 : mutex_lock(&wf->mutex);
92 : 0 : ____intel_wakeref_put_last(wf);
93 : : }
94 : :
95 : 0 : void __intel_wakeref_init(struct intel_wakeref *wf,
96 : : struct intel_runtime_pm *rpm,
97 : : const struct intel_wakeref_ops *ops,
98 : : struct intel_wakeref_lockclass *key)
99 : : {
100 : 0 : wf->rpm = rpm;
101 : 0 : wf->ops = ops;
102 : :
103 : 0 : __mutex_init(&wf->mutex, "wakeref.mutex", &key->mutex);
104 : 0 : atomic_set(&wf->count, 0);
105 : 0 : wf->wakeref = 0;
106 : :
107 : 0 : INIT_WORK(&wf->work, __intel_wakeref_put_work);
108 : 0 : lockdep_init_map(&wf->work.lockdep_map, "wakeref.work", &key->work, 0);
109 : 0 : }
110 : :
111 : 0 : int intel_wakeref_wait_for_idle(struct intel_wakeref *wf)
112 : : {
113 : 0 : int err;
114 : :
115 : 0 : might_sleep();
116 : :
117 [ # # # # : 0 : err = wait_var_event_killable(&wf->wakeref,
# # ]
118 : : !intel_wakeref_is_active(wf));
119 [ # # ]: 0 : if (err)
120 : : return err;
121 : :
122 : 0 : intel_wakeref_unlock_wait(wf);
123 : 0 : return 0;
124 : : }
125 : :
126 : 0 : static void wakeref_auto_timeout(struct timer_list *t)
127 : : {
128 : 0 : struct intel_wakeref_auto *wf = from_timer(wf, t, timer);
129 : 0 : intel_wakeref_t wakeref;
130 : 0 : unsigned long flags;
131 : :
132 [ # # ]: 0 : if (!refcount_dec_and_lock_irqsave(&wf->count, &wf->lock, &flags))
133 : 0 : return;
134 : :
135 : 0 : wakeref = fetch_and_zero(&wf->wakeref);
136 : 0 : spin_unlock_irqrestore(&wf->lock, flags);
137 : :
138 : 0 : intel_runtime_pm_put(wf->rpm, wakeref);
139 : : }
140 : :
141 : 0 : void intel_wakeref_auto_init(struct intel_wakeref_auto *wf,
142 : : struct intel_runtime_pm *rpm)
143 : : {
144 : 0 : spin_lock_init(&wf->lock);
145 : 0 : timer_setup(&wf->timer, wakeref_auto_timeout, 0);
146 : 0 : refcount_set(&wf->count, 0);
147 : 0 : wf->wakeref = 0;
148 : 0 : wf->rpm = rpm;
149 : 0 : }
150 : :
151 : 0 : void intel_wakeref_auto(struct intel_wakeref_auto *wf, unsigned long timeout)
152 : : {
153 : 0 : unsigned long flags;
154 : :
155 [ # # ]: 0 : if (!timeout) {
156 [ # # ]: 0 : if (del_timer_sync(&wf->timer))
157 : 0 : wakeref_auto_timeout(&wf->timer);
158 : 0 : return;
159 : : }
160 : :
161 : : /* Our mission is that we only extend an already active wakeref */
162 : 0 : assert_rpm_wakelock_held(wf->rpm);
163 : :
164 [ # # ]: 0 : if (!refcount_inc_not_zero(&wf->count)) {
165 : 0 : spin_lock_irqsave(&wf->lock, flags);
166 [ # # ]: 0 : if (!refcount_inc_not_zero(&wf->count)) {
167 : 0 : INTEL_WAKEREF_BUG_ON(wf->wakeref);
168 : 0 : wf->wakeref = intel_runtime_pm_get_if_in_use(wf->rpm);
169 : 0 : refcount_set(&wf->count, 1);
170 : : }
171 : 0 : spin_unlock_irqrestore(&wf->lock, flags);
172 : : }
173 : :
174 : : /*
175 : : * If we extend a pending timer, we will only get a single timer
176 : : * callback and so need to cancel the local inc by running the
177 : : * elided callback to keep the wf->count balanced.
178 : : */
179 [ # # ]: 0 : if (mod_timer(&wf->timer, jiffies + timeout))
180 : 0 : wakeref_auto_timeout(&wf->timer);
181 : : }
182 : :
183 : 0 : void intel_wakeref_auto_fini(struct intel_wakeref_auto *wf)
184 : : {
185 : 0 : intel_wakeref_auto(wf, 0);
186 : 0 : INTEL_WAKEREF_BUG_ON(wf->wakeref);
187 : 0 : }
|