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