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

Annotation of prex-old/sys/kern/irq.c, Revision 1.1.1.1.2.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 */
1.1.1.1.2.1! nbrk       70: static void    irq_thread(void *);
1.1       nbrk       71:
1.1.1.1.2.1! nbrk       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() */
1.1       nbrk       75:
                     76: /*
                     77:  * irq_attach - attach ISR and IST to the specified interrupt.
                     78:  *
1.1.1.1.2.1! nbrk       79:  * Returns irq handle, or NULL on failure.  The interrupt of
        !            80:  * attached irq will be unmasked (enabled) in this routine.
1.1       nbrk       81:  * TODO: Interrupt sharing is not supported, for now.
                     82:  */
1.1.1.1.2.1! nbrk       83: irq_t
        !            84: irq_attach(int vector, int prio, int shared, int (*isr)(int), void (*ist)(int))
1.1       nbrk       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();
1.1.1.1.2.1! nbrk       95:                return NULL;
1.1       nbrk       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:                 */
1.1.1.1.2.1! nbrk      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");
1.1       nbrk      113:        }
                    114:        irq_table[vector] = irq;
                    115:        irq_lock();
1.1.1.1.2.1! nbrk      116:        mode = shared ? IMODE_LEVEL : IMODE_EDGE;
1.1       nbrk      117:        interrupt_setup(vector, mode);
                    118:        interrupt_unmask(vector, prio);
                    119:        irq_unlock();
                    120:
                    121:        sched_unlock();
1.1.1.1.2.1! nbrk      122:        DPRINTF(("IRQ%d attached priority=%d\n", vector, prio));
        !           123:        return irq;
1.1       nbrk      124: }
                    125:
                    126: /*
                    127:  * Detach an interrupt handler from the interrupt chain.
1.1.1.1.2.1! nbrk      128:  * The detached interrupt will be masked off if nobody
        !           129:  * attaches to it, anymore.
1.1       nbrk      130:  */
                    131: void
1.1.1.1.2.1! nbrk      132: irq_detach(irq_t irq)
1.1       nbrk      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)
1.1.1.1.2.1! nbrk      144:                kthread_terminate(irq->thread);
        !           145:
1.1       nbrk      146:        kmem_free(irq);
                    147: }
                    148:
                    149: /*
                    150:  * Lock IRQ.
                    151:  *
                    152:  * All H/W interrupts are masked off.
1.1.1.1.2.1! nbrk      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.
1.1       nbrk      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;
1.1.1.1.2.1! nbrk      166:
        !           167:        ASSERT(nr_irq_locks != 0);
1.1       nbrk      168: }
                    169:
                    170: /*
                    171:  * Unlock IRQ.
                    172:  *
1.1.1.1.2.1! nbrk      173:  * If lock count becomes 0, the interrupt is restored to
        !           174:  * original state at first irq_lock() call.
1.1       nbrk      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
1.1.1.1.2.1! nbrk      190: irq_thread(void *arg)
1.1       nbrk      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();
1.1.1.1.2.1! nbrk      204:                if (irq->istreq <= 0) {
1.1       nbrk      205:                        /*
1.1.1.1.2.1! nbrk      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.
1.1       nbrk      212:                         */
1.1.1.1.2.1! nbrk      213:                        sched_sleep(&irq->istevt);
1.1       nbrk      214:                }
1.1.1.1.2.1! nbrk      215:                irq->istreq--;
        !           216:                ASSERT(irq->istreq >= 0);
1.1       nbrk      217:                interrupt_enable();
                    218:
1.1.1.1.2.1! nbrk      219:                /*
        !           220:                 * Call IST
        !           221:                 */
        !           222:                (*func)(vec);
1.1       nbrk      223:        }
                    224:        /* NOTREACHED */
                    225: }
                    226:
                    227: /*
                    228:  * Interrupt handler.
                    229:  *
1.1.1.1.2.1! nbrk      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.
1.1       nbrk      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:
1.1.1.1.2.1! nbrk      246:        /*
        !           247:         * Call ISR
        !           248:         */
        !           249:        rc = (*irq->isr)(vector);
1.1       nbrk      250:
                    251:        if (rc == INT_CONTINUE) {
1.1.1.1.2.1! nbrk      252:                /*
        !           253:                 * Kick IST
        !           254:                 */
1.1       nbrk      255:                ASSERT(irq->ist);
1.1.1.1.2.1! nbrk      256:                irq->istreq++;
        !           257:                sched_wakeup(&irq->istevt);
        !           258:                ASSERT(irq->istreq != 0);
1.1       nbrk      259:        }
                    260: }
                    261:
                    262: void
                    263: irq_init(void)
                    264: {
1.1.1.1.2.1! nbrk      265:
        !           266:        /* Start interrupt processing. */
1.1       nbrk      267:        interrupt_enable();
                    268: }

CVSweb