[BACK]Return to i80321_intr.c CVS log [TXT][DIR] Up to [local] / sys / arch / arm / xscale

Annotation of sys/arch/arm/xscale/i80321_intr.c, Revision 1.1.1.1

1.1       nbrk        1: /* $OpenBSD: i80321_intr.c,v 1.11 2007/05/19 15:47:16 miod Exp $ */
                      2:
                      3: /*
                      4:  * Copyright (c) 2006 Dale Rahn <drahn@openbsd.org>
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
                     19: #include <sys/param.h>
                     20: #include <sys/systm.h>
                     21: #include <sys/malloc.h>
                     22: #include <sys/evcount.h>
                     23:
                     24: #include <uvm/uvm.h>   /* uvmexp */
                     25:
                     26: #include <machine/intr.h>
                     27:
                     28: #include <arm/cpufunc.h>
                     29: #include <arm/xscale/i80321reg.h>
                     30: #include <arm/xscale/i80321var.h>
                     31:
                     32: /*
                     33:  * autoconf glue
                     34:  */
                     35: int            i80321intc_match(struct device *, void *, void *);
                     36: void           i80321intc_attach(struct device *, struct device *, void *);
                     37:
                     38: /* internal functions */
                     39: static void    i80321intc_write_intctl(uint32_t mask);
                     40: void           i80321intc_write_steer(uint32_t mask);
                     41: uint32_t       i80321intc_read_intsrc(void);
                     42: void           i80321intc_calc_mask(void);
                     43: void           i80321intc_init(void);
                     44: void           i80321intc_intr_init(void);
                     45: static void    i80321intc_setipl(int new);
                     46: void           i80321intc_do_pending(void);
                     47:
                     48: uint32_t       i80321intc_imask[NIPL];
                     49: uint32_t       i80321intc_smask[NIPL];
                     50:
                     51: #define SI_TO_IRQBIT(x)        (1 << (x))
                     52:
                     53: __volatile int current_ipl_level;
                     54: __volatile int softint_pending;
                     55:
                     56: struct cfattach i80321intc_ca = {
                     57:        sizeof(struct device), i80321intc_match, i80321intc_attach
                     58: };
                     59:
                     60: struct cfdriver i80321intc_cd = {
                     61:        NULL, "i80321intc", DV_DULL
                     62: };
                     63:
                     64: int i80321intc_attached = 0;
                     65:
                     66: int
                     67: i80321intc_match(struct device *parent, void *v, void *aux)
                     68: {
                     69:        if (i80321intc_attached == 0)
                     70:                return 1;
                     71:
                     72:        i80321intc_attached = 1;
                     73:        return 0;
                     74: }
                     75:
                     76: void
                     77: i80321intc_attach(struct device *parent, struct device *self, void *args)
                     78: {
                     79:        i80321intc_init();
                     80: }
                     81:
                     82: static inline void
                     83: i80321intc_write_intctl(uint32_t mask)
                     84: {
                     85:        __asm__ volatile ("mcr p6, 0, %0, c0, c0, 0" : : "r" (mask));
                     86: }
                     87:
                     88: void
                     89: i80321intc_write_steer(uint32_t mask)
                     90: {
                     91:        __asm__ volatile ("mcr p6, 0, %0, c4, c0, 0" : : "r" (mask));
                     92: }
                     93:
                     94: uint32_t
                     95: i80321intc_read_intsrc(void)
                     96: {
                     97:        uint32_t mask;
                     98:        __asm__ volatile ("mrc p6, 0, %0, c8, c0, 0" : "=r" (mask));
                     99:        return mask;
                    100: }
                    101:
                    102: static inline void
                    103: i80321intc_setipl(int new)
                    104: {
                    105:        int psw;
                    106:
                    107:        psw = disable_interrupts(I32_bit);
                    108:        current_ipl_level = new;
                    109:        i80321intc_write_intctl(i80321intc_imask[new]);
                    110:        restore_interrupts(psw);
                    111: }
                    112:
                    113:
                    114: struct intrq i80321_handler[NIRQ];
                    115:
                    116: /*
                    117:  * Recompute the irq mask bits.
                    118:  * Must be called with interrupts disabled.
                    119:  */
                    120: void
                    121: i80321intc_calc_mask(void)
                    122: {
                    123:        int irq;
                    124:        struct intrhand *ih;
                    125:        int i;
                    126:
                    127:        for (irq = 0; irq < NIRQ; irq++) {
                    128:                int i;
                    129:                int max = IPL_NONE;
                    130:                int min = IPL_HIGH;
                    131:                TAILQ_FOREACH(ih, &i80321_handler[irq].iq_list, ih_list) {
                    132:                        if (ih->ih_ipl > max)
                    133:                                max = ih->ih_ipl;
                    134:
                    135:                        if (ih->ih_ipl < min)
                    136:                                min = ih->ih_ipl;
                    137:                }
                    138:
                    139:                i80321_handler[irq].iq_irq = max;
                    140:
                    141:                if (max == IPL_NONE)
                    142:                        min = IPL_NONE; /* interrupt not enabled */
                    143: #if 0
                    144:                printf("irq %d: min %x max %x\n", irq, min, max);
                    145: #endif
                    146:
                    147:                /* Enable interrupts at lower levels */
                    148:                for (i = 0; i < min; i++)
                    149:                        i80321intc_imask[i] |= (1 << irq);
                    150:                /* Disable interrupts at upper levels */
                    151:                for (;i <= IPL_HIGH; i++)
                    152:                        i80321intc_imask[i] &= ~(1 << irq);
                    153:        }
                    154:        /* initialize soft interrupt mask */
                    155:        for (i = IPL_NONE; i <= IPL_HIGH; i++)  {
                    156:                i80321intc_smask[i] = 0;
                    157:                if (i < IPL_SOFT)
                    158:                        i80321intc_smask[i] |= SI_TO_IRQBIT(SI_SOFT);
                    159:                if (i < IPL_SOFTCLOCK)
                    160:                        i80321intc_smask[i] |= SI_TO_IRQBIT(SI_SOFTCLOCK);
                    161:                if (i < IPL_SOFTNET)
                    162:                        i80321intc_smask[i] |= SI_TO_IRQBIT(SI_SOFTNET);
                    163:                if (i < IPL_SOFTSERIAL)
                    164:                        i80321intc_smask[i] |= SI_TO_IRQBIT(SI_SOFTSERIAL);
                    165: #if 0
                    166:                printf("mask[%d]: %x %x\n", i, i80321intc_smask[i],
                    167:                    i80321intc_imask[i]);
                    168: #endif
                    169:        }
                    170:
                    171:        i80321intc_setipl(current_ipl_level);
                    172: }
                    173:
                    174: void
                    175: i80321intc_do_pending(void)
                    176: {
                    177:        static int processing = 0;
                    178:        int oldirqstate, spl_save;
                    179:
                    180:        oldirqstate = disable_interrupts(I32_bit);
                    181:
                    182:        spl_save = current_ipl_level;
                    183:
                    184:        if (processing == 1) {
                    185:                restore_interrupts(oldirqstate);
                    186:                return;
                    187:        }
                    188:
                    189: #define DO_SOFTINT(si, ipl) \
                    190:        if ((softint_pending & i80321intc_smask[current_ipl_level]) &   \
                    191:            SI_TO_IRQBIT(si)) {                                         \
                    192:                softint_pending &= ~SI_TO_IRQBIT(si);                   \
                    193:                if (current_ipl_level < ipl)                            \
                    194:                        i80321intc_setipl(ipl);                         \
                    195:                restore_interrupts(oldirqstate);                        \
                    196:                softintr_dispatch(si);                                  \
                    197:                oldirqstate = disable_interrupts(I32_bit);              \
                    198:                i80321intc_setipl(spl_save);                            \
                    199:        }
                    200:
                    201:        do {
                    202:                DO_SOFTINT(SI_SOFTSERIAL, IPL_SOFTSERIAL);
                    203:                DO_SOFTINT(SI_SOFTNET, IPL_SOFTNET);
                    204:                DO_SOFTINT(SI_SOFTCLOCK, IPL_SOFTCLOCK);
                    205:                DO_SOFTINT(SI_SOFT, IPL_SOFT);
                    206:        } while (softint_pending & i80321intc_smask[current_ipl_level]);
                    207:
                    208:
                    209:        processing = 0;
                    210:        restore_interrupts(oldirqstate);
                    211: }
                    212:
                    213: void
                    214: splx(int new)
                    215: {
                    216:        i80321intc_setipl(new);
                    217:
                    218:        if (softint_pending & i80321intc_smask[current_ipl_level])
                    219:                i80321intc_do_pending();
                    220: }
                    221:
                    222: int
                    223: _spllower(int new)
                    224: {
                    225:        int old = current_ipl_level;
                    226:        splx(new);
                    227:        return (old);
                    228: }
                    229:
                    230: int
                    231: _splraise(int new)
                    232: {
                    233:        int old;
                    234:        old = current_ipl_level;
                    235:
                    236:        /*
                    237:         * setipl must always be called because there is a race window
                    238:         * where the variable is updated before the mask is set
                    239:         * an interrupt occurs in that window without the mask always
                    240:         * being set, the hardware might not get updated on the next
                    241:         * splraise completely messing up spl protection.
                    242:         */
                    243:        if (old > new)
                    244:                new = old;
                    245:
                    246:        i80321intc_setipl(new);
                    247:
                    248:        return (old);
                    249: }
                    250:
                    251: void
                    252: _setsoftintr(int si)
                    253: {
                    254:        int oldirqstate;
                    255:
                    256:         oldirqstate = disable_interrupts(I32_bit);
                    257:        softint_pending |= SI_TO_IRQBIT(si);
                    258:        restore_interrupts(oldirqstate);
                    259:
                    260:        /* Process unmasked pending soft interrupts. */
                    261:        if (softint_pending & i80321intc_smask[current_ipl_level])
                    262:                i80321intc_do_pending();
                    263: }
                    264:
                    265: /*
                    266:  * i80321_icu_init:
                    267:  *
                    268:  *     Initialize the i80321 ICU.  Called early in bootstrap
                    269:  *     to make sure the ICU is in a pristine state.
                    270:  */
                    271: void
                    272: i80321intc_intr_init(void)
                    273: {
                    274:        i80321intc_write_intctl(0);
                    275:
                    276:        i80321intc_write_steer(0);
                    277: }
                    278:
                    279: /*
                    280:  * i80321_intr_init:
                    281:  *
                    282:  *      Initialize the rest of the interrupt subsystem, making it
                    283:  *      ready to handle interrupts from devices.
                    284:  */
                    285: void
                    286: i80321intc_init(void)
                    287: {
                    288:        struct intrq *iq;
                    289:        int i;
                    290:
                    291:        for (i = 0; i < NIRQ; i++) {
                    292:                iq = &i80321_handler[i];
                    293:                TAILQ_INIT(&iq->iq_list);
                    294:        }
                    295:
                    296:        i80321intc_calc_mask();
                    297:
                    298:        /* Enable IRQs (don't yet use FIQs). */
                    299:        enable_interrupts(I32_bit);
                    300: }
                    301:
                    302: void *
                    303: i80321_intr_establish(int irq, int ipl, int (*func)(void *), void *arg,
                    304:     char *name)
                    305: {
                    306:        struct intrq *iq;
                    307:        struct intrhand *ih;
                    308:        uint32_t oldirqstate;
                    309:
                    310:        if (irq < 0 || irq > NIRQ)
                    311:                panic("i80321_intr_establish: IRQ %d out of range", irq);
                    312:
                    313:        ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
                    314:        if (ih == NULL)
                    315:                return (NULL);
                    316:
                    317:        ih->ih_func = func;
                    318:        ih->ih_arg = arg;
                    319:        ih->ih_ipl = ipl;
                    320:        ih->ih_name = name;
                    321:        ih->ih_irq = irq;
                    322:
                    323:        iq = &i80321_handler[irq];
                    324:
                    325:        if (name != NULL)
                    326:                evcount_attach(&ih->ih_count, name, (void *)&ih->ih_irq,
                    327:                    &evcount_intr);
                    328:
                    329:        /* All IOP321 interrupts are level-triggered. */
                    330:        iq->iq_ist = IST_LEVEL;
                    331:
                    332:        oldirqstate = disable_interrupts(I32_bit);
                    333:
                    334:        TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
                    335:
                    336:        i80321intc_calc_mask();
                    337:
                    338:        restore_interrupts(oldirqstate);
                    339:
                    340:        return (ih);
                    341: }
                    342:
                    343:
                    344: void
                    345: i80321_intr_disestablish(void *cookie)
                    346: {
                    347:        struct intrhand *ih = cookie;
                    348:        struct intrq *iq = &i80321_handler[ih->ih_irq];
                    349:        int oldirqstate;
                    350:
                    351:        oldirqstate = disable_interrupts(I32_bit);
                    352:
                    353:        TAILQ_REMOVE(&iq->iq_list, ih, ih_list);
                    354:        if (ih->ih_name != NULL)
                    355:                evcount_detach(&ih->ih_count);
                    356:
                    357:        i80321intc_calc_mask();
                    358:
                    359:        restore_interrupts(oldirqstate);
                    360: }
                    361:
                    362: void
                    363: i80321_irq_handler(void *arg)
                    364: {
                    365:        struct clockframe *frame = arg;
                    366:        uint32_t hwpend;
                    367:        int irq;
                    368:        int saved_spl_level;
                    369:        struct intrhand *ih;
                    370:
                    371:        saved_spl_level = current_ipl_level;
                    372:
                    373:        /* get pending IRQs */
                    374:        hwpend = i80321intc_read_intsrc();
                    375:
                    376:        while ((irq = find_first_bit(hwpend)) >= 0) {
                    377:                /* XXX: Should we handle IRQs in priority order? */
                    378:
                    379:                /* raise spl to stop interrupts of lower priorities */
                    380:                if (saved_spl_level < i80321_handler[irq].iq_irq)
                    381:                        i80321intc_setipl(i80321_handler[irq].iq_irq);
                    382:
                    383:                /* Enable interrupt */
                    384:                enable_interrupts(I32_bit);
                    385:                TAILQ_FOREACH(ih, &i80321_handler[irq].iq_list, ih_list) {
                    386:                        if ((ih->ih_func)( ih->ih_arg == 0
                    387:                            ? frame : ih->ih_arg))
                    388:                                ih->ih_count.ec_count++;
                    389:                }
                    390:                /* Disable interrupt */
                    391:                disable_interrupts(I32_bit);
                    392:                hwpend &= ~(1<<irq);
                    393:        }
                    394:        uvmexp.intrs++;
                    395:
                    396:        /* restore spl to that was when this interrupt happen */
                    397:        i80321intc_setipl(saved_spl_level);
                    398:
                    399:        if(softint_pending & i80321intc_smask[current_ipl_level])
                    400:                i80321intc_do_pending();
                    401: }
                    402:
                    403: #ifdef DIAGNOSTIC
                    404: void
                    405: i80321_splassert_check(int wantipl, const char *func)
                    406: {
                    407:        int oldipl = current_ipl_level;
                    408:
                    409:        if (oldipl < wantipl) {
                    410:                splassert_fail(wantipl, oldipl, func);
                    411:                /*
                    412:                 * If the splassert_ctl is set to not panic, raise the ipl
                    413:                 * in a feeble attempt to reduce damage.
                    414:                 */
                    415:                i80321intc_setipl(wantipl);
                    416:        }
                    417: }
                    418: #endif

CVSweb