| 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 | |
| 35 | enum 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 | |
| 43 | struct 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 | |
| 57 | static 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 | |
| 63 | static inline uint32_t timer_bucket_get(struct timer *timer) { |
| 64 | return (timer->flags >> TIMER_FLAG_BUCKET_SHIFT) & TIMER_FLAG_BUCKET_MASK; |
| 65 | } |
| 66 | |
| 67 | static 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 | |
| 71 | static inline cpu_id_t timer_cpu_get(struct timer *timer) { |
| 72 | return timer->flags & TIMER_FLAG_CPU_MASK; |
| 73 | } |
| 74 | |
| 75 | static 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 | |
| 85 | void timer_add(struct timer *timer); |
| 86 | void timer_add_on(struct timer *timer, cpu_id_t cpu); |
| 87 | |
| 88 | /* Wrappers around `add()` with flag setting */ |
| 89 | void timer_add_local(struct timer *timer); |
| 90 | void timer_add_global(struct timer *timer); |
| 91 | |
| 92 | bool timer_modify(struct timer *timer, time_us_t new); |
| 93 | bool timer_modify_pending(struct timer *timer, time_us_t new); |
| 94 | |
| 95 | /* Only modify if `new` is nearer than `expiration` */ |
| 96 | bool 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 */ |
| 100 | bool timer_delete(struct timer *timer); |
| 101 | bool timer_delete_sync(struct timer *timer); |
| 102 | bool timer_shutdown(struct timer *timer); |
| 103 | bool timer_shutdown_sync(struct timer *timer); |
| 104 | |
| 105 | struct irq_context; |
| 106 | enum irq_result timer_isr(void *ctx, irq_t vec, struct irq_context *); |
| 107 | void timers_init(void); |
| 108 | |
| 109 | static inline time_us_t timer_delta_us(time_us_t delta_us) { |
| 110 | return time_get_us() + delta_us; |
| 111 | } |
| 112 | |