1 /* $NetBSD: sa11x0_irqhandler.c,v 1.6 2005/12/11 12:16:51 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1996, 1997, 1998, 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to the NetBSD Foundation 8 * by IWAMOTO Toshihiro. 9 * 10 * This code is derived from software contributed to The NetBSD Foundation 11 * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace 12 * Simulation Facility, NASA Ames Research Center. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by the NetBSD 25 * Foundation, Inc. and its contributors. 26 * 4. Neither the name of The NetBSD Foundation nor the names of its 27 * contributors may be used to endorse or promote products derived 28 * from this software without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 31 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 32 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 33 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 34 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 35 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 36 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 37 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 38 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 39 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 40 * POSSIBILITY OF SUCH DAMAGE. 41 */ 42 43 /*- 44 * Copyright (c) 1991 The Regents of the University of California. 45 * All rights reserved. 46 * 47 * This code is derived from software contributed to Berkeley by 48 * William Jolitz. 49 * 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 1. Redistributions of source code must retain the above copyright 54 * notice, this list of conditions and the following disclaimer. 55 * 2. Redistributions in binary form must reproduce the above copyright 56 * notice, this list of conditions and the following disclaimer in the 57 * documentation and/or other materials provided with the distribution. 58 * 3. Neither the name of the University nor the names of its contributors 59 * may be used to endorse or promote products derived from this software 60 * without specific prior written permission. 61 * 62 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 63 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 64 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 65 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 66 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 67 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 68 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 69 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 70 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 72 * SUCH DAMAGE. 73 * 74 * @(#)isa.c 7.2 (Berkeley) 5/13/91 75 */ 76 77 78 #include <sys/cdefs.h> 79 __KERNEL_RCSID(0, "$NetBSD: sa11x0_irqhandler.c,v 1.6 2005/12/11 12:16:51 christos Exp $"); 80 81 #include "opt_irqstats.h" 82 83 #include <sys/param.h> 84 #include <sys/kernel.h> 85 #include <sys/systm.h> 86 #include <sys/syslog.h> 87 #include <sys/malloc.h> 88 #include <uvm/uvm_extern.h> 89 90 #include <arm/sa11x0/sa11x0_reg.h> 91 #include <arm/sa11x0/sa11x0_var.h> 92 93 #include <machine/intr.h> 94 #include <machine/cpu.h> 95 96 irqhandler_t *irqhandlers[NIRQS]; 97 98 int current_intr_depth; 99 u_int actual_mask; 100 #ifdef hpcarm 101 #define IPL_LEVELS (NIPL+1) 102 u_int imask[NIPL]; 103 #else 104 u_int spl_mask; 105 u_int irqmasks[IPL_LEVELS]; 106 #endif 107 u_int irqblock[NIRQS]; 108 109 110 extern void set_spl_masks(void); 111 static int fakeintr(void *); 112 #ifdef DEBUG 113 static int dumpirqhandlers(void); 114 #endif 115 void intr_calculatemasks(void); 116 117 const struct evcnt *sa11x0_intr_evcnt(sa11x0_chipset_tag_t, int); 118 void stray_irqhandler(void *); 119 120 /* 121 * Recalculate the interrupt masks from scratch. 122 * We could code special registry and deregistry versions of this function that 123 * would be faster, but the code would be nastier, and we don't expect this to 124 * happen very much anyway. 125 */ 126 void 127 intr_calculatemasks(void) 128 { 129 int irq, level; 130 struct irqhandler *q; 131 int intrlevel[ICU_LEN]; 132 133 /* First, figure out which levels each IRQ uses. */ 134 for (irq = 0; irq < ICU_LEN; irq++) { 135 int levels = 0; 136 for (q = irqhandlers[irq]; q; q = q->ih_next) 137 levels |= 1 << q->ih_level; 138 intrlevel[irq] = levels; 139 } 140 141 /* Then figure out which IRQs use each level. */ 142 #ifdef hpcarm 143 for (level = 0; level < NIPL; level++) { 144 #else 145 for (level = 0; level <= IPL_LEVELS; level++) { 146 #endif 147 int irqs = 0; 148 for (irq = 0; irq < ICU_LEN; irq++) 149 if (intrlevel[irq] & (1 << level)) 150 irqs |= 1 << irq; 151 #ifdef hpcarm 152 imask[level] = irqs; 153 #else 154 irqmasks[level] = irqs; 155 #endif 156 } 157 158 /* 159 * Enforce a hierarchy that gives slow devices a better chance at not 160 * dropping data. 161 */ 162 #ifdef hpcarm 163 for (level = NIPL - 1; level > 0; level--) 164 imask[level - 1] |= imask[level]; 165 #else 166 for (level = IPL_LEVELS; level > 0; level--) 167 irqmasks[level - 1] |= irqmasks[level]; 168 #endif 169 /* 170 * Calculate irqblock[], which emulates hardware interrupt levels. 171 */ 172 for (irq = 0; irq < ICU_LEN; irq++) { 173 int irqs = 1 << irq; 174 for (q = irqhandlers[irq]; q; q = q->ih_next) 175 #ifdef hpcarm 176 irqs |= ~imask[q->ih_level]; 177 #else 178 irqs |= ~irqmasks[q->ih_level]; 179 #endif 180 irqblock[irq] = irqs; 181 } 182 } 183 184 185 const struct evcnt * 186 sa11x0_intr_evcnt(sa11x0_chipset_tag_t ic, int irq) 187 { 188 189 /* XXX for now, no evcnt parent reported */ 190 return NULL; 191 } 192 193 void * 194 sa11x0_intr_establish(sa11x0_chipset_tag_t ic, int irq, int type, int level, 195 int (*ih_fun)(void *), void *ih_arg) 196 { 197 int saved_cpsr; 198 struct irqhandler **p, *q, *ih; 199 static struct irqhandler fakehand = {fakeintr}; 200 201 /* no point in sleeping unless someone can free memory. */ 202 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 203 if (ih == NULL) 204 panic("sa11x0_intr_establish: can't malloc handler info"); 205 206 if (irq < 0 || irq >= ICU_LEN || type == IST_NONE) 207 panic("intr_establish: bogus irq or type"); 208 209 /* All interrupts are level intrs. */ 210 211 /* 212 * Figure out where to put the handler. 213 * This is O(N^2), but we want to preserve the order, and N is 214 * generally small. 215 */ 216 for (p = &irqhandlers[irq]; (q = *p) != NULL; p = &q->ih_next) 217 ; 218 219 /* 220 * Actually install a fake handler momentarily, since we might be doing 221 * this with interrupts enabled and don't want the real routine called 222 * until masking is set up. 223 */ 224 fakehand.ih_level = level; 225 *p = &fakehand; 226 227 intr_calculatemasks(); 228 229 /* 230 * Poke the real handler in now. 231 */ 232 ih->ih_func = ih_fun; 233 ih->ih_arg = ih_arg; 234 #ifdef hpcarm 235 ih->ih_count = 0; 236 #else 237 ih->ih_num = 0; 238 #endif 239 ih->ih_next = NULL; 240 ih->ih_level = level; 241 #ifdef hpcarm 242 ih->ih_irq = irq; 243 #endif 244 ih->ih_name = NULL; /* XXX */ 245 *p = ih; 246 247 saved_cpsr = SetCPSR(I32_bit, I32_bit); 248 set_spl_masks(); 249 250 irq_setmasks(); 251 252 SetCPSR(I32_bit, saved_cpsr & I32_bit); 253 #ifdef DEBUG 254 dumpirqhandlers(); 255 #endif 256 return (ih); 257 } 258 259 #ifdef hpcarm 260 /* 261 * Deregister an interrupt handler. 262 */ 263 void 264 sa11x0_intr_disestablish(sa11x0_chipset_tag_t ic, void *arg) 265 { 266 struct irqhandler *ih = arg; 267 int irq = ih->ih_irq; 268 int saved_cpsr; 269 struct irqhandler **p, *q; 270 271 #if DIAGNOSTIC 272 if (irq < 0 || irq >= ICU_LEN) 273 panic("intr_disestablish: bogus irq"); 274 #endif 275 276 /* 277 * Remove the handler from the chain. 278 * This is O(n^2), too. 279 */ 280 for (p = &irqhandlers[irq]; (q = *p) != NULL && q != ih; 281 p = &q->ih_next) 282 ; 283 if (q) 284 *p = q->ih_next; 285 else 286 panic("intr_disestablish: handler not registered"); 287 free(ih, M_DEVBUF); 288 289 intr_calculatemasks(); 290 saved_cpsr = SetCPSR(I32_bit, I32_bit); 291 set_spl_masks(); 292 293 irq_setmasks(); 294 SetCPSR(I32_bit, saved_cpsr & I32_bit); 295 296 } 297 #endif 298 299 void 300 stray_irqhandler(void *p) 301 { 302 303 printf("stray interrupt\n"); 304 } 305 306 int 307 fakeintr(void *p) 308 { 309 310 return 0; 311 } 312 313 #ifdef DEBUG 314 int 315 dumpirqhandlers() 316 { 317 int irq; 318 struct irqhandler *p; 319 320 for (irq = 0; irq < ICU_LEN; irq++) { 321 printf("irq %d:", irq); 322 p = irqhandlers[irq]; 323 for (; p; p = p->ih_next) 324 printf("ih_func: 0x%lx, ", (unsigned long)p->ih_func); 325 printf("\n"); 326 } 327 return 0; 328 } 329 #endif 330 /* End of irqhandler.c */ 331