1 /* $NetBSD: intr.c,v 1.22 2009/12/01 09:50:51 pooka Exp $ */
4 * Copyright (c) 2008 Antti Kantee. All Rights Reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.22 2009/12/01 09:50:51 pooka Exp $");
31 #include <sys/param.h>
34 #include <sys/kthread.h>
37 #include <rump/rumpuser.h>
39 #include "rump_private.h"
42 * Interrupt simulator. It executes hardclock() and softintrs.
45 time_t time_uptime
= 0;
47 #define SI_MPSAFE 0x01
48 #define SI_ONLIST 0x02
49 #define SI_KILLME 0x04
52 void (*si_func
)(void *);
57 LIST_ENTRY(softint
) si_entries
;
60 static struct rumpuser_mtx
*si_mtx
;
62 struct rumpuser_cv
*si_cv
;
63 LIST_HEAD(, softint
) si_pending
;
66 /* rumpuser structures since we call rumpuser interfaces directly */
67 static struct rumpuser_cv
*clockcv
;
68 static struct rumpuser_mtx
*clockmtx
;
69 static struct timespec clockbase
, clockup
;
70 static unsigned clkgen
;
72 kcondvar_t lbolt
; /* Oh Kath Ra */
75 rump_getuptime(struct timespec
*ts
)
81 if (__predict_false(i
++ > 10)) {
86 } while (startgen
!= clkgen
|| clkgen
% 2 != 0);
90 rump_gettime(struct timespec
*ts
)
92 struct timespec ts_up
;
94 rump_getuptime(&ts_up
);
95 timespecadd(&clockbase
, &ts_up
, ts
);
104 struct timespec tick
, curtime
;
106 int ticks
= 0, error
;
109 rumpuser_gettime(&sec
, &nsec
, &error
);
110 clockbase
.tv_sec
= sec
;
111 clockbase
.tv_nsec
= nsec
;
114 tick
.tv_nsec
= 1000000000/hz
;
116 rumpuser_mutex_enter(clockmtx
);
117 rumpuser_cv_signal(clockcv
);
122 /* wait until the next tick. XXX: what if the clock changes? */
123 while (rumpuser_cv_timedwait(clockcv
, clockmtx
,
124 curtime
.tv_sec
, curtime
.tv_nsec
) == 0)
127 /* if !maincpu: continue */
132 cv_broadcast(&lbolt
);
136 timespecadd(&clockup
, &tick
, &clockup
);
138 timespecadd(&clockup
, &clockbase
, &curtime
);
143 * Soft interrupt execution thread. Note that we run without a CPU
144 * context until we start processing the interrupt. This is to avoid
151 void (*func
)(void *) = NULL
;
154 int mylevel
= (uintptr_t)arg
;
155 struct softint_lev
*si_lvlp
, *si_lvl
;
156 struct cpu_data
*cd
= &curcpu()->ci_data
;
160 si_lvlp
= cd
->cpu_softcpu
;
161 si_lvl
= &si_lvlp
[mylevel
];
164 * XXX: si_mtx is unnecessary, and should open an interface
165 * which allows to use schedmtx for the cv wait
167 rumpuser_mutex_enter_nowrap(si_mtx
);
169 if (!LIST_EMPTY(&si_lvl
->si_pending
)) {
170 si
= LIST_FIRST(&si_lvl
->si_pending
);
173 mpsafe
= si
->si_flags
& SI_MPSAFE
;
175 si
->si_flags
&= ~SI_ONLIST
;
176 LIST_REMOVE(si
, si_entries
);
177 if (si
->si_flags
& SI_KILLME
) {
178 rumpuser_mutex_exit(si_mtx
);
180 softint_disestablish(si
);
182 rumpuser_mutex_enter_nowrap(si_mtx
);
186 rumpuser_cv_wait_nowrap(si_lvl
->si_cv
, si_mtx
);
189 rumpuser_mutex_exit(si_mtx
);
193 KERNEL_LOCK(1, curlwp
);
196 KERNEL_UNLOCK_ONE(curlwp
);
199 rumpuser_mutex_enter_nowrap(si_mtx
);
202 panic("sithread unreachable");
209 rumpuser_mutex_init(&si_mtx
);
210 rumpuser_cv_init(&clockcv
);
211 rumpuser_mutex_init(&clockmtx
);
212 cv_init(&lbolt
, "oh kath ra");
216 softint_init(struct cpu_info
*ci
)
218 struct cpu_data
*cd
= &ci
->ci_data
;
219 struct softint_lev
*slev
;
225 slev
= kmem_alloc(sizeof(struct softint_lev
) * SOFTINT_COUNT
, KM_SLEEP
);
226 for (i
= 0; i
< SOFTINT_COUNT
; i
++) {
227 rumpuser_cv_init(&slev
[i
].si_cv
);
228 LIST_INIT(&slev
[i
].si_pending
);
230 cd
->cpu_softcpu
= slev
;
232 for (i
= 0; i
< SOFTINT_COUNT
; i
++) {
233 rv
= kthread_create(PRI_NONE
,
234 KTHREAD_MPSAFE
| KTHREAD_INTR
, NULL
,
235 sithread
, (void *)(uintptr_t)i
,
236 NULL
, "rumpsi%d", i
);
239 rumpuser_mutex_enter(clockmtx
);
240 for (i
= 0; i
< ncpu
; i
++) {
241 rv
= kthread_create(PRI_NONE
,
242 KTHREAD_MPSAFE
| KTHREAD_INTR
,
243 cpu_lookup(i
), doclock
, NULL
, NULL
,
246 panic("clock thread creation failed: %d", rv
);
250 * Make sure we have a clocktime before returning.
253 rumpuser_cv_wait(clockcv
, clockmtx
);
254 rumpuser_mutex_exit(clockmtx
);
258 * Soft interrupts bring two choices. If we are running with thread
259 * support enabled, defer execution, otherwise execute in place.
260 * See softint_schedule().
262 * As there is currently no clear concept of when a thread finishes
263 * work (although rump_clear_curlwp() is close), simply execute all
264 * softints in the timer thread. This is probably not the most
265 * efficient method, but good enough for now.
268 softint_establish(u_int flags
, void (*func
)(void *), void *arg
)
272 si
= kmem_alloc(sizeof(*si
), KM_SLEEP
);
275 si
->si_flags
= flags
& SOFTINT_MPSAFE
? SI_MPSAFE
: 0;
276 si
->si_level
= flags
& SOFTINT_LVLMASK
;
277 KASSERT(si
->si_level
< SOFTINT_COUNT
);
283 softint_schedule(void *arg
)
285 struct softint
*si
= arg
;
286 struct cpu_data
*cd
= &curcpu()->ci_data
;
287 struct softint_lev
*si_lvl
= cd
->cpu_softcpu
;
290 si
->si_func(si
->si_arg
);
292 if (!(si
->si_flags
& SI_ONLIST
)) {
293 LIST_INSERT_HEAD(&si_lvl
[si
->si_level
].si_pending
,
295 si
->si_flags
|= SI_ONLIST
;
300 /* flimsy disestablish: should wait for softints to finish */
302 softint_disestablish(void *cook
)
304 struct softint
*si
= cook
;
306 rumpuser_mutex_enter(si_mtx
);
307 if (si
->si_flags
& SI_ONLIST
) {
308 si
->si_flags
|= SI_KILLME
;
311 rumpuser_mutex_exit(si_mtx
);
312 kmem_free(si
, sizeof(*si
));
316 rump_softint_run(struct cpu_info
*ci
)
318 struct cpu_data
*cd
= &ci
->ci_data
;
319 struct softint_lev
*si_lvl
= cd
->cpu_softcpu
;
325 for (i
= 0; i
< SOFTINT_COUNT
; i
++) {
326 if (!LIST_EMPTY(&si_lvl
[i
].si_pending
))
327 rumpuser_cv_signal(si_lvl
[i
].si_cv
);
342 return curlwp
->l_pflag
& LP_INTR
;