Statistics
| Branch: | Revision:

scoutos / prex-0.9.0 / bsp / hal / x86 / pc / interrupt.c @ 03e9c04a

History | View | Annotate | Download (5.32 KB)

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
 * interrupt.c - interrupt management routines for intel 8259 chip
32
 */
33

    
34
#include <sys/ipl.h>
35
#include <kernel.h>
36
#include <irq.h>
37
#include <cpufunc.h>
38
#include <context.h>
39
#include <locore.h>
40
#include <hal.h>
41

    
42

    
43
/* Number of IRQ lines */
44
#define NIRQS                16
45

    
46
/* I/O address for master/slave programmable interrupt controller */
47
#define PIC_M           0x20
48
#define PIC_S           0xa0
49

    
50
/* Edge/level control register */
51
#define ELCR            0x4d0
52

    
53
/*
54
 * Interrupt priority level
55
 *
56
 * Each interrupt has its logical priority level, with 0 being
57
 * the highest priority. While some ISR is running, all lower
58
 * priority interrupts are masked off.
59
 */
60
static volatile int irq_level;
61

    
62
/*
63
 * Interrupt mapping table
64
 */
65
static int        ipl_table[NIRQS];        /* Vector -> level */
66
static u_int        mask_table[NIPLS];        /* Level -> mask */
67

    
68
/*
69
 * Set mask for current ipl
70
 */
71
static void
72
update_mask(void)
73
{
74
        u_int mask = mask_table[irq_level];
75

    
76
        outb(PIC_M + 1, mask & 0xff);
77
        outb(PIC_S + 1, mask >> 8);
78
}
79

    
80
/*
81
 * Unmask interrupt in PIC for specified irq.
82
 * The interrupt mask table is also updated.
83
 * Assumed CPU interrupt is disabled in caller.
84
 */
85
void
86
interrupt_unmask(int vector, int level)
87
{
88
        u_int unmask = (u_int)~(1 << vector);
89
        int i, s;
90

    
91
        s = splhigh();
92
        ipl_table[vector] = level;
93
        /*
94
         * Unmask target interrupt for all
95
         * lower interrupt levels.
96
         */
97
        for (i = 0; i < level; i++)
98
                mask_table[i] &= unmask;
99
        update_mask();
100
        splx(s);
101
}
102

    
103
/*
104
 * Mask interrupt in PIC for specified irq.
105
 * Interrupt must be disabled when this routine is called.
106
 */
107
void
108
interrupt_mask(int vector)
109
{
110
        u_int mask = (u_int)(1 << vector);
111
        int i, level, s;
112

    
113
        s = splhigh();
114
        level = ipl_table[vector];
115
        for (i = 0; i < level; i++)
116
                mask_table[i] |= mask;
117
        ipl_table[vector] = IPL_NONE;
118
        update_mask();
119
        splx(s);
120
}
121

    
122
/*
123
 * Setup interrupt mode.
124
 * Select whether an interrupt trigger is edge or level.
125
 */
126
void
127
interrupt_setup(int vector, int mode)
128
{
129
        int port, s;
130
        u_int bit;
131
        u_char val;
132

    
133
        s = splhigh();
134
        port = vector < 8 ? ELCR : ELCR + 1;
135
        bit = (u_int)(1 << (vector & 7));
136

    
137
        val = inb(port);
138
        if (mode == IMODE_LEVEL)
139
                val |= bit;
140
        else
141
                val &= ~bit;
142
        outb(port, val);
143
        splx(s);
144
}
145

    
146
/*
147
 * Common interrupt handler.
148
 *
149
 * This routine is called from the low level interrupt routine
150
 * written in assemble code. The interrupt flag is automatically
151
 * disabled by h/w in CPU when the interrupt is occurred. The
152
 * target interrupt will be masked in ICU while the irq handler
153
 * is called.
154
 */
155
void
156
interrupt_handler(struct cpu_regs *regs)
157
{
158
        int vector = (int)regs->trap_no;
159
        int old_ipl, new_ipl;
160

    
161
        /* Adjust interrupt level */
162
        old_ipl = irq_level;
163
        new_ipl = ipl_table[vector];
164
        if (new_ipl > old_ipl)                /* Ignore spurious interrupt */
165
                irq_level = new_ipl;
166
        update_mask();
167

    
168
        /* Send acknowledge to PIC for specified irq */
169
        if (vector & 8)                        /* Slave ? */
170
                outb(PIC_S, 0x20);        /* Non specific EOI to slave */
171
        outb(PIC_M, 0x20);                /* Non specific EOI to master */
172

    
173
        /* Dispatch interrupt */
174
        splon();
175
        irq_handler(vector);
176
        sploff();
177

    
178
        /* Restore interrupt level */
179
        irq_level = old_ipl;
180
        update_mask();
181
}
182

    
183
/*
184
 * Initialize 8259 interrupt controllers.
185
 * All interrupts will be masked off in ICU.
186
 */
187
void
188
interrupt_init(void)
189
{
190
        int i;
191

    
192
        irq_level = IPL_NONE;
193

    
194
        for (i = 0; i < NIRQS; i++)
195
                ipl_table[i] = IPL_NONE;
196

    
197
        for (i = 0; i < NIPLS; i++)
198
                mask_table[i] = 0xfffb;
199

    
200
        outb_p(PIC_M, 0x11);                /* Start initialization edge, master */
201
        outb_p(PIC_M + 1, 0x20);        /* Set h/w vector = 0x20 */
202
        outb_p(PIC_M + 1, 0x04);        /* Chain to slave (IRQ2) */
203
        outb_p(PIC_M + 1, 0x01);        /* 8086 mode */
204

    
205
        outb_p(PIC_S, 0x11);                /* Start initialization edge, master */
206
        outb_p(PIC_S + 1, 0x28);        /* Set h/w vector = 0x28 */
207
        outb_p(PIC_S + 1, 0x02);        /* Slave (cascade) */
208
        outb_p(PIC_S + 1, 0x01);        /* 8086 mode */
209

    
210
        outb(PIC_S + 1, 0xff);                /* Mask all */
211
        outb(PIC_M + 1, 0xfb);                /* Mask all except IRQ2 (cascade) */
212
}