Prex Home / Browse Source - Prex Version: 0.9.0

root/sys/kern/irq.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. irq_attach
  2. irq_detach
  3. irq_thread
  4. irq_handler
  5. irq_info
  6. irq_init

   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] */