1 /* $NetBSD: shared_intr.c,v 1.12 2000/02/10 07:45:02 mjacob 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.12 2000/02/10 07:45:02 mjacob 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 intr[i].intr_private = NULL; 88 } 89 90 return (intr); 91 } 92 93 int 94 alpha_shared_intr_dispatch(intr, num) 95 struct alpha_shared_intr *intr; 96 unsigned int num; 97 { 98 struct alpha_shared_intrhand *ih; 99 int rv, handled; 100 101 ih = intr[num].intr_q.tqh_first; 102 handled = 0; 103 while (ih != NULL) { 104 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 114 handled = handled || (rv != 0); 115 ih = ih->ih_q.tqe_next; 116 } 117 118 return (handled); 119 } 120 121 void * 122 alpha_shared_intr_establish(intr, num, type, level, fn, arg, basename) 123 struct alpha_shared_intr *intr; 124 unsigned int num; 125 int type, level; 126 int (*fn) __P((void *)); 127 void *arg; 128 const char *basename; 129 { 130 struct alpha_shared_intrhand *ih; 131 132 if (intr[num].intr_sharetype == IST_UNUSABLE) { 133 printf("alpha_shared_intr_establish: %s %d: unusable\n", 134 basename, num); 135 return NULL; 136 } 137 138 /* no point in sleeping unless someone can free memory. */ 139 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 140 if (ih == NULL) 141 panic("alpha_shared_intr_establish: can't malloc intrhand"); 142 143 #ifdef DIAGNOSTIC 144 if (type == IST_NONE) 145 panic("alpha_shared_intr_establish: bogus type"); 146 #endif 147 148 switch (intr[num].intr_sharetype) { 149 case IST_EDGE: 150 case IST_LEVEL: 151 if (type == intr[num].intr_sharetype) 152 break; 153 case IST_PULSE: 154 if (type != IST_NONE) { 155 if (intr[num].intr_q.tqh_first == NULL) { 156 printf("alpha_shared_intr_establish: %s %d: warning: using %s on %s\n", 157 basename, num, intr_typename(type), 158 intr_typename(intr[num].intr_sharetype)); 159 type = intr[num].intr_sharetype; 160 } else { 161 panic("alpha_shared_intr_establish: %s %d: can't share %s with %s", 162 basename, num, intr_typename(type), 163 intr_typename(intr[num].intr_sharetype)); 164 } 165 } 166 break; 167 168 case IST_NONE: 169 /* not currently used; safe */ 170 break; 171 } 172 173 ih->ih_fn = fn; 174 ih->ih_arg = arg; 175 ih->ih_level = level; 176 ih->ih_num = num; 177 178 intr[num].intr_sharetype = type; 179 TAILQ_INSERT_TAIL(&intr[num].intr_q, ih, ih_q); 180 181 return (ih); 182 } 183 184 void 185 alpha_shared_intr_disestablish(intr, cookie, basename) 186 struct alpha_shared_intr *intr; 187 void *cookie; 188 const char *basename; 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 TAILQ_REMOVE(&intr[num].intr_q, ih, ih_q); 198 } 199 200 int 201 alpha_shared_intr_get_sharetype(intr, num) 202 struct alpha_shared_intr *intr; 203 unsigned int num; 204 { 205 206 return (intr[num].intr_sharetype); 207 } 208 209 int 210 alpha_shared_intr_isactive(intr, num) 211 struct alpha_shared_intr *intr; 212 unsigned int num; 213 { 214 215 return (intr[num].intr_q.tqh_first != NULL); 216 } 217 218 void 219 alpha_shared_intr_set_dfltsharetype(intr, num, newdfltsharetype) 220 struct alpha_shared_intr *intr; 221 unsigned int num; 222 int newdfltsharetype; 223 { 224 225 #ifdef DIAGNOSTIC 226 if (alpha_shared_intr_isactive(intr, num)) 227 panic("alpha_shared_intr_set_dfltsharetype on active intr"); 228 #endif 229 230 intr[num].intr_dfltsharetype = newdfltsharetype; 231 intr[num].intr_sharetype = intr[num].intr_dfltsharetype; 232 } 233 234 void 235 alpha_shared_intr_set_maxstrays(intr, num, newmaxstrays) 236 struct alpha_shared_intr *intr; 237 unsigned int num; 238 int newmaxstrays; 239 { 240 int s = splhigh(); 241 intr[num].intr_maxstrays = newmaxstrays; 242 intr[num].intr_nstrays = 0; 243 splx(s); 244 } 245 246 void 247 alpha_shared_intr_stray(intr, num, basename) 248 struct alpha_shared_intr *intr; 249 unsigned int num; 250 const char *basename; 251 { 252 253 intr[num].intr_nstrays++; 254 255 if (intr[num].intr_maxstrays == 0) 256 return; 257 258 if (intr[num].intr_nstrays <= intr[num].intr_maxstrays) 259 log(LOG_ERR, "stray %s %d%s\n", basename, num, 260 intr[num].intr_nstrays >= intr[num].intr_maxstrays ? 261 "; stopped logging" : ""); 262 } 263 264 void 265 alpha_shared_intr_set_private(intr, num, v) 266 struct alpha_shared_intr *intr; 267 unsigned int num; 268 void *v; 269 { 270 271 intr[num].intr_private = v; 272 } 273 274 void * 275 alpha_shared_intr_get_private(intr, num) 276 struct alpha_shared_intr *intr; 277 unsigned int num; 278 { 279 280 return (intr[num].intr_private); 281 } 282