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