Annotation of prex/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(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