xref: /titanic_50/usr/src/uts/common/os/softint.c (revision a1af7ba02a81ee5af0f2cd6b30b99957a93fc605)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*a1af7ba0Scwb  * Common Development and Distribution License (the "License").
6*a1af7ba0Scwb  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*a1af7ba0Scwb  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <sys/types.h>
297c478bd9Sstevel@tonic-gate #include <sys/param.h>
307c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
317c478bd9Sstevel@tonic-gate #include <sys/systm.h>
327c478bd9Sstevel@tonic-gate #include <sys/spl.h>
337c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
347c478bd9Sstevel@tonic-gate #include <sys/debug.h>
357c478bd9Sstevel@tonic-gate #include <sys/kdi_impl.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate /*
387c478bd9Sstevel@tonic-gate  * Handle software interrupts through 'softcall' mechanism
39f8047eabSsudheer  *
40f8047eabSsudheer  * At present softcall mechanism uses a global list headed by softhead.
41f8047eabSsudheer  * Entries are added to tail and removed from head so as to preserve FIFO
42f8047eabSsudheer  * nature of entries in the softcall list. softcall() takes care of adding
43f8047eabSsudheer  * entries to the softtail.
44f8047eabSsudheer  *
45f8047eabSsudheer  * softint must take care of executing the entries in the FIFO
46f8047eabSsudheer  * order. It could be called simultaneously from multiple cpus, however only
47f8047eabSsudheer  * one instance of softint should process the softcall list, this is
48f8047eabSsudheer  * ensured by
49f8047eabSsudheer  * - the state the variable softcall_state will be at time to time.
50f8047eabSsudheer  *   (IDLE->PEND->DRAIN->IDLE)
51f8047eabSsudheer  *
52f8047eabSsudheer  * These states are needed for softcall mechanism since  Solaris has only
53f8047eabSsudheer  * one interface(ie. siron ) as of now for
54f8047eabSsudheer  * - raising a soft interrupt architecture independently(ie not through
55f8047eabSsudheer  *   setsoftint(..) )
56f8047eabSsudheer  * - to process the softcall queue.
577c478bd9Sstevel@tonic-gate  */
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate #define	NSOFTCALLS	200
60f8047eabSsudheer /*
61f8047eabSsudheer  * Defined states for softcall processing.
62f8047eabSsudheer  */
63f8047eabSsudheer #define	SOFT_IDLE		0x01	/* no processing is needed */
64f8047eabSsudheer #define	SOFT_PEND		0x02	/* softcall list needs processing */
65f8047eabSsudheer #define	SOFT_DRAIN		0x04	/* the list is being processed */
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate typedef struct softcall {
687c478bd9Sstevel@tonic-gate 	void (*sc_func)(void *);	/* function to call */
697c478bd9Sstevel@tonic-gate 	void *sc_arg;			/* arg to pass to func */
707c478bd9Sstevel@tonic-gate 	struct softcall *sc_next;	/* next in list */
717c478bd9Sstevel@tonic-gate } softcall_t;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate static softcall_t softcalls[NSOFTCALLS], *softhead, *softtail, *softfree;
74f8047eabSsudheer static uint_t	softcall_state;
757c478bd9Sstevel@tonic-gate 
76f8047eabSsudheer /*
77f8047eabSsudheer  * protects softcall lists and control variable softcall_state.
78f8047eabSsudheer  */
79f8047eabSsudheer static kmutex_t	softcall_lock;
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate static void (*kdi_softcall_func)(void);
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate extern void siron(void);
84*a1af7ba0Scwb extern void kdi_siron(void);
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate void
877c478bd9Sstevel@tonic-gate softcall_init(void)
887c478bd9Sstevel@tonic-gate {
897c478bd9Sstevel@tonic-gate 	softcall_t *sc;
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	for (sc = softcalls; sc < &softcalls[NSOFTCALLS]; sc++) {
927c478bd9Sstevel@tonic-gate 		sc->sc_next = softfree;
937c478bd9Sstevel@tonic-gate 		softfree = sc;
947c478bd9Sstevel@tonic-gate 	}
957c478bd9Sstevel@tonic-gate 	mutex_init(&softcall_lock, NULL, MUTEX_SPIN, (void *)ipltospl(SPL8));
967c478bd9Sstevel@tonic-gate }
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate  * Call function func with argument arg
1007c478bd9Sstevel@tonic-gate  * at some later time at software interrupt priority
1017c478bd9Sstevel@tonic-gate  */
1027c478bd9Sstevel@tonic-gate void
1037c478bd9Sstevel@tonic-gate softcall(void (*func)(void *), void *arg)
1047c478bd9Sstevel@tonic-gate {
1057c478bd9Sstevel@tonic-gate 	softcall_t *sc;
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	/*
1087c478bd9Sstevel@tonic-gate 	 * protect against cross-calls
1097c478bd9Sstevel@tonic-gate 	 */
1107c478bd9Sstevel@tonic-gate 	mutex_enter(&softcall_lock);
1117c478bd9Sstevel@tonic-gate 	/* coalesce identical softcalls */
1127c478bd9Sstevel@tonic-gate 	for (sc = softhead; sc != 0; sc = sc->sc_next) {
1137c478bd9Sstevel@tonic-gate 		if (sc->sc_func == func && sc->sc_arg == arg) {
1147c478bd9Sstevel@tonic-gate 			mutex_exit(&softcall_lock);
1157c478bd9Sstevel@tonic-gate 			return;
1167c478bd9Sstevel@tonic-gate 		}
1177c478bd9Sstevel@tonic-gate 	}
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	if ((sc = softfree) == 0)
1207c478bd9Sstevel@tonic-gate 		panic("too many softcalls");
1217c478bd9Sstevel@tonic-gate 	softfree = sc->sc_next;
1227c478bd9Sstevel@tonic-gate 	sc->sc_func = func;
1237c478bd9Sstevel@tonic-gate 	sc->sc_arg = arg;
1247c478bd9Sstevel@tonic-gate 	sc->sc_next = 0;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	if (softhead) {
1277c478bd9Sstevel@tonic-gate 		softtail->sc_next = sc;
1287c478bd9Sstevel@tonic-gate 		softtail = sc;
1297c478bd9Sstevel@tonic-gate 		mutex_exit(&softcall_lock);
1307c478bd9Sstevel@tonic-gate 	} else {
1317c478bd9Sstevel@tonic-gate 		softhead = softtail = sc;
132f8047eabSsudheer 		if (softcall_state == SOFT_DRAIN)
133f8047eabSsudheer 			/*
134f8047eabSsudheer 			 * softint is already running; no need to
135f8047eabSsudheer 			 * raise a siron. Due to lock protection of
136f8047eabSsudheer 			 * softhead / softcall state, we know
137f8047eabSsudheer 			 * that softint() will see the new addition to
138f8047eabSsudheer 			 * the softhead queue.
139f8047eabSsudheer 			 */
140f8047eabSsudheer 			mutex_exit(&softcall_lock);
141f8047eabSsudheer 		else {
142f8047eabSsudheer 			softcall_state = SOFT_PEND;
1437c478bd9Sstevel@tonic-gate 			mutex_exit(&softcall_lock);
1447c478bd9Sstevel@tonic-gate 			siron();
1457c478bd9Sstevel@tonic-gate 		}
1467c478bd9Sstevel@tonic-gate 	}
147f8047eabSsudheer }
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate void
1507c478bd9Sstevel@tonic-gate kdi_softcall(void (*func)(void))
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate 	kdi_softcall_func = func;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	if (softhead == NULL)
155*a1af7ba0Scwb 		kdi_siron();
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate /*
159f8047eabSsudheer  * Called to process software interrupts take one off queue, call it,
160f8047eabSsudheer  * repeat.
161f8047eabSsudheer  *
162f8047eabSsudheer  * Note queue may change during call; softcall_lock and state variables
163f8047eabSsudheer  * softcall_state ensures that
164f8047eabSsudheer  * -we don't have multiple cpus pulling from the list (thus causing
165f8047eabSsudheer  *  a violation of FIFO order).
166f8047eabSsudheer  * -we don't miss a new entry having been added to the head.
167f8047eabSsudheer  * -we don't miss a wakeup.
1687c478bd9Sstevel@tonic-gate  */
169f8047eabSsudheer 
1707c478bd9Sstevel@tonic-gate void
1717c478bd9Sstevel@tonic-gate softint(void)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate 	softcall_t *sc;
1747c478bd9Sstevel@tonic-gate 	void (*func)();
1757c478bd9Sstevel@tonic-gate 	caddr_t arg;
1767c478bd9Sstevel@tonic-gate 
177f8047eabSsudheer 	/*
178f8047eabSsudheer 	 * Check if we are asked to process the softcall list.
179f8047eabSsudheer 	 */
1807c478bd9Sstevel@tonic-gate 	mutex_enter(&softcall_lock);
181f8047eabSsudheer 	if (softcall_state != SOFT_PEND) {
182f8047eabSsudheer 		mutex_exit(&softcall_lock);
183f8047eabSsudheer 		goto out;
184f8047eabSsudheer 	}
185f8047eabSsudheer 	softcall_state = SOFT_DRAIN;
186f8047eabSsudheer 
187f8047eabSsudheer 	for (;;) {
1887c478bd9Sstevel@tonic-gate 		if ((sc = softhead) != NULL) {
1897c478bd9Sstevel@tonic-gate 			func = sc->sc_func;
1907c478bd9Sstevel@tonic-gate 			arg = sc->sc_arg;
1917c478bd9Sstevel@tonic-gate 			softhead = sc->sc_next;
1927c478bd9Sstevel@tonic-gate 			sc->sc_next = softfree;
1937c478bd9Sstevel@tonic-gate 			softfree = sc;
1947c478bd9Sstevel@tonic-gate 		}
195f8047eabSsudheer 		if (sc == NULL) {
196f8047eabSsudheer 			softcall_state = SOFT_IDLE;
1977c478bd9Sstevel@tonic-gate 			mutex_exit(&softcall_lock);
1987c478bd9Sstevel@tonic-gate 			break;
1997c478bd9Sstevel@tonic-gate 		}
200f8047eabSsudheer 		mutex_exit(&softcall_lock);
201f8047eabSsudheer 		func(arg);
202f8047eabSsudheer 		mutex_enter(&softcall_lock);
203f8047eabSsudheer 	}
204f8047eabSsudheer out:
2057c478bd9Sstevel@tonic-gate 	if ((func = kdi_softcall_func) != NULL) {
2067c478bd9Sstevel@tonic-gate 		kdi_softcall_func = NULL;
2077c478bd9Sstevel@tonic-gate 		func();
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate }
210