1 /* $NetBSD: shared_intr.c,v 1.6 1998/08/01 18:52:36 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.6 1998/08/01 18:52:36 thorpej Exp $"); 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/malloc.h> 41 #include <sys/syslog.h> 42 #include <sys/queue.h> 43 44 #include <machine/intr.h> 45 46 extern int cold; 47 48 static const char *intr_typename __P((int)); 49 50 static const char * 51 intr_typename(type) 52 int type; 53 { 54 55 switch (type) { 56 case IST_UNUSABLE: 57 return ("disabled"); 58 case IST_NONE: 59 return ("none"); 60 case IST_PULSE: 61 return ("pulsed"); 62 case IST_EDGE: 63 return ("edge-triggered"); 64 case IST_LEVEL: 65 return ("level-triggered"); 66 } 67 panic("intr_typename: unknown type %d", type); 68 } 69 70 struct alpha_shared_intr * 71 alpha_shared_intr_alloc(n) 72 unsigned int n; 73 { 74 struct alpha_shared_intr *intr; 75 unsigned int i; 76 77 intr = malloc(n * sizeof (struct alpha_shared_intr), M_DEVBUF, 78 cold ? M_NOWAIT : M_WAITOK); 79 if (intr == NULL) 80 panic("alpha_shared_intr_alloc: couldn't malloc intr"); 81 82 for (i = 0; i < n; i++) { 83 TAILQ_INIT(&intr[i].intr_q); 84 intr[i].intr_sharetype = IST_NONE; 85 intr[i].intr_dfltsharetype = IST_NONE; 86 intr[i].intr_nstrays = 0; 87 intr[i].intr_maxstrays = 5; 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 241 #ifdef DIAGNOSTIC 242 if (alpha_shared_intr_isactive(intr, num)) 243 panic("alpha_shared_intr_set_maxstrays on active intr"); 244 #endif 245 246 intr[num].intr_maxstrays = newmaxstrays; 247 intr[num].intr_nstrays = 0; 248 } 249 250 void 251 alpha_shared_intr_stray(intr, num, basename) 252 struct alpha_shared_intr *intr; 253 unsigned int num; 254 const char *basename; 255 { 256 257 intr[num].intr_nstrays++; 258 259 if (intr[num].intr_maxstrays == 0) 260 return; 261 262 if (intr[num].intr_nstrays <= intr[num].intr_maxstrays) 263 log(LOG_ERR, "stray %s %d%s\n", basename, num, 264 intr[num].intr_nstrays >= intr[num].intr_maxstrays ? 265 "; stopped logging" : ""); 266 } 267