[BACK]Return to ep93xx_intr.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / arm / ep93xx

Annotation of src/sys/arch/arm/ep93xx/ep93xx_intr.c, Revision 1.22.6.1

1.22.6.1! skrll       1: /* $NetBSD: ep93xx_intr.c,v 1.22 2014/03/26 08:51:59 christos Exp $ */
1.1       joff        2:
                      3: /*
                      4:  * Copyright (c) 2002 The NetBSD Foundation, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Jesse Off
                      9:  *
                     10:  * This code is derived from software contributed to The NetBSD Foundation
                     11:  * by Ichiro FUKUHARA and Naoto Shimazaki.
                     12:  *
                     13:  * Redistribution and use in source and binary forms, with or without
                     14:  * modification, are permitted provided that the following conditions
                     15:  * are met:
                     16:  * 1. Redistributions of source code must retain the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer.
                     18:  * 2. Redistributions in binary form must reproduce the above copyright
                     19:  *    notice, this list of conditions and the following disclaimer in the
                     20:  *    documentation and/or other materials provided with the distribution.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     23:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     24:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     25:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     26:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     27:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     28:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     29:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     30:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     31:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     32:  * POSSIBILITY OF SUCH DAMAGE.
                     33:  */
                     34:
                     35: #include <sys/cdefs.h>
1.22.6.1! skrll      36: __KERNEL_RCSID(0, "$NetBSD: ep93xx_intr.c,v 1.22 2014/03/26 08:51:59 christos Exp $");
1.1       joff       37:
                     38: /*
                     39:  * Interrupt support for the Cirrus Logic EP93XX
                     40:  */
                     41:
                     42: #include <sys/param.h>
                     43: #include <sys/systm.h>
                     44: #include <sys/malloc.h>
                     45: #include <sys/termios.h>
                     46:
1.22.6.1! skrll      47: #include <sys/cpu.h>
1.16      dyoung     48: #include <sys/bus.h>
1.19      matt       49: #include <sys/intr.h>
1.1       joff       50:
1.19      matt       51: #include <arm/locore.h>
1.1       joff       52:
                     53: #include <arm/ep93xx/ep93xxreg.h>
                     54: #include <arm/ep93xx/ep93xxvar.h>
                     55:
                     56: /* Interrupt handler queues. */
                     57: struct intrq intrq[NIRQ];
                     58:
                     59: /* Interrupts to mask at each level. */
1.18      skrll      60: static uint32_t vic1_imask[NIPL];
                     61: static uint32_t vic2_imask[NIPL];
1.1       joff       62:
                     63: /* Current interrupt priority level. */
1.7       perry      64: volatile int hardware_spl_level;
1.1       joff       65:
                     66: /* Software copy of the IRQs we have enabled. */
1.18      skrll      67: volatile uint32_t vic1_intr_enabled;
                     68: volatile uint32_t vic2_intr_enabled;
1.1       joff       69:
1.17      skrll      70: void   ep93xx_intr_dispatch(struct trapframe *);
1.1       joff       71:
1.18      skrll      72: #define VIC1REG(reg)   *((volatile uint32_t*) (EP93XX_AHB_VBASE + \
1.1       joff       73:        EP93XX_AHB_VIC1 + (reg)))
1.18      skrll      74: #define VIC2REG(reg)   *((volatile uint32_t*) (EP93XX_AHB_VBASE + \
1.1       joff       75:        EP93XX_AHB_VIC2 + (reg)))
                     76:
                     77: static void
1.18      skrll      78: ep93xx_set_intrmask(uint32_t vic1_irqs, uint32_t vic2_irqs)
1.1       joff       79: {
                     80:        VIC1REG(EP93XX_VIC_IntEnClear) = vic1_irqs;
                     81:        VIC1REG(EP93XX_VIC_IntEnable) = vic1_intr_enabled & ~vic1_irqs;
                     82:        VIC2REG(EP93XX_VIC_IntEnClear) = vic2_irqs;
                     83:        VIC2REG(EP93XX_VIC_IntEnable) = vic2_intr_enabled & ~vic2_irqs;
                     84: }
                     85:
                     86: static void
                     87: ep93xx_enable_irq(int irq)
                     88: {
                     89:        if (irq < VIC_NIRQ) {
                     90:                vic1_intr_enabled |= (1U << irq);
                     91:                VIC1REG(EP93XX_VIC_IntEnable) = (1U << irq);
                     92:        } else {
                     93:                vic2_intr_enabled |= (1U << (irq - VIC_NIRQ));
                     94:                VIC2REG(EP93XX_VIC_IntEnable) = (1U << (irq - VIC_NIRQ));
                     95:        }
                     96: }
                     97:
1.7       perry      98: static inline void
1.1       joff       99: ep93xx_disable_irq(int irq)
                    100: {
                    101:        if (irq < VIC_NIRQ) {
                    102:                vic1_intr_enabled &= ~(1U << irq);
                    103:                VIC1REG(EP93XX_VIC_IntEnClear) = (1U << irq);
                    104:        } else {
                    105:                vic2_intr_enabled &= ~(1U << (irq - VIC_NIRQ));
                    106:                VIC2REG(EP93XX_VIC_IntEnClear) = (1U << (irq - VIC_NIRQ));
                    107:        }
                    108: }
                    109:
                    110: /*
                    111:  * NOTE: This routine must be called with interrupts disabled in the CPSR.
                    112:  */
                    113: static void
                    114: ep93xx_intr_calculate_masks(void)
                    115: {
                    116:        struct intrq *iq;
                    117:        struct intrhand *ih;
                    118:        int irq, ipl;
                    119:
                    120:        /* First, figure out which IPLs each IRQ has. */
                    121:        for (irq = 0; irq < NIRQ; irq++) {
                    122:                int levels = 0;
                    123:                iq = &intrq[irq];
                    124:                ep93xx_disable_irq(irq);
                    125:                for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
                    126:                     ih = TAILQ_NEXT(ih, ih_list))
                    127:                        levels |= (1U << ih->ih_ipl);
                    128:                iq->iq_levels = levels;
                    129:        }
                    130:
                    131:        /* Next, figure out which IRQs are used by each IPL. */
                    132:        for (ipl = 0; ipl < NIPL; ipl++) {
                    133:                int vic1_irqs = 0;
                    134:                int vic2_irqs = 0;
                    135:                for (irq = 0; irq < VIC_NIRQ; irq++) {
                    136:                        if (intrq[irq].iq_levels & (1U << ipl))
                    137:                                vic1_irqs |= (1U << irq);
                    138:                }
                    139:                vic1_imask[ipl] = vic1_irqs;
                    140:                for (irq = 0; irq < VIC_NIRQ; irq++) {
                    141:                        if (intrq[irq + VIC_NIRQ].iq_levels & (1U << ipl))
                    142:                                vic2_irqs |= (1U << irq);
                    143:                }
                    144:                vic2_imask[ipl] = vic2_irqs;
                    145:        }
                    146:
1.10      matt      147:        KASSERT(vic1_imask[IPL_NONE] == 0);
                    148:        KASSERT(vic2_imask[IPL_NONE] == 0);
1.14      tsutsui   149:        KASSERT(vic1_imask[IPL_SOFTCLOCK] == 0);
                    150:        KASSERT(vic2_imask[IPL_SOFTCLOCK] == 0);
                    151:        KASSERT(vic1_imask[IPL_SOFTBIO] == 0);
                    152:        KASSERT(vic2_imask[IPL_SOFTBIO] == 0);
                    153:        KASSERT(vic1_imask[IPL_SOFTNET] == 0);
                    154:        KASSERT(vic2_imask[IPL_SOFTNET] == 0);
                    155:        KASSERT(vic1_imask[IPL_SOFTSERIAL] == 0);
                    156:        KASSERT(vic2_imask[IPL_SOFTSERIAL] == 0);
1.1       joff      157:
                    158:        /*
1.14      tsutsui   159:         * splsched() must block anything that uses the scheduler.
1.1       joff      160:         */
1.12      matt      161:        vic1_imask[IPL_SCHED] |= vic1_imask[IPL_VM];
                    162:        vic2_imask[IPL_SCHED] |= vic2_imask[IPL_VM];
1.1       joff      163:
                    164:        /*
                    165:         * splhigh() must block "everything".
                    166:         */
1.12      matt      167:        vic1_imask[IPL_HIGH] |= vic1_imask[IPL_SCHED];
                    168:        vic2_imask[IPL_HIGH] |= vic2_imask[IPL_SCHED];
1.1       joff      169:
                    170:        /*
                    171:         * Now compute which IRQs must be blocked when servicing any
                    172:         * given IRQ.
                    173:         */
                    174:        for (irq = 0; irq < NIRQ; irq++) {
                    175:                int     vic1_irqs;
                    176:                int     vic2_irqs;
                    177:
                    178:                if (irq < VIC_NIRQ) {
                    179:                        vic1_irqs = (1U << irq);
                    180:                        vic2_irqs = 0;
                    181:                } else {
                    182:                        vic1_irqs = 0;
                    183:                        vic2_irqs = (1U << (irq - VIC_NIRQ));
                    184:                }
                    185:                iq = &intrq[irq];
                    186:                if (TAILQ_FIRST(&iq->iq_list) != NULL)
                    187:                        ep93xx_enable_irq(irq);
                    188:                for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
                    189:                     ih = TAILQ_NEXT(ih, ih_list)) {
                    190:                        vic1_irqs |= vic1_imask[ih->ih_ipl];
                    191:                        vic2_irqs |= vic2_imask[ih->ih_ipl];
                    192:                }
                    193:                iq->iq_vic1_mask = vic1_irqs;
                    194:                iq->iq_vic2_mask = vic2_irqs;
                    195:        }
                    196: }
                    197:
1.7       perry     198: inline void
1.1       joff      199: splx(int new)
                    200: {
                    201:        u_int   oldirqstate;
                    202:
                    203:        oldirqstate = disable_interrupts(I32_bit);
1.12      matt      204:        set_curcpl(new);
1.1       joff      205:        if (new != hardware_spl_level) {
                    206:                hardware_spl_level = new;
                    207:                ep93xx_set_intrmask(vic1_imask[new], vic2_imask[new]);
                    208:        }
                    209:        restore_interrupts(oldirqstate);
                    210:
1.10      matt      211: #ifdef __HAVE_FAST_SOFTINTS
1.12      matt      212:        cpu_dosoftints();
1.10      matt      213: #endif
1.1       joff      214: }
                    215:
                    216: int
                    217: _splraise(int ipl)
                    218: {
                    219:        int     old;
                    220:        u_int   oldirqstate;
                    221:
                    222:        oldirqstate = disable_interrupts(I32_bit);
1.12      matt      223:        old = curcpl();
                    224:        set_curcpl(ipl);
1.1       joff      225:        restore_interrupts(oldirqstate);
                    226:        return (old);
                    227: }
                    228:
                    229: int
                    230: _spllower(int ipl)
                    231: {
1.12      matt      232:        int     old = curcpl();
1.1       joff      233:
                    234:        if (old <= ipl)
                    235:                return (old);
                    236:        splx(ipl);
                    237:        return (old);
                    238: }
                    239:
                    240: /*
                    241:  * ep93xx_intr_init:
                    242:  *
                    243:  *     Initialize the rest of the interrupt subsystem, making it
                    244:  *     ready to handle interrupts from devices.
                    245:  */
                    246: void
                    247: ep93xx_intr_init(void)
                    248: {
                    249:        struct intrq *iq;
                    250:        int i;
                    251:
                    252:        vic1_intr_enabled = 0;
                    253:        vic2_intr_enabled = 0;
                    254:
                    255:        for (i = 0; i < NIRQ; i++) {
                    256:                iq = &intrq[i];
                    257:                TAILQ_INIT(&iq->iq_list);
                    258:
1.22      christos  259:                snprintf(iq->iq_name, sizeof(iq->iq_name), "irq %d", i);
1.1       joff      260:                evcnt_attach_dynamic(&iq->iq_ev, EVCNT_TYPE_INTR,
                    261:                                     NULL, (i < VIC_NIRQ ? "vic1" : "vic2"),
                    262:                                     iq->iq_name);
                    263:        }
1.12      matt      264:        curcpu()->ci_intr_depth = 0;
                    265:        set_curcpl(0);
1.1       joff      266:        hardware_spl_level = 0;
                    267:
                    268:        /* All interrupts should use IRQ not FIQ */
                    269:        VIC1REG(EP93XX_VIC_IntSelect) = 0;
                    270:        VIC2REG(EP93XX_VIC_IntSelect) = 0;
                    271:
                    272:        ep93xx_intr_calculate_masks();
                    273:
                    274:        /* Enable IRQs (don't yet use FIQs). */
                    275:        enable_interrupts(I32_bit);
                    276: }
                    277:
                    278: void *
                    279: ep93xx_intr_establish(int irq, int ipl, int (*ih_func)(void *), void *arg)
                    280: {
                    281:        struct intrq*           iq;
                    282:        struct intrhand*        ih;
                    283:        u_int                   oldirqstate;
                    284:
                    285:        if (irq < 0 || irq > NIRQ)
                    286:                panic("ep93xx_intr_establish: IRQ %d out of range", irq);
                    287:        if (ipl < 0 || ipl > NIPL)
                    288:                panic("ep93xx_intr_establish: IPL %d out of range", ipl);
                    289:
                    290:        ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
                    291:        if (ih == NULL)
                    292:                return (NULL);
                    293:
                    294:        ih->ih_func = ih_func;
                    295:        ih->ih_arg = arg;
                    296:        ih->ih_irq = irq;
                    297:        ih->ih_ipl = ipl;
                    298:
                    299:        iq = &intrq[irq];
                    300:
                    301:        oldirqstate = disable_interrupts(I32_bit);
                    302:        TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
                    303:        ep93xx_intr_calculate_masks();
                    304:        restore_interrupts(oldirqstate);
                    305:
                    306:        return (ih);
                    307: }
                    308:
                    309: void
                    310: ep93xx_intr_disestablish(void *cookie)
                    311: {
                    312:        struct intrhand*        ih = cookie;
                    313:        struct intrq*           iq = &intrq[ih->ih_irq];
                    314:        u_int                   oldirqstate;
                    315:
                    316:        oldirqstate = disable_interrupts(I32_bit);
                    317:        TAILQ_REMOVE(&iq->iq_list, ih, ih_list);
                    318:        ep93xx_intr_calculate_masks();
                    319:        restore_interrupts(oldirqstate);
                    320: }
                    321:
                    322: void
1.17      skrll     323: ep93xx_intr_dispatch(struct trapframe *frame)
1.1       joff      324: {
                    325:        struct intrq*           iq;
                    326:        struct intrhand*        ih;
                    327:        u_int                   oldirqstate;
                    328:        int                     pcpl;
1.18      skrll     329:        uint32_t                vic1_hwpend;
                    330:        uint32_t                vic2_hwpend;
1.1       joff      331:        int                     irq;
                    332:
1.12      matt      333:        pcpl = curcpl();
1.1       joff      334:
                    335:        vic1_hwpend = VIC1REG(EP93XX_VIC_IRQStatus);
                    336:        vic2_hwpend = VIC2REG(EP93XX_VIC_IRQStatus);
                    337:
                    338:        hardware_spl_level = pcpl;
                    339:        ep93xx_set_intrmask(vic1_imask[pcpl] | vic1_hwpend,
                    340:                             vic2_imask[pcpl] | vic2_hwpend);
                    341:
                    342:        vic1_hwpend &= ~vic1_imask[pcpl];
                    343:        vic2_hwpend &= ~vic2_imask[pcpl];
                    344:
1.3       joff      345:        if (vic1_hwpend) {
1.1       joff      346:                irq = ffs(vic1_hwpend) - 1;
                    347:
                    348:                iq = &intrq[irq];
                    349:                iq->iq_ev.ev_count++;
1.15      matt      350:                curcpu()->ci_data.cpu_nintr++;
1.12      matt      351:                TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
                    352:                        set_curcpl(ih->ih_ipl);
1.1       joff      353:                        oldirqstate = enable_interrupts(I32_bit);
                    354:                        (void) (*ih->ih_func)(ih->ih_arg ? ih->ih_arg : frame);
                    355:                        restore_interrupts(oldirqstate);
                    356:                }
1.3       joff      357:        } else if (vic2_hwpend) {
1.1       joff      358:                irq = ffs(vic2_hwpend) - 1;
                    359:
                    360:                iq = &intrq[irq + VIC_NIRQ];
                    361:                iq->iq_ev.ev_count++;
1.15      matt      362:                curcpu()->ci_data.cpu_nintr++;
1.12      matt      363:                TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
                    364:                        set_curcpl(ih->ih_ipl);
1.1       joff      365:                        oldirqstate = enable_interrupts(I32_bit);
                    366:                        (void) (*ih->ih_func)(ih->ih_arg ? ih->ih_arg : frame);
                    367:                        restore_interrupts(oldirqstate);
                    368:                }
                    369:        }
                    370:
1.12      matt      371:        set_curcpl(pcpl);
1.1       joff      372:        hardware_spl_level = pcpl;
                    373:        ep93xx_set_intrmask(vic1_imask[pcpl], vic2_imask[pcpl]);
                    374:
1.10      matt      375: #ifdef __HAVE_FAST_SOFTINTS
1.12      matt      376:        cpu_dosoftints();
1.10      matt      377: #endif
1.1       joff      378: }

CVSweb <webmaster@jp.NetBSD.org>