1 /* $NetBSD: shared_intr.c,v 1.10 1999/12/08 23:54:55 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1996 Carnegie-Mellon University. 5 * All rights reserved. 6 * 7 * Authors: Chris G. Demetriou 8 * 9 * Permission to use, copy, modify and distribute this software and 10 * its documentation is hereby granted, provided that both the copyright 11 * notice and this permission notice appear in all copies of the 12 * software, derivative works or modified versions, and any portions 13 * thereof, and that both notices appear in supporting documentation. 14 * 15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 * 19 * Carnegie Mellon requests users of this software to return to 20 * 21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 22 * School of Computer Science 23 * Carnegie Mellon University 24 * Pittsburgh PA 15213-3890 25 * 26 * any improvements or extensions that they make and grant Carnegie the 27 * rights to redistribute these changes. 28 */ 29 30 /* 31 * Common shared-interrupt-line functionality. 32 */ 33 34 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 35 36 __KERNEL_RCSID(0, "$NetBSD: shared_intr.c,v 1.10 1999/12/08 23:54:55 thorpej Exp $"); 37 38 #include <sys/param.h> 39 #include <sys/kernel.h> 40 #include <sys/systm.h> 41 #include <sys/malloc.h> 42 #include <sys/syslog.h> 43 #include <sys/queue.h> 44 45 #include <machine/intr.h> 46 47 static const char *intr_typename __P((int)); 48 49 static const char * 50 intr_typename(type) 51 int type; 52 { 53 54 switch (type) { 55 case IST_UNUSABLE: 56 return ("disabled"); 57 case IST_NONE: 58 return ("none"); 59 case IST_PULSE: 60 return ("pulsed"); 61 case IST_EDGE: 62 return ("edge-triggered"); 63 case IST_LEVEL: 64 return ("level-triggered"); 65 } 66 panic("intr_typename: unknown type %d", type); 67 } 68 69 struct alpha_shared_intr * 70 alpha_shared_intr_alloc(n) 71 unsigned int n; 72 { 73 struct alpha_shared_intr *intr; 74 unsigned int i; 75 76 intr = malloc(n * sizeof (struct alpha_shared_intr), M_DEVBUF, 77 cold ? M_NOWAIT : M_WAITOK); 78 if (intr == NULL) 79 panic("alpha_shared_intr_alloc: couldn't malloc intr"); 80 81 for (i = 0; i < n; i++) { 82 TAILQ_INIT(&intr[i].intr_q); 83 intr[i].intr_sharetype = IST_NONE; 84 intr[i].intr_dfltsharetype = IST_NONE; 85 intr[i].intr_nstrays = 0; 86 intr[i].intr_maxstrays = 5; 87 } 88 89 return (intr); 90 } 91 92 int 93 alpha_shared_intr_dispatch(intr, num) 94 struct alpha_shared_intr *intr; 95 unsigned int num; 96 { 97 struct alpha_shared_intrhand *ih; 98 int rv, handled; 99 100 ih = intr[num].intr_q.tqh_first; 101 handled = 0; 102 while (ih != NULL) { 103 104 /* 105 * The handler returns one of three values: 106 * 0: This interrupt wasn't for me. 107 * 1: This interrupt was for me. 108 * -1: This interrupt might have been for me, but I can't say 109 * for sure. 110 */ 111 rv = (*ih->ih_fn)(ih->ih_arg); 112 113 handled = handled || (rv != 0); 114 ih = ih->ih_q.tqe_next; 115 } 116 117 return (handled); 118 } 119 120 void * 121 alpha_shared_intr_establish(intr, num, type, level, fn, arg, basename) 122 struct alpha_shared_intr *intr; 123 unsigned int num; 124 int type, level; 125 int (*fn) __P((void *)); 126 void *arg; 127 const char *basename; 128 { 129 struct alpha_shared_intrhand *ih; 130 131 if (intr[num].intr_sharetype == IST_UNUSABLE) { 132 printf("alpha_shared_intr_establish: %s %d: unusable\n", 133 basename, num); 134 return NULL; 135 } 136 137 /* no point in sleeping unless someone can free memory. */ 138 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 139 if (ih == NULL) 140 panic("alpha_shared_intr_establish: can't malloc intrhand"); 141 142 #ifdef DIAGNOSTIC 143 if (type == IST_NONE) 144 panic("alpha_shared_intr_establish: bogus type"); 145 #endif 146 147 switch (intr[num].intr_sharetype) { 148 case IST_EDGE: 149 case IST_LEVEL: 150 if (type == intr[num].intr_sharetype) 151 break; 152 case IST_PULSE: 153 if (type != IST_NONE) { 154 if (intr[num].intr_q.tqh_first == NULL) { 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_fn = fn; 173 ih->ih_arg = arg; 174 ih->ih_level = level; 175 ih->ih_num = num; 176 177 intr[num].intr_sharetype = type; 178 TAILQ_INSERT_TAIL(&intr[num].intr_q, ih, ih_q); 179 180 return (ih); 181 } 182 183 void 184 alpha_shared_intr_disestablish(intr, cookie, basename) 185 struct alpha_shared_intr *intr; 186 void *cookie; 187 const char *basename; 188 { 189 struct alpha_shared_intrhand *ih = cookie; 190 unsigned int num = ih->ih_num; 191 192 /* 193 * Just remove it from the list and free the entry. We let 194 * the caller deal with resetting the share type, if appropriate. 195 */ 196 TAILQ_REMOVE(&intr[num].intr_q, ih, ih_q); 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 (intr[num].intr_q.tqh_first != NULL); 215 } 216 217 void 218 alpha_shared_intr_set_dfltsharetype(intr, num, newdfltsharetype) 219 struct alpha_shared_intr *intr; 220 unsigned int num; 221 int newdfltsharetype; 222 { 223 224 #ifdef DIAGNOSTIC 225 if (alpha_shared_intr_isactive(intr, num)) 226 panic("alpha_shared_intr_set_dfltsharetype on active intr"); 227 #endif 228 229 intr[num].intr_dfltsharetype = newdfltsharetype; 230 intr[num].intr_sharetype = intr[num].intr_dfltsharetype; 231 } 232 233 void 234 alpha_shared_intr_set_maxstrays(intr, num, newmaxstrays) 235 struct alpha_shared_intr *intr; 236 unsigned int num; 237 int newmaxstrays; 238 { 239 240 #ifdef DIAGNOSTIC 241 if (alpha_shared_intr_isactive(intr, num)) 242 panic("alpha_shared_intr_set_maxstrays on active intr"); 243 #endif 244 245 intr[num].intr_maxstrays = newmaxstrays; 246 intr[num].intr_nstrays = 0; 247 } 248 249 void 250 alpha_shared_intr_stray(intr, num, basename) 251 struct alpha_shared_intr *intr; 252 unsigned int num; 253 const char *basename; 254 { 255 256 intr[num].intr_nstrays++; 257 258 if (intr[num].intr_maxstrays == 0) 259 return; 260 261 if (intr[num].intr_nstrays <= intr[num].intr_maxstrays) 262 log(LOG_ERR, "stray %s %d%s\n", basename, num, 263 intr[num].intr_nstrays >= intr[num].intr_maxstrays ? 264 "; stopped logging" : ""); 265 } 266 267 void 268 alpha_shared_intr_set_private(intr, num, v) 269 struct alpha_shared_intr *intr; 270 unsigned int num; 271 void *v; 272 { 273 274 intr[num].intr_private = v; 275 } 276 277 void * 278 alpha_shared_intr_get_private(intr, num) 279 struct alpha_shared_intr *intr; 280 unsigned int num; 281 { 282 283 return (intr[num].intr_private); 284 } 285