Annotation of sys/arch/arm/sa11x0/sa11x0_intr.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pxa2x0_intr.c,v 1.15 2007/05/19 15:47:16 miod Exp $ */
! 2: /* $NetBSD: pxa2x0_intr.c,v 1.5 2003/07/15 00:24:55 lukem Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2002 Genetec Corporation. All rights reserved.
! 6: * Written by Hiroyuki Bessho for Genetec Corporation.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. All advertising materials mentioning features or use of this software
! 17: * must display the following acknowledgement:
! 18: * This product includes software developed for the NetBSD Project by
! 19: * Genetec Corporation.
! 20: * 4. The name of Genetec Corporation may not be used to endorse or
! 21: * promote products derived from this software without specific prior
! 22: * written permission.
! 23: *
! 24: * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
! 25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 26: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 27: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION
! 28: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 29: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 30: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 31: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 32: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 33: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 34: * POSSIBILITY OF SUCH DAMAGE.
! 35: */
! 36:
! 37: /*
! 38: * IRQ handler for the Intel StrongARM SA-11[01]0 processor.
! 39: * It has integrated interrupt controller.
! 40: */
! 41:
! 42: #include <sys/cdefs.h>
! 43: /*
! 44: __KERNEL_RCSID(0, "$NetBSD: pxa2x0_intr.c,v 1.5 2003/07/15 00:24:55 lukem Exp $");
! 45: */
! 46:
! 47: #include <sys/cdefs.h>
! 48:
! 49: #include <sys/param.h>
! 50: #include <sys/systm.h>
! 51: #include <sys/malloc.h>
! 52: #include <sys/evcount.h>
! 53: #include <sys/queue.h>
! 54: #include <uvm/uvm_extern.h>
! 55:
! 56: #include <machine/bus.h>
! 57: #include <machine/intr.h>
! 58: #include <machine/lock.h>
! 59:
! 60: #include <arm/sa11x0/sa11x0_reg.h>
! 61: #include <arm/sa11x0/sa11x0_var.h>
! 62: #include <arm/sa11x0/sa11x0_intr.h>
! 63:
! 64: /*
! 65: * INTC autoconf glue
! 66: */
! 67: int saic_match(struct device *, void *, void *);
! 68: void saic_attach(struct device *, struct device *, void *);
! 69:
! 70: struct cfattach saic_ca = {
! 71: sizeof(struct device), saic_match, saic_attach
! 72: };
! 73:
! 74: struct cfdriver saic_cd = {
! 75: NULL, "saic", DV_DULL
! 76: };
! 77:
! 78: static int saic_attached;
! 79: vaddr_t saic_base;
! 80:
! 81: int sa11x0_stray_interrupt(void *);
! 82: void sa11x0_init_interrupt_masks(void);
! 83: void *_sa11x0_intr_establish(int irqno, int level,
! 84: int (*func)(void *), void *arg, char *name);
! 85: void sa11x0_intr_disestablish(void *cookie);
! 86:
! 87: /* XXX defined in arch/arm/sa11x0/sa11x0_intr.h */
! 88: #define read_icu(offset) (*(volatile uint32_t *)(saic_base+(offset)))
! 89: #define write_icu(offset,value) \
! 90: (*(volatile uint32_t *)(saic_base+(offset))=(value))
! 91:
! 92:
! 93: /*
! 94: * interrupt dispatch table.
! 95: */
! 96: #if 1
! 97: #define MULTIPLE_HANDLERS_ON_ONE_IRQ
! 98: #endif
! 99: #ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ
! 100: struct intrhand {
! 101: TAILQ_ENTRY(intrhand) ih_list; /* link on intrq list */
! 102: int (*ih_func)(void *); /* handler */
! 103: void *ih_arg; /* arg for handler */
! 104: char *ih_name;
! 105: struct evcount ih_count;
! 106: int ih_irq;
! 107: int ih_level;
! 108: };
! 109: #endif
! 110:
! 111: static struct intrhandler{
! 112: #ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ
! 113: TAILQ_HEAD(,intrhand) list;
! 114: #else
! 115: sa11x0_irq_handler_t func;
! 116: char *name;
! 117: void *arg; /* NULL for stackframe */
! 118: int ih_irq;
! 119: struct evcount ih_count;
! 120: #endif
! 121: } handler[ICU_LEN];
! 122:
! 123: __volatile int softint_pending;
! 124: __volatile int current_spl_level;
! 125: /* interrupt masks for each level */
! 126: int sa11x0_imask[NIPL];
! 127: static int extirq_level[ICU_LEN];
! 128:
! 129:
! 130: int
! 131: saic_match(struct device *parent, void *cf, void *aux)
! 132: {
! 133: struct saip_attach_args *saa = aux;
! 134:
! 135: if (saic_attached || saa->sai_addr != SAIPIC_BASE)
! 136: return (0);
! 137:
! 138: return (1);
! 139: }
! 140:
! 141: void
! 142: saic_attach(struct device *parent, struct device *self, void *args)
! 143: {
! 144: int i;
! 145:
! 146: saic_attached = 1;
! 147:
! 148: printf(": SA-11x0 Interrupt Controller\n");
! 149:
! 150: //#define SAIPIC_ICCR 0x14 /* XXX what's this? typo or err in spec?? */
! 151:
! 152: write_icu(SAIPIC_CR, 1);
! 153: write_icu(SAIPIC_MR, 0);
! 154:
! 155: for(i = 0; i < sizeof handler / sizeof handler[0]; ++i){
! 156: #ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ
! 157: TAILQ_INIT(&handler[i].list);
! 158: extirq_level[i] = IPL_NONE;
! 159: #else
! 160: handler[i].name = "stray";
! 161: handler[i].func = sa11x0_stray_interrupt;
! 162: handler[i].arg = (void *)(u_int32_t) i;
! 163: extirq_level[i] = IPL_SERIAL;
! 164: #endif
! 165:
! 166: }
! 167:
! 168: sa11x0_init_interrupt_masks();
! 169:
! 170: _splraise(IPL_TTY);
! 171: enable_interrupts(I32_bit);
! 172: }
! 173:
! 174: /*
! 175: * Invoked very early on from the board-specific initarm(), in order to
! 176: * inform us the virtual address of the interrupt controller's registers.
! 177: */
! 178: void
! 179: sa11x0_intr_bootstrap(vaddr_t addr)
! 180: {
! 181:
! 182: saic_base = addr;
! 183: }
! 184:
! 185: #if 0
! 186: /*
! 187: * PXA27x has MSL interface and SSP3 interrupts [0,1], USIM interface
! 188: * and SSP2 interrupts [15,16]. PXA255 has bits [0..6,15] reserved and
! 189: * bit [16] network SSP interrupt. We don't need any of those, so we
! 190: * map software interrupts to bits [0..1,15..16]. Sadly there are no
! 191: * four contiguous bits safe enough to use on both processors.
! 192: */
! 193: #define SI_TO_IRQBIT(si) ((si) < 2 ? 1U<<(si) : 1U<<(15-2+(si)))
! 194: #else
! 195: #define SI_TO_IRQBIT(si) (1 << (si))
! 196: #endif /* 0 */
! 197:
! 198: /*
! 199: * Map a software interrupt queue to an interrupt priority level.
! 200: */
! 201: static const int si_to_ipl[SI_NQUEUES] = {
! 202: IPL_SOFT, /* SI_SOFT */
! 203: IPL_SOFTCLOCK, /* SI_SOFTCLOCK */
! 204: IPL_SOFTNET, /* SI_SOFTNET */
! 205: IPL_SOFTSERIAL, /* SI_SOFTSERIAL */
! 206: };
! 207:
! 208: /*
! 209: * called from irq_entry.
! 210: */
! 211: void
! 212: sa11x0_irq_handler(void *arg)
! 213: {
! 214: struct clockframe *frame = arg;
! 215: uint32_t irqbits;
! 216: int irqno;
! 217: int saved_spl_level;
! 218: #ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ
! 219: struct intrhand *ih;
! 220: #endif
! 221:
! 222: saved_spl_level = current_spl_level;
! 223:
! 224: /* get pending IRQs */
! 225: irqbits = read_icu(SAIPIC_IP);
! 226:
! 227: while ((irqno = find_first_bit(irqbits)) >= 0) {
! 228: /* XXX: Should we handle IRQs in priority order? */
! 229:
! 230: /* raise spl to stop interrupts of lower priorities */
! 231: if (saved_spl_level < extirq_level[irqno])
! 232: sa11x0_setipl(extirq_level[irqno]);
! 233:
! 234: /* Enable interrupt */
! 235: enable_interrupts(I32_bit);
! 236:
! 237: #ifndef MULTIPLE_HANDLERS_ON_ONE_IRQ
! 238: (* handler[irqno].func)(
! 239: handler[irqno].arg == 0
! 240: ? frame : handler[irqno].arg );
! 241: handler[irqno].ih_count.ec_count++;
! 242: #else
! 243: TAILQ_FOREACH(ih, &handler[irqno].list, ih_list) {
! 244: if ((ih->ih_func)( ih->ih_arg == 0
! 245: ? frame : ih->ih_arg))
! 246: ih->ih_count.ec_count++;
! 247: }
! 248: #endif
! 249:
! 250: /* Disable interrupt */
! 251: disable_interrupts(I32_bit);
! 252:
! 253: irqbits &= ~(1<<irqno);
! 254: }
! 255:
! 256: /* restore spl to that was when this interrupt happen */
! 257: sa11x0_setipl(saved_spl_level);
! 258:
! 259: if(softint_pending & sa11x0_imask[current_spl_level])
! 260: sa11x0_do_pending();
! 261: }
! 262:
! 263: int
! 264: sa11x0_stray_interrupt(void *cookie)
! 265: {
! 266: int irqno = (int)cookie;
! 267: printf("stray interrupt %d\n", irqno);
! 268:
! 269: if (1 <= irqno && irqno < ICU_LEN){
! 270: int save = disable_interrupts(I32_bit);
! 271: write_icu(SAIPIC_MR,
! 272: read_icu(SAIPIC_MR) & ~(1U<<irqno));
! 273: restore_interrupts(save);
! 274: }
! 275:
! 276: return 0;
! 277: }
! 278:
! 279:
! 280:
! 281: /*
! 282: * Interrupt Mask Handling
! 283: */
! 284:
! 285: #ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ
! 286: void sa11x0_update_intr_masks(void);
! 287:
! 288: void
! 289: sa11x0_update_intr_masks()
! 290: #else
! 291: void sa11x0_update_intr_masks(int irqno, int level);
! 292:
! 293: void
! 294: sa11x0_update_intr_masks(int irqno, int irqlevel)
! 295: #endif
! 296: {
! 297: int psw;
! 298:
! 299: #ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ
! 300: int irq;
! 301: #ifdef DEBUG
! 302: int level;
! 303: #endif
! 304: struct intrhand *ih;
! 305: psw = disable_interrupts(I32_bit);
! 306:
! 307: /* First figure out which levels each IRQ uses. */
! 308: for (irq = 0; irq < ICU_LEN; irq++) {
! 309: int i;
! 310: int max = IPL_NONE;
! 311: int min = IPL_HIGH; /* XXX kill IPL_SERIAL */
! 312: TAILQ_FOREACH(ih, &handler[irq].list, ih_list) {
! 313: if (ih->ih_level > max)
! 314: max = ih->ih_level;
! 315:
! 316: if (ih->ih_level < min)
! 317: min = ih->ih_level;
! 318: }
! 319:
! 320: extirq_level[irq] = max;
! 321:
! 322: if (min == IPL_HIGH)
! 323: min = IPL_NONE;
! 324:
! 325: /* Enable interrupt at lower level */
! 326: for(i = 0; i < min; ++i)
! 327: sa11x0_imask[i] |= (1 << irq);
! 328:
! 329: /* Disable interrupt at upper level */
! 330: for( ; i < NIPL-1; ++i)
! 331: sa11x0_imask[i] &= ~(1 << irq);
! 332: }
! 333:
! 334: /* fixup */
! 335: sa11x0_imask[IPL_NONE] |=
! 336: SI_TO_IRQBIT(SI_SOFT) |
! 337: SI_TO_IRQBIT(SI_SOFTCLOCK) |
! 338: SI_TO_IRQBIT(SI_SOFTNET) |
! 339: SI_TO_IRQBIT(SI_SOFTSERIAL);
! 340: sa11x0_imask[IPL_SOFT] |=
! 341: SI_TO_IRQBIT(SI_SOFTCLOCK) |
! 342: SI_TO_IRQBIT(SI_SOFTNET) |
! 343: SI_TO_IRQBIT(SI_SOFTSERIAL);
! 344: sa11x0_imask[IPL_SOFTCLOCK] |=
! 345: SI_TO_IRQBIT(SI_SOFTNET) |
! 346: SI_TO_IRQBIT(SI_SOFTSERIAL);
! 347: sa11x0_imask[IPL_SOFTNET] |=
! 348: SI_TO_IRQBIT(SI_SOFTSERIAL);
! 349: sa11x0_imask[IPL_SOFTSERIAL] |=
! 350: 0;
! 351: #else
! 352: int level; /* debug */
! 353: int mask = 1U<<irqno;
! 354: int i;
! 355: psw = disable_interrupts(I32_bit);
! 356:
! 357: for(i = 0; i < irqlevel; ++i)
! 358: sa11x0_imask[i] |= mask; /* Enable interrupt at lower level */
! 359:
! 360: for( ; i < NIPL-1; ++i)
! 361: sa11x0_imask[i] &= ~mask; /* Disable interrupt at upper level */
! 362: #endif
! 363:
! 364: /*
! 365: * Enforce a hierarchy that gives "slow" device (or devices with
! 366: * limited input buffer space/"real-time" requirements) a better
! 367: * chance at not dropping data.
! 368: */
! 369: sa11x0_imask[IPL_BIO] &= sa11x0_imask[IPL_SOFTNET];
! 370: sa11x0_imask[IPL_NET] &= sa11x0_imask[IPL_BIO];
! 371: sa11x0_imask[IPL_SOFTSERIAL] &= sa11x0_imask[IPL_NET];
! 372: sa11x0_imask[IPL_TTY] &= sa11x0_imask[IPL_SOFTSERIAL];
! 373:
! 374: /*
! 375: * splvm() blocks all interrupts that use the kernel memory
! 376: * allocation facilities.
! 377: */
! 378: sa11x0_imask[IPL_VM] &= sa11x0_imask[IPL_TTY];
! 379:
! 380: /*
! 381: * Audio devices are not allowed to perform memory allocation
! 382: * in their interrupt routines, and they have fairly "real-time"
! 383: * requirements, so give them a high interrupt priority.
! 384: */
! 385: sa11x0_imask[IPL_AUDIO] &= sa11x0_imask[IPL_VM];
! 386:
! 387: /*
! 388: * splclock() must block anything that uses the scheduler.
! 389: */
! 390: sa11x0_imask[IPL_CLOCK] &= sa11x0_imask[IPL_AUDIO];
! 391:
! 392: /*
! 393: * splhigh() must block "everything".
! 394: */
! 395: sa11x0_imask[IPL_HIGH] &= sa11x0_imask[IPL_STATCLOCK];
! 396:
! 397: /*
! 398: * XXX We need serial drivers to run at the absolute highest priority
! 399: * in order to avoid overruns, so serial > high.
! 400: */
! 401: sa11x0_imask[IPL_TTY] &= sa11x0_imask[IPL_HIGH];
! 402:
! 403: #ifdef DEBUG
! 404: for (level = IPL_NONE; level < NIPL; level++) {
! 405: printf("imask %d, %x\n", level, sa11x0_imask[level]);
! 406: }
! 407: #endif
! 408:
! 409: #ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ
! 410: for (irq = 0; irq < ICU_LEN; irq++) {
! 411: int max_irq = IPL_NONE;
! 412: TAILQ_FOREACH(ih, &handler[irq].list, ih_list) {
! 413: if (ih->ih_level > max_irq)
! 414: max_irq = ih->ih_level;
! 415: }
! 416: extirq_level[irq] = max_irq;
! 417: }
! 418: #endif
! 419:
! 420: write_icu(SAIPIC_MR, sa11x0_imask[current_spl_level]);
! 421:
! 422: restore_interrupts(psw);
! 423: }
! 424:
! 425:
! 426: void
! 427: sa11x0_init_interrupt_masks(void)
! 428: {
! 429:
! 430: memset(sa11x0_imask, 0, sizeof(sa11x0_imask));
! 431:
! 432: /*
! 433: * IPL_NONE has soft interrupts enabled only, at least until
! 434: * hardware handlers are installed.
! 435: */
! 436: sa11x0_imask[IPL_NONE] =
! 437: SI_TO_IRQBIT(SI_SOFT) |
! 438: SI_TO_IRQBIT(SI_SOFTCLOCK) |
! 439: SI_TO_IRQBIT(SI_SOFTNET) |
! 440: SI_TO_IRQBIT(SI_SOFTSERIAL);
! 441:
! 442: /*
! 443: * Initialize the soft interrupt masks to block themselves.
! 444: */
! 445: sa11x0_imask[IPL_SOFT] = ~SI_TO_IRQBIT(SI_SOFT);
! 446: sa11x0_imask[IPL_SOFTCLOCK] = ~SI_TO_IRQBIT(SI_SOFTCLOCK);
! 447: sa11x0_imask[IPL_SOFTNET] = ~SI_TO_IRQBIT(SI_SOFTNET);
! 448: sa11x0_imask[IPL_SOFTSERIAL] = ~SI_TO_IRQBIT(SI_SOFTSERIAL);
! 449:
! 450: sa11x0_imask[IPL_SOFT] &= sa11x0_imask[IPL_NONE];
! 451:
! 452: /*
! 453: * splsoftclock() is the only interface that users of the
! 454: * generic software interrupt facility have to block their
! 455: * soft intrs, so splsoftclock() must also block IPL_SOFT.
! 456: */
! 457: sa11x0_imask[IPL_SOFTCLOCK] &= sa11x0_imask[IPL_SOFT];
! 458:
! 459: /*
! 460: * splsoftnet() must also block splsoftclock(), since we don't
! 461: * want timer-driven network events to occur while we're
! 462: * processing incoming packets.
! 463: */
! 464: sa11x0_imask[IPL_SOFTNET] &= sa11x0_imask[IPL_SOFTCLOCK];
! 465: }
! 466:
! 467: void
! 468: sa11x0_do_pending(void)
! 469: {
! 470: static __cpu_simple_lock_t processing = __SIMPLELOCK_UNLOCKED;
! 471: int oldirqstate, spl_save;
! 472:
! 473: if (__cpu_simple_lock_try(&processing) == 0)
! 474: return;
! 475:
! 476: spl_save = current_spl_level;
! 477:
! 478: oldirqstate = disable_interrupts(I32_bit);
! 479:
! 480: #if 1
! 481: #define DO_SOFTINT(si,ipl) \
! 482: if ((softint_pending & sa11x0_imask[current_spl_level]) & \
! 483: SI_TO_IRQBIT(si)) { \
! 484: softint_pending &= ~SI_TO_IRQBIT(si); \
! 485: if (current_spl_level < ipl) \
! 486: sa11x0_setipl(ipl); \
! 487: restore_interrupts(oldirqstate); \
! 488: softintr_dispatch(si); \
! 489: oldirqstate = disable_interrupts(I32_bit); \
! 490: sa11x0_setipl(spl_save); \
! 491: }
! 492:
! 493: do {
! 494: DO_SOFTINT(SI_SOFTSERIAL,IPL_SOFTSERIAL);
! 495: DO_SOFTINT(SI_SOFTNET, IPL_SOFTNET);
! 496: DO_SOFTINT(SI_SOFTCLOCK, IPL_SOFTCLOCK);
! 497: DO_SOFTINT(SI_SOFT, IPL_SOFT);
! 498: } while( softint_pending & sa11x0_imask[current_spl_level] );
! 499: #else
! 500: while( (si = find_first_bit(softint_pending & sa11x0_imask[current_spl_level])) >= 0 ){
! 501: softint_pending &= ~SI_TO_IRQBIT(si);
! 502: if (current_spl_level < ipl)
! 503: sa11x0_setipl(ipl);
! 504: restore_interrupts(oldirqstate);
! 505: softintr_dispatch(si);
! 506: oldirqstate = disable_interrupts(I32_bit);
! 507: sa11x0_setipl(spl_save);
! 508: }
! 509: #endif
! 510:
! 511: __cpu_simple_unlock(&processing);
! 512:
! 513: restore_interrupts(oldirqstate);
! 514: }
! 515:
! 516:
! 517: #undef splx
! 518: void
! 519: splx(int ipl)
! 520: {
! 521:
! 522: sa11x0_splx(ipl);
! 523: }
! 524:
! 525: #undef _splraise
! 526: int
! 527: _splraise(int ipl)
! 528: {
! 529:
! 530: return sa11x0_splraise(ipl);
! 531: }
! 532:
! 533: #undef _spllower
! 534: int
! 535: _spllower(int ipl)
! 536: {
! 537:
! 538: return sa11x0_spllower(ipl);
! 539: }
! 540:
! 541: #undef _setsoftintr
! 542: void
! 543: _setsoftintr(int si)
! 544: {
! 545:
! 546: return sa11x0_setsoftintr(si);
! 547: }
! 548:
! 549: void *
! 550: _sa11x0_intr_establish(int irqno, int level,
! 551: int (*func)(void *), void *arg, char *name)
! 552: {
! 553: int psw;
! 554: #ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ
! 555: struct intrhand *ih;
! 556: #else
! 557: struct intrhandler *ih;
! 558: #endif
! 559:
! 560: if (irqno < 0 || irqno >= ICU_LEN - 1)
! 561: panic("intr_establish: bogus irq number %d", irqno);
! 562:
! 563: psw = disable_interrupts(I32_bit);
! 564:
! 565: #ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ
! 566: /* no point in sleeping unless someone can free memory. */
! 567: MALLOC(ih, struct intrhand *, sizeof *ih, M_DEVBUF,
! 568: cold ? M_NOWAIT : M_WAITOK);
! 569: if (ih == NULL)
! 570: panic("intr_establish: can't malloc handler info");
! 571: ih->ih_func = func;
! 572: ih->ih_arg = arg;
! 573: ih->ih_level = level;
! 574: ih->ih_irq = irqno;
! 575:
! 576: TAILQ_INSERT_TAIL(&handler[irqno].list, ih, ih_list);
! 577: #else
! 578: ih = &handler[irqno];
! 579: ih->arg = arg;
! 580: ih->func = func;
! 581: ih->name = name;
! 582: ih->ih_irq = irqno;
! 583: extirq_level[irqno] = level;
! 584: #endif
! 585:
! 586: if (name != NULL)
! 587: evcount_attach(&ih->ih_count, name, (void *)&ih->ih_irq,
! 588: &evcount_intr);
! 589:
! 590: #ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ
! 591: sa11x0_update_intr_masks();
! 592: #else
! 593: sa11x0_update_intr_masks(irqno, level);
! 594: #endif
! 595:
! 596: restore_interrupts(psw);
! 597:
! 598: return (ih);
! 599: }
! 600:
! 601: void
! 602: sa11x0_intr_disestablish(void *cookie)
! 603: {
! 604:
! 605: #ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ
! 606: int psw;
! 607: struct intrhand *ih = cookie;
! 608: int irqno = ih->ih_irq;
! 609:
! 610: psw = disable_interrupts(I32_bit);
! 611: TAILQ_REMOVE(&handler[irqno].list, ih, ih_list);
! 612:
! 613: FREE(ih, M_DEVBUF);
! 614:
! 615: sa11x0_update_intr_masks();
! 616:
! 617: restore_interrupts(psw);
! 618: #else
! 619: struct intrhandler *lhandler = cookie;
! 620: int irqno;
! 621: int psw;
! 622: struct intrhandler *ih;
! 623: irqno = lhandler - handler;
! 624:
! 625: if (irqno < 1 || irqno >= ICU_LEN)
! 626: panic("intr_disestablish: bogus irq number %d", irqno);
! 627:
! 628: psw = disable_interrupts(I32_bit);
! 629:
! 630: ih = &handler[irqno];
! 631: if (ih->name != NULL)
! 632: evcount_detach(&ih->ih_count);
! 633:
! 634: ih->arg = (void *) irqno;
! 635: ih->func = sa11x0_stray_interrupt;
! 636: ih->name = "stray";
! 637: extirq_level[irqno] = IPL_SERIAL;
! 638: sa11x0_update_intr_masks(irqno, IPL_SERIAL);
! 639:
! 640: restore_interrupts(psw);
! 641: #endif
! 642: }
! 643:
! 644: /*
! 645: * Glue for drivers of sa11x0 compatible integrated logic.
! 646: */
! 647:
! 648: void *
! 649: sa11x0_intr_establish(sa11x0_chipset_tag_t ic, int irq, int type, int level,
! 650: int (*ih_fun)(void *), void *ih_arg, char *name)
! 651: {
! 652: /* XXX */
! 653: return _sa11x0_intr_establish(irq, level, ih_fun, ih_arg, name);
! 654: }
! 655:
! 656: void
! 657: sa11x0_setipl(int new)
! 658: {
! 659: u_int32_t intr_mask;
! 660:
! 661: intr_mask = sa11x0_imask[new];
! 662: current_spl_level = new;
! 663: write_icu( SAIPIC_MR, intr_mask );
! 664: }
! 665:
! 666:
! 667: void
! 668: sa11x0_splx(int new)
! 669: {
! 670: int psw;
! 671:
! 672: psw = disable_interrupts(I32_bit);
! 673: sa11x0_setipl(new);
! 674: restore_interrupts(psw);
! 675:
! 676: /* If there are pending software interrupts, process them. */
! 677: if (softint_pending & sa11x0_imask[current_spl_level])
! 678: sa11x0_do_pending();
! 679: }
! 680:
! 681:
! 682: int
! 683: sa11x0_splraise(int ipl)
! 684: {
! 685: int old, psw;
! 686:
! 687: old = current_spl_level;
! 688: if( ipl > current_spl_level ){
! 689: psw = disable_interrupts(I32_bit);
! 690: sa11x0_setipl(ipl);
! 691: restore_interrupts(psw);
! 692: }
! 693:
! 694: return (old);
! 695: }
! 696:
! 697: int
! 698: sa11x0_spllower(int ipl)
! 699: {
! 700: int old = current_spl_level;
! 701: int psw = disable_interrupts(I32_bit);
! 702: sa11x0_splx(ipl);
! 703: restore_interrupts(psw);
! 704: return(old);
! 705: }
! 706:
! 707: void
! 708: sa11x0_setsoftintr(int si)
! 709: {
! 710: #if 0
! 711: atomic_set_bit( (u_int *)&softint_pending, SI_TO_IRQBIT(si) );
! 712: #else
! 713: softint_pending |= SI_TO_IRQBIT(si);
! 714: #endif
! 715:
! 716: /* Process unmasked pending soft interrupts. */
! 717: if ( softint_pending & sa11x0_imask[current_spl_level] )
! 718: sa11x0_do_pending();
! 719: }
! 720:
! 721: const char *
! 722: sa11x0_intr_string(void *cookie)
! 723: {
! 724: #ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ
! 725: struct intrhand *ih = cookie;
! 726: #else
! 727: struct intrhandler *lhandler = cookie;
! 728: #endif
! 729: static char irqstr[32];
! 730:
! 731: if (ih == NULL)
! 732: snprintf(irqstr, sizeof irqstr, "couldn't establish interrupt");
! 733: else
! 734: snprintf(irqstr, sizeof irqstr, "irq %ld", ih->ih_irq);
! 735:
! 736: return irqstr;
! 737: }
! 738:
! 739: #ifdef DIAGNOSTIC
! 740: void
! 741: sa11x0_splassert_check(int wantipl, const char *func)
! 742: {
! 743: int oldipl = current_spl_level, psw;
! 744:
! 745: if (oldipl < wantipl) {
! 746: splassert_fail(wantipl, oldipl, func);
! 747: /*
! 748: * If the splassert_ctl is set to not panic, raise the ipl
! 749: * in a feeble attempt to reduce damage.
! 750: */
! 751: psw = disable_interrupts(I32_bit);
! 752: sa11x0_setipl(wantipl);
! 753: restore_interrupts(psw);
! 754: }
! 755: }
! 756: #endif
CVSweb