OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [x86/] [kernel/] [i8259_64.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
#include <linux/linkage.h>
2
#include <linux/errno.h>
3
#include <linux/signal.h>
4
#include <linux/sched.h>
5
#include <linux/ioport.h>
6
#include <linux/interrupt.h>
7
#include <linux/timex.h>
8
#include <linux/slab.h>
9
#include <linux/random.h>
10
#include <linux/init.h>
11
#include <linux/kernel_stat.h>
12
#include <linux/sysdev.h>
13
#include <linux/bitops.h>
14
 
15
#include <asm/acpi.h>
16
#include <asm/atomic.h>
17
#include <asm/system.h>
18
#include <asm/io.h>
19
#include <asm/hw_irq.h>
20
#include <asm/pgtable.h>
21
#include <asm/delay.h>
22
#include <asm/desc.h>
23
#include <asm/apic.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
 
36
#define BI(x,y) \
37
        BUILD_IRQ(x##y)
38
 
39
#define BUILD_16_IRQS(x) \
40
        BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
41
        BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
42
        BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
43
        BI(x,c) BI(x,d) BI(x,e) BI(x,f)
44
 
45
/*
46
 * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
47
 * (these are usually mapped to vectors 0x30-0x3f)
48
 */
49
 
50
/*
51
 * The IO-APIC gives us many more interrupt sources. Most of these
52
 * are unused but an SMP system is supposed to have enough memory ...
53
 * sometimes (mostly wrt. hw bugs) we get corrupted vectors all
54
 * across the spectrum, so we really want to be prepared to get all
55
 * of these. Plus, more powerful systems might have more than 64
56
 * IO-APIC registers.
57
 *
58
 * (these are usually mapped into the 0x30-0xff vector range)
59
 */
60
                                      BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
61
BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)
62
BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)
63
BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf)
64
 
65
#undef BUILD_16_IRQS
66
#undef BI
67
 
68
 
69
#define IRQ(x,y) \
70
        IRQ##x##y##_interrupt
71
 
72
#define IRQLIST_16(x) \
73
        IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
74
        IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
75
        IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
76
        IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
77
 
78
/* for the irq vectors */
79
static void (*interrupt[NR_VECTORS - FIRST_EXTERNAL_VECTOR])(void) = {
80
                                          IRQLIST_16(0x2), IRQLIST_16(0x3),
81
        IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
82
        IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
83
        IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf)
84
};
85
 
86
#undef IRQ
87
#undef IRQLIST_16
88
 
89
/*
90
 * This is the 'legacy' 8259A Programmable Interrupt Controller,
91
 * present in the majority of PC/AT boxes.
92
 * plus some generic x86 specific things if generic specifics makes
93
 * any sense at all.
94
 * this file should become arch/i386/kernel/irq.c when the old irq.c
95
 * moves to arch independent land
96
 */
97
 
98
static int i8259A_auto_eoi;
99
DEFINE_SPINLOCK(i8259A_lock);
100
static void mask_and_ack_8259A(unsigned int);
101
 
102
static struct irq_chip i8259A_chip = {
103
        .name           = "XT-PIC",
104
        .mask           = disable_8259A_irq,
105
        .disable        = disable_8259A_irq,
106
        .unmask         = enable_8259A_irq,
107
        .mask_ack       = mask_and_ack_8259A,
108
};
109
 
110
/*
111
 * 8259A PIC functions to handle ISA devices:
112
 */
113
 
114
/*
115
 * This contains the irq mask for both 8259A irq controllers,
116
 */
117
static unsigned int cached_irq_mask = 0xffff;
118
 
119
#define __byte(x,y)     (((unsigned char *)&(y))[x])
120
#define cached_21       (__byte(0,cached_irq_mask))
121
#define cached_A1       (__byte(1,cached_irq_mask))
122
 
123
/*
124
 * Not all IRQs can be routed through the IO-APIC, eg. on certain (older)
125
 * boards the timer interrupt is not really connected to any IO-APIC pin,
126
 * it's fed to the master 8259A's IR0 line only.
127
 *
128
 * Any '1' bit in this mask means the IRQ is routed through the IO-APIC.
129
 * this 'mixed mode' IRQ handling costs nothing because it's only used
130
 * at IRQ setup time.
131
 */
132
unsigned long io_apic_irqs;
133
 
134
void disable_8259A_irq(unsigned int irq)
135
{
136
        unsigned int mask = 1 << irq;
137
        unsigned long flags;
138
 
139
        spin_lock_irqsave(&i8259A_lock, flags);
140
        cached_irq_mask |= mask;
141
        if (irq & 8)
142
                outb(cached_A1,0xA1);
143
        else
144
                outb(cached_21,0x21);
145
        spin_unlock_irqrestore(&i8259A_lock, flags);
146
}
147
 
148
void enable_8259A_irq(unsigned int irq)
149
{
150
        unsigned int mask = ~(1 << irq);
151
        unsigned long flags;
152
 
153
        spin_lock_irqsave(&i8259A_lock, flags);
154
        cached_irq_mask &= mask;
155
        if (irq & 8)
156
                outb(cached_A1,0xA1);
157
        else
158
                outb(cached_21,0x21);
159
        spin_unlock_irqrestore(&i8259A_lock, flags);
160
}
161
 
162
int i8259A_irq_pending(unsigned int irq)
163
{
164
        unsigned int mask = 1<<irq;
165
        unsigned long flags;
166
        int ret;
167
 
168
        spin_lock_irqsave(&i8259A_lock, flags);
169
        if (irq < 8)
170
                ret = inb(0x20) & mask;
171
        else
172
                ret = inb(0xA0) & (mask >> 8);
173
        spin_unlock_irqrestore(&i8259A_lock, flags);
174
 
175
        return ret;
176
}
177
 
178
void make_8259A_irq(unsigned int irq)
179
{
180
        disable_irq_nosync(irq);
181
        io_apic_irqs &= ~(1<<irq);
182
        set_irq_chip_and_handler_name(irq, &i8259A_chip, handle_level_irq,
183
                                      "XT");
184
        enable_irq(irq);
185
}
186
 
187
/*
188
 * This function assumes to be called rarely. Switching between
189
 * 8259A registers is slow.
190
 * This has to be protected by the irq controller spinlock
191
 * before being called.
192
 */
193
static inline int i8259A_irq_real(unsigned int irq)
194
{
195
        int value;
196
        int irqmask = 1<<irq;
197
 
198
        if (irq < 8) {
199
                outb(0x0B,0x20);                /* ISR register */
200
                value = inb(0x20) & irqmask;
201
                outb(0x0A,0x20);                /* back to the IRR register */
202
                return value;
203
        }
204
        outb(0x0B,0xA0);                /* ISR register */
205
        value = inb(0xA0) & (irqmask >> 8);
206
        outb(0x0A,0xA0);                /* back to the IRR register */
207
        return value;
208
}
209
 
210
/*
211
 * Careful! The 8259A is a fragile beast, it pretty
212
 * much _has_ to be done exactly like this (mask it
213
 * first, _then_ send the EOI, and the order of EOI
214
 * to the two 8259s is important!
215
 */
216
static void mask_and_ack_8259A(unsigned int irq)
217
{
218
        unsigned int irqmask = 1 << irq;
219
        unsigned long flags;
220
 
221
        spin_lock_irqsave(&i8259A_lock, flags);
222
        /*
223
         * Lightweight spurious IRQ detection. We do not want
224
         * to overdo spurious IRQ handling - it's usually a sign
225
         * of hardware problems, so we only do the checks we can
226
         * do without slowing down good hardware unnecessarily.
227
         *
228
         * Note that IRQ7 and IRQ15 (the two spurious IRQs
229
         * usually resulting from the 8259A-1|2 PICs) occur
230
         * even if the IRQ is masked in the 8259A. Thus we
231
         * can check spurious 8259A IRQs without doing the
232
         * quite slow i8259A_irq_real() call for every IRQ.
233
         * This does not cover 100% of spurious interrupts,
234
         * but should be enough to warn the user that there
235
         * is something bad going on ...
236
         */
237
        if (cached_irq_mask & irqmask)
238
                goto spurious_8259A_irq;
239
        cached_irq_mask |= irqmask;
240
 
241
handle_real_irq:
242
        if (irq & 8) {
243
                inb(0xA1);              /* DUMMY - (do we need this?) */
244
                outb(cached_A1,0xA1);
245
                outb(0x60+(irq&7),0xA0);/* 'Specific EOI' to slave */
246
                outb(0x62,0x20);        /* 'Specific EOI' to master-IRQ2 */
247
        } else {
248
                inb(0x21);              /* DUMMY - (do we need this?) */
249
                outb(cached_21,0x21);
250
                outb(0x60+irq,0x20);    /* 'Specific EOI' to master */
251
        }
252
        spin_unlock_irqrestore(&i8259A_lock, flags);
253
        return;
254
 
255
spurious_8259A_irq:
256
        /*
257
         * this is the slow path - should happen rarely.
258
         */
259
        if (i8259A_irq_real(irq))
260
                /*
261
                 * oops, the IRQ _is_ in service according to the
262
                 * 8259A - not spurious, go handle it.
263
                 */
264
                goto handle_real_irq;
265
 
266
        {
267
                static int spurious_irq_mask;
268
                /*
269
                 * At this point we can be sure the IRQ is spurious,
270
                 * lets ACK and report it. [once per IRQ]
271
                 */
272
                if (!(spurious_irq_mask & irqmask)) {
273
                        printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq);
274
                        spurious_irq_mask |= irqmask;
275
                }
276
                atomic_inc(&irq_err_count);
277
                /*
278
                 * Theoretically we do not have to handle this IRQ,
279
                 * but in Linux this does not cause problems and is
280
                 * simpler for us.
281
                 */
282
                goto handle_real_irq;
283
        }
284
}
285
 
286
void init_8259A(int auto_eoi)
287
{
288
        unsigned long flags;
289
 
290
        i8259A_auto_eoi = auto_eoi;
291
 
292
        spin_lock_irqsave(&i8259A_lock, flags);
293
 
294
        outb(0xff, 0x21);       /* mask all of 8259A-1 */
295
        outb(0xff, 0xA1);       /* mask all of 8259A-2 */
296
 
297
        /*
298
         * outb_p - this has to work on a wide range of PC hardware.
299
         */
300
        outb_p(0x11, 0x20);     /* ICW1: select 8259A-1 init */
301
        outb_p(IRQ0_VECTOR, 0x21);      /* ICW2: 8259A-1 IR0-7 mapped to 0x30-0x37 */
302
        outb_p(0x04, 0x21);     /* 8259A-1 (the master) has a slave on IR2 */
303
        if (auto_eoi)
304
                outb_p(0x03, 0x21);     /* master does Auto EOI */
305
        else
306
                outb_p(0x01, 0x21);     /* master expects normal EOI */
307
 
308
        outb_p(0x11, 0xA0);     /* ICW1: select 8259A-2 init */
309
        outb_p(IRQ8_VECTOR, 0xA1);      /* ICW2: 8259A-2 IR0-7 mapped to 0x38-0x3f */
310
        outb_p(0x02, 0xA1);     /* 8259A-2 is a slave on master's IR2 */
311
        outb_p(0x01, 0xA1);     /* (slave's support for AEOI in flat mode
312
                                    is to be investigated) */
313
 
314
        if (auto_eoi)
315
                /*
316
                 * in AEOI mode we just have to mask the interrupt
317
                 * when acking.
318
                 */
319
                i8259A_chip.mask_ack = disable_8259A_irq;
320
        else
321
                i8259A_chip.mask_ack = mask_and_ack_8259A;
322
 
323
        udelay(100);            /* wait for 8259A to initialize */
324
 
325
        outb(cached_21, 0x21);  /* restore master IRQ mask */
326
        outb(cached_A1, 0xA1);  /* restore slave IRQ mask */
327
 
328
        spin_unlock_irqrestore(&i8259A_lock, flags);
329
}
330
 
331
static char irq_trigger[2];
332
/**
333
 * ELCR registers (0x4d0, 0x4d1) control edge/level of IRQ
334
 */
335
static void restore_ELCR(char *trigger)
336
{
337
        outb(trigger[0], 0x4d0);
338
        outb(trigger[1], 0x4d1);
339
}
340
 
341
static void save_ELCR(char *trigger)
342
{
343
        /* IRQ 0,1,2,8,13 are marked as reserved */
344
        trigger[0] = inb(0x4d0) & 0xF8;
345
        trigger[1] = inb(0x4d1) & 0xDE;
346
}
347
 
348
static int i8259A_resume(struct sys_device *dev)
349
{
350
        init_8259A(i8259A_auto_eoi);
351
        restore_ELCR(irq_trigger);
352
        return 0;
353
}
354
 
355
static int i8259A_suspend(struct sys_device *dev, pm_message_t state)
356
{
357
        save_ELCR(irq_trigger);
358
        return 0;
359
}
360
 
361
static int i8259A_shutdown(struct sys_device *dev)
362
{
363
        /* Put the i8259A into a quiescent state that
364
         * the kernel initialization code can get it
365
         * out of.
366
         */
367
        outb(0xff, 0x21);       /* mask all of 8259A-1 */
368
        outb(0xff, 0xA1);       /* mask all of 8259A-1 */
369
        return 0;
370
}
371
 
372
static struct sysdev_class i8259_sysdev_class = {
373
        set_kset_name("i8259"),
374
        .suspend = i8259A_suspend,
375
        .resume = i8259A_resume,
376
        .shutdown = i8259A_shutdown,
377
};
378
 
379
static struct sys_device device_i8259A = {
380
        .id     = 0,
381
        .cls    = &i8259_sysdev_class,
382
};
383
 
384
static int __init i8259A_init_sysfs(void)
385
{
386
        int error = sysdev_class_register(&i8259_sysdev_class);
387
        if (!error)
388
                error = sysdev_register(&device_i8259A);
389
        return error;
390
}
391
 
392
device_initcall(i8259A_init_sysfs);
393
 
394
/*
395
 * IRQ2 is cascade interrupt to second interrupt controller
396
 */
397
 
398
static struct irqaction irq2 = {
399
        .handler = no_action,
400
        .mask = CPU_MASK_NONE,
401
        .name = "cascade",
402
};
403
DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
404
        [0 ... IRQ0_VECTOR - 1] = -1,
405
        [IRQ0_VECTOR] = 0,
406
        [IRQ1_VECTOR] = 1,
407
        [IRQ2_VECTOR] = 2,
408
        [IRQ3_VECTOR] = 3,
409
        [IRQ4_VECTOR] = 4,
410
        [IRQ5_VECTOR] = 5,
411
        [IRQ6_VECTOR] = 6,
412
        [IRQ7_VECTOR] = 7,
413
        [IRQ8_VECTOR] = 8,
414
        [IRQ9_VECTOR] = 9,
415
        [IRQ10_VECTOR] = 10,
416
        [IRQ11_VECTOR] = 11,
417
        [IRQ12_VECTOR] = 12,
418
        [IRQ13_VECTOR] = 13,
419
        [IRQ14_VECTOR] = 14,
420
        [IRQ15_VECTOR] = 15,
421
        [IRQ15_VECTOR + 1 ... NR_VECTORS - 1] = -1
422
};
423
 
424
void __init init_ISA_irqs (void)
425
{
426
        int i;
427
 
428
        init_bsp_APIC();
429
        init_8259A(0);
430
 
431
        for (i = 0; i < NR_IRQS; i++) {
432
                irq_desc[i].status = IRQ_DISABLED;
433
                irq_desc[i].action = NULL;
434
                irq_desc[i].depth = 1;
435
 
436
                if (i < 16) {
437
                        /*
438
                         * 16 old-style INTA-cycle interrupts:
439
                         */
440
                        set_irq_chip_and_handler_name(i, &i8259A_chip,
441
                                                      handle_level_irq, "XT");
442
                } else {
443
                        /*
444
                         * 'high' PCI IRQs filled in on demand
445
                         */
446
                        irq_desc[i].chip = &no_irq_chip;
447
                }
448
        }
449
}
450
 
451
void __init init_IRQ(void)
452
{
453
        int i;
454
 
455
        init_ISA_irqs();
456
        /*
457
         * Cover the whole vector space, no vector can escape
458
         * us. (some of these will be overridden and become
459
         * 'special' SMP interrupts)
460
         */
461
        for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
462
                int vector = FIRST_EXTERNAL_VECTOR + i;
463
                if (vector != IA32_SYSCALL_VECTOR)
464
                        set_intr_gate(vector, interrupt[i]);
465
        }
466
 
467
#ifdef CONFIG_SMP
468
        /*
469
         * The reschedule interrupt is a CPU-to-CPU reschedule-helper
470
         * IPI, driven by wakeup.
471
         */
472
        set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
473
 
474
        /* IPIs for invalidation */
475
        set_intr_gate(INVALIDATE_TLB_VECTOR_START+0, invalidate_interrupt0);
476
        set_intr_gate(INVALIDATE_TLB_VECTOR_START+1, invalidate_interrupt1);
477
        set_intr_gate(INVALIDATE_TLB_VECTOR_START+2, invalidate_interrupt2);
478
        set_intr_gate(INVALIDATE_TLB_VECTOR_START+3, invalidate_interrupt3);
479
        set_intr_gate(INVALIDATE_TLB_VECTOR_START+4, invalidate_interrupt4);
480
        set_intr_gate(INVALIDATE_TLB_VECTOR_START+5, invalidate_interrupt5);
481
        set_intr_gate(INVALIDATE_TLB_VECTOR_START+6, invalidate_interrupt6);
482
        set_intr_gate(INVALIDATE_TLB_VECTOR_START+7, invalidate_interrupt7);
483
 
484
        /* IPI for generic function call */
485
        set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
486
 
487
        /* Low priority IPI to cleanup after moving an irq */
488
        set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt);
489
#endif
490
        set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
491
        set_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
492
 
493
        /* self generated IPI for local APIC timer */
494
        set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
495
 
496
        /* IPI vectors for APIC spurious and error interrupts */
497
        set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
498
        set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
499
 
500
        if (!acpi_ioapic)
501
                setup_irq(2, &irq2);
502
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.