xref: /titanic_44/usr/src/uts/common/os/softint.c (revision 3d0479833b8db89da4bca3e8e8e88f996686aa8e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <sys/param.h>
30 #include <sys/t_lock.h>
31 #include <sys/systm.h>
32 #include <sys/spl.h>
33 #include <sys/cmn_err.h>
34 #include <sys/debug.h>
35 #include <sys/kdi_impl.h>
36 
37 /*
38  * Handle software interrupts through 'softcall' mechanism
39  *
40  * At present softcall mechanism uses a global list headed by softhead.
41  * Entries are added to tail and removed from head so as to preserve FIFO
42  * nature of entries in the softcall list. softcall() takes care of adding
43  * entries to the softtail.
44  *
45  * softint must take care of executing the entries in the FIFO
46  * order. It could be called simultaneously from multiple cpus, however only
47  * one instance of softint should process the softcall list, this is
48  * ensured by
49  * - the state the variable softcall_state will be at time to time.
50  *   (IDLE->PEND->DRAIN->IDLE)
51  *
52  * These states are needed for softcall mechanism since  Solaris has only
53  * one interface(ie. siron ) as of now for
54  * - raising a soft interrupt architecture independently(ie not through
55  *   setsoftint(..) )
56  * - to process the softcall queue.
57  */
58 
59 #define	NSOFTCALLS	200
60 /*
61  * Defined states for softcall processing.
62  */
63 #define	SOFT_IDLE		0x01	/* no processing is needed */
64 #define	SOFT_PEND		0x02	/* softcall list needs processing */
65 #define	SOFT_DRAIN		0x04	/* the list is being processed */
66 
67 typedef struct softcall {
68 	void (*sc_func)(void *);	/* function to call */
69 	void *sc_arg;			/* arg to pass to func */
70 	struct softcall *sc_next;	/* next in list */
71 } softcall_t;
72 
73 static softcall_t softcalls[NSOFTCALLS], *softhead, *softtail, *softfree;
74 static uint_t	softcall_state;
75 
76 /*
77  * protects softcall lists and control variable softcall_state.
78  */
79 static kmutex_t	softcall_lock;
80 
81 static void (*kdi_softcall_func)(void);
82 
83 extern void siron(void);
84 extern void kdi_siron(void);
85 
86 void
87 softcall_init(void)
88 {
89 	softcall_t *sc;
90 
91 	for (sc = softcalls; sc < &softcalls[NSOFTCALLS]; sc++) {
92 		sc->sc_next = softfree;
93 		softfree = sc;
94 	}
95 	mutex_init(&softcall_lock, NULL, MUTEX_SPIN, (void *)ipltospl(SPL8));
96 }
97 
98 /*
99  * Call function func with argument arg
100  * at some later time at software interrupt priority
101  */
102 void
103 softcall(void (*func)(void *), void *arg)
104 {
105 	softcall_t *sc;
106 
107 	/*
108 	 * protect against cross-calls
109 	 */
110 	mutex_enter(&softcall_lock);
111 	/* coalesce identical softcalls */
112 	for (sc = softhead; sc != 0; sc = sc->sc_next) {
113 		if (sc->sc_func == func && sc->sc_arg == arg) {
114 			mutex_exit(&softcall_lock);
115 			return;
116 		}
117 	}
118 
119 	if ((sc = softfree) == 0)
120 		panic("too many softcalls");
121 	softfree = sc->sc_next;
122 	sc->sc_func = func;
123 	sc->sc_arg = arg;
124 	sc->sc_next = 0;
125 
126 	if (softhead) {
127 		softtail->sc_next = sc;
128 		softtail = sc;
129 		mutex_exit(&softcall_lock);
130 	} else {
131 		softhead = softtail = sc;
132 		if (softcall_state == SOFT_DRAIN)
133 			/*
134 			 * softint is already running; no need to
135 			 * raise a siron. Due to lock protection of
136 			 * softhead / softcall state, we know
137 			 * that softint() will see the new addition to
138 			 * the softhead queue.
139 			 */
140 			mutex_exit(&softcall_lock);
141 		else {
142 			softcall_state = SOFT_PEND;
143 			mutex_exit(&softcall_lock);
144 			siron();
145 		}
146 	}
147 }
148 
149 void
150 kdi_softcall(void (*func)(void))
151 {
152 	kdi_softcall_func = func;
153 
154 	if (softhead == NULL)
155 		kdi_siron();
156 }
157 
158 /*
159  * Called to process software interrupts take one off queue, call it,
160  * repeat.
161  *
162  * Note queue may change during call; softcall_lock and state variables
163  * softcall_state ensures that
164  * -we don't have multiple cpus pulling from the list (thus causing
165  *  a violation of FIFO order).
166  * -we don't miss a new entry having been added to the head.
167  * -we don't miss a wakeup.
168  */
169 
170 void
171 softint(void)
172 {
173 	softcall_t *sc;
174 	void (*func)();
175 	caddr_t arg;
176 
177 	/*
178 	 * Check if we are asked to process the softcall list.
179 	 */
180 	mutex_enter(&softcall_lock);
181 	if (softcall_state != SOFT_PEND) {
182 		mutex_exit(&softcall_lock);
183 		goto out;
184 	}
185 	softcall_state = SOFT_DRAIN;
186 
187 	for (;;) {
188 		if ((sc = softhead) != NULL) {
189 			func = sc->sc_func;
190 			arg = sc->sc_arg;
191 			softhead = sc->sc_next;
192 			sc->sc_next = softfree;
193 			softfree = sc;
194 		}
195 		if (sc == NULL) {
196 			softcall_state = SOFT_IDLE;
197 			mutex_exit(&softcall_lock);
198 			break;
199 		}
200 		mutex_exit(&softcall_lock);
201 		func(arg);
202 		mutex_enter(&softcall_lock);
203 	}
204 out:
205 	if ((func = kdi_softcall_func) != NULL) {
206 		kdi_softcall_func = NULL;
207 		func();
208 	}
209 }
210