1 /* $OpenBSD: shared_intr.c,v 1.10 2001/06/25 00:43:07 mickey 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 __P((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 ih = intr[num].intr_q.tqh_first; 99 handled = 0; 100 while (ih != NULL) { 101 102 /* 103 * The handler returns one of three values: 104 * 0: This interrupt wasn't for me. 105 * 1: This interrupt was for me. 106 * -1: This interrupt might have been for me, but I can't say 107 * for sure. 108 */ 109 rv = (*ih->ih_fn)(ih->ih_arg); 110 111 handled = handled || (rv != 0); 112 ih = ih->ih_q.tqe_next; 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) __P((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 case IST_LEVEL: 148 if (type == intr[num].intr_sharetype) 149 break; 150 case IST_PULSE: 151 if (type != IST_NONE) { 152 if (intr[num].intr_q.tqh_first == NULL) { 153 printf("alpha_shared_intr_establish: %s %d: warning: using %s on %s\n", 154 basename, num, intr_typename(type), 155 intr_typename(intr[num].intr_sharetype)); 156 type = intr[num].intr_sharetype; 157 } else { 158 panic("alpha_shared_intr_establish: %s %d: can't share %s with %s", 159 basename, num, intr_typename(type), 160 intr_typename(intr[num].intr_sharetype)); 161 } 162 } 163 break; 164 165 case IST_NONE: 166 /* not currently used; safe */ 167 break; 168 } 169 170 ih->ih_intrhead = intr; 171 ih->ih_fn = fn; 172 ih->ih_arg = arg; 173 ih->ih_level = level; 174 ih->ih_num = num; 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, basename) 184 struct alpha_shared_intr *intr; 185 void *cookie; 186 const char *basename; 187 { 188 struct alpha_shared_intrhand *ih = cookie; 189 unsigned int num = ih->ih_num; 190 191 /* 192 * Just remove it from the list and free the entry. We let 193 * the caller deal with resetting the share type, if appropriate. 194 */ 195 TAILQ_REMOVE(&intr[num].intr_q, ih, ih_q); 196 } 197 198 int 199 alpha_shared_intr_get_sharetype(intr, num) 200 struct alpha_shared_intr *intr; 201 unsigned int num; 202 { 203 204 return (intr[num].intr_sharetype); 205 } 206 207 int 208 alpha_shared_intr_isactive(intr, num) 209 struct alpha_shared_intr *intr; 210 unsigned int num; 211 { 212 213 return (intr[num].intr_q.tqh_first != NULL); 214 } 215 216 void 217 alpha_shared_intr_set_dfltsharetype(intr, num, newdfltsharetype) 218 struct alpha_shared_intr *intr; 219 unsigned int num; 220 int newdfltsharetype; 221 { 222 223 #ifdef DIAGNOSTIC 224 if (alpha_shared_intr_isactive(intr, num)) 225 panic("alpha_shared_intr_set_dfltsharetype on active intr"); 226 #endif 227 228 intr[num].intr_dfltsharetype = newdfltsharetype; 229 intr[num].intr_sharetype = intr[num].intr_dfltsharetype; 230 } 231 232 void 233 alpha_shared_intr_set_maxstrays(intr, num, newmaxstrays) 234 struct alpha_shared_intr *intr; 235 unsigned int num; 236 int newmaxstrays; 237 { 238 int s = splhigh(); 239 intr[num].intr_maxstrays = newmaxstrays; 240 intr[num].intr_nstrays = 0; 241 splx(s); 242 } 243 244 void 245 alpha_shared_intr_stray(intr, num, basename) 246 struct alpha_shared_intr *intr; 247 unsigned int num; 248 const char *basename; 249 { 250 251 intr[num].intr_nstrays++; 252 253 if (intr[num].intr_maxstrays == 0) 254 return; 255 256 if (intr[num].intr_nstrays <= intr[num].intr_maxstrays) 257 log(LOG_ERR, "stray %s %d%s\n", basename, num, 258 intr[num].intr_nstrays >= intr[num].intr_maxstrays ? 259 "; stopped logging" : ""); 260 } 261 262 void 263 alpha_shared_intr_set_private(intr, num, v) 264 struct alpha_shared_intr *intr; 265 unsigned int num; 266 void *v; 267 { 268 269 intr[num].intr_private = v; 270 } 271 272 void * 273 alpha_shared_intr_get_private(intr, num) 274 struct alpha_shared_intr *intr; 275 unsigned int num; 276 { 277 278 return (intr[num].intr_private); 279 } 280