1 /* $NetBSD: sa11x0_irqhandler.c,v 1.12 2007/10/17 19:53:43 garbled 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.12 2007/10/17 19:53:43 garbled 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 irqmasks[IPL_LEVELS]; 105 #endif 106 107 extern void set_spl_masks(void); 108 static int fakeintr(void *); 109 #ifdef INTR_DEBUG 110 static int dumpirqhandlers(void); 111 #endif 112 void intr_calculatemasks(void); 113 114 const struct evcnt *sa11x0_intr_evcnt(sa11x0_chipset_tag_t, int); 115 void stray_irqhandler(void *); 116 117 /* 118 * Recalculate the interrupt masks from scratch. 119 * We could code special registry and deregistry versions of this function that 120 * would be faster, but the code would be nastier, and we don't expect this to 121 * happen very much anyway. 122 */ 123 void 124 intr_calculatemasks(void) 125 { 126 int irq, level; 127 struct irqhandler *q; 128 int intrlevel[ICU_LEN]; 129 130 /* First, figure out which levels each IRQ uses. */ 131 for (irq = 0; irq < ICU_LEN; irq++) { 132 int levels = 0; 133 for (q = irqhandlers[irq]; q; q = q->ih_next) 134 levels |= 1 << q->ih_level; 135 intrlevel[irq] = levels; 136 } 137 138 /* Then figure out which IRQs use each level. */ 139 #ifdef hpcarm 140 for (level = 0; level < NIPL; level++) { 141 #else 142 for (level = 0; level <= IPL_LEVELS; level++) { 143 #endif 144 int irqs = 0; 145 for (irq = 0; irq < ICU_LEN; irq++) 146 if (intrlevel[irq] & (1 << level)) 147 irqs |= 1 << irq; 148 #ifdef hpcarm 149 imask[level] = irqs; 150 #else 151 irqmasks[level] = irqs; 152 #endif 153 } 154 155 /* 156 * Enforce a hierarchy that gives slow devices a better chance at not 157 * dropping data. 158 */ 159 #ifdef hpcarm 160 for (level = NIPL - 1; level > 0; level--) 161 imask[level - 1] |= imask[level]; 162 #else 163 for (level = IPL_LEVELS; level > 0; level--) 164 irqmasks[level - 1] |= irqmasks[level]; 165 #endif 166 } 167 168 169 const struct evcnt * 170 sa11x0_intr_evcnt(sa11x0_chipset_tag_t ic, int irq) 171 { 172 173 /* XXX for now, no evcnt parent reported */ 174 return NULL; 175 } 176 177 void * 178 sa11x0_intr_establish(sa11x0_chipset_tag_t ic, int irq, int type, int level, 179 int (*ih_fun)(void *), void *ih_arg) 180 { 181 int saved_cpsr; 182 struct irqhandler **p, *q, *ih; 183 static struct irqhandler fakehand = {fakeintr}; 184 185 /* no point in sleeping unless someone can free memory. */ 186 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 187 if (ih == NULL) 188 panic("sa11x0_intr_establish: can't malloc handler info"); 189 190 if (irq < 0 || irq >= ICU_LEN || type == IST_NONE) 191 panic("intr_establish: bogus irq or type"); 192 193 /* All interrupts are level intrs. */ 194 195 /* 196 * Figure out where to put the handler. 197 * This is O(N^2), but we want to preserve the order, and N is 198 * generally small. 199 */ 200 for (p = &irqhandlers[irq]; (q = *p) != NULL; p = &q->ih_next) 201 continue; 202 203 /* 204 * Actually install a fake handler momentarily, since we might be doing 205 * this with interrupts enabled and don't want the real routine called 206 * until masking is set up. 207 */ 208 fakehand.ih_level = level; 209 *p = &fakehand; 210 211 intr_calculatemasks(); 212 213 /* 214 * Poke the real handler in now. 215 */ 216 ih->ih_func = ih_fun; 217 ih->ih_arg = ih_arg; 218 #ifdef hpcarm 219 ih->ih_count = 0; 220 #else 221 ih->ih_num = 0; 222 #endif 223 ih->ih_next = NULL; 224 ih->ih_level = level; 225 #ifdef hpcarm 226 ih->ih_irq = irq; 227 #endif 228 ih->ih_name = NULL; /* XXX */ 229 *p = ih; 230 231 saved_cpsr = SetCPSR(I32_bit, I32_bit); 232 set_spl_masks(); 233 234 irq_setmasks(); 235 236 SetCPSR(I32_bit, saved_cpsr & I32_bit); 237 #ifdef INTR_DEBUG 238 dumpirqhandlers(); 239 #endif 240 return ih; 241 } 242 243 #ifdef hpcarm 244 /* 245 * Deregister an interrupt handler. 246 */ 247 void 248 sa11x0_intr_disestablish(sa11x0_chipset_tag_t ic, void *arg) 249 { 250 struct irqhandler *ih = arg; 251 int irq = ih->ih_irq; 252 int saved_cpsr; 253 struct irqhandler **p, *q; 254 255 #if DIAGNOSTIC 256 if (irq < 0 || irq >= ICU_LEN) 257 panic("intr_disestablish: bogus irq"); 258 #endif 259 260 /* 261 * Remove the handler from the chain. 262 * This is O(n^2), too. 263 */ 264 for (p = &irqhandlers[irq]; (q = *p) != NULL && q != ih; 265 p = &q->ih_next) 266 continue; 267 if (q) 268 *p = q->ih_next; 269 else 270 panic("intr_disestablish: handler not registered"); 271 free(ih, M_DEVBUF); 272 273 intr_calculatemasks(); 274 saved_cpsr = SetCPSR(I32_bit, I32_bit); 275 set_spl_masks(); 276 277 irq_setmasks(); 278 SetCPSR(I32_bit, saved_cpsr & I32_bit); 279 280 } 281 #endif 282 283 void 284 stray_irqhandler(void *p) 285 { 286 287 printf("stray interrupt\n"); 288 } 289 290 int 291 fakeintr(void *p) 292 { 293 294 return 0; 295 } 296 297 #ifdef INTR_DEBUG 298 int 299 dumpirqhandlers(void) 300 { 301 int irq; 302 struct irqhandler *p; 303 304 for (irq = 0; irq < ICU_LEN; irq++) { 305 printf("irq %d:", irq); 306 p = irqhandlers[irq]; 307 for (; p; p = p->ih_next) 308 printf("ih_func: 0x%lx, ", (unsigned long)p->ih_func); 309 printf("\n"); 310 } 311 return 0; 312 } 313 #endif 314