|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/sys/kern/irq.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.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 services 36 * 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 as 46 * quickly as possible. ISR will run within a context of the thread 47 * running when interrupt occurs. So, only few kernel services are 48 * available within ISR. 49 * 50 * - Interrupt Service Thread (IST) 51 * 52 * IST is automatically activated if ISR returns INT_CONTINUE. It 53 * will be called when the system enters safer condition than ISR. 54 * A device driver should use IST to do heavy I/O operation as much 55 * as possible. Since ISR for the same IRQ line may be invoked during 56 * IST, the shared data, resources, and device registers must be 57 * synchronized by disabling interrupts. IST does not have to be 58 * reentrant because it is not interrupted by same IST itself. 59 */ 60 61 #include <kernel.h> 62 #include <event.h> 63 #include <kmem.h> 64 #include <sched.h> 65 #include <thread.h> 66 #include <irq.h> 67 #include <hal.h> 68 69 /* forward declarations */ 70 static void irq_thread(void *); 71 72 static struct irq *irq_table[MAXIRQS]; /* IRQ descriptor table */ 73 74 /* 75 * irq_attach - attach ISR and IST to the specified interrupt. 76 * 77 * Returns irq handle, or panic on failure. The interrupt of 78 * attached irq will be unmasked (enabled) in this routine. 79 * TODO: Interrupt sharing is not supported, for now. 80 */ 81 irq_t 82 irq_attach(int vector, int pri, int shared, 83 int (*isr)(void *), void (*ist)(void *), void *data) 84 { 85 struct irq *irq; 86 int mode; 87 88 ASSERT(isr != NULL); 89 90 sched_lock(); 91 if ((irq = kmem_alloc(sizeof(*irq))) == NULL) 92 panic("irq_attach"); 93 94 memset(irq, 0, sizeof(*irq)); 95 irq->vector = vector; 96 irq->priority = pri; 97 irq->isr = isr; 98 irq->ist = ist; 99 irq->data = data; 100 101 if (ist != IST_NONE) { 102 /* 103 * Create a new thread for IST. 104 */ 105 irq->thread = kthread_create(&irq_thread, irq, ISTPRI(pri)); 106 if (irq->thread == NULL) 107 panic("irq_attach"); 108 109 event_init(&irq->istevt, "interrupt"); 110 } 111 irq_table[vector] = irq; 112 mode = shared ? IMODE_LEVEL : IMODE_EDGE; 113 interrupt_setup(vector, mode); 114 interrupt_unmask(vector, pri); 115 116 sched_unlock(); 117 DPRINTF(("IRQ%d attached priority=%d\n", vector, pri)); 118 return irq; 119 } 120 121 /* 122 * Detach an interrupt handler from the interrupt chain. 123 * The detached interrupt will be masked off if nobody 124 * attaches to it, anymore. 125 */ 126 void 127 irq_detach(irq_t irq) 128 { 129 ASSERT(irq != NULL); 130 ASSERT(irq->vector < MAXIRQS); 131 132 interrupt_mask(irq->vector); 133 irq_table[irq->vector] = NULL; 134 if (irq->thread != NULL) 135 kthread_terminate(irq->thread); 136 137 kmem_free(irq); 138 } 139 140 /* 141 * Interrupt service thread. 142 * This is a common dispatcher to all interrupt threads. 143 */ 144 static void 145 irq_thread(void *arg) 146 { 147 void (*fn)(void *); 148 void *data; 149 struct irq *irq; 150 151 splhigh(); 152 153 irq = (struct irq *)arg; 154 fn = irq->ist; 155 data = irq->data; 156 157 for (;;) { 158 if (irq->istreq <= 0) { 159 /* 160 * Since the interrupt is disabled above, 161 * an interrupt for this vector keeps 162 * pending until this thread enters sleep 163 * state. Thus, we don't lose any IST 164 * requests even if the interrupt is fired 165 * here. 166 */ 167 sched_sleep(&irq->istevt); 168 } 169 irq->istreq--; 170 ASSERT(irq->istreq >= 0); 171 172 /* 173 * Call IST 174 */ 175 spl0(); 176 (*fn)(data); 177 splhigh(); 178 } 179 /* NOTREACHED */ 180 } 181 182 /* 183 * Interrupt handler. 184 * 185 * This routine will call the corresponding ISR for the 186 * requested interrupt vector. HAL code must call this 187 * routine with scheduler locked. 188 */ 189 void 190 irq_handler(int vector) 191 { 192 struct irq *irq; 193 int rc; 194 195 irq = irq_table[vector]; 196 if (irq == NULL) { 197 DPRINTF(("Random interrupt ignored\n")); 198 return; 199 } 200 ASSERT(irq->isr != NULL); 201 202 /* Profile */ 203 irq->count++; 204 205 /* 206 * Call ISR 207 */ 208 rc = (*irq->isr)(irq->data); 209 210 if (rc == INT_CONTINUE) { 211 /* 212 * Kick IST 213 */ 214 ASSERT(irq->ist != IST_NONE); 215 irq->istreq++; 216 sched_wakeup(&irq->istevt); 217 ASSERT(irq->istreq != 0); 218 } 219 } 220 221 /* 222 * Return irq information. 223 */ 224 int 225 irq_info(struct irqinfo *info) 226 { 227 int vec = info->cookie; 228 int found = 0; 229 struct irq *irq; 230 231 while (vec < MAXIRQS) { 232 if (irq_table[vec]) { 233 found = 1; 234 break; 235 } 236 vec++; 237 } 238 if (!found) 239 return ESRCH; 240 241 irq = irq_table[vec]; 242 info->vector = irq->vector; 243 info->count = irq->count; 244 info->priority = irq->priority; 245 info->istreq = irq->istreq; 246 info->thread = irq->thread; 247 info->cookie = vec + 1; 248 return 0; 249 } 250 251 /* 252 * Start interrupt processing. 253 */ 254 void 255 irq_init(void) 256 { 257 258 interrupt_init(); 259 260 /* Enable interrupts */ 261 spl0(); 262 } /* [<][>][^][v][top][bottom][index][help] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |