i80321_icu.c revision 1.4
1/* $NetBSD: i80321_icu.c,v 1.4 2002/08/14 19:47:18 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 2001, 2002 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38/* 39 * Interrupt support for the Intel i80321 I/O Processor. 40 */ 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/malloc.h> 45 46#include <uvm/uvm_extern.h> 47 48#include <machine/bus.h> 49#include <machine/intr.h> 50 51#include <arm/cpufunc.h> 52 53#include <arm/xscale/i80321reg.h> 54#include <arm/xscale/i80321var.h> 55 56/* Interrupt handler queues. */ 57struct intrq intrq[NIRQ]; 58 59/* Interrupts to mask at each level. */ 60static int imask[NIPL]; 61 62/* Current interrupt priority level. */ 63__volatile int current_spl_level; 64 65/* Interrupts pending. */ 66static __volatile int ipending; 67 68/* Software copy of the IRQs we have enabled. */ 69__volatile uint32_t intr_enabled; 70 71/* Mask if interrupts steered to FIQs. */ 72uint32_t intr_steer; 73 74/* 75 * Map a software interrupt queue index (to the unused bits in the 76 * ICU registers -- XXX will need to revisit this if those bits are 77 * ever used in future steppings). 78 */ 79static const uint32_t si_to_irqbit[SI_NQUEUES] = { 80 ICU_INT_bit26, /* SI_SOFT */ 81 ICU_INT_bit22, /* SI_SOFTCLOCK */ 82 ICU_INT_bit5, /* SI_SOFTNET */ 83 ICU_INT_bit4, /* SI_SOFTSERIAL */ 84}; 85 86#define INT_SWMASK \ 87 ((1U << ICU_INT_bit26) | (1U << ICU_INT_bit22) | \ 88 (1U << ICU_INT_bit5) | (1U << ICU_INT_bit4)) 89 90#define SI_TO_IRQBIT(si) (1U << si_to_irqbit[(si)]) 91 92/* 93 * Map a software interrupt queue to an interrupt priority level. 94 */ 95static const int si_to_ipl[SI_NQUEUES] = { 96 IPL_SOFT, /* SI_SOFT */ 97 IPL_SOFTCLOCK, /* SI_SOFTCLOCK */ 98 IPL_SOFTNET, /* SI_SOFTNET */ 99 IPL_SOFTSERIAL, /* SI_SOFTSERIAL */ 100}; 101 102/* 103 * Interrupt bit names. 104 */ 105const char *i80321_irqnames[] = { 106 "DMA0 EOT", 107 "DMA0 EOC", 108 "DMA1 EOT", 109 "DMA1 EOC", 110 "irq 4", 111 "irq 5", 112 "AAU EOT", 113 "AAU EOC", 114 "core PMU", 115 "TMR0 (hardclock)", 116 "TMR1", 117 "I2C0", 118 "I2C1", 119 "MU", 120 "BIST", 121 "periph PMU", 122 "XScale PMU", 123 "BIU error", 124 "ATU error", 125 "MCU error", 126 "DMA0 error", 127 "DMA1 error", 128 "irq 22", 129 "AAU error", 130 "MU error", 131 "SSP", 132 "irq 26", 133 "irq 27", 134 "irq 28", 135 "irq 29", 136 "irq 30", 137 "irq 31", 138}; 139 140void i80321_intr_dispatch(struct clockframe *frame); 141 142static __inline uint32_t 143i80321_iintsrc_read(void) 144{ 145 uint32_t iintsrc; 146 147 __asm __volatile("mrc p6, 0, %0, c8, c0, 0" 148 : "=r" (iintsrc)); 149 150 /* 151 * The IINTSRC register shows bits that are active even 152 * if they are masked in INTCTL, so we have to mask them 153 * off with the interrupts we consider enabled. 154 */ 155 return (iintsrc & intr_enabled); 156} 157 158static __inline void 159i80321_set_intrmask(void) 160{ 161 162 __asm __volatile("mcr p6, 0, %0, c0, c0, 0" 163 : 164 : "r" (intr_enabled & ICU_INT_HWMASK)); 165} 166 167static __inline void 168i80321_set_intrsteer(void) 169{ 170 171 __asm __volatile("mcr p6, 0, %0, c4, c0, 0" 172 : 173 : "r" (intr_steer & ICU_INT_HWMASK)); 174} 175 176static __inline void 177i80321_enable_irq(int irq) 178{ 179 180 intr_enabled |= (1U << irq); 181 i80321_set_intrmask(); 182} 183 184static __inline void 185i80321_disable_irq(int irq) 186{ 187 188 intr_enabled &= ~(1U << irq); 189 i80321_set_intrmask(); 190} 191 192/* 193 * NOTE: This routine must be called with interrupts disabled in the CPSR. 194 */ 195static void 196i80321_intr_calculate_masks(void) 197{ 198 struct intrq *iq; 199 struct intrhand *ih; 200 int irq, ipl; 201 202 /* First, figure out which IPLs each IRQ has. */ 203 for (irq = 0; irq < NIRQ; irq++) { 204 int levels = 0; 205 iq = &intrq[irq]; 206 i80321_disable_irq(irq); 207 for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL; 208 ih = TAILQ_NEXT(ih, ih_list)) 209 levels |= (1U << ih->ih_ipl); 210 iq->iq_levels = levels; 211 } 212 213 /* Next, figure out which IRQs are used by each IPL. */ 214 for (ipl = 0; ipl < NIPL; ipl++) { 215 int irqs = 0; 216 for (irq = 0; irq < NIRQ; irq++) { 217 if (intrq[irq].iq_levels & (1U << ipl)) 218 irqs |= (1U << irq); 219 } 220 imask[ipl] = irqs; 221 } 222 223 imask[IPL_NONE] = 0; 224 225 /* 226 * Initialize the soft interrupt masks to block themselves. 227 */ 228 imask[IPL_SOFT] = SI_TO_IRQBIT(SI_SOFT); 229 imask[IPL_SOFTCLOCK] = SI_TO_IRQBIT(SI_SOFTCLOCK); 230 imask[IPL_SOFTNET] = SI_TO_IRQBIT(SI_SOFTNET); 231 imask[IPL_SOFTSERIAL] = SI_TO_IRQBIT(SI_SOFTSERIAL); 232 233 /* 234 * splsoftclock() is the only interface that users of the 235 * generic software interrupt facility have to block their 236 * soft intrs, so splsoftclock() must also block IPL_SOFT. 237 */ 238 imask[IPL_SOFTCLOCK] |= imask[IPL_SOFT]; 239 240 /* 241 * splsoftnet() must also block splsoftclock(), since we don't 242 * want timer-driven network events to occur while we're 243 * processing incoming packets. 244 */ 245 imask[IPL_SOFTNET] |= imask[IPL_SOFTCLOCK]; 246 247 /* 248 * Enforce a heirarchy that gives "slow" device (or devices with 249 * limited input buffer space/"real-time" requirements) a better 250 * chance at not dropping data. 251 */ 252 imask[IPL_BIO] |= imask[IPL_SOFTNET]; 253 imask[IPL_NET] |= imask[IPL_BIO]; 254 imask[IPL_SOFTSERIAL] |= imask[IPL_NET]; 255 imask[IPL_TTY] |= imask[IPL_SOFTSERIAL]; 256 257 /* 258 * splvm() blocks all interrupts that use the kernel memory 259 * allocation facilities. 260 */ 261 imask[IPL_IMP] |= imask[IPL_TTY]; 262 263 /* 264 * Audio devices are not allowed to perform memory allocation 265 * in their interrupt routines, and they have fairly "real-time" 266 * requirements, so give them a high interrupt priority. 267 */ 268 imask[IPL_AUDIO] |= imask[IPL_IMP]; 269 270 /* 271 * splclock() must block anything that uses the scheduler. 272 */ 273 imask[IPL_CLOCK] |= imask[IPL_AUDIO]; 274 275 /* 276 * No separate statclock on the IQ80310. 277 */ 278 imask[IPL_STATCLOCK] |= imask[IPL_CLOCK]; 279 280 /* 281 * splhigh() must block "everything". 282 */ 283 imask[IPL_HIGH] |= imask[IPL_STATCLOCK]; 284 285 /* 286 * XXX We need serial drivers to run at the absolute highest priority 287 * in order to avoid overruns, so serial > high. 288 */ 289 imask[IPL_SERIAL] |= imask[IPL_HIGH]; 290 291 /* 292 * Now compute which IRQs must be blocked when servicing any 293 * given IRQ. 294 */ 295 for (irq = 0; irq < NIRQ; irq++) { 296 int irqs = (1U << irq); 297 iq = &intrq[irq]; 298 if (TAILQ_FIRST(&iq->iq_list) != NULL) 299 i80321_enable_irq(irq); 300 for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL; 301 ih = TAILQ_NEXT(ih, ih_list)) 302 irqs |= imask[ih->ih_ipl]; 303 iq->iq_mask = irqs; 304 } 305} 306 307static void 308i80321_do_pending(void) 309{ 310 static __cpu_simple_lock_t processing = __SIMPLELOCK_UNLOCKED; 311 int new, oldirqstate; 312 313 if (__cpu_simple_lock_try(&processing) == 0) 314 return; 315 316 new = current_spl_level; 317 318 oldirqstate = disable_interrupts(I32_bit); 319 320#define DO_SOFTINT(si) \ 321 if ((ipending & ~new) & SI_TO_IRQBIT(si)) { \ 322 ipending &= ~SI_TO_IRQBIT(si); \ 323 current_spl_level |= imask[si_to_ipl[(si)]]; \ 324 restore_interrupts(oldirqstate); \ 325 softintr_dispatch(si); \ 326 oldirqstate = disable_interrupts(I32_bit); \ 327 current_spl_level = new; \ 328 } 329 330 DO_SOFTINT(SI_SOFTSERIAL); 331 DO_SOFTINT(SI_SOFTNET); 332 DO_SOFTINT(SI_SOFTCLOCK); 333 DO_SOFTINT(SI_SOFT); 334 335 __cpu_simple_unlock(&processing); 336 337 restore_interrupts(oldirqstate); 338} 339 340int 341_splraise(int ipl) 342{ 343 int old; 344 345 old = current_spl_level; 346 current_spl_level |= imask[ipl]; 347 348 return (old); 349} 350 351__inline void 352splx(int new) 353{ 354 int oldirqstate, hwpend; 355 356 current_spl_level = new; 357 358 /* 359 * If there are pending HW interrupts which are being 360 * unmasked, then enable them in the INTCTL register. 361 * This will cause them to come flooding in. 362 */ 363 hwpend = (ipending & ICU_INT_HWMASK) & ~new; 364 if (hwpend != 0) { 365 oldirqstate = disable_interrupts(I32_bit); 366 intr_enabled |= hwpend; 367 i80321_set_intrmask(); 368 restore_interrupts(oldirqstate); 369 } 370 371 /* If there are software interrupts to process, do it. */ 372 if ((ipending & INT_SWMASK) & ~new) 373 i80321_do_pending(); 374} 375 376int 377_spllower(int ipl) 378{ 379 int old = current_spl_level; 380 381 splx(imask[ipl]); 382 return (old); 383} 384 385void 386_setsoftintr(int si) 387{ 388 int oldirqstate; 389 390 oldirqstate = disable_interrupts(I32_bit); 391 ipending |= SI_TO_IRQBIT(si); 392 restore_interrupts(oldirqstate); 393 394 /* Process unmasked pending soft interrupts. */ 395 if ((ipending & INT_SWMASK) & ~current_spl_level) 396 i80321_do_pending(); 397} 398 399/* 400 * i80321_icu_init: 401 * 402 * Initialize the i80321 ICU. Called early in bootstrap 403 * to make sure the ICU is in a pristine state. 404 */ 405void 406i80321_icu_init(void) 407{ 408 409 intr_enabled = 0; /* All interrupts disabled */ 410 i80321_set_intrmask(); 411 412 intr_steer = 0; /* All interrupts steered to IRQ */ 413 i80321_set_intrsteer(); 414} 415 416/* 417 * i80321_intr_init: 418 * 419 * Initialize the rest of the interrupt subsystem, making it 420 * ready to handle interrupts from devices. 421 */ 422void 423i80321_intr_init(void) 424{ 425 struct intrq *iq; 426 int i; 427 428 intr_enabled = 0; 429 430 for (i = 0; i < NIRQ; i++) { 431 iq = &intrq[i]; 432 TAILQ_INIT(&iq->iq_list); 433 434 evcnt_attach_dynamic(&iq->iq_ev, EVCNT_TYPE_INTR, 435 NULL, "iop321", i80321_irqnames[i]); 436 } 437 438 i80321_intr_calculate_masks(); 439 440 /* Enable IRQs (don't yet use FIQs). */ 441 enable_interrupts(I32_bit); 442} 443 444void * 445i80321_intr_establish(int irq, int ipl, int (*func)(void *), void *arg) 446{ 447 struct intrq *iq; 448 struct intrhand *ih; 449 u_int oldirqstate; 450 451 if (irq < 0 || irq > NIRQ) 452 panic("i80321_intr_establish: IRQ %d out of range", irq); 453 454 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT); 455 if (ih == NULL) 456 return (NULL); 457 458 ih->ih_func = func; 459 ih->ih_arg = arg; 460 ih->ih_ipl = ipl; 461 ih->ih_irq = irq; 462 463 iq = &intrq[irq]; 464 465 /* All IOP321 interrupts are level-triggered. */ 466 iq->iq_ist = IST_LEVEL; 467 468 oldirqstate = disable_interrupts(I32_bit); 469 470 TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list); 471 472 i80321_intr_calculate_masks(); 473 474 restore_interrupts(oldirqstate); 475 476 return (ih); 477} 478 479void 480i80321_intr_disestablish(void *cookie) 481{ 482 struct intrhand *ih = cookie; 483 struct intrq *iq = &intrq[ih->ih_irq]; 484 int oldirqstate; 485 486 oldirqstate = disable_interrupts(I32_bit); 487 488 TAILQ_REMOVE(&iq->iq_list, ih, ih_list); 489 490 i80321_intr_calculate_masks(); 491 492 restore_interrupts(oldirqstate); 493} 494 495void 496i80321_intr_dispatch(struct clockframe *frame) 497{ 498 struct intrq *iq; 499 struct intrhand *ih; 500 int oldirqstate, pcpl, irq, ibit, hwpend; 501 502 pcpl = current_spl_level; 503 504 hwpend = i80321_iintsrc_read(); 505 506 /* 507 * Disable all the interrupts that are pending. We will 508 * reenable them once they are processed and not masked. 509 */ 510 intr_enabled &= ~hwpend; 511 i80321_set_intrmask(); 512 513 while (hwpend != 0) { 514 irq = ffs(hwpend) - 1; 515 ibit = (1U << irq); 516 517 hwpend &= ~ibit; 518 519 if (pcpl & ibit) { 520 /* 521 * IRQ is masked; mark it as pending and check 522 * the next one. Note: the IRQ is already disabled. 523 */ 524 ipending |= ibit; 525 continue; 526 } 527 528 ipending &= ~ibit; 529 530 iq = &intrq[irq]; 531 iq->iq_ev.ev_count++; 532 uvmexp.intrs++; 533 current_spl_level |= iq->iq_mask; 534 oldirqstate = enable_interrupts(I32_bit); 535 for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL; 536 ih = TAILQ_NEXT(ih, ih_list)) { 537 (void) (*ih->ih_func)(ih->ih_arg ? ih->ih_arg : frame); 538 } 539 restore_interrupts(oldirqstate); 540 541 current_spl_level = pcpl; 542 543 /* Re-enable this interrupt now that's it's cleared. */ 544 intr_enabled |= ibit; 545 i80321_set_intrmask(); 546 } 547 548 /* Check for pendings soft intrs. */ 549 if ((ipending & INT_SWMASK) & ~current_spl_level) { 550 oldirqstate = enable_interrupts(I32_bit); 551 i80321_do_pending(); 552 restore_interrupts(oldirqstate); 553 } 554} 555