Branch data Line data Source code
1 : : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 : : /*
3 : : * run something, but later.
4 : : *
5 : : * Timers are run when the SBE timer interrupt triggers (based on us setting
6 : : * it) or when the regular heartbeat call from the OS occurs and there's a
7 : : * timer that's expired.
8 : : *
9 : : * Copyright 2014-2019 IBM Corp.
10 : : */
11 : :
12 : : #include <timer.h>
13 : : #include <timebase.h>
14 : : #include <lock.h>
15 : : #include <fsp.h>
16 : : #include <device.h>
17 : : #include <opal.h>
18 : : #include <sbe.h>
19 : :
20 : : #ifdef __TEST__
21 : : #define this_cpu() ((void *)-1)
22 : : #define cpu_relax()
23 : : #else
24 : : #include <cpu.h>
25 : : #endif
26 : :
27 : : /* Heartbeat requested from Linux */
28 : : #define HEARTBEAT_DEFAULT_MS 200
29 : :
30 : : static struct lock timer_lock = LOCK_UNLOCKED;
31 : : static LIST_HEAD(timer_list);
32 : : static LIST_HEAD(timer_poll_list);
33 : : static bool timer_in_poll;
34 : : static uint64_t timer_poll_gen;
35 : :
36 : 100 : static inline void update_timer_expiry(uint64_t target)
37 : : {
38 : 100 : if (sbe_timer_ok())
39 : 100 : sbe_update_timer_expiry(target);
40 : 100 : }
41 : :
42 : 100 : void init_timer(struct timer *t, timer_func_t expiry, void *data)
43 : : {
44 : 100 : t->link.next = t->link.prev = NULL;
45 : 100 : t->target = 0;
46 : 100 : t->expiry = expiry;
47 : 100 : t->user_data = data;
48 : 100 : t->running = NULL;
49 : 100 : }
50 : :
51 : 100 : static void __remove_timer(struct timer *t)
52 : : {
53 : 100 : list_del(&t->link);
54 : 100 : t->link.next = t->link.prev = NULL;
55 : 100 : }
56 : :
57 : 0 : static void __sync_timer(struct timer *t)
58 : : {
59 : : sync();
60 : :
61 : : /* Guard against re-entrancy */
62 : 0 : assert(t->running != this_cpu());
63 : :
64 : 0 : while (t->running) {
65 : 0 : unlock(&timer_lock);
66 : : smt_lowest();
67 : 0 : while (t->running)
68 : 0 : barrier();
69 : : smt_medium();
70 : : /* Should we call the pollers here ? */
71 : 0 : lock(&timer_lock);
72 : : }
73 : 0 : }
74 : :
75 : 0 : void sync_timer(struct timer *t)
76 : : {
77 : 0 : lock(&timer_lock);
78 : 0 : __sync_timer(t);
79 : 0 : unlock(&timer_lock);
80 : 0 : }
81 : :
82 : 0 : void cancel_timer(struct timer *t)
83 : : {
84 : 0 : lock(&timer_lock);
85 : 0 : __sync_timer(t);
86 : 0 : if (t->link.next)
87 : 0 : __remove_timer(t);
88 : 0 : unlock(&timer_lock);
89 : 0 : }
90 : :
91 : 0 : void cancel_timer_async(struct timer *t)
92 : : {
93 : 0 : lock(&timer_lock);
94 : 0 : if (t->link.next)
95 : 0 : __remove_timer(t);
96 : 0 : unlock(&timer_lock);
97 : 0 : }
98 : :
99 : 100 : static void __schedule_timer_at(struct timer *t, uint64_t when)
100 : : {
101 : : struct timer *lt;
102 : :
103 : : /* If the timer is already scheduled, take it out */
104 : 100 : if (t->link.next)
105 : 0 : __remove_timer(t);
106 : :
107 : : /* Update target */
108 : 100 : t->target = when;
109 : :
110 : 100 : if (when == TIMER_POLL) {
111 : : /* It's a poller, add it to the poller list */
112 : 0 : t->gen = timer_poll_gen;
113 : 0 : list_add_tail(&timer_poll_list, &t->link);
114 : : } else {
115 : : /* It's a real timer, add it in the right spot in the
116 : : * ordered timer list
117 : : */
118 : 2761 : list_for_each(&timer_list, lt, link) {
119 : 2757 : if (when >= lt->target)
120 : 2661 : continue;
121 : 96 : list_add_before(&timer_list, <->link, &t->link);
122 : 96 : goto bail;
123 : : }
124 : 4 : list_add_tail(&timer_list, &t->link);
125 : : }
126 : 100 : bail:
127 : : /* Pick up the next timer and upddate the SBE HW timer */
128 : 100 : lt = list_top(&timer_list, struct timer, link);
129 : 100 : if (lt) {
130 : 100 : update_timer_expiry(lt->target);
131 : : }
132 : 100 : }
133 : :
134 : 100 : void schedule_timer_at(struct timer *t, uint64_t when)
135 : : {
136 : 100 : lock(&timer_lock);
137 : 100 : __schedule_timer_at(t, when);
138 : 100 : unlock(&timer_lock);
139 : 100 : }
140 : :
141 : 100 : uint64_t schedule_timer(struct timer *t, uint64_t how_long)
142 : : {
143 : 100 : uint64_t now = mftb();
144 : :
145 : 100 : if (how_long == TIMER_POLL)
146 : 0 : schedule_timer_at(t, TIMER_POLL);
147 : : else
148 : 100 : schedule_timer_at(t, now + how_long);
149 : :
150 : 100 : return now;
151 : : }
152 : :
153 : 65466 : static void __check_poll_timers(uint64_t now)
154 : : {
155 : : struct timer *t;
156 : :
157 : : /* Don't call this from multiple CPUs at once */
158 : 65466 : if (timer_in_poll)
159 : 0 : return;
160 : 65466 : timer_in_poll = true;
161 : :
162 : : /*
163 : : * Poll timers might re-enqueue themselves and don't have an
164 : : * expiry so we can't do like normal timers and just run until
165 : : * we hit a wall. Instead, each timer has a generation count,
166 : : * which we set to the current global gen count when we schedule
167 : : * it and update when we run it. It will only be considered if
168 : : * the generation count is different than the current one. We
169 : : * don't try to compare generations being larger or smaller
170 : : * because at boot, this can be called quite quickly and I want
171 : : * to be safe vs. wraps.
172 : : */
173 : 65466 : timer_poll_gen++;
174 : : for (;;) {
175 : 65466 : t = list_top(&timer_poll_list, struct timer, link);
176 : :
177 : : /* Top timer has a different generation than current ? Must
178 : : * be older, we are done.
179 : : */
180 : 65466 : if (!t || t->gen == timer_poll_gen)
181 : : break;
182 : :
183 : : /* Top of list still running, we have to delay handling it,
184 : : * let's reprogram the SLW with a small delay. We chose
185 : : * arbitrarily 1us.
186 : : */
187 : 0 : if (t->running) {
188 : 0 : update_timer_expiry(now + usecs_to_tb(1));
189 : 0 : break;
190 : : }
191 : :
192 : : /* Allright, first remove it and mark it running */
193 : 0 : __remove_timer(t);
194 : 0 : t->running = this_cpu();
195 : :
196 : : /* Now we can unlock and call it's expiry */
197 : 0 : unlock(&timer_lock);
198 : 0 : t->expiry(t, t->user_data, now);
199 : :
200 : : /* Re-lock and mark not running */
201 : 0 : lock(&timer_lock);
202 : 0 : t->running = NULL;
203 : : }
204 : 65466 : timer_in_poll = false;
205 : : }
206 : :
207 : 65566 : static void __check_timers(uint64_t now)
208 : : {
209 : : struct timer *t;
210 : :
211 : : for (;;) {
212 : 65566 : t = list_top(&timer_list, struct timer, link);
213 : :
214 : : /* Top of list not expired ? that's it ... */
215 : 65566 : if (!t || t->target > now)
216 : : break;
217 : :
218 : : /* Top of list still running, we have to delay handling
219 : : * it. For now just skip until the next poll, when we have
220 : : * SLW interrupts, we'll probably want to trip another one
221 : : * ASAP
222 : : */
223 : 100 : if (t->running)
224 : 0 : break;
225 : :
226 : : /* Allright, first remove it and mark it running */
227 : 100 : __remove_timer(t);
228 : 100 : t->running = this_cpu();
229 : :
230 : : /* Now we can unlock and call it's expiry */
231 : 100 : unlock(&timer_lock);
232 : 100 : t->expiry(t, t->user_data, now);
233 : :
234 : : /* Re-lock and mark not running */
235 : 100 : lock(&timer_lock);
236 : 100 : t->running = NULL;
237 : :
238 : : /* Update time stamp */
239 : 100 : now = mftb();
240 : : }
241 : 65466 : }
242 : :
243 : 65466 : void check_timers(bool from_interrupt)
244 : : {
245 : 65466 : uint64_t now = mftb();
246 : :
247 : : /* This is the polling variant, the SLW interrupt path, when it
248 : : * exists, will use a slight variant of this that doesn't call
249 : : * the pollers
250 : : */
251 : :
252 : : /* Lockless "peek", a bit racy but shouldn't be a problem as
253 : : * we are only looking at whether the list is empty
254 : : */
255 : 130932 : if (list_empty_nocheck(&timer_poll_list) &&
256 : 65466 : list_empty_nocheck(&timer_list))
257 : 0 : return;
258 : :
259 : : /* Take lock and try again */
260 : 65466 : lock(&timer_lock);
261 : 65466 : if (!from_interrupt)
262 : 65466 : __check_poll_timers(now);
263 : 65466 : __check_timers(now);
264 : 65466 : unlock(&timer_lock);
265 : : }
266 : :
267 : : #ifndef __TEST__
268 : :
269 : : void late_init_timers(void)
270 : : {
271 : : int heartbeat = HEARTBEAT_DEFAULT_MS;
272 : :
273 : : /* Add a property requesting the OS to call opal_poll_event() at
274 : : * a specified interval in order for us to run our background
275 : : * low priority pollers.
276 : : *
277 : : * If a platform quirk exists, use that, else use the default.
278 : : *
279 : : * If we have an SBE timer facility, we run this 10 times slower,
280 : : * we could possibly completely get rid of it.
281 : : *
282 : : * We use a value in milliseconds, we don't want this to ever be
283 : : * faster than that.
284 : : */
285 : : if (platform.heartbeat_time) {
286 : : heartbeat = platform.heartbeat_time();
287 : : } else if (sbe_timer_ok()) {
288 : : heartbeat = HEARTBEAT_DEFAULT_MS * 10;
289 : : }
290 : :
291 : : dt_add_property_cells(opal_node, "ibm,heartbeat-ms", heartbeat);
292 : : }
293 : : #endif
|