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