1/* $OpenBSD: clockintr.h,v 1.29 2024/02/25 19:15:50 cheloha Exp $ */
2/*
3 * Copyright (c) 2020-2024 Scott Cheloha <cheloha@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#ifndef _SYS_CLOCKINTR_H_
19#define _SYS_CLOCKINTR_H_
20
21#include <sys/stdint.h>
22
23struct clockintr_stat {
24 uint64_t cs_dispatched; /* total time in dispatch (ns) */
25 uint64_t cs_early; /* number of early dispatch calls */
26 uint64_t cs_earliness; /* total earliness (ns) */
27 uint64_t cs_lateness; /* total lateness (ns) */
28 uint64_t cs_prompt; /* number of prompt dispatch calls */
29 uint64_t cs_run; /* number of events dispatched */
30 uint64_t cs_spurious; /* number of spurious dispatch calls */
31};
32
33#ifdef _KERNEL
34
35#include <sys/mutex.h>
36#include <sys/queue.h>
37
38struct clockqueue;
39struct clockrequest;
40struct cpu_info;
41
42/*
43 * Platform API
44 */
45
46struct intrclock {
47 void *ic_cookie;
48 void (*ic_rearm)(void *, uint64_t);
49 void (*ic_trigger)(void *);
50};
51
52/*
53 * Schedulable clock interrupt callback.
54 *
55 * Struct member protections:
56 *
57 * I Immutable after initialization.
58 * m Parent queue mutex (cl_queue->cq_mtx).
59 */
60struct clockintr {
61 uint64_t cl_expiration; /* [m] dispatch time */
62 TAILQ_ENTRY(clockintr) cl_alink; /* [m] cq_all glue */
63 TAILQ_ENTRY(clockintr) cl_plink; /* [m] cq_pend glue */
64 void *cl_arg; /* [I] argument */
65 void (*cl_func)(struct clockrequest *, void*, void*); /* [I] callback */
66 struct clockqueue *cl_queue; /* [I] parent queue */
67 uint32_t cl_flags; /* [m] CLST_* flags */
68};
69
70#define CLST_PENDING 0x00000001 /* scheduled to run */
71
72/*
73 * Interface for callback rescheduling requests.
74 *
75 * Struct member protections:
76 *
77 * I Immutable after initialization.
78 * o Owned by a single CPU.
79 */
80struct clockrequest {
81 uint64_t cr_expiration; /* [o] copy of dispatch time */
82 struct clockqueue *cr_queue; /* [I] enclosing queue */
83 uint32_t cr_flags; /* [o] CR_* flags */
84};
85
86#define CR_RESCHEDULE 0x00000001 /* reschedule upon return */
87
88/*
89 * Per-CPU clock interrupt state.
90 *
91 * Struct member protections:
92 *
93 * a Modified atomically.
94 * I Immutable after initialization.
95 * m Per-queue mutex (cq_mtx).
96 * o Owned by a single CPU.
97 */
98struct clockqueue {
99 struct clockrequest cq_request; /* [o] callback request object */
100 struct mutex cq_mtx; /* [a] per-queue mutex */
101 uint64_t cq_uptime; /* [o] cached uptime */
102 TAILQ_HEAD(, clockintr) cq_all; /* [m] established clockintr list */
103 TAILQ_HEAD(, clockintr) cq_pend;/* [m] pending clockintr list */
104 struct clockintr *cq_running; /* [m] running clockintr */
105 struct clockintr cq_hardclock; /* [o] hardclock handle */
106 struct intrclock cq_intrclock; /* [I] local interrupt clock */
107 struct clockintr_stat cq_stat; /* [o] dispatch statistics */
108 volatile uint32_t cq_gen; /* [o] cq_stat update generation */
109 volatile uint32_t cq_dispatch; /* [o] dispatch is running */
110 uint32_t cq_flags; /* [m] CQ_* flags; see below */
111};
112
113#define CQ_INIT 0x00000001 /* clockintr_cpu_init() done */
114#define CQ_INTRCLOCK 0x00000002 /* intrclock installed */
115#define CQ_IGNORE_REQUEST 0x00000004 /* ignore callback requests */
116#define CQ_NEED_WAKEUP 0x00000008 /* caller at barrier */
117#define CQ_STATE_MASK 0x0000000f
118
119void clockintr_cpu_init(const struct intrclock *);
120int clockintr_dispatch(void *);
121void clockintr_trigger(void);
122
123/*
124 * Kernel API
125 */
126
127#define CL_BARRIER 0x00000001 /* block if callback is running */
128#define CL_FLAG_MASK 0x00000001
129
130uint64_t clockintr_advance(struct clockintr *, uint64_t);
131void clockintr_bind(struct clockintr *, struct cpu_info *,
132 void (*)(struct clockrequest *, void *, void *), void *);
133void clockintr_cancel(struct clockintr *);
134void clockintr_schedule(struct clockintr *, uint64_t);
135void clockintr_stagger(struct clockintr *, uint64_t, uint32_t, uint32_t);
136void clockintr_unbind(struct clockintr *, uint32_t);
137uint64_t clockrequest_advance(struct clockrequest *, uint64_t);
138uint64_t clockrequest_advance_random(struct clockrequest *, uint64_t, uint32_t);
139void clockqueue_init(struct clockqueue *);
140int sysctl_clockintr(int *, u_int, void *, size_t *, void *, size_t);
141
142#endif /* _KERNEL */
143
144#endif /* !_SYS_CLOCKINTR_H_ */