1
2
3
4
5
6
7
8
9#include "qemu/osdep.h"
10#include "hw/ptimer.h"
11#include "migration/vmstate.h"
12#include "qemu/host-utils.h"
13#include "sysemu/replay.h"
14#include "sysemu/cpu-timers.h"
15#include "sysemu/qtest.h"
16#include "block/aio.h"
17#include "sysemu/cpus.h"
18#include "hw/clock.h"
19
20#define DELTA_ADJUST 1
21#define DELTA_NO_ADJUST -1
22
23struct ptimer_state
24{
25 uint8_t enabled;
26 uint64_t limit;
27 uint64_t delta;
28 uint32_t period_frac;
29 int64_t period;
30 int64_t last_event;
31 int64_t next_event;
32 uint8_t policy_mask;
33 QEMUTimer *timer;
34 ptimer_cb callback;
35 void *callback_opaque;
36
37
38
39
40
41
42 bool in_transaction;
43 bool need_reload;
44};
45
46
47static void ptimer_trigger(ptimer_state *s)
48{
49 s->callback(s->callback_opaque);
50}
51
52static void ptimer_reload(ptimer_state *s, int delta_adjust)
53{
54 uint32_t period_frac;
55 uint64_t period;
56 uint64_t delta;
57 bool suppress_trigger = false;
58
59
60
61
62
63
64
65 if (delta_adjust == 0 &&
66 (s->policy_mask & PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT)) {
67 suppress_trigger = true;
68 }
69 if (s->delta == 0 && !(s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)
70 && !suppress_trigger) {
71 ptimer_trigger(s);
72 }
73
74
75
76
77
78
79 delta = s->delta;
80 period = s->period;
81 period_frac = s->period_frac;
82
83 if (delta == 0 && !(s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_RELOAD)) {
84 delta = s->delta = s->limit;
85 }
86
87 if (s->period == 0) {
88 if (!qtest_enabled()) {
89 fprintf(stderr, "Timer with period zero, disabling\n");
90 }
91 timer_del(s->timer);
92 s->enabled = 0;
93 return;
94 }
95
96 if (s->policy_mask & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD) {
97 if (delta_adjust != DELTA_NO_ADJUST) {
98 delta += delta_adjust;
99 }
100 }
101
102 if (delta == 0 && (s->policy_mask & PTIMER_POLICY_CONTINUOUS_TRIGGER)) {
103 if (s->enabled == 1 && s->limit == 0) {
104 delta = 1;
105 }
106 }
107
108 if (delta == 0 && (s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)) {
109 if (delta_adjust != DELTA_NO_ADJUST) {
110 delta = 1;
111 }
112 }
113
114 if (delta == 0 && (s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_RELOAD)) {
115 if (s->enabled == 1 && s->limit != 0) {
116 delta = 1;
117 }
118 }
119
120 if (delta == 0) {
121 if (s->enabled == 0) {
122
123 return;
124 }
125 if (!qtest_enabled()) {
126 fprintf(stderr, "Timer with delta zero, disabling\n");
127 }
128 timer_del(s->timer);
129 s->enabled = 0;
130 return;
131 }
132
133
134
135
136
137
138
139
140
141
142 if (s->enabled == 1 && (delta * period < 10000) &&
143 !icount_enabled() && !qtest_enabled()) {
144 period = 10000 / delta;
145 period_frac = 0;
146 }
147
148 s->last_event = s->next_event;
149 s->next_event = s->last_event + delta * period;
150 if (period_frac) {
151 s->next_event += ((int64_t)period_frac * delta) >> 32;
152 }
153 timer_mod(s->timer, s->next_event);
154}
155
156static void ptimer_tick(void *opaque)
157{
158 ptimer_state *s = (ptimer_state *)opaque;
159 bool trigger = true;
160
161
162
163
164
165
166
167
168 ptimer_transaction_begin(s);
169
170 if (s->enabled == 2) {
171 s->delta = 0;
172 s->enabled = 0;
173 } else {
174 int delta_adjust = DELTA_ADJUST;
175
176 if (s->delta == 0 || s->limit == 0) {
177
178
179
180
181 delta_adjust = DELTA_NO_ADJUST;
182 }
183
184 if (!(s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)) {
185
186
187 trigger = (delta_adjust == DELTA_ADJUST);
188 }
189
190 s->delta = s->limit;
191
192 ptimer_reload(s, delta_adjust);
193 }
194
195 if (trigger) {
196 ptimer_trigger(s);
197 }
198
199 ptimer_transaction_commit(s);
200}
201
202uint64_t ptimer_get_count(ptimer_state *s)
203{
204 uint64_t counter;
205
206 if (s->enabled && s->delta != 0) {
207 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
208 int64_t next = s->next_event;
209 int64_t last = s->last_event;
210 bool expired = (now - next >= 0);
211 bool oneshot = (s->enabled == 2);
212
213
214 if (expired) {
215
216
217 counter = 0;
218 } else {
219 uint64_t rem;
220 uint64_t div;
221 int clz1, clz2;
222 int shift;
223 uint32_t period_frac = s->period_frac;
224 uint64_t period = s->period;
225
226 if (!oneshot && (s->delta * period < 10000) &&
227 !icount_enabled() && !qtest_enabled()) {
228 period = 10000 / s->delta;
229 period_frac = 0;
230 }
231
232
233
234
235
236
237
238
239
240
241
242 rem = next - now;
243 div = period;
244
245 clz1 = clz64(rem);
246 clz2 = clz64(div);
247 shift = clz1 < clz2 ? clz1 : clz2;
248
249 rem <<= shift;
250 div <<= shift;
251 if (shift >= 32) {
252 div |= ((uint64_t)period_frac << (shift - 32));
253 } else {
254 if (shift != 0)
255 div |= (period_frac >> (32 - shift));
256
257
258 if ((uint32_t)(period_frac << shift))
259 div += 1;
260 }
261 counter = rem / div;
262
263 if (s->policy_mask & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD) {
264
265
266 if (!oneshot && s->delta == s->limit) {
267 if (now == last) {
268
269
270
271 if (counter == s->limit + DELTA_ADJUST) {
272 return 0;
273 }
274 } else if (counter == s->limit) {
275
276
277
278 return 0;
279 }
280 }
281 }
282 }
283
284 if (s->policy_mask & PTIMER_POLICY_NO_COUNTER_ROUND_DOWN) {
285
286
287
288 if (now != last) {
289 counter += 1;
290 }
291 }
292 } else {
293 counter = s->delta;
294 }
295 return counter;
296}
297
298void ptimer_set_count(ptimer_state *s, uint64_t count)
299{
300 assert(s->in_transaction);
301 s->delta = count;
302 if (s->enabled) {
303 s->need_reload = true;
304 }
305}
306
307void ptimer_run(ptimer_state *s, int oneshot)
308{
309 bool was_disabled = !s->enabled;
310
311 assert(s->in_transaction);
312
313 if (was_disabled && s->period == 0) {
314 if (!qtest_enabled()) {
315 fprintf(stderr, "Timer with period zero, disabling\n");
316 }
317 return;
318 }
319 s->enabled = oneshot ? 2 : 1;
320 if (was_disabled) {
321 s->need_reload = true;
322 }
323}
324
325
326
327void ptimer_stop(ptimer_state *s)
328{
329 assert(s->in_transaction);
330
331 if (!s->enabled)
332 return;
333
334 s->delta = ptimer_get_count(s);
335 timer_del(s->timer);
336 s->enabled = 0;
337 s->need_reload = false;
338}
339
340
341void ptimer_set_period(ptimer_state *s, int64_t period)
342{
343 assert(s->in_transaction);
344 s->delta = ptimer_get_count(s);
345 s->period = period;
346 s->period_frac = 0;
347 if (s->enabled) {
348 s->need_reload = true;
349 }
350}
351
352
353void ptimer_set_period_from_clock(ptimer_state *s, const Clock *clk,
354 unsigned int divisor)
355{
356
357
358
359
360
361
362 uint64_t raw_period = clock_get(clk);
363 uint64_t period_frac;
364
365 assert(s->in_transaction);
366 s->delta = ptimer_get_count(s);
367 s->period = extract64(raw_period, 32, 32);
368 period_frac = extract64(raw_period, 0, 32);
369
370
371
372
373
374
375 s->period *= divisor;
376 period_frac *= divisor;
377 s->period += extract64(period_frac, 32, 32);
378 s->period_frac = (uint32_t)period_frac;
379
380 if (s->enabled) {
381 s->need_reload = true;
382 }
383}
384
385
386void ptimer_set_freq(ptimer_state *s, uint32_t freq)
387{
388 assert(s->in_transaction);
389 s->delta = ptimer_get_count(s);
390 s->period = 1000000000ll / freq;
391 s->period_frac = (1000000000ll << 32) / freq;
392 if (s->enabled) {
393 s->need_reload = true;
394 }
395}
396
397
398
399void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload)
400{
401 assert(s->in_transaction);
402 s->limit = limit;
403 if (reload)
404 s->delta = limit;
405 if (s->enabled && reload) {
406 s->need_reload = true;
407 }
408}
409
410uint64_t ptimer_get_limit(ptimer_state *s)
411{
412 return s->limit;
413}
414
415void ptimer_transaction_begin(ptimer_state *s)
416{
417 assert(!s->in_transaction);
418 s->in_transaction = true;
419 s->need_reload = false;
420}
421
422void ptimer_transaction_commit(ptimer_state *s)
423{
424 assert(s->in_transaction);
425
426
427
428
429
430
431
432 while (s->need_reload && s->enabled) {
433 s->need_reload = false;
434 s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
435 ptimer_reload(s, 0);
436 }
437
438 s->in_transaction = false;
439}
440
441const VMStateDescription vmstate_ptimer = {
442 .name = "ptimer",
443 .version_id = 1,
444 .minimum_version_id = 1,
445 .fields = (VMStateField[]) {
446 VMSTATE_UINT8(enabled, ptimer_state),
447 VMSTATE_UINT64(limit, ptimer_state),
448 VMSTATE_UINT64(delta, ptimer_state),
449 VMSTATE_UINT32(period_frac, ptimer_state),
450 VMSTATE_INT64(period, ptimer_state),
451 VMSTATE_INT64(last_event, ptimer_state),
452 VMSTATE_INT64(next_event, ptimer_state),
453 VMSTATE_TIMER_PTR(timer, ptimer_state),
454 VMSTATE_END_OF_LIST()
455 }
456};
457
458ptimer_state *ptimer_init(ptimer_cb callback, void *callback_opaque,
459 uint8_t policy_mask)
460{
461 ptimer_state *s;
462
463
464 assert(callback);
465
466 s = g_new0(ptimer_state, 1);
467 s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ptimer_tick, s);
468 s->policy_mask = policy_mask;
469 s->callback = callback;
470 s->callback_opaque = callback_opaque;
471
472
473
474
475
476
477 assert(!((policy_mask & PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT) &&
478 (policy_mask & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)));
479 return s;
480}
481
482void ptimer_free(ptimer_state *s)
483{
484 timer_free(s->timer);
485 g_free(s);
486}
487