intr.c revision 1.7
1/*	$NetBSD: intr.c,v 1.7 2008/10/10 20:13:58 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
41struct softint {
42	void (*si_func)(void *);
43	void *si_arg;
44	bool si_onlist;
45	bool si_mpsafe;
46
47	LIST_ENTRY(softint) si_entries;
48};
49static LIST_HEAD(, softint) si_pending = LIST_HEAD_INITIALIZER(si_pending);
50static kmutex_t si_mtx;
51static kcondvar_t si_cv;
52
53static void
54intr_worker(void *arg)
55{
56	struct softint *si;
57	void (*func)(void *) = NULL;
58	void *funarg = NULL; /* XXX gcc */
59	bool mpsafe = false; /* XXX gcc */
60
61	for (;;) {
62		/*
63		 * XXX: not exactly executed once per tick, but without
64		 * a proper timer ticktocking we don't really care.
65		 */
66		callout_hardclock();
67
68		mutex_enter(&si_mtx);
69		if (LIST_EMPTY(&si_pending)) {
70			cv_timedwait(&si_cv, &si_mtx, 1);
71		} else {
72			si = LIST_FIRST(&si_pending);
73			func = si->si_func;
74			funarg = si->si_arg;
75			mpsafe = si->si_mpsafe;
76
77			si->si_onlist = false;
78			LIST_REMOVE(si, si_entries);
79		}
80		mutex_exit(&si_mtx);
81
82		if (func) {
83			if (!mpsafe)
84				KERNEL_LOCK(1, curlwp);
85			func(funarg);
86			func = NULL;
87			if (!mpsafe)
88				KERNEL_UNLOCK_ONE(curlwp);
89		}
90	}
91}
92
93void
94softint_init(struct cpu_info *ci)
95{
96	int rv;
97
98	mutex_init(&si_mtx, MUTEX_DEFAULT, IPL_NONE);
99	cv_init(&si_cv, "intrw8");
100
101	/* XXX: should have separate "wanttimer" control */
102	if (rump_threads) {
103		rv = kthread_create(PRI_NONE, 0, NULL, intr_worker, NULL, NULL,
104		    "rumpmtr");
105		if (rv)
106			panic("timer thread creation failed %d", rv);
107	}
108}
109
110/*
111 * Soft interrupts bring two choices.  If we are running with thread
112 * support enabled, defer execution, otherwise execute in place.
113 * See softint_schedule().
114 *
115 * As there is currently no clear concept of when a thread finishes
116 * work (although rump_clear_curlwp() is close), simply execute all
117 * softints in the timer thread.  This is probably not the most
118 * efficient method, but good enough for now.
119 */
120void *
121softint_establish(u_int flags, void (*func)(void *), void *arg)
122{
123	struct softint *si;
124
125	si = kmem_alloc(sizeof(*si), KM_SLEEP);
126	si->si_func = func;
127	si->si_arg = arg;
128	si->si_onlist = false;
129	si->si_mpsafe = flags & SOFTINT_MPSAFE;
130
131	return si;
132}
133
134void
135softint_schedule(void *arg)
136{
137	struct softint *si = arg;
138
139	if (!rump_threads) {
140		si->si_func(si->si_arg);
141	} else {
142		mutex_enter(&si_mtx);
143		if (!si->si_onlist) {
144			LIST_INSERT_HEAD(&si_pending, si, si_entries);
145			si->si_onlist = true;
146		}
147		cv_signal(&si_cv);
148		mutex_exit(&si_mtx);
149	}
150}
151
152bool
153cpu_intr_p()
154{
155
156	return false;
157}
158