1 /* $OpenBSD: shared_intr.c,v 1.16 2009/09/30 20:16:22 miod 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 = malloc(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 /* 101 * The handler returns one of three values: 102 * 0: This interrupt wasn't for me. 103 * 1: This interrupt was for me. 104 * -1: This interrupt might have been for me, but I can't say 105 * for sure. 106 */ 107 if ((rv = (*ih->ih_fn)(ih->ih_arg))) 108 ih->ih_count.ec_count++; 109 110 handled = handled || (rv != 0); 111 } 112 113 return (handled); 114 } 115 116 void * 117 alpha_shared_intr_establish(intr, num, type, level, fn, arg, basename) 118 struct alpha_shared_intr *intr; 119 unsigned int num; 120 int type, level; 121 int (*fn)(void *); 122 void *arg; 123 const char *basename; 124 { 125 struct alpha_shared_intrhand *ih; 126 127 if (intr[num].intr_sharetype == IST_UNUSABLE) { 128 printf("alpha_shared_intr_establish: %s %d: unusable\n", 129 basename, num); 130 return NULL; 131 } 132 133 /* no point in sleeping unless someone can free memory. */ 134 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 135 if (ih == NULL) 136 panic("alpha_shared_intr_establish: can't malloc intrhand"); 137 138 #ifdef DIAGNOSTIC 139 if (type == IST_NONE) 140 panic("alpha_shared_intr_establish: bogus type"); 141 #endif 142 143 switch (intr[num].intr_sharetype) { 144 case IST_EDGE: 145 case IST_LEVEL: 146 if (type == intr[num].intr_sharetype) 147 break; 148 case IST_PULSE: 149 if (type != IST_NONE) { 150 if (TAILQ_EMPTY(&intr[num].intr_q)) { 151 printf("alpha_shared_intr_establish: %s %d: warning: using %s on %s\n", 152 basename, num, intr_typename(type), 153 intr_typename(intr[num].intr_sharetype)); 154 type = intr[num].intr_sharetype; 155 } else { 156 panic("alpha_shared_intr_establish: %s %d: can't share %s with %s", 157 basename, num, intr_typename(type), 158 intr_typename(intr[num].intr_sharetype)); 159 } 160 } 161 break; 162 163 case IST_NONE: 164 /* not currently used; safe */ 165 break; 166 } 167 168 ih->ih_intrhead = intr; 169 ih->ih_fn = fn; 170 ih->ih_arg = arg; 171 ih->ih_level = level; 172 ih->ih_num = num; 173 evcount_attach(&ih->ih_count, basename, (void *)&ih->ih_num, 174 &evcount_intr); 175 176 intr[num].intr_sharetype = type; 177 TAILQ_INSERT_TAIL(&intr[num].intr_q, ih, ih_q); 178 179 return (ih); 180 } 181 182 void 183 alpha_shared_intr_disestablish(intr, cookie) 184 struct alpha_shared_intr *intr; 185 void *cookie; 186 { 187 struct alpha_shared_intrhand *ih = cookie; 188 unsigned int num = ih->ih_num; 189 190 /* 191 * Just remove it from the list and free the entry. We let 192 * the caller deal with resetting the share type, if appropriate. 193 */ 194 evcount_detach(&ih->ih_count); 195 TAILQ_REMOVE(&intr[num].intr_q, ih, ih_q); 196 free(ih, M_DEVBUF); 197 } 198 199 int 200 alpha_shared_intr_get_sharetype(intr, num) 201 struct alpha_shared_intr *intr; 202 unsigned int num; 203 { 204 205 return (intr[num].intr_sharetype); 206 } 207 208 int 209 alpha_shared_intr_isactive(intr, num) 210 struct alpha_shared_intr *intr; 211 unsigned int num; 212 { 213 214 return (!TAILQ_EMPTY(&intr[num].intr_q)); 215 } 216 217 int 218 alpha_shared_intr_firstactive(struct alpha_shared_intr *intr, unsigned int num) 219 { 220 221 return (!TAILQ_EMPTY(&intr[num].intr_q) && 222 TAILQ_NEXT(intr[num].intr_q.tqh_first, ih_q) == NULL); 223 } 224 225 void 226 alpha_shared_intr_set_dfltsharetype(intr, num, newdfltsharetype) 227 struct alpha_shared_intr *intr; 228 unsigned int num; 229 int newdfltsharetype; 230 { 231 232 #ifdef DIAGNOSTIC 233 if (alpha_shared_intr_isactive(intr, num)) 234 panic("alpha_shared_intr_set_dfltsharetype on active intr"); 235 #endif 236 237 intr[num].intr_dfltsharetype = newdfltsharetype; 238 intr[num].intr_sharetype = intr[num].intr_dfltsharetype; 239 } 240 241 void 242 alpha_shared_intr_set_maxstrays(intr, num, newmaxstrays) 243 struct alpha_shared_intr *intr; 244 unsigned int num; 245 int newmaxstrays; 246 { 247 int s = splhigh(); 248 intr[num].intr_maxstrays = newmaxstrays; 249 intr[num].intr_nstrays = 0; 250 splx(s); 251 } 252 253 void 254 alpha_shared_intr_reset_strays(intr, num) 255 struct alpha_shared_intr *intr; 256 unsigned int num; 257 { 258 259 /* 260 * Don't bother blocking interrupts; this doesn't have to be 261 * precise, but it does need to be fast. 262 */ 263 intr[num].intr_nstrays = 0; 264 } 265 266 void 267 alpha_shared_intr_stray(intr, num, basename) 268 struct alpha_shared_intr *intr; 269 unsigned int num; 270 const char *basename; 271 { 272 273 intr[num].intr_nstrays++; 274 275 if (intr[num].intr_maxstrays == 0) 276 return; 277 278 if (intr[num].intr_nstrays <= intr[num].intr_maxstrays) 279 log(LOG_ERR, "stray %s %d%s\n", basename, num, 280 intr[num].intr_nstrays >= intr[num].intr_maxstrays ? 281 "; stopped logging" : ""); 282 } 283 284 void 285 alpha_shared_intr_set_private(intr, num, v) 286 struct alpha_shared_intr *intr; 287 unsigned int num; 288 void *v; 289 { 290 291 intr[num].intr_private = v; 292 } 293 294 void * 295 alpha_shared_intr_get_private(intr, num) 296 struct alpha_shared_intr *intr; 297 unsigned int num; 298 { 299 300 return (intr[num].intr_private); 301 } 302