1 /* $NetBSD: shared_intr.c,v 1.16 2001/07/27 00:25:19 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.16 2001/07/27 00:25:19 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(int type) 51 { 52 53 switch (type) { 54 case IST_UNUSABLE: 55 return ("disabled"); 56 case IST_NONE: 57 return ("none"); 58 case IST_PULSE: 59 return ("pulsed"); 60 case IST_EDGE: 61 return ("edge-triggered"); 62 case IST_LEVEL: 63 return ("level-triggered"); 64 } 65 panic("intr_typename: unknown type %d", type); 66 } 67 68 struct alpha_shared_intr * 69 alpha_shared_intr_alloc(unsigned int n, unsigned int namesize) 70 { 71 struct alpha_shared_intr *intr; 72 unsigned int i; 73 74 intr = malloc(n * sizeof (struct alpha_shared_intr), M_DEVBUF, 75 cold ? M_NOWAIT : M_WAITOK); 76 if (intr == NULL) 77 panic("alpha_shared_intr_alloc: couldn't malloc intr"); 78 79 for (i = 0; i < n; i++) { 80 TAILQ_INIT(&intr[i].intr_q); 81 intr[i].intr_sharetype = IST_NONE; 82 intr[i].intr_dfltsharetype = IST_NONE; 83 intr[i].intr_nstrays = 0; 84 intr[i].intr_maxstrays = 5; 85 intr[i].intr_private = NULL; 86 if (namesize != 0) { 87 intr[i].intr_string = malloc(namesize, M_DEVBUF, 88 cold ? M_NOWAIT : M_WAITOK); 89 if (intr[i].intr_string == NULL) 90 panic("alpha_shared_intr_alloc: couldn't " 91 "malloc intr string"); 92 } else 93 intr[i].intr_string = NULL; 94 } 95 96 return (intr); 97 } 98 99 int 100 alpha_shared_intr_dispatch(struct alpha_shared_intr *intr, unsigned int num) 101 { 102 struct alpha_shared_intrhand *ih; 103 int rv, handled; 104 105 atomic_add_ulong(&intr[num].intr_evcnt.ev_count, 1); 106 107 ih = intr[num].intr_q.tqh_first; 108 handled = 0; 109 while (ih != NULL) { 110 111 /* 112 * The handler returns one of three values: 113 * 0: This interrupt wasn't for me. 114 * 1: This interrupt was for me. 115 * -1: This interrupt might have been for me, but I can't say 116 * for sure. 117 */ 118 rv = (*ih->ih_fn)(ih->ih_arg); 119 120 handled = handled || (rv != 0); 121 ih = ih->ih_q.tqe_next; 122 } 123 124 return (handled); 125 } 126 127 void * 128 alpha_shared_intr_establish(struct alpha_shared_intr *intr, unsigned int num, 129 int type, int level, int (*fn)(void *), void *arg, const char *basename) 130 { 131 struct alpha_shared_intrhand *ih; 132 133 if (intr[num].intr_sharetype == IST_UNUSABLE) { 134 printf("alpha_shared_intr_establish: %s %d: unusable\n", 135 basename, num); 136 return NULL; 137 } 138 139 /* no point in sleeping unless someone can free memory. */ 140 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 141 if (ih == NULL) 142 panic("alpha_shared_intr_establish: can't malloc intrhand"); 143 144 #ifdef DIAGNOSTIC 145 if (type == IST_NONE) 146 panic("alpha_shared_intr_establish: bogus type"); 147 #endif 148 149 switch (intr[num].intr_sharetype) { 150 case IST_EDGE: 151 case IST_LEVEL: 152 if (type == intr[num].intr_sharetype) 153 break; 154 case IST_PULSE: 155 if (type != IST_NONE) { 156 if (intr[num].intr_q.tqh_first == NULL) { 157 printf("alpha_shared_intr_establish: %s %d: warning: using %s on %s\n", 158 basename, num, intr_typename(type), 159 intr_typename(intr[num].intr_sharetype)); 160 type = intr[num].intr_sharetype; 161 } else { 162 panic("alpha_shared_intr_establish: %s %d: can't share %s with %s", 163 basename, num, intr_typename(type), 164 intr_typename(intr[num].intr_sharetype)); 165 } 166 } 167 break; 168 169 case IST_NONE: 170 /* not currently used; safe */ 171 break; 172 } 173 174 ih->ih_intrhead = intr; 175 ih->ih_fn = fn; 176 ih->ih_arg = arg; 177 ih->ih_level = level; 178 ih->ih_num = num; 179 180 intr[num].intr_sharetype = type; 181 TAILQ_INSERT_TAIL(&intr[num].intr_q, ih, ih_q); 182 183 return (ih); 184 } 185 186 void 187 alpha_shared_intr_disestablish(struct alpha_shared_intr *intr, 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(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(struct alpha_shared_intr *intr, unsigned int num) 210 { 211 212 return (intr[num].intr_q.tqh_first != NULL); 213 } 214 215 int 216 alpha_shared_intr_firstactive(struct alpha_shared_intr *intr, unsigned int num) 217 { 218 219 return (intr[num].intr_q.tqh_first != NULL && 220 intr[num].intr_q.tqh_first->ih_q.tqe_next == NULL); 221 } 222 223 void 224 alpha_shared_intr_set_dfltsharetype(struct alpha_shared_intr *intr, 225 unsigned int num, int newdfltsharetype) 226 { 227 228 #ifdef DIAGNOSTIC 229 if (alpha_shared_intr_isactive(intr, num)) 230 panic("alpha_shared_intr_set_dfltsharetype on active intr"); 231 #endif 232 233 intr[num].intr_dfltsharetype = newdfltsharetype; 234 intr[num].intr_sharetype = intr[num].intr_dfltsharetype; 235 } 236 237 void 238 alpha_shared_intr_set_maxstrays(struct alpha_shared_intr *intr, 239 unsigned int num, int newmaxstrays) 240 { 241 int s = splhigh(); 242 intr[num].intr_maxstrays = newmaxstrays; 243 intr[num].intr_nstrays = 0; 244 splx(s); 245 } 246 247 void 248 alpha_shared_intr_stray(struct alpha_shared_intr *intr, unsigned int num, 249 const char *basename) 250 { 251 252 intr[num].intr_nstrays++; 253 254 if (intr[num].intr_maxstrays == 0) 255 return; 256 257 if (intr[num].intr_nstrays <= intr[num].intr_maxstrays) 258 log(LOG_ERR, "stray %s %d%s\n", basename, num, 259 intr[num].intr_nstrays >= intr[num].intr_maxstrays ? 260 "; stopped logging" : ""); 261 } 262 263 void 264 alpha_shared_intr_set_private(struct alpha_shared_intr *intr, 265 unsigned int num, void *v) 266 { 267 268 intr[num].intr_private = v; 269 } 270 271 void * 272 alpha_shared_intr_get_private(struct alpha_shared_intr *intr, 273 unsigned int num) 274 { 275 276 return (intr[num].intr_private); 277 } 278 279 struct evcnt * 280 alpha_shared_intr_evcnt(struct alpha_shared_intr *intr, 281 unsigned int num) 282 { 283 284 return (&intr[num].intr_evcnt); 285 } 286 287 char * 288 alpha_shared_intr_string(struct alpha_shared_intr *intr, 289 unsigned int num) 290 { 291 292 return (intr[num].intr_string); 293 } 294