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