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