intr.c revision 1.10 1 /* $NetBSD: intr.c,v 1.10 2008/12/18 00:12:00 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2008 Antti Kantee. All Rights Reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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.
14 *
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
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/param.h>
29 #include <sys/cpu.h>
30 #include <sys/kthread.h>
31 #include <sys/intr.h>
32
33 #include <rump/rumpuser.h>
34
35 #include "rump_private.h"
36
37 /*
38 * Interrupt simulator. It executes hardclock() and softintrs.
39 */
40
41 time_t time_uptime = 1;
42
43 struct softint {
44 void (*si_func)(void *);
45 void *si_arg;
46 bool si_onlist;
47 bool si_mpsafe;
48
49 LIST_ENTRY(softint) si_entries;
50 };
51 static LIST_HEAD(, softint) si_pending = LIST_HEAD_INITIALIZER(si_pending);
52 static kmutex_t si_mtx;
53 static kcondvar_t si_cv;
54
55 #define INTRTHREAD_DEFAULT 2
56 #define INTRTHREAD_MAX 20
57 static int wrkidle, wrktotal;
58
59 static void sithread(void *);
60
61 static void
62 makeworker(bool bootstrap)
63 {
64 int rv;
65
66 if (wrktotal > INTRTHREAD_MAX) {
67 /* XXX: ratecheck */
68 printf("maximum interrupt threads (%d) reached\n",
69 INTRTHREAD_MAX);
70 return;
71 }
72 rv = kthread_create(PRI_NONE, 0, NULL, sithread,
73 NULL, NULL, "rumpsi");
74 if (rv) {
75 if (bootstrap)
76 panic("intr thread creation failed %d", rv);
77 else
78 printf("intr thread creation failed %d\n", rv);
79 } else {
80 wrkidle++;
81 wrktotal++;
82 }
83 }
84
85 /*
86 * clock "interrupt"
87 */
88 static void
89 doclock(void *noarg)
90 {
91 static int ticks = 0;
92 extern int hz;
93
94 for (;;) {
95 callout_hardclock();
96
97 /* XXX: will drift */
98 if (++ticks == hz) {
99 time_uptime++;
100 ticks = 0;
101 }
102 kpause("tickw8", false, 1, NULL);
103 }
104 }
105
106 /*
107 * run a scheduled soft interrupt
108 */
109 static void
110 sithread(void *arg)
111 {
112 struct softint *si;
113 void (*func)(void *) = NULL;
114 void *funarg;
115 bool mpsafe;
116
117 mutex_enter(&si_mtx);
118 for (;;) {
119 if (!LIST_EMPTY(&si_pending)) {
120 si = LIST_FIRST(&si_pending);
121 func = si->si_func;
122 funarg = si->si_arg;
123 mpsafe = si->si_mpsafe;
124
125 si->si_onlist = false;
126 LIST_REMOVE(si, si_entries);
127 } else {
128 cv_wait(&si_cv, &si_mtx);
129 continue;
130 }
131 wrkidle--;
132 if (__predict_false(wrkidle == 0))
133 makeworker(false);
134 mutex_exit(&si_mtx);
135
136 if (!mpsafe)
137 KERNEL_LOCK(1, curlwp);
138 func(funarg);
139 if (!mpsafe)
140 KERNEL_UNLOCK_ONE(curlwp);
141
142 mutex_enter(&si_mtx);
143 wrkidle++;
144 }
145 }
146
147 void
148 softint_init(struct cpu_info *ci)
149 {
150 int rv;
151
152 mutex_init(&si_mtx, MUTEX_DEFAULT, IPL_NONE);
153 cv_init(&si_cv, "intrw8"); /* cv of temporary w8ness */
154
155 /* XXX: should have separate "wanttimer" control */
156 if (rump_threads) {
157 rv = kthread_create(PRI_NONE, 0, NULL, doclock,
158 NULL, NULL, "rumpclk");
159 if (rv)
160 panic("clock thread creation failed: %d", rv);
161 mutex_enter(&si_mtx);
162 while (wrktotal < INTRTHREAD_DEFAULT) {
163 makeworker(true);
164 }
165 mutex_exit(&si_mtx);
166 }
167 }
168
169 /*
170 * Soft interrupts bring two choices. If we are running with thread
171 * support enabled, defer execution, otherwise execute in place.
172 * See softint_schedule().
173 *
174 * As there is currently no clear concept of when a thread finishes
175 * work (although rump_clear_curlwp() is close), simply execute all
176 * softints in the timer thread. This is probably not the most
177 * efficient method, but good enough for now.
178 */
179 void *
180 softint_establish(u_int flags, void (*func)(void *), void *arg)
181 {
182 struct softint *si;
183
184 si = kmem_alloc(sizeof(*si), KM_SLEEP);
185 si->si_func = func;
186 si->si_arg = arg;
187 si->si_onlist = false;
188 si->si_mpsafe = flags & SOFTINT_MPSAFE;
189
190 return si;
191 }
192
193 void
194 softint_schedule(void *arg)
195 {
196 struct softint *si = arg;
197
198 if (!rump_threads) {
199 si->si_func(si->si_arg);
200 } else {
201 mutex_enter(&si_mtx);
202 if (!si->si_onlist) {
203 LIST_INSERT_HEAD(&si_pending, si, si_entries);
204 si->si_onlist = true;
205 }
206 cv_signal(&si_cv);
207 mutex_exit(&si_mtx);
208 }
209 }
210
211 bool
212 cpu_intr_p(void)
213 {
214
215 return false;
216 }
217