1 /* $NetBSD: pxa2x0_intr.c,v 1.1 2002/10/19 19:31:39 bsh Exp $ */ 2 3 /* 4 * Copyright (c) 2002 Genetec Corporation. All rights reserved. 5 * Written by Hiroyuki Bessho for Genetec Corporation. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the NetBSD Project by 18 * Genetec Corporation. 19 * 4. The name of Genetec Corporation may not be used to endorse or 20 * promote products derived from this software without specific prior 21 * written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND 24 * 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 GENETEC CORPORATION 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 * IRQ handler for the Intel PXA2X0 processor. 38 * It has integrated interrupt controller. 39 */ 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/malloc.h> 43 #include <uvm/uvm_extern.h> 44 #include <machine/bus.h> 45 #include <machine/intr.h> 46 #include <arm/cpufunc.h> 47 48 #include <arm/xscale/pxa2x0reg.h> 49 #include <arm/xscale/pxa2x0var.h> 50 #include <arm/sa11x0/sa11x0_var.h> 51 #include <arm/xscale/pxa2x0_intr.h> 52 53 /* 54 * interrupt dispatch table. 55 */ 56 #ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ 57 struct intrhand { 58 TAILQ_ENTRY(intrhand) ih_list; /* link on intrq list */ 59 int (*ih_func)(void *); /* handler */ 60 void *ih_arg; /* arg for handler */ 61 }; 62 #endif 63 64 static struct { 65 #ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ 66 TAILQ_HEAD(,intrhand) list; 67 #else 68 pxa2x0_irq_handler_t func; 69 #endif 70 void *cookie; /* NULL for stackframe */ 71 /* struct evbnt ev; */ 72 } handler[ICU_LEN]; 73 74 __volatile int softint_pending; 75 76 __volatile int current_spl_level; 77 __volatile int intr_mask; 78 /* interrupt masks for each level */ 79 int pxa2x0_imask[NIPL]; 80 static int extirq_level[ICU_LEN]; 81 82 int current_intr_depth; 83 84 static __inline void 85 __raise(int ipl) 86 { 87 if( current_spl_level < ipl ){ 88 pxa2x0_setipl(ipl); 89 } 90 } 91 92 93 /* 94 * Map a software interrupt queue to an interrupt priority level. 95 */ 96 static const int si_to_ipl[SI_NQUEUES] = { 97 IPL_SOFT, /* SI_SOFT */ 98 IPL_SOFTCLOCK, /* SI_SOFTCLOCK */ 99 IPL_SOFTNET, /* SI_SOFTNET */ 100 IPL_SOFTSERIAL, /* SI_SOFTSERIAL */ 101 }; 102 103 /* 104 * called from irq_entry. 105 */ 106 void 107 pxa2x0_irq_handler(struct clockframe *frame) 108 { 109 uint32_t irqbits; 110 int irqno; 111 int saved_spl_level; 112 113 ++current_intr_depth; 114 saved_spl_level = current_spl_level; 115 116 /* get pending IRQs */ 117 irqbits = read_icu(SAIPIC_IP); 118 119 while( (irqno = find_first_bit(irqbits)) >= 0 ){ 120 /* XXX: Shuould we handle IRQs in priority order? */ 121 122 /* raise spl to stop interrupts of lower priorities */ 123 if( saved_spl_level < extirq_level[irqno] ) 124 pxa2x0_setipl(extirq_level[irqno]); 125 126 #ifdef notyet 127 /* Enable interrupt */ 128 #endif 129 #ifndef MULTIPLE_HANDLERS_ON_ONE_IRQ 130 (* handler[irqno].func)( 131 handler[irqno].cookie == 0 132 ? frame : handler[irqno].cookie ); 133 #else 134 /* process all handlers for this interrupt. 135 XXX not yet */ 136 #endif 137 138 #ifdef notyet 139 /* Disable interrupt */ 140 #endif 141 142 irqbits &= ~(1<<irqno); 143 } 144 145 /* restore spl to that was when this interrupt happen */ 146 pxa2x0_setipl(saved_spl_level); 147 148 if( softint_pending & intr_mask ) 149 pxa2x0_do_pending(); 150 151 --current_intr_depth; 152 } 153 154 static int 155 stray_interrupt( void *cookie ) 156 { 157 int irqno = (int)cookie; 158 printf( "stray interrupt %d\n", irqno ); 159 160 if( PXA2X0_IRQ_MIN <= irqno && irqno < ICU_LEN ){ 161 int save = disable_interrupts(I32_bit); 162 write_icu( SAIPIC_MR, 163 read_icu(SAIPIC_MR) & ~(1U<<irqno) ); 164 restore_interrupts(save); 165 } 166 167 return 0; 168 } 169 170 171 172 /* 173 * Interrupt Mask Handling 174 */ 175 176 void 177 pxa2x0_update_intr_masks( int irqno, int level ) 178 { 179 int mask = 1U<<irqno; 180 int psw = disable_interrupts(I32_bit); 181 int i; 182 183 184 for( i=IPL_BIO; i < level; ++i ) 185 pxa2x0_imask[i] |= mask; /* Enable interrupt at lower level */ 186 for( ; i < NIPL-1; ++i ) 187 pxa2x0_imask[i] &= ~mask; /* Disable itnerrupt at upper level */ 188 189 /* 190 * Enforce a heirarchy that gives "slow" device (or devices with 191 * limited input buffer space/"real-time" requirements) a better 192 * chance at not dropping data. 193 */ 194 pxa2x0_imask[IPL_BIO] &= pxa2x0_imask[IPL_SOFTNET]; 195 pxa2x0_imask[IPL_NET] &= pxa2x0_imask[IPL_BIO]; 196 pxa2x0_imask[IPL_SOFTSERIAL] &= pxa2x0_imask[IPL_NET]; 197 pxa2x0_imask[IPL_TTY] &= pxa2x0_imask[IPL_SOFTSERIAL]; 198 199 /* 200 * splvm() blocks all interrupts that use the kernel memory 201 * allocation facilities. 202 */ 203 pxa2x0_imask[IPL_IMP] &= pxa2x0_imask[IPL_TTY]; 204 205 /* 206 * Audio devices are not allowed to perform memory allocation 207 * in their interrupt routines, and they have fairly "real-time" 208 * requirements, so give them a high interrupt priority. 209 */ 210 pxa2x0_imask[IPL_AUDIO] &= pxa2x0_imask[IPL_IMP]; 211 212 /* 213 * splclock() must block anything that uses the scheduler. 214 */ 215 pxa2x0_imask[IPL_CLOCK] &= pxa2x0_imask[IPL_AUDIO]; 216 217 /* 218 * splhigh() must block "everything". 219 */ 220 pxa2x0_imask[IPL_HIGH] &= pxa2x0_imask[IPL_STATCLOCK]; 221 222 /* 223 * XXX We need serial drivers to run at the absolute highest priority 224 * in order to avoid overruns, so serial > high. 225 */ 226 pxa2x0_imask[IPL_SERIAL] &= pxa2x0_imask[IPL_HIGH]; 227 228 write_icu( SAIPIC_MR, pxa2x0_imask[current_spl_level] ); 229 230 restore_interrupts(psw); 231 } 232 233 234 static void 235 init_interrupt_masks(void) 236 { 237 int i; 238 pxa2x0_imask[IPL_NONE] = 0xffffffff; 239 240 for( i = IPL_BIO; i < NIPL; ++i ) 241 pxa2x0_imask[i] = 0; 242 243 /* 244 * Initialize the soft interrupt masks to block themselves. 245 */ 246 pxa2x0_imask[IPL_SOFT] = ~SI_TO_IRQBIT(SI_SOFT); 247 pxa2x0_imask[IPL_SOFTCLOCK] = ~SI_TO_IRQBIT(SI_SOFTCLOCK); 248 pxa2x0_imask[IPL_SOFTNET] = ~SI_TO_IRQBIT(SI_SOFTNET); 249 pxa2x0_imask[IPL_SOFTSERIAL] = ~SI_TO_IRQBIT(SI_SOFTSERIAL); 250 251 /* 252 * splsoftclock() is the only interface that users of the 253 * generic software interrupt facility have to block their 254 * soft intrs, so splsoftclock() must also block IPL_SOFT. 255 */ 256 pxa2x0_imask[IPL_SOFTCLOCK] &= pxa2x0_imask[IPL_SOFT]; 257 258 /* 259 * splsoftnet() must also block splsoftclock(), since we don't 260 * want timer-driven network events to occur while we're 261 * processing incoming packets. 262 */ 263 pxa2x0_imask[IPL_SOFTNET] &= pxa2x0_imask[IPL_SOFTCLOCK]; 264 265 } 266 267 void 268 pxa2x0_do_pending(void) 269 { 270 static __cpu_simple_lock_t processing = __SIMPLELOCK_UNLOCKED; 271 int oldirqstate, spl_save; 272 273 if (__cpu_simple_lock_try(&processing) == 0) 274 return; 275 276 spl_save = current_spl_level; 277 278 oldirqstate = disable_interrupts(I32_bit); 279 280 #if 1 281 #define DO_SOFTINT(si,ipl) \ 282 if ((softint_pending & intr_mask) & SI_TO_IRQBIT(si)) { \ 283 softint_pending &= ~SI_TO_IRQBIT(si); \ 284 __raise(ipl); \ 285 restore_interrupts(oldirqstate); \ 286 softintr_dispatch(si); \ 287 oldirqstate = disable_interrupts(I32_bit); \ 288 pxa2x0_setipl(spl_save); \ 289 } 290 291 do { 292 DO_SOFTINT(SI_SOFTSERIAL,IPL_SOFTSERIAL); 293 DO_SOFTINT(SI_SOFTNET, IPL_SOFTNET); 294 DO_SOFTINT(SI_SOFTCLOCK, IPL_SOFTCLOCK); 295 DO_SOFTINT(SI_SOFT, IPL_SOFT); 296 } while( softint_pending & intr_mask ); 297 #else 298 while( (si = find_first_bit(softint_pending & intr_mask)) >= 0 ){ 299 softint_pending &= ~SI_TO_IRQBIT(si); 300 __raise(si_to_ipl(si)); 301 restore_interrupts(oldirqstate); 302 softintr_dispatch(si); 303 oldirqstate = disable_interrupts(I32_bit); 304 pxa2x0_setipl(spl_save); 305 } 306 #endif 307 308 __cpu_simple_unlock(&processing); 309 310 restore_interrupts(oldirqstate); 311 } 312 313 314 #undef splx 315 void 316 splx(int ipl) 317 { 318 pxa2x0_splx(ipl); 319 } 320 321 #undef _splraise 322 int 323 _splraise(int ipl) 324 { 325 return pxa2x0_splraise(ipl); 326 } 327 328 #undef _spllower 329 int 330 _spllower(int ipl) 331 { 332 return pxa2x0_spllower(ipl); 333 } 334 335 #undef _setsoftintr 336 void 337 _setsoftintr(int si) 338 { 339 return pxa2x0_setsoftintr(si); 340 } 341 342 343 344 /* 345 * Initialize interrupt dispatcher. 346 */ 347 void 348 pxa2x0_intr_init(void) 349 { 350 int i; 351 352 for( i=0; i < sizeof handler / sizeof handler[0]; ++i ){ 353 handler[i].func = stray_interrupt; 354 handler[i].cookie = (void *)(i); 355 extirq_level[i] = IPL_SERIAL; 356 } 357 358 init_interrupt_masks(); 359 360 _splraise(IPL_SERIAL); 361 enable_interrupts(I32_bit); 362 } 363 364 void 365 pxa2x0_set_intcbase( vaddr_t addr ) 366 { 367 pxaic_base = addr; 368 } 369 370 void * 371 pxa2x0_intr_establish(int irqno, int level, 372 int (*func)(void *), void *cookie) 373 { 374 int psw; 375 376 if (irqno < PXA2X0_IRQ_MIN || irqno >= ICU_LEN ) 377 panic("intr_establish: bogus irq number %d", irqno); 378 379 psw = disable_interrupts(I32_bit); 380 381 handler[irqno].cookie = cookie; 382 handler[irqno].func = func; 383 extirq_level[irqno] = level; 384 pxa2x0_update_intr_masks( irqno, level ); 385 386 intr_mask = pxa2x0_imask[current_spl_level]; 387 388 restore_interrupts(psw); 389 390 return ( &handler[irqno] ); 391 } 392 393 394 395 /* 396 * Glue for drivers of sa11x0 compatible integrated logics. 397 */ 398 void * 399 sa11x0_intr_establish(sa11x0_chipset_tag_t ic, int irq, int type, int level, 400 int (*ih_fun)(void *), void *ih_arg) 401 { 402 return pxa2x0_intr_establish(irq,level,ih_fun,ih_arg); 403 } 404 405