Commit | Line | Data |
---|---|---|
1da177e4 | 1 | #include <linux/linkage.h> |
1da177e4 LT |
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> | |
1da177e4 LT |
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> | |
1da177e4 LT |
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> | |
2b8e05b5 | 24 | #include <asm/i8259.h> |
1da177e4 | 25 | |
1da177e4 LT |
26 | /* |
27 | * Common place to define all x86 IRQ vectors | |
28 | * | |
29 | * This builds up the IRQ handler stubs using some ugly macros in irq.h | |
30 | * | |
31 | * These macros create the low-level assembly IRQ routines that save | |
32 | * register context and call do_IRQ(). do_IRQ() then does all the | |
33 | * operations that are needed to keep the AT (or SMP IOAPIC) | |
34 | * interrupt-controller happy. | |
35 | */ | |
36 | ||
0bc471d9 TG |
37 | #define IRQ_NAME2(nr) nr##_interrupt(void) |
38 | #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) | |
39 | ||
40 | /* | |
41 | * SMP has a few special interrupts for IPI messages | |
42 | */ | |
43 | ||
44 | #define BUILD_IRQ(nr) \ | |
45 | asmlinkage void IRQ_NAME(nr); \ | |
9d25d4db | 46 | asm("\n.text\n.p2align\n" \ |
0bc471d9 TG |
47 | "IRQ" #nr "_interrupt:\n\t" \ |
48 | "push $~(" #nr ") ; " \ | |
6209ed9d LT |
49 | "jmp common_interrupt\n" \ |
50 | ".previous"); | |
0bc471d9 | 51 | |
1da177e4 LT |
52 | #define BI(x,y) \ |
53 | BUILD_IRQ(x##y) | |
54 | ||
55 | #define BUILD_16_IRQS(x) \ | |
56 | BI(x,0) BI(x,1) BI(x,2) BI(x,3) \ | |
57 | BI(x,4) BI(x,5) BI(x,6) BI(x,7) \ | |
58 | BI(x,8) BI(x,9) BI(x,a) BI(x,b) \ | |
59 | BI(x,c) BI(x,d) BI(x,e) BI(x,f) | |
60 | ||
1da177e4 LT |
61 | /* |
62 | * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts: | |
c97beb47 | 63 | * (these are usually mapped to vectors 0x30-0x3f) |
1da177e4 | 64 | */ |
1da177e4 | 65 | |
1da177e4 | 66 | /* |
2b8e05b5 | 67 | * The IO-APIC gives us many more interrupt sources. Most of these |
1da177e4 LT |
68 | * are unused but an SMP system is supposed to have enough memory ... |
69 | * sometimes (mostly wrt. hw bugs) we get corrupted vectors all | |
70 | * across the spectrum, so we really want to be prepared to get all | |
71 | * of these. Plus, more powerful systems might have more than 64 | |
72 | * IO-APIC registers. | |
73 | * | |
74 | * (these are usually mapped into the 0x30-0xff vector range) | |
75 | */ | |
e500f574 | 76 | BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3) |
1da177e4 LT |
77 | BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7) |
78 | BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb) | |
e500f574 | 79 | BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf) |
1da177e4 | 80 | |
1da177e4 | 81 | #undef BUILD_16_IRQS |
1da177e4 LT |
82 | #undef BI |
83 | ||
84 | ||
85 | #define IRQ(x,y) \ | |
86 | IRQ##x##y##_interrupt | |
87 | ||
88 | #define IRQLIST_16(x) \ | |
89 | IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \ | |
90 | IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \ | |
91 | IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \ | |
92 | IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f) | |
93 | ||
8fb6e5f5 | 94 | /* for the irq vectors */ |
3e7622f9 | 95 | static void (*__initdata interrupt[NR_VECTORS - FIRST_EXTERNAL_VECTOR])(void) = { |
e500f574 | 96 | IRQLIST_16(0x2), IRQLIST_16(0x3), |
1da177e4 LT |
97 | IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7), |
98 | IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb), | |
e500f574 | 99 | IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf) |
1da177e4 LT |
100 | }; |
101 | ||
102 | #undef IRQ | |
103 | #undef IRQLIST_16 | |
1da177e4 | 104 | |
2b8e05b5 PJ |
105 | |
106 | ||
107 | ||
1da177e4 LT |
108 | /* |
109 | * IRQ2 is cascade interrupt to second interrupt controller | |
110 | */ | |
111 | ||
df5ddf62 TG |
112 | static struct irqaction irq2 = { |
113 | .handler = no_action, | |
114 | .mask = CPU_MASK_NONE, | |
115 | .name = "cascade", | |
116 | }; | |
550f2299 | 117 | DEFINE_PER_CPU(vector_irq_t, vector_irq) = { |
bc5e81a1 EB |
118 | [0 ... IRQ0_VECTOR - 1] = -1, |
119 | [IRQ0_VECTOR] = 0, | |
120 | [IRQ1_VECTOR] = 1, | |
121 | [IRQ2_VECTOR] = 2, | |
122 | [IRQ3_VECTOR] = 3, | |
123 | [IRQ4_VECTOR] = 4, | |
124 | [IRQ5_VECTOR] = 5, | |
125 | [IRQ6_VECTOR] = 6, | |
126 | [IRQ7_VECTOR] = 7, | |
127 | [IRQ8_VECTOR] = 8, | |
128 | [IRQ9_VECTOR] = 9, | |
129 | [IRQ10_VECTOR] = 10, | |
130 | [IRQ11_VECTOR] = 11, | |
131 | [IRQ12_VECTOR] = 12, | |
132 | [IRQ13_VECTOR] = 13, | |
133 | [IRQ14_VECTOR] = 14, | |
134 | [IRQ15_VECTOR] = 15, | |
135 | [IRQ15_VECTOR + 1 ... NR_VECTORS - 1] = -1 | |
e500f574 | 136 | }; |
1da177e4 | 137 | |
780209af | 138 | void __init init_ISA_irqs(void) |
1da177e4 LT |
139 | { |
140 | int i; | |
141 | ||
1da177e4 | 142 | init_bsp_APIC(); |
1da177e4 LT |
143 | init_8259A(0); |
144 | ||
2c6927a3 | 145 | for (i = 0; i < 16; i++) { |
ee32c973 | 146 | struct irq_desc *desc = irq_to_desc(i); |
08678b08 YL |
147 | |
148 | desc->status = IRQ_DISABLED; | |
149 | desc->action = NULL; | |
150 | desc->depth = 1; | |
1da177e4 | 151 | |
2c6927a3 YL |
152 | /* |
153 | * 16 old-style INTA-cycle interrupts: | |
154 | */ | |
155 | set_irq_chip_and_handler_name(i, &i8259A_chip, | |
a460e745 | 156 | handle_level_irq, "XT"); |
1da177e4 LT |
157 | } |
158 | } | |
159 | ||
b0387830 GOC |
160 | void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ"))); |
161 | ||
9b658f6f | 162 | static void __init smp_intr_init(void) |
1da177e4 | 163 | { |
1da177e4 | 164 | #ifdef CONFIG_SMP |
1da177e4 LT |
165 | /* |
166 | * The reschedule interrupt is a CPU-to-CPU reschedule-helper | |
167 | * IPI, driven by wakeup. | |
168 | */ | |
305b92a2 | 169 | alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); |
1da177e4 | 170 | |
e5bc8b6b | 171 | /* IPIs for invalidation */ |
305b92a2 AM |
172 | alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+0, invalidate_interrupt0); |
173 | alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+1, invalidate_interrupt1); | |
174 | alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+2, invalidate_interrupt2); | |
175 | alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+3, invalidate_interrupt3); | |
176 | alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+4, invalidate_interrupt4); | |
177 | alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+5, invalidate_interrupt5); | |
178 | alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+6, invalidate_interrupt6); | |
179 | alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+7, invalidate_interrupt7); | |
1da177e4 LT |
180 | |
181 | /* IPI for generic function call */ | |
305b92a2 | 182 | alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); |
61014292 | 183 | |
1a781a77 IM |
184 | /* IPI for generic single function call */ |
185 | alloc_intr_gate(CALL_FUNCTION_SINGLE_VECTOR, | |
186 | call_function_single_interrupt); | |
187 | ||
61014292 EB |
188 | /* Low priority IPI to cleanup after moving an irq */ |
189 | set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt); | |
190 | #endif | |
2f97435e GC |
191 | } |
192 | ||
9b658f6f | 193 | static void __init apic_intr_init(void) |
2f97435e | 194 | { |
2f97435e | 195 | smp_intr_init(); |
2f97435e | 196 | |
305b92a2 AM |
197 | alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); |
198 | alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt); | |
1da177e4 | 199 | |
1da177e4 | 200 | /* self generated IPI for local APIC timer */ |
305b92a2 | 201 | alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); |
1da177e4 LT |
202 | |
203 | /* IPI vectors for APIC spurious and error interrupts */ | |
305b92a2 AM |
204 | alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); |
205 | alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); | |
2f97435e GC |
206 | } |
207 | ||
208 | void __init native_init_IRQ(void) | |
209 | { | |
210 | int i; | |
211 | ||
212 | init_ISA_irqs(); | |
213 | /* | |
214 | * Cover the whole vector space, no vector can escape | |
215 | * us. (some of these will be overridden and become | |
216 | * 'special' SMP interrupts) | |
217 | */ | |
218 | for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) { | |
219 | int vector = FIRST_EXTERNAL_VECTOR + i; | |
220 | if (vector != IA32_SYSCALL_VECTOR) | |
221 | set_intr_gate(vector, interrupt[i]); | |
222 | } | |
223 | ||
224 | apic_intr_init(); | |
1da177e4 | 225 | |
1da177e4 LT |
226 | if (!acpi_ioapic) |
227 | setup_irq(2, &irq2); | |
228 | } |