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