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