source: trunk/packages/xen-3.1/xen-3.1/xen/arch/x86/i8259.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 11.3 KB
Line 
1/******************************************************************************
2 * i8259.c
3 *
4 * Well, this is required for SMP systems as well, as it build interrupt
5 * tables for IO APICS as well as uniprocessor 8259-alikes.
6 */
7
8#include <xen/config.h>
9#include <xen/init.h>
10#include <xen/types.h>
11#include <asm/regs.h>
12#include <xen/errno.h>
13#include <xen/sched.h>
14#include <xen/irq.h>
15#include <asm/atomic.h>
16#include <asm/system.h>
17#include <asm/io.h>
18#include <asm/desc.h>
19#include <asm/bitops.h>
20#include <xen/delay.h>
21#include <asm/apic.h>
22#include <asm/asm_defns.h>
23#include <io_ports.h>
24
25/*
26 * Common place to define all x86 IRQ vectors
27 *
28 * This builds up the IRQ handler stubs using some ugly macros in irq.h
29 *
30 * These macros create the low-level assembly IRQ routines that save
31 * register context and call do_IRQ(). do_IRQ() then does all the
32 * operations that are needed to keep the AT (or SMP IOAPIC)
33 * interrupt-controller happy.
34 */
35
36BUILD_COMMON_IRQ()
37
38#define BI(x,y) \
39    BUILD_IRQ(x##y)
40
41#define BUILD_16_IRQS(x) \
42    BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
43    BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
44    BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
45    BI(x,c) BI(x,d) BI(x,e) BI(x,f)
46
47BUILD_16_IRQS(0x0) BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
48BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)
49BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)
50BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf)
51
52#undef BUILD_16_IRQS
53#undef BI
54
55
56/*
57 * The following vectors are part of the Linux architecture, there
58 * is no hardware IRQ pin equivalent for them, they are triggered
59 * through the ICC by us (IPIs)
60 */
61BUILD_SMP_INTERRUPT(event_check_interrupt,EVENT_CHECK_VECTOR)
62BUILD_SMP_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR)
63BUILD_SMP_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
64
65/*
66 * Every pentium local APIC has two 'local interrupts', with a
67 * soft-definable vector attached to both interrupts, one of
68 * which is a timer interrupt, the other one is error counter
69 * overflow. Linux uses the local APIC timer interrupt to get
70 * a much simpler SMP time architecture:
71 */
72BUILD_SMP_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR)
73BUILD_SMP_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR)
74BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
75BUILD_SMP_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR)
76
77#define IRQ(x,y) \
78    IRQ##x##y##_interrupt
79
80#define IRQLIST_16(x) \
81    IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
82    IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
83    IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
84    IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
85
86    static void (*interrupt[])(void) = {
87        IRQLIST_16(0x0), IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3),
88        IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
89        IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
90        IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf)
91    };
92
93#undef IRQ
94#undef IRQLIST_16
95
96/*
97 * This is the 'legacy' 8259A Programmable Interrupt Controller,
98 * present in the majority of PC/AT boxes.
99 * plus some generic x86 specific things if generic specifics makes
100 * any sense at all.
101 * this file should become arch/i386/kernel/irq.c when the old irq.c
102 * moves to arch independent land
103 */
104
105static DEFINE_SPINLOCK(i8259A_lock);
106
107static void disable_8259A_vector(unsigned int vector)
108{
109    disable_8259A_irq(LEGACY_IRQ_FROM_VECTOR(vector));
110}
111
112static void enable_8259A_vector(unsigned int vector)
113{
114    enable_8259A_irq(LEGACY_IRQ_FROM_VECTOR(vector));
115}
116
117static void mask_and_ack_8259A_vector(unsigned int);
118
119static void end_8259A_vector(unsigned int vector)
120{
121    if (!(irq_desc[vector].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
122        enable_8259A_vector(vector);
123}
124
125static unsigned int startup_8259A_vector(unsigned int vector)
126{ 
127    enable_8259A_vector(vector);
128    return 0; /* never anything pending */
129}
130
131static struct hw_interrupt_type i8259A_irq_type = {
132    .typename = "XT-PIC",
133    .startup  = startup_8259A_vector,
134    .shutdown = disable_8259A_vector,
135    .enable   = enable_8259A_vector,
136    .disable  = disable_8259A_vector,
137    .ack      = mask_and_ack_8259A_vector,
138    .end      = end_8259A_vector
139};
140
141/*
142 * 8259A PIC functions to handle ISA devices:
143 */
144
145/*
146 * This contains the irq mask for both 8259A irq controllers,
147 */
148static unsigned int cached_irq_mask = 0xffff;
149
150#define __byte(x,y) (((unsigned char *)&(y))[x])
151#define cached_21   (__byte(0,cached_irq_mask))
152#define cached_A1   (__byte(1,cached_irq_mask))
153
154/*
155 * Not all IRQs can be routed through the IO-APIC, eg. on certain (older)
156 * boards the timer interrupt is not really connected to any IO-APIC pin,
157 * it's fed to the master 8259A's IR0 line only.
158 *
159 * Any '1' bit in this mask means the IRQ is routed through the IO-APIC.
160 * this 'mixed mode' IRQ handling costs nothing because it's only used
161 * at IRQ setup time.
162 */
163unsigned long io_apic_irqs;
164
165void disable_8259A_irq(unsigned int irq)
166{
167    unsigned int mask = 1 << irq;
168    unsigned long flags;
169
170    spin_lock_irqsave(&i8259A_lock, flags);
171    cached_irq_mask |= mask;
172    if (irq & 8)
173        outb(cached_A1,0xA1);
174    else
175        outb(cached_21,0x21);
176    spin_unlock_irqrestore(&i8259A_lock, flags);
177}
178
179void enable_8259A_irq(unsigned int irq)
180{
181    unsigned int mask = ~(1 << irq);
182    unsigned long flags;
183
184    spin_lock_irqsave(&i8259A_lock, flags);
185    cached_irq_mask &= mask;
186    if (irq & 8)
187        outb(cached_A1,0xA1);
188    else
189        outb(cached_21,0x21);
190    spin_unlock_irqrestore(&i8259A_lock, flags);
191}
192
193int i8259A_irq_pending(unsigned int irq)
194{
195    unsigned int mask = 1<<irq;
196    unsigned long flags;
197    int ret;
198
199    spin_lock_irqsave(&i8259A_lock, flags);
200    if (irq < 8)
201        ret = inb(0x20) & mask;
202    else
203        ret = inb(0xA0) & (mask >> 8);
204    spin_unlock_irqrestore(&i8259A_lock, flags);
205
206    return ret;
207}
208
209/*
210 * This function assumes to be called rarely. Switching between
211 * 8259A registers is slow.
212 * This has to be protected by the irq controller spinlock
213 * before being called.
214 */
215static inline int i8259A_irq_real(unsigned int irq)
216{
217    int value;
218    int irqmask = 1<<irq;
219
220    if (irq < 8) {
221        outb(0x0B,0x20);                /* ISR register */
222        value = inb(0x20) & irqmask;
223        outb(0x0A,0x20);                /* back to the IRR register */
224        return value;
225    }
226    outb(0x0B,0xA0);                    /* ISR register */
227    value = inb(0xA0) & (irqmask >> 8);
228    outb(0x0A,0xA0);                    /* back to the IRR register */
229    return value;
230}
231
232/*
233 * Careful! The 8259A is a fragile beast, it pretty
234 * much _has_ to be done exactly like this (mask it
235 * first, _then_ send the EOI, and the order of EOI
236 * to the two 8259s is important!
237 */
238static void mask_and_ack_8259A_vector(unsigned int vector)
239{
240    unsigned int irq = LEGACY_IRQ_FROM_VECTOR(vector);
241    unsigned int irqmask = 1 << irq;
242    unsigned long flags;
243
244    spin_lock_irqsave(&i8259A_lock, flags);
245    /*
246     * Lightweight spurious IRQ detection. We do not want
247     * to overdo spurious IRQ handling - it's usually a sign
248     * of hardware problems, so we only do the checks we can
249     * do without slowing down good hardware unnecesserily.
250     *
251     * Note that IRQ7 and IRQ15 (the two spurious IRQs
252     * usually resulting from the 8259A-1|2 PICs) occur
253     * even if the IRQ is masked in the 8259A. Thus we
254     * can check spurious 8259A IRQs without doing the
255     * quite slow i8259A_irq_real() call for every IRQ.
256     * This does not cover 100% of spurious interrupts,
257     * but should be enough to warn the user that there
258     * is something bad going on ...
259     */
260    if (cached_irq_mask & irqmask)
261        goto spurious_8259A_irq;
262    cached_irq_mask |= irqmask;
263
264 handle_real_irq:
265    if (irq & 8) {
266        inb(0xA1);              /* DUMMY - (do we need this?) */
267        outb(cached_A1,0xA1);
268        outb(0x60+(irq&7),0xA0);/* 'Specific EOI' to slave */
269        outb(0x62,0x20);        /* 'Specific EOI' to master-IRQ2 */
270    } else {
271        inb(0x21);              /* DUMMY - (do we need this?) */
272        outb(cached_21,0x21);
273        outb(0x60+irq,0x20);    /* 'Specific EOI' to master */
274    }
275    spin_unlock_irqrestore(&i8259A_lock, flags);
276    return;
277
278 spurious_8259A_irq:
279    /*
280     * this is the slow path - should happen rarely.
281     */
282    if (i8259A_irq_real(irq))
283        /*
284         * oops, the IRQ _is_ in service according to the
285         * 8259A - not spurious, go handle it.
286         */
287        goto handle_real_irq;
288
289    {
290        static int spurious_irq_mask;
291        /*
292         * At this point we can be sure the IRQ is spurious,
293         * lets ACK and report it. [once per IRQ]
294         */
295        if (!(spurious_irq_mask & irqmask)) {
296            printk("spurious 8259A interrupt: IRQ%d.\n", irq);
297            spurious_irq_mask |= irqmask;
298        }
299        atomic_inc(&irq_err_count);
300        /*
301         * Theoretically we do not have to handle this IRQ,
302         * but in Linux this does not cause problems and is
303         * simpler for us.
304         */
305        goto handle_real_irq;
306    }
307}
308
309void __init init_8259A(int auto_eoi)
310{
311    unsigned long flags;
312
313    spin_lock_irqsave(&i8259A_lock, flags);
314
315    outb(0xff, 0x21);   /* mask all of 8259A-1 */
316    outb(0xff, 0xA1);   /* mask all of 8259A-2 */
317
318    /*
319     * outb_p - this has to work on a wide range of PC hardware.
320     */
321    outb_p(0x11, 0x20);     /* ICW1: select 8259A-1 init */
322    outb_p(FIRST_LEGACY_VECTOR + 0, 0x21); /* ICW2: 8259A-1 IR0-7 */
323    outb_p(0x04, 0x21);     /* 8259A-1 (the master) has a slave on IR2 */
324    if (auto_eoi)
325        outb_p(0x03, 0x21); /* master does Auto EOI */
326    else
327        outb_p(0x01, 0x21); /* master expects normal EOI */
328
329    outb_p(0x11, 0xA0);     /* ICW1: select 8259A-2 init */
330    outb_p(FIRST_LEGACY_VECTOR + 8, 0xA1); /* ICW2: 8259A-2 IR0-7 */
331    outb_p(0x02, 0xA1);     /* 8259A-2 is a slave on master's IR2 */
332    outb_p(0x01, 0xA1);     /* (slave's support for AEOI in flat mode
333                               is to be investigated) */
334
335    if (auto_eoi)
336        /*
337         * in AEOI mode we just have to mask the interrupt
338         * when acking.
339         */
340        i8259A_irq_type.ack = disable_8259A_vector;
341    else
342        i8259A_irq_type.ack = mask_and_ack_8259A_vector;
343
344    udelay(100);            /* wait for 8259A to initialize */
345
346    outb(cached_21, 0x21);  /* restore master IRQ mask */
347    outb(cached_A1, 0xA1);  /* restore slave IRQ mask */
348
349    spin_unlock_irqrestore(&i8259A_lock, flags);
350}
351
352static struct irqaction cascade = { no_action, "cascade", NULL};
353
354void __init init_IRQ(void)
355{
356    int i;
357
358    init_bsp_APIC();
359
360    init_8259A(0);
361
362    for ( i = 0; i < NR_IRQS; i++ )
363    {
364        irq_desc[i].status  = IRQ_DISABLED;
365        irq_desc[i].handler = &no_irq_type;
366        irq_desc[i].action  = NULL;
367        irq_desc[i].depth   = 1;
368        spin_lock_init(&irq_desc[i].lock);
369        set_intr_gate(i, interrupt[i]);
370    }
371
372    for ( i = 0; i < 16; i++ )
373    {
374        vector_irq[LEGACY_VECTOR(i)] = i;
375        irq_desc[LEGACY_VECTOR(i)].handler = &i8259A_irq_type;
376    }
377
378    apic_intr_init();
379
380    /* Set the clock to HZ Hz */
381#define CLOCK_TICK_RATE 1193180 /* crystal freq (Hz) */
382#define LATCH (((CLOCK_TICK_RATE)+(HZ/2))/HZ)
383    outb_p(0x34, PIT_MODE);        /* binary, mode 2, LSB/MSB, ch 0 */
384    outb_p(LATCH & 0xff, PIT_CH0); /* LSB */
385    outb(LATCH >> 8, PIT_CH0);     /* MSB */
386
387    setup_irq(2, &cascade);
388}
389
Note: See TracBrowser for help on using the repository browser.