Prex Home / Browse Source - Prex Version: 0.9.0

root/bsp/hal/ppc/prep/interrupt.c

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

DEFINITIONS

This source file includes following definitions.
  1. update_mask
  2. interrupt_unmask
  3. interrupt_mask
  4. interrupt_setup
  5. interrupt_lookup
  6. interrupt_handler
  7. interrupt_init

   1 /*-
   2  * Copyright (c) 2009, 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  * interrupt.c - interrupt management routines for intel 8259 chip
  32  */
  33 
  34 #include <kernel.h>
  35 #include <hal.h>
  36 #include <irq.h>
  37 #include <io.h>
  38 #include <cpufunc.h>
  39 #include <context.h>
  40 #include <trap.h>
  41 #include <clock.h>
  42 #include <locore.h>
  43 #include <sys/ipl.h>
  44 
  45 /* Number of IRQ lines */
  46 #define NIRQS           16
  47 
  48 /* I/O address for master/slave programmable interrupt controller */
  49 #define PIC_M           0x20
  50 #define PIC_S           0xa0
  51 
  52 /* Edge/level control register */
  53 #define ELCR            0x4d0
  54 
  55 /*
  56  * Interrupt priority level
  57  *
  58  * Each interrupt has its logical priority level, with 0 being
  59  * the highest priority. While some ISR is running, all lower
  60  * priority interrupts are masked off.
  61  */
  62 static volatile int irq_level;
  63 
  64 /*
  65  * Interrupt mapping table
  66  */
  67 static int      ipl_table[NIRQS];       /* Vector -> level */
  68 static u_int    mask_table[NIPLS];      /* Level -> mask */
  69 
  70 /*
  71  * Set mask for current ipl
  72  */
  73 static void
  74 update_mask(void)
  75 {
  76         u_int mask = mask_table[irq_level];
  77 
  78         outb(PIC_M + 1, mask & 0xff);
  79         outb(PIC_S + 1, mask >> 8);
  80 }
  81 
  82 /*
  83  * Unmask interrupt in PIC for specified irq.
  84  * The interrupt mask table is also updated.
  85  * Assumed CPU interrupt is disabled in caller.
  86  */
  87 void
  88 interrupt_unmask(int vector, int level)
  89 {
  90         u_int unmask = (u_int)~(1 << vector);
  91         int i, s;
  92 
  93         s = splhigh();
  94         ipl_table[vector] = level;
  95         /*
  96          * Unmask target interrupt for all
  97          * lower interrupt levels.
  98          */
  99         for (i = 0; i < level; i++)
 100                 mask_table[i] &= unmask;
 101         update_mask();
 102         splx(s);
 103 }
 104 
 105 /*
 106  * Mask interrupt in PIC for specified irq.
 107  * Interrupt must be disabled when this routine is called.
 108  */
 109 void
 110 interrupt_mask(int vector)
 111 {
 112         u_int mask = (u_int)(1 << vector);
 113         int i, level, s;
 114 
 115         s = splhigh();
 116         level = ipl_table[vector];
 117         for (i = 0; i < level; i++)
 118                 mask_table[i] |= mask;
 119         ipl_table[vector] = IPL_NONE;
 120         update_mask();
 121         splx(s);
 122 }
 123 
 124 /*
 125  * Setup interrupt mode.
 126  * Select whether an interrupt trigger is edge or level.
 127  */
 128 void
 129 interrupt_setup(int vector, int mode)
 130 {
 131         int port, s;
 132         u_int bit;
 133         u_char val;
 134 
 135         s = splhigh();
 136         port = vector < 8 ? ELCR : ELCR + 1;
 137         bit = (u_int)(1 << (vector & 7));
 138 
 139         val = inb(port);
 140         if (mode == IMODE_LEVEL)
 141                 val |= bit;
 142         else
 143                 val &= ~bit;
 144         outb(port, val);
 145         splx(s);
 146 }
 147 
 148 /*
 149  * Get interrupt source.
 150  */
 151 static int
 152 interrupt_lookup(void)
 153 {
 154         int irq;
 155 
 156         outb(PIC_M, 0x0c);      /* poll and ack */
 157         irq = inb(PIC_M) & 7;
 158         if (irq == 2) {
 159                 outb(PIC_S, 0x0c);
 160                 irq = (inb(PIC_M) & 7) + 8;
 161         }
 162         return irq;
 163 }
 164 
 165 /*
 166  * Common interrupt handler.
 167  *
 168  * This routine is called from the low level interrupt routine
 169  * written in assemble code. The interrupt flag is automatically
 170  * disabled by h/w in CPU when the interrupt is occurred. The
 171  * target interrupt will be masked in ICU while the irq handler
 172  * is called.
 173  */
 174 void
 175 interrupt_handler(struct cpu_regs *regs)
 176 {
 177         int vector;
 178         int old_ipl, new_ipl;
 179 
 180         /* Handle decrementer interrupt */
 181         if (regs->trap_no == TRAP_DECREMENTER) {
 182                 clock_isr(NULL);
 183                 return;
 184         }
 185 
 186         /* Find pending interrupt */
 187         vector = interrupt_lookup();
 188 
 189         /* Adjust interrupt level */
 190         old_ipl = irq_level;
 191         new_ipl = ipl_table[vector];
 192         if (new_ipl > old_ipl)          /* Ignore spurious interrupt */
 193                 irq_level = new_ipl;
 194         update_mask();
 195 
 196         /* Dispatch interrupt */
 197         splon();
 198         irq_handler(vector);
 199         sploff();
 200 
 201         /* Restore interrupt level */
 202         irq_level = old_ipl;
 203         update_mask();
 204 }
 205 
 206 /*
 207  * Initialize 8259 interrupt controllers.
 208  * All interrupts will be masked off in ICU.
 209  */
 210 void
 211 interrupt_init(void)
 212 {
 213         int i;
 214 
 215         irq_level = IPL_NONE;
 216 
 217         for (i = 0; i < NIRQS; i++)
 218                 ipl_table[i] = IPL_NONE;
 219 
 220         for (i = 0; i < NIPLS; i++)
 221                 mask_table[i] = 0xfffb;
 222 
 223         outb(PIC_M, 0x11);      /* Start initialization edge, master */
 224         outb(PIC_M + 1, 0x00);  /* Set h/w vector = 0x0 */
 225         outb(PIC_M + 1, 0x04);  /* Chain to slave (IRQ2) */
 226         outb(PIC_M + 1, 0x01);  /* 8086 mode */
 227 
 228         outb(PIC_S, 0x11);      /* Start initialization edge, master */
 229         outb(PIC_S + 1, 0x08);  /* Set h/w vector = 0x8 */
 230         outb(PIC_S + 1, 0x02);  /* Slave (cascade) */
 231         outb(PIC_S + 1, 0x01);  /* 8086 mode */
 232 
 233         outb(PIC_S, 0x0b);      /* Read ISR by default */
 234         outb(PIC_M, 0x0b);      /* Read ISR by default */
 235 
 236         outb(PIC_S + 1, 0xff);  /* Mask all */
 237         outb(PIC_M + 1, 0xfb);  /* Mask all except IRQ2 (cascade) */
 238 }

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