1 /* $OpenBSD: shared_intr.c,v 1.22 2015/09/02 14:07:43 deraadt Exp $ */ 2 /* $NetBSD: shared_intr.c,v 1.13 2000/03/19 01:46:18 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1996 Carnegie-Mellon University. 6 * All rights reserved. 7 * 8 * Authors: Chris G. Demetriou 9 * 10 * Permission to use, copy, modify and distribute this software and 11 * its documentation is hereby granted, provided that both the copyright 12 * notice and this permission notice appear in all copies of the 13 * software, derivative works or modified versions, and any portions 14 * thereof, and that both notices appear in supporting documentation. 15 * 16 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 17 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 18 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 19 * 20 * Carnegie Mellon requests users of this software to return to 21 * 22 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 23 * School of Computer Science 24 * Carnegie Mellon University 25 * Pittsburgh PA 15213-3890 26 * 27 * any improvements or extensions that they make and grant Carnegie the 28 * rights to redistribute these changes. 29 */ 30 31 /* 32 * Common shared-interrupt-line functionality. 33 */ 34 35 #include <sys/param.h> 36 #include <sys/kernel.h> 37 #include <sys/systm.h> 38 #include <sys/malloc.h> 39 #include <sys/syslog.h> 40 #include <sys/queue.h> 41 42 #include <machine/intr.h> 43 44 static const char *intr_typename(int); 45 46 static const char * 47 intr_typename(type) 48 int type; 49 { 50 51 switch (type) { 52 case IST_UNUSABLE: 53 return ("disabled"); 54 case IST_NONE: 55 return ("none"); 56 case IST_PULSE: 57 return ("pulsed"); 58 case IST_EDGE: 59 return ("edge-triggered"); 60 case IST_LEVEL: 61 return ("level-triggered"); 62 } 63 panic("intr_typename: unknown type %d", type); 64 } 65 66 struct alpha_shared_intr * 67 alpha_shared_intr_alloc(n) 68 unsigned int n; 69 { 70 struct alpha_shared_intr *intr; 71 unsigned int i; 72 73 intr = mallocarray(n, sizeof(struct alpha_shared_intr), M_DEVBUF, 74 cold ? M_NOWAIT : M_WAITOK); 75 if (intr == NULL) 76 panic("alpha_shared_intr_alloc: couldn't malloc intr"); 77 78 for (i = 0; i < n; i++) { 79 TAILQ_INIT(&intr[i].intr_q); 80 intr[i].intr_sharetype = IST_NONE; 81 intr[i].intr_dfltsharetype = IST_NONE; 82 intr[i].intr_nstrays = 0; 83 intr[i].intr_maxstrays = 5; 84 intr[i].intr_private = NULL; 85 } 86 87 return (intr); 88 } 89 90 int 91 alpha_shared_intr_dispatch(intr, num) 92 struct alpha_shared_intr *intr; 93 unsigned int num; 94 { 95 struct alpha_shared_intrhand *ih; 96 int rv, handled; 97 98 handled = 0; 99 TAILQ_FOREACH(ih, &intr[num].intr_q, ih_q) { 100 #if defined(MULTIPROCESSOR) 101 /* XXX Need to support IPL_MPSAFE eventually. */ 102 if (ih->ih_level < IPL_CLOCK) 103 __mp_lock(&kernel_lock); 104 #endif 105 /* 106 * The handler returns one of three values: 107 * 0: This interrupt wasn't for me. 108 * 1: This interrupt was for me. 109 * -1: This interrupt might have been for me, but I can't say 110 * for sure. 111 */ 112 rv = (*ih->ih_fn)(ih->ih_arg); 113 if (rv) 114 ih->ih_count.ec_count++; 115 #if defined(MULTIPROCESSOR) 116 if (ih->ih_level < IPL_CLOCK) 117 __mp_unlock(&kernel_lock); 118 #endif 119 handled = handled || (rv != 0); 120 if (intr_shared_edge == 0 && rv == 1) 121 break; 122 } 123 124 return (handled); 125 } 126 127 void * 128 alpha_shared_intr_establish(intr, num, type, level, fn, arg, basename) 129 struct alpha_shared_intr *intr; 130 unsigned int num; 131 int type, level; 132 int (*fn)(void *); 133 void *arg; 134 const char *basename; 135 { 136 struct alpha_shared_intrhand *ih; 137 138 if (intr[num].intr_sharetype == IST_UNUSABLE) { 139 printf("alpha_shared_intr_establish: %s %d: unusable\n", 140 basename, num); 141 return NULL; 142 } 143 144 /* no point in sleeping unless someone can free memory. */ 145 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 146 if (ih == NULL) 147 panic("alpha_shared_intr_establish: can't malloc intrhand"); 148 149 #ifdef DIAGNOSTIC 150 if (type == IST_NONE) 151 panic("alpha_shared_intr_establish: bogus type"); 152 #endif 153 154 switch (intr[num].intr_sharetype) { 155 case IST_EDGE: 156 intr_shared_edge = 1; 157 /* FALLTHROUGH */ 158 case IST_LEVEL: 159 if (type == intr[num].intr_sharetype) 160 break; 161 case IST_PULSE: 162 if (type != IST_NONE) { 163 if (TAILQ_EMPTY(&intr[num].intr_q)) { 164 printf("alpha_shared_intr_establish: %s %d: warning: using %s on %s\n", 165 basename, num, intr_typename(type), 166 intr_typename(intr[num].intr_sharetype)); 167 type = intr[num].intr_sharetype; 168 } else { 169 panic("alpha_shared_intr_establish: %s %d: can't share %s with %s", 170 basename, num, intr_typename(type), 171 intr_typename(intr[num].intr_sharetype)); 172 } 173 } 174 break; 175 176 case IST_NONE: 177 /* not currently used; safe */ 178 break; 179 } 180 181 ih->ih_intrhead = intr; 182 ih->ih_fn = fn; 183 ih->ih_arg = arg; 184 ih->ih_level = level; 185 ih->ih_num = num; 186 evcount_attach(&ih->ih_count, basename, &ih->ih_num); 187 188 intr[num].intr_sharetype = type; 189 TAILQ_INSERT_TAIL(&intr[num].intr_q, ih, ih_q); 190 191 return (ih); 192 } 193 194 void 195 alpha_shared_intr_disestablish(intr, cookie) 196 struct alpha_shared_intr *intr; 197 void *cookie; 198 { 199 struct alpha_shared_intrhand *ih = cookie; 200 unsigned int num = ih->ih_num; 201 202 /* 203 * Just remove it from the list and free the entry. We let 204 * the caller deal with resetting the share type, if appropriate. 205 */ 206 evcount_detach(&ih->ih_count); 207 TAILQ_REMOVE(&intr[num].intr_q, ih, ih_q); 208 free(ih, M_DEVBUF, sizeof *ih); 209 } 210 211 int 212 alpha_shared_intr_get_sharetype(intr, num) 213 struct alpha_shared_intr *intr; 214 unsigned int num; 215 { 216 217 return (intr[num].intr_sharetype); 218 } 219 220 int 221 alpha_shared_intr_isactive(intr, num) 222 struct alpha_shared_intr *intr; 223 unsigned int num; 224 { 225 226 return (!TAILQ_EMPTY(&intr[num].intr_q)); 227 } 228 229 int 230 alpha_shared_intr_firstactive(struct alpha_shared_intr *intr, unsigned int num) 231 { 232 233 return (!TAILQ_EMPTY(&intr[num].intr_q) && 234 TAILQ_NEXT(intr[num].intr_q.tqh_first, ih_q) == NULL); 235 } 236 237 void 238 alpha_shared_intr_set_dfltsharetype(intr, num, newdfltsharetype) 239 struct alpha_shared_intr *intr; 240 unsigned int num; 241 int newdfltsharetype; 242 { 243 244 #ifdef DIAGNOSTIC 245 if (alpha_shared_intr_isactive(intr, num)) 246 panic("alpha_shared_intr_set_dfltsharetype on active intr"); 247 #endif 248 249 intr[num].intr_dfltsharetype = newdfltsharetype; 250 intr[num].intr_sharetype = intr[num].intr_dfltsharetype; 251 } 252 253 void 254 alpha_shared_intr_set_maxstrays(intr, num, newmaxstrays) 255 struct alpha_shared_intr *intr; 256 unsigned int num; 257 int newmaxstrays; 258 { 259 int s = splhigh(); 260 intr[num].intr_maxstrays = newmaxstrays; 261 intr[num].intr_nstrays = 0; 262 splx(s); 263 } 264 265 void 266 alpha_shared_intr_reset_strays(intr, num) 267 struct alpha_shared_intr *intr; 268 unsigned int num; 269 { 270 271 /* 272 * Don't bother blocking interrupts; this doesn't have to be 273 * precise, but it does need to be fast. 274 */ 275 intr[num].intr_nstrays = 0; 276 } 277 278 void 279 alpha_shared_intr_stray(intr, num, basename) 280 struct alpha_shared_intr *intr; 281 unsigned int num; 282 const char *basename; 283 { 284 285 intr[num].intr_nstrays++; 286 287 if (intr[num].intr_maxstrays == 0) 288 return; 289 290 if (intr[num].intr_nstrays <= intr[num].intr_maxstrays) 291 log(LOG_ERR, "stray %s %d%s\n", basename, num, 292 intr[num].intr_nstrays >= intr[num].intr_maxstrays ? 293 "; stopped logging" : ""); 294 } 295 296 void 297 alpha_shared_intr_set_private(intr, num, v) 298 struct alpha_shared_intr *intr; 299 unsigned int num; 300 void *v; 301 { 302 303 intr[num].intr_private = v; 304 } 305 306 void * 307 alpha_shared_intr_get_private(intr, num) 308 struct alpha_shared_intr *intr; 309 unsigned int num; 310 { 311 312 return (intr[num].intr_private); 313 } 314