[BACK]Return to irq.c CVS log [TXT][DIR] Up to [local] / prex / sys / kern

Annotation of prex/sys/kern/irq.c, Revision 1.1

1.1     ! nbrk        1: /*-
        !             2:  * Copyright (c) 2005-2007, Kohsuke Ohtani
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms, with or without
        !             6:  * modification, are permitted provided that the following conditions
        !             7:  * are met:
        !             8:  * 1. Redistributions of source code must retain the above copyright
        !             9:  *    notice, this list of conditions and the following disclaimer.
        !            10:  * 2. Redistributions in binary form must reproduce the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer in the
        !            12:  *    documentation and/or other materials provided with the distribution.
        !            13:  * 3. Neither the name of the author nor the names of any co-contributors
        !            14:  *    may be used to endorse or promote products derived from this software
        !            15:  *    without specific prior written permission.
        !            16:  *
        !            17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            20:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
        !            21:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            27:  * SUCH DAMAGE.
        !            28:  */
        !            29:
        !            30: /*
        !            31:  * irq.c - interrupt request management routines.
        !            32:  */
        !            33:
        !            34: /**
        !            35:  * We define the following two different types of interrupt
        !            36:  * services in order to improve real-time performance.
        !            37:  *
        !            38:  * - Interrupt Service Routine (ISR)
        !            39:  *
        !            40:  *  ISR is started by an actual hardware interrupt. The associated
        !            41:  *  interrupt is disabled in Interrupt Control Unit (ICU), and CPU
        !            42:  *  interrupt is enabled while ISR runs.
        !            43:  *  If ISR determines that the corresponding device generated the
        !            44:  *  interrupt, ISR must program the device to stop that interrupt.
        !            45:  *  Then, ISR should do minimum I/O operation and return control
        !            46:  *  as quickly as possible. ISR will run within a context of the
        !            47:  *  thread running when interrupt occurs. So, only few kernel
        !            48:  *  services are available within ISR. We can use irq_level value
        !            49:  *  to detect the illegal call from ISR code.
        !            50:  *
        !            51:  * - Interrupt Service Thread (IST)
        !            52:  *
        !            53:  *  IST is automatically activated if ISR returns INT_CONTINUE. It
        !            54:  *  will be called when the system enters safer condition than ISR.
        !            55:  *  A device driver should use IST to do heavy I/O operation as much
        !            56:  *  as possible. Since ISR for the same IRQ line may be invoked
        !            57:  *  during IST, the shared data, resources, and device registers
        !            58:  *  must be synchronized by using irq_lock(). IST does not have to
        !            59:  *  be reentrant because it is not interrupted by same IST itself.
        !            60:  */
        !            61:
        !            62: #include <kernel.h>
        !            63: #include <event.h>
        !            64: #include <kmem.h>
        !            65: #include <sched.h>
        !            66: #include <thread.h>
        !            67: #include <irq.h>
        !            68:
        !            69: /* forward declarations */
        !            70: static void    irq_thread(void *);
        !            71:
        !            72: static struct irq      *irq_table[NIRQS];      /* IRQ descriptor table */
        !            73: static volatile int    nr_irq_locks;           /* lock counter */
        !            74: static volatile int    saved_irq_state;        /* state saved by irq_lock() */
        !            75:
        !            76: /*
        !            77:  * irq_attach - attach ISR and IST to the specified interrupt.
        !            78:  *
        !            79:  * Returns irq handle, or NULL on failure.  The interrupt of
        !            80:  * attached irq will be unmasked (enabled) in this routine.
        !            81:  * TODO: Interrupt sharing is not supported, for now.
        !            82:  */
        !            83: irq_t
        !            84: irq_attach(int vector, int prio, int shared, int (*isr)(int), void (*ist)(int))
        !            85: {
        !            86:        struct irq *irq;
        !            87:        int mode;
        !            88:
        !            89:        ASSERT(irq_level == 0);
        !            90:        ASSERT(isr != NULL);
        !            91:
        !            92:        sched_lock();
        !            93:        if ((irq = kmem_alloc(sizeof(struct irq))) == NULL) {
        !            94:                sched_unlock();
        !            95:                return NULL;
        !            96:        }
        !            97:        memset(irq, 0, sizeof(struct irq));
        !            98:        irq->vector = vector;
        !            99:        irq->isr = isr;
        !           100:        irq->ist = ist;
        !           101:
        !           102:        if (ist != NULL) {
        !           103:                /*
        !           104:                 * Create a new thread for IST.
        !           105:                 */
        !           106:                irq->thread = kthread_create(&irq_thread, irq, ISTPRIO(prio));
        !           107:                if (irq->thread == NULL) {
        !           108:                        kmem_free(irq);
        !           109:                        sched_unlock();
        !           110:                        return NULL;
        !           111:                }
        !           112:                event_init(&irq->istevt, "interrupt");
        !           113:        }
        !           114:        irq_table[vector] = irq;
        !           115:        irq_lock();
        !           116:        mode = shared ? IMODE_LEVEL : IMODE_EDGE;
        !           117:        interrupt_setup(vector, mode);
        !           118:        interrupt_unmask(vector, prio);
        !           119:        irq_unlock();
        !           120:
        !           121:        sched_unlock();
        !           122:        DPRINTF(("IRQ%d attached priority=%d\n", vector, prio));
        !           123:        return irq;
        !           124: }
        !           125:
        !           126: /*
        !           127:  * Detach an interrupt handler from the interrupt chain.
        !           128:  * The detached interrupt will be masked off if nobody
        !           129:  * attaches to it, anymore.
        !           130:  */
        !           131: void
        !           132: irq_detach(irq_t irq)
        !           133: {
        !           134:        ASSERT(irq_level == 0);
        !           135:        ASSERT(irq);
        !           136:        ASSERT(irq->vector < NIRQS);
        !           137:
        !           138:        irq_lock();
        !           139:        interrupt_mask(irq->vector);
        !           140:        irq_unlock();
        !           141:
        !           142:        irq_table[irq->vector] = NULL;
        !           143:        if (irq->thread != NULL)
        !           144:                kthread_terminate(irq->thread);
        !           145:
        !           146:        kmem_free(irq);
        !           147: }
        !           148:
        !           149: /*
        !           150:  * Lock IRQ.
        !           151:  *
        !           152:  * All H/W interrupts are masked off.
        !           153:  * Caller is no need to save the interrupt state before
        !           154:  * irq_lock() because it is automatically restored in
        !           155:  * irq_unlock() when no one is locking the IRQ anymore.
        !           156:  */
        !           157: void
        !           158: irq_lock(void)
        !           159: {
        !           160:        int s;
        !           161:
        !           162:        interrupt_save(&s);
        !           163:        interrupt_disable();
        !           164:        if (++nr_irq_locks == 1)
        !           165:                saved_irq_state = s;
        !           166:
        !           167:        ASSERT(nr_irq_locks != 0);
        !           168: }
        !           169:
        !           170: /*
        !           171:  * Unlock IRQ.
        !           172:  *
        !           173:  * If lock count becomes 0, the interrupt is restored to
        !           174:  * original state at first irq_lock() call.
        !           175:  */
        !           176: void
        !           177: irq_unlock(void)
        !           178: {
        !           179:        ASSERT(nr_irq_locks > 0);
        !           180:
        !           181:        if (--nr_irq_locks == 0)
        !           182:                interrupt_restore(saved_irq_state);
        !           183: }
        !           184:
        !           185: /*
        !           186:  * Interrupt service thread.
        !           187:  * This is a common dispatcher to all interrupt threads.
        !           188:  */
        !           189: static void
        !           190: irq_thread(void *arg)
        !           191: {
        !           192:        int vec;
        !           193:        void (*func)(int);
        !           194:        struct irq *irq;
        !           195:
        !           196:        interrupt_enable();
        !           197:
        !           198:        irq = (struct irq *)arg;
        !           199:        func = irq->ist;
        !           200:        vec = irq->vector;
        !           201:
        !           202:        for (;;) {
        !           203:                interrupt_disable();
        !           204:                if (irq->istreq <= 0) {
        !           205:                        /*
        !           206:                         * Since the interrupt is disabled above,
        !           207:                         * an interrupt for this vector keeps
        !           208:                         * pending until this thread enters sleep
        !           209:                         * state. Thus, we don't lose any IST
        !           210:                         * requests even if the interrupt is fired
        !           211:                         * here.
        !           212:                         */
        !           213:                        sched_sleep(&irq->istevt);
        !           214:                }
        !           215:                irq->istreq--;
        !           216:                ASSERT(irq->istreq >= 0);
        !           217:                interrupt_enable();
        !           218:
        !           219:                /*
        !           220:                 * Call IST
        !           221:                 */
        !           222:                (*func)(vec);
        !           223:        }
        !           224:        /* NOTREACHED */
        !           225: }
        !           226:
        !           227: /*
        !           228:  * Interrupt handler.
        !           229:  *
        !           230:  * This routine will call the corresponding ISR for the
        !           231:  * requested interrupt vector. This routine is called from
        !           232:  * the code in the architecture dependent layer. We
        !           233:  * assumes the scheduler is already locked by caller.
        !           234:  */
        !           235: void
        !           236: irq_handler(int vector)
        !           237: {
        !           238:        struct irq *irq;
        !           239:        int rc;
        !           240:
        !           241:        irq = irq_table[vector];
        !           242:        if (irq == NULL)
        !           243:                return;         /* Ignore stray interrupt */
        !           244:        ASSERT(irq->isr);
        !           245:
        !           246:        /*
        !           247:         * Call ISR
        !           248:         */
        !           249:        rc = (*irq->isr)(vector);
        !           250:
        !           251:        if (rc == INT_CONTINUE) {
        !           252:                /*
        !           253:                 * Kick IST
        !           254:                 */
        !           255:                ASSERT(irq->ist);
        !           256:                irq->istreq++;
        !           257:                sched_wakeup(&irq->istevt);
        !           258:                ASSERT(irq->istreq != 0);
        !           259:        }
        !           260: }
        !           261:
        !           262: void
        !           263: irq_init(void)
        !           264: {
        !           265:
        !           266:        /* Start interrupt processing. */
        !           267:        interrupt_enable();
        !           268: }

CVSweb