1/* @title: Timer */
2#pragma once
3#include <structures/hlist.h>
4#include <time/time.h>
5#include <types/types.h>
6
7/* timer_flags: 32 bit bitflags
8 *
9 * ┌───────────────────────────────────────────────────────┐
10 * Bits │ 31..28 27..24 23..20 19..16 15..12 11..8 7..4 3..0 │
11 * Use │ %%%% %%%% %%PM ID## #### #### #### #### │
12 * └───────────────────────────────────────────────────────┘
13 *
14 * I - IRQ timer - not executed in DPC
15 * D - Deferrable (Only activates when CPU non-idle)
16 * M - Migrating
17 * P - Pinned
18 *
19 * %%% - Bucket idx (if present, up to 1023)
20 * ### - CPU target for this timer
21 *
22 * A - Unused (available)
23 * * - Unused (unavailable)
24 *
25 */
26
27#define TIMER_FLAG_CPU_MASK 0x0003FFFF
28#define TIMER_FLAG_CPU(c) ((c) & TIMER_FLAG_CPU_MASK)
29
30#define TIMER_FLAG_BUCKET_MASK 0x3FF
31#define TIMER_FLAG_BUCKET_SHIFT 22
32#define TIMER_FLAG_BUCKET(b) \
33 (((b) & TIMER_FLAG_BUCKET_MASK) << TIMER_FLAG_BUCKET_SHIFT)
34
35enum timer_flags {
36 TIMER_FLAG_NONE = 0,
37 TIMER_FLAG_DEFERRABLE = 1 << 18,
38 TIMER_FLAG_IRQ = 1 << 19,
39 TIMER_FLAG_MIGRATING = 1 << 20,
40 TIMER_FLAG_PINNED = 1 << 21,
41};
42
43struct timer {
44 struct hlist_node hlist_node;
45 time_us_t expiration_us;
46 void (*func)(struct timer *timer);
47 enum timer_flags flags;
48
49 void *data;
50};
51
52#define TIMER_DECLARE(n, fn, ...) \
53 struct timer n = (struct timer) { \
54 .func = fn \
55 }
56
57static inline void timer_bucket_set(struct timer *timer, uint32_t bucket) {
58 timer->flags =
59 (timer->flags & ~(TIMER_FLAG_BUCKET_MASK << TIMER_FLAG_BUCKET_SHIFT)) |
60 TIMER_FLAG_BUCKET(bucket);
61}
62
63static inline uint32_t timer_bucket_get(struct timer *timer) {
64 return (timer->flags >> TIMER_FLAG_BUCKET_SHIFT) & TIMER_FLAG_BUCKET_MASK;
65}
66
67static inline void timer_cpu_set(struct timer *timer, cpu_id_t cpu) {
68 timer->flags = (timer->flags & ~TIMER_FLAG_CPU_MASK) | TIMER_FLAG_CPU(cpu);
69}
70
71static inline cpu_id_t timer_cpu_get(struct timer *timer) {
72 return timer->flags & TIMER_FLAG_CPU_MASK;
73}
74
75static inline void timer_init(struct timer *timer, void (*func)(struct timer *),
76 void *data) {
77 timer->hlist_node.next = NULL;
78 timer->hlist_node.pprev = NULL;
79 timer->expiration_us = 0;
80 timer->func = func;
81 timer->flags = TIMER_FLAG_NONE;
82 timer->data = data;
83}
84
85void timer_add(struct timer *timer);
86void timer_add_on(struct timer *timer, cpu_id_t cpu);
87
88/* Wrappers around `add()` with flag setting */
89void timer_add_local(struct timer *timer);
90void timer_add_global(struct timer *timer);
91
92bool timer_modify(struct timer *timer, time_us_t new);
93bool timer_modify_pending(struct timer *timer, time_us_t new);
94
95/* Only modify if `new` is nearer than `expiration` */
96bool timer_modify_reduce(struct timer *timer, time_us_t new);
97
98/* `_sync()` functions wait for the handler to finish,
99 * and non-`_sync()` functions do not */
100bool timer_delete(struct timer *timer);
101bool timer_delete_sync(struct timer *timer);
102bool timer_shutdown(struct timer *timer);
103bool timer_shutdown_sync(struct timer *timer);
104
105struct irq_context;
106enum irq_result timer_isr(void *ctx, irq_t vec, struct irq_context *);
107void timers_init(void);
108
109static inline time_us_t timer_delta_us(time_us_t delta_us) {
110 return time_get_us() + delta_us;
111}
112