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