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