xref: /onnv-gate/usr/src/uts/common/os/softint.c (revision 4652:017019fc1cf1)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*4652Scwb  * Common Development and Distribution License (the "License").
6*4652Scwb  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*4652Scwb  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/param.h>
300Sstevel@tonic-gate #include <sys/t_lock.h>
310Sstevel@tonic-gate #include <sys/systm.h>
320Sstevel@tonic-gate #include <sys/spl.h>
330Sstevel@tonic-gate #include <sys/cmn_err.h>
340Sstevel@tonic-gate #include <sys/debug.h>
350Sstevel@tonic-gate #include <sys/kdi_impl.h>
360Sstevel@tonic-gate 
370Sstevel@tonic-gate /*
380Sstevel@tonic-gate  * Handle software interrupts through 'softcall' mechanism
39522Ssudheer  *
40522Ssudheer  * At present softcall mechanism uses a global list headed by softhead.
41522Ssudheer  * Entries are added to tail and removed from head so as to preserve FIFO
42522Ssudheer  * nature of entries in the softcall list. softcall() takes care of adding
43522Ssudheer  * entries to the softtail.
44522Ssudheer  *
45522Ssudheer  * softint must take care of executing the entries in the FIFO
46522Ssudheer  * order. It could be called simultaneously from multiple cpus, however only
47522Ssudheer  * one instance of softint should process the softcall list, this is
48522Ssudheer  * ensured by
49522Ssudheer  * - the state the variable softcall_state will be at time to time.
50522Ssudheer  *   (IDLE->PEND->DRAIN->IDLE)
51522Ssudheer  *
52522Ssudheer  * These states are needed for softcall mechanism since  Solaris has only
53522Ssudheer  * one interface(ie. siron ) as of now for
54522Ssudheer  * - raising a soft interrupt architecture independently(ie not through
55522Ssudheer  *   setsoftint(..) )
56522Ssudheer  * - to process the softcall queue.
570Sstevel@tonic-gate  */
580Sstevel@tonic-gate 
590Sstevel@tonic-gate #define	NSOFTCALLS	200
60522Ssudheer /*
61522Ssudheer  * Defined states for softcall processing.
62522Ssudheer  */
63522Ssudheer #define	SOFT_IDLE		0x01	/* no processing is needed */
64522Ssudheer #define	SOFT_PEND		0x02	/* softcall list needs processing */
65522Ssudheer #define	SOFT_DRAIN		0x04	/* the list is being processed */
660Sstevel@tonic-gate 
670Sstevel@tonic-gate typedef struct softcall {
680Sstevel@tonic-gate 	void (*sc_func)(void *);	/* function to call */
690Sstevel@tonic-gate 	void *sc_arg;			/* arg to pass to func */
700Sstevel@tonic-gate 	struct softcall *sc_next;	/* next in list */
710Sstevel@tonic-gate } softcall_t;
720Sstevel@tonic-gate 
730Sstevel@tonic-gate static softcall_t softcalls[NSOFTCALLS], *softhead, *softtail, *softfree;
74522Ssudheer static uint_t	softcall_state;
750Sstevel@tonic-gate 
76522Ssudheer /*
77522Ssudheer  * protects softcall lists and control variable softcall_state.
78522Ssudheer  */
79522Ssudheer static kmutex_t	softcall_lock;
800Sstevel@tonic-gate 
810Sstevel@tonic-gate static void (*kdi_softcall_func)(void);
820Sstevel@tonic-gate 
830Sstevel@tonic-gate extern void siron(void);
84*4652Scwb extern void kdi_siron(void);
850Sstevel@tonic-gate 
860Sstevel@tonic-gate void
870Sstevel@tonic-gate softcall_init(void)
880Sstevel@tonic-gate {
890Sstevel@tonic-gate 	softcall_t *sc;
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	for (sc = softcalls; sc < &softcalls[NSOFTCALLS]; sc++) {
920Sstevel@tonic-gate 		sc->sc_next = softfree;
930Sstevel@tonic-gate 		softfree = sc;
940Sstevel@tonic-gate 	}
950Sstevel@tonic-gate 	mutex_init(&softcall_lock, NULL, MUTEX_SPIN, (void *)ipltospl(SPL8));
960Sstevel@tonic-gate }
970Sstevel@tonic-gate 
980Sstevel@tonic-gate /*
990Sstevel@tonic-gate  * Call function func with argument arg
1000Sstevel@tonic-gate  * at some later time at software interrupt priority
1010Sstevel@tonic-gate  */
1020Sstevel@tonic-gate void
1030Sstevel@tonic-gate softcall(void (*func)(void *), void *arg)
1040Sstevel@tonic-gate {
1050Sstevel@tonic-gate 	softcall_t *sc;
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	/*
1080Sstevel@tonic-gate 	 * protect against cross-calls
1090Sstevel@tonic-gate 	 */
1100Sstevel@tonic-gate 	mutex_enter(&softcall_lock);
1110Sstevel@tonic-gate 	/* coalesce identical softcalls */
1120Sstevel@tonic-gate 	for (sc = softhead; sc != 0; sc = sc->sc_next) {
1130Sstevel@tonic-gate 		if (sc->sc_func == func && sc->sc_arg == arg) {
1140Sstevel@tonic-gate 			mutex_exit(&softcall_lock);
1150Sstevel@tonic-gate 			return;
1160Sstevel@tonic-gate 		}
1170Sstevel@tonic-gate 	}
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	if ((sc = softfree) == 0)
1200Sstevel@tonic-gate 		panic("too many softcalls");
1210Sstevel@tonic-gate 	softfree = sc->sc_next;
1220Sstevel@tonic-gate 	sc->sc_func = func;
1230Sstevel@tonic-gate 	sc->sc_arg = arg;
1240Sstevel@tonic-gate 	sc->sc_next = 0;
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	if (softhead) {
1270Sstevel@tonic-gate 		softtail->sc_next = sc;
1280Sstevel@tonic-gate 		softtail = sc;
1290Sstevel@tonic-gate 		mutex_exit(&softcall_lock);
1300Sstevel@tonic-gate 	} else {
1310Sstevel@tonic-gate 		softhead = softtail = sc;
132522Ssudheer 		if (softcall_state == SOFT_DRAIN)
133522Ssudheer 			/*
134522Ssudheer 			 * softint is already running; no need to
135522Ssudheer 			 * raise a siron. Due to lock protection of
136522Ssudheer 			 * softhead / softcall state, we know
137522Ssudheer 			 * that softint() will see the new addition to
138522Ssudheer 			 * the softhead queue.
139522Ssudheer 			 */
140522Ssudheer 			mutex_exit(&softcall_lock);
141522Ssudheer 		else {
142522Ssudheer 			softcall_state = SOFT_PEND;
143522Ssudheer 			mutex_exit(&softcall_lock);
144522Ssudheer 			siron();
145522Ssudheer 		}
1460Sstevel@tonic-gate 	}
1470Sstevel@tonic-gate }
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate void
1500Sstevel@tonic-gate kdi_softcall(void (*func)(void))
1510Sstevel@tonic-gate {
1520Sstevel@tonic-gate 	kdi_softcall_func = func;
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	if (softhead == NULL)
155*4652Scwb 		kdi_siron();
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate /*
159522Ssudheer  * Called to process software interrupts take one off queue, call it,
160522Ssudheer  * repeat.
161522Ssudheer  *
162522Ssudheer  * Note queue may change during call; softcall_lock and state variables
163522Ssudheer  * softcall_state ensures that
164522Ssudheer  * -we don't have multiple cpus pulling from the list (thus causing
165522Ssudheer  *  a violation of FIFO order).
166522Ssudheer  * -we don't miss a new entry having been added to the head.
167522Ssudheer  * -we don't miss a wakeup.
1680Sstevel@tonic-gate  */
169522Ssudheer 
1700Sstevel@tonic-gate void
1710Sstevel@tonic-gate softint(void)
1720Sstevel@tonic-gate {
1730Sstevel@tonic-gate 	softcall_t *sc;
1740Sstevel@tonic-gate 	void (*func)();
1750Sstevel@tonic-gate 	caddr_t arg;
1760Sstevel@tonic-gate 
177522Ssudheer 	/*
178522Ssudheer 	 * Check if we are asked to process the softcall list.
179522Ssudheer 	 */
180522Ssudheer 	mutex_enter(&softcall_lock);
181522Ssudheer 	if (softcall_state != SOFT_PEND) {
182522Ssudheer 		mutex_exit(&softcall_lock);
183522Ssudheer 		goto out;
184522Ssudheer 	}
185522Ssudheer 	softcall_state = SOFT_DRAIN;
186522Ssudheer 
1870Sstevel@tonic-gate 	for (;;) {
1880Sstevel@tonic-gate 		if ((sc = softhead) != NULL) {
1890Sstevel@tonic-gate 			func = sc->sc_func;
1900Sstevel@tonic-gate 			arg = sc->sc_arg;
1910Sstevel@tonic-gate 			softhead = sc->sc_next;
1920Sstevel@tonic-gate 			sc->sc_next = softfree;
1930Sstevel@tonic-gate 			softfree = sc;
1940Sstevel@tonic-gate 		}
195522Ssudheer 		if (sc == NULL) {
196522Ssudheer 			softcall_state = SOFT_IDLE;
197522Ssudheer 			mutex_exit(&softcall_lock);
1980Sstevel@tonic-gate 			break;
199522Ssudheer 		}
200522Ssudheer 		mutex_exit(&softcall_lock);
2010Sstevel@tonic-gate 		func(arg);
202522Ssudheer 		mutex_enter(&softcall_lock);
2030Sstevel@tonic-gate 	}
204522Ssudheer out:
2050Sstevel@tonic-gate 	if ((func = kdi_softcall_func) != NULL) {
2060Sstevel@tonic-gate 		kdi_softcall_func = NULL;
2070Sstevel@tonic-gate 		func();
2080Sstevel@tonic-gate 	}
2090Sstevel@tonic-gate }
210