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