[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     ! 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