[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

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(u_long);
                     71:
                     72: static struct irq *irq_table[NIRQS];   /* IRQ descriptor table */
                     73: static volatile int nr_irq_locks;      /* lock count for interrupt */
                     74: static volatile int saved_irq_state;   /* IRQ state saved by irq_lock() */
                     75:
                     76: /*
                     77:  * irq_attach - attach ISR and IST to the specified interrupt.
                     78:  * @vector: interrupt vector number
                     79:  * @prio:   interrupt priority level.
                     80:  * @shared: true if it allows the IRQ sharing.
                     81:  * @isr:    pointer to the interrupt service routine.
                     82:  * @ist:    pointer to the interrupt service thread. NULL for no ist.
                     83:  *
                     84:  * irq_attach() returns irq handle which is needed for irq_detach().
                     85:  * Or, it returns -1 if it failed.
                     86:  * The interrupt of attached irq will be unmasked (enabled) in this
                     87:  * routine.
                     88:  *
                     89:  * TODO: Interrupt sharing is not supported, for now.
                     90:  */
                     91: int
                     92: irq_attach(int vector, int prio, int shared, int (*isr)(int),
                     93:           void (*ist)(int))
                     94: {
                     95:        struct irq *irq;
                     96:        thread_t th;
                     97:        int mode;
                     98:
                     99:        ASSERT(irq_level == 0);
                    100:        ASSERT(isr != NULL);
                    101:
                    102:        sched_lock();
                    103:        if ((irq = kmem_alloc(sizeof(struct irq))) == NULL) {
                    104:                sched_unlock();
                    105:                return -1;
                    106:        }
                    107:        memset(irq, 0, sizeof(struct irq));
                    108:        irq->vector = vector;
                    109:        irq->isr = isr;
                    110:        irq->ist = ist;
                    111:
                    112:        if (ist != NULL) {
                    113:                /*
                    114:                 * Create a new thread for IST.
                    115:                 */
                    116:                th = kernel_thread(ISTPRIO(prio), irq_thread, (u_long)irq);
                    117:                if (th == NULL)
                    118:                        panic("irq_attach");
                    119:                irq->thread = th;
                    120:                event_init(&irq->ist_event, "interrupt");
                    121:        }
                    122:        irq_table[vector] = irq;
                    123:        mode = shared ? IMODE_LEVEL : IMODE_EDGE;
                    124:
                    125:        irq_lock();
                    126:        interrupt_setup(vector, mode);
                    127:        interrupt_unmask(vector, prio);
                    128:        irq_unlock();
                    129:
                    130:        sched_unlock();
                    131:        printk("IRQ%d attached priority=%d\n", vector, prio);
                    132:        return (int)irq;
                    133: }
                    134:
                    135: /*
                    136:  * Detach an interrupt handler from the interrupt chain.
                    137:  * The detached interrupt will be masked off if nobody attaches
                    138:  * to it, anymore.
                    139:  */
                    140: void
                    141: irq_detach(int handle)
                    142: {
                    143:        struct irq *irq = (struct irq *)handle;
                    144:
                    145:        ASSERT(irq_level == 0);
                    146:        ASSERT(irq);
                    147:        ASSERT(irq->vector < NIRQS);
                    148:
                    149:        irq_lock();
                    150:        interrupt_mask(irq->vector);
                    151:        irq_unlock();
                    152:
                    153:        irq_table[irq->vector] = NULL;
                    154:        if (irq->thread != NULL)
                    155:                thread_kill(irq->thread);
                    156:        kmem_free(irq);
                    157: }
                    158:
                    159: /*
                    160:  * Lock IRQ.
                    161:  *
                    162:  * All H/W interrupts are masked off.
                    163:  * Caller is no need to save the interrupt state before irq_lock()
                    164:  * because it is automatically restored in irq_unlock() when no one
                    165:  * is locking the IRQ anymore.
                    166:  */
                    167: void
                    168: irq_lock(void)
                    169: {
                    170:        int s;
                    171:
                    172:        interrupt_save(&s);
                    173:        interrupt_disable();
                    174:        if (++nr_irq_locks == 1)
                    175:                saved_irq_state = s;
                    176: }
                    177:
                    178: /*
                    179:  * Unlock IRQ.
                    180:  *
                    181:  * If lock count becomes 0, the interrupt is restored to original
                    182:  * state at first irq_lock() call.
                    183:  */
                    184: void
                    185: irq_unlock(void)
                    186: {
                    187:        ASSERT(nr_irq_locks > 0);
                    188:
                    189:        if (--nr_irq_locks == 0)
                    190:                interrupt_restore(saved_irq_state);
                    191: }
                    192:
                    193: /*
                    194:  * Interrupt service thread.
                    195:  * This is a common dispatcher to all interrupt threads.
                    196:  */
                    197: static void
                    198: irq_thread(u_long arg)
                    199: {
                    200:        int vec;
                    201:        void (*func)(int);
                    202:        struct irq *irq;
                    203:
                    204:        interrupt_enable();
                    205:
                    206:        irq = (struct irq *)arg;
                    207:        func = irq->ist;
                    208:        vec = irq->vector;
                    209:
                    210:        for (;;) {
                    211:                interrupt_disable();
                    212:                if (irq->ist_request <= 0) {
                    213:                        /*
                    214:                         * Since the interrupt is disabled above, an
                    215:                         * interrupt for this vector keeps pending until
                    216:                         * this thread enters sleep state. Thus, we don't
                    217:                         * lose any IST requests even if the interrupt
                    218:                         * is fired here.
                    219:                         */
                    220:                        sched_sleep(&irq->ist_event);
                    221:                }
                    222:                irq->ist_request--;
                    223:                ASSERT(irq->ist_request >= 0);
                    224:                interrupt_enable();
                    225:
                    226:                /* Call IST */
                    227:                (func)(vec);
                    228:        }
                    229:        /* NOTREACHED */
                    230: }
                    231:
                    232: /*
                    233:  * Interrupt handler.
                    234:  *
                    235:  * This routine will call the corresponding ISR for the requested
                    236:  * interrupt vector. This routine is called from the code in the
                    237:  * architecture dependent layer. We assumes the scheduler is already
                    238:  * locked by caller.
                    239:  */
                    240: void
                    241: irq_handler(int vector)
                    242: {
                    243:        struct irq *irq;
                    244:        int rc;
                    245:
                    246:        irq = irq_table[vector];
                    247:        if (irq == NULL)
                    248:                return;         /* Ignore stray interrupt */
                    249:        ASSERT(irq->isr);
                    250:
                    251:        /* Call ISR */
                    252:        rc = (irq->isr)(vector);
                    253:
                    254:        if (rc == INT_CONTINUE) {
                    255:                /* Kick IST */
                    256:                ASSERT(irq->ist);
                    257:                irq->ist_request++;
                    258:                sched_wakeup(&irq->ist_event);
                    259:        }
                    260:        irq->count++;
                    261: }
                    262:
                    263: #if defined(DEBUG) && defined(CONFIG_KDUMP)
                    264: void
                    265: irq_dump(void)
                    266: {
                    267:        int vector;
                    268:        struct irq *irq;
                    269:
                    270:        printk("IRQ dump:\n");
                    271:        printk(" vector isr      ist      prio     count\n");
                    272:        printk(" ------ -------- -------- -------- --------\n");
                    273:
                    274:        for (vector = 0; vector < NIRQS; vector++) {
                    275:                irq = irq_table[vector];
                    276:                if (irq) {
                    277:                        printk("   %4d %08x %08x      %3d %8d\n",
                    278:                               vector, irq->isr, irq->ist,
                    279:                               (irq->thread ? irq->thread->prio : 0),
                    280:                               irq->count);
                    281:                }
                    282:        }
                    283: }
                    284: #endif
                    285:
                    286: void
                    287: irq_init(void)
                    288: {
                    289:        /*
                    290:         * Start interrupt processing.
                    291:         */
                    292:        interrupt_enable();
                    293: }

CVSweb