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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/param.h> 31 #include <sys/t_lock.h> 32 #include <sys/systm.h> 33 #include <sys/spl.h> 34 #include <sys/cmn_err.h> 35 #include <sys/debug.h> 36 #include <sys/kdi_impl.h> 37 38 /* 39 * Handle software interrupts through 'softcall' mechanism 40 * 41 * At present softcall mechanism uses a global list headed by softhead. 42 * Entries are added to tail and removed from head so as to preserve FIFO 43 * nature of entries in the softcall list. softcall() takes care of adding 44 * entries to the softtail. 45 * 46 * softint must take care of executing the entries in the FIFO 47 * order. It could be called simultaneously from multiple cpus, however only 48 * one instance of softint should process the softcall list, this is 49 * ensured by 50 * - the state the variable softcall_state will be at time to time. 51 * (IDLE->PEND->DRAIN->IDLE) 52 * 53 * These states are needed for softcall mechanism since Solaris has only 54 * one interface(ie. siron ) as of now for 55 * - raising a soft interrupt architecture independently(ie not through 56 * setsoftint(..) ) 57 * - to process the softcall queue. 58 */ 59 60 #define NSOFTCALLS 200 61 /* 62 * Defined states for softcall processing. 63 */ 64 #define SOFT_IDLE 0x01 /* no processing is needed */ 65 #define SOFT_PEND 0x02 /* softcall list needs processing */ 66 #define SOFT_DRAIN 0x04 /* the list is being processed */ 67 68 typedef struct softcall { 69 void (*sc_func)(void *); /* function to call */ 70 void *sc_arg; /* arg to pass to func */ 71 struct softcall *sc_next; /* next in list */ 72 } softcall_t; 73 74 static softcall_t softcalls[NSOFTCALLS], *softhead, *softtail, *softfree; 75 static uint_t softcall_state; 76 77 /* 78 * protects softcall lists and control variable softcall_state. 79 */ 80 static kmutex_t softcall_lock; 81 82 static void (*kdi_softcall_func)(void); 83 84 extern void 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 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