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