Commit | Line | Data |
---|---|---|
77883860 | 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> | |
77883860 | 7 | #include <linux/timex.h> |
1da177e4 | 8 | #include <linux/random.h> |
47f16ca7 | 9 | #include <linux/kprobes.h> |
1da177e4 LT |
10 | #include <linux/init.h> |
11 | #include <linux/kernel_stat.h> | |
edbaa603 | 12 | #include <linux/device.h> |
1da177e4 | 13 | #include <linux/bitops.h> |
77883860 | 14 | #include <linux/acpi.h> |
aa09e6cd JSR |
15 | #include <linux/io.h> |
16 | #include <linux/delay.h> | |
1da177e4 | 17 | |
60063497 | 18 | #include <linux/atomic.h> |
1da177e4 | 19 | #include <asm/timer.h> |
77883860 | 20 | #include <asm/hw_irq.h> |
1da177e4 | 21 | #include <asm/pgtable.h> |
1da177e4 LT |
22 | #include <asm/desc.h> |
23 | #include <asm/apic.h> | |
8e6dafd6 | 24 | #include <asm/setup.h> |
1da177e4 | 25 | #include <asm/i8259.h> |
aa09e6cd | 26 | #include <asm/traps.h> |
3879a6f3 | 27 | #include <asm/prom.h> |
1da177e4 | 28 | |
77883860 PE |
29 | /* |
30 | * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts: | |
31 | * (these are usually mapped to vectors 0x30-0x3f) | |
32 | */ | |
33 | ||
34 | /* | |
35 | * The IO-APIC gives us many more interrupt sources. Most of these | |
36 | * are unused but an SMP system is supposed to have enough memory ... | |
37 | * sometimes (mostly wrt. hw bugs) we get corrupted vectors all | |
38 | * across the spectrum, so we really want to be prepared to get all | |
39 | * of these. Plus, more powerful systems might have more than 64 | |
40 | * IO-APIC registers. | |
41 | * | |
42 | * (these are usually mapped into the 0x30-0xff vector range) | |
43 | */ | |
1da177e4 | 44 | |
2ae111cd CG |
45 | /* |
46 | * IRQ2 is cascade interrupt to second interrupt controller | |
47 | */ | |
48 | static struct irqaction irq2 = { | |
49 | .handler = no_action, | |
2ae111cd | 50 | .name = "cascade", |
9bbbff25 | 51 | .flags = IRQF_NO_THREAD, |
2ae111cd CG |
52 | }; |
53 | ||
497c9a19 | 54 | DEFINE_PER_CPU(vector_irq_t, vector_irq) = { |
9345005f | 55 | [0 ... NR_VECTORS - 1] = VECTOR_UNDEFINED, |
497c9a19 YL |
56 | }; |
57 | ||
b77b881f YL |
58 | int vector_used_by_percpu_irq(unsigned int vector) |
59 | { | |
60 | int cpu; | |
61 | ||
62 | for_each_online_cpu(cpu) { | |
9345005f | 63 | if (per_cpu(vector_irq, cpu)[vector] > VECTOR_UNDEFINED) |
b77b881f YL |
64 | return 1; |
65 | } | |
66 | ||
67 | return 0; | |
68 | } | |
69 | ||
d9112f43 | 70 | void __init init_ISA_irqs(void) |
1da177e4 | 71 | { |
011d578f TG |
72 | struct irq_chip *chip = legacy_pic->chip; |
73 | const char *name = chip->name; | |
1da177e4 LT |
74 | int i; |
75 | ||
598c73d2 | 76 | #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) |
7371d9fc PE |
77 | init_bsp_APIC(); |
78 | #endif | |
b81bb373 | 79 | legacy_pic->init(0); |
1da177e4 | 80 | |
95d76acc | 81 | for (i = 0; i < nr_legacy_irqs(); i++) |
2c778651 | 82 | irq_set_chip_and_handler_name(i, chip, handle_level_irq, name); |
7371d9fc | 83 | } |
1da177e4 | 84 | |
54e2603f | 85 | void __init init_IRQ(void) |
66bcaf0b | 86 | { |
97943390 SS |
87 | int i; |
88 | ||
89 | /* | |
90 | * On cpu 0, Assign IRQ0_VECTOR..IRQ15_VECTOR's to IRQ 0..15. | |
91 | * If these IRQ's are handled by legacy interrupt-controllers like PIC, | |
92 | * then this configuration will likely be static after the boot. If | |
93 | * these IRQ's are handled by more mordern controllers like IO-APIC, | |
94 | * then this vector space can be freed and re-used dynamically as the | |
95 | * irq's migrate etc. | |
96 | */ | |
95d76acc | 97 | for (i = 0; i < nr_legacy_irqs(); i++) |
97943390 SS |
98 | per_cpu(vector_irq, 0)[IRQ0_VECTOR + i] = i; |
99 | ||
66bcaf0b TG |
100 | x86_init.irqs.intr_init(); |
101 | } | |
2ae111cd | 102 | |
36e9e1ea SS |
103 | /* |
104 | * Setup the vector to irq mappings. | |
105 | */ | |
106 | void setup_vector_irq(int cpu) | |
107 | { | |
108 | #ifndef CONFIG_X86_IO_APIC | |
109 | int irq; | |
110 | ||
111 | /* | |
112 | * On most of the platforms, legacy PIC delivers the interrupts on the | |
113 | * boot cpu. But there are certain platforms where PIC interrupts are | |
114 | * delivered to multiple cpu's. If the legacy IRQ is handled by the | |
115 | * legacy PIC, for the new cpu that is coming online, setup the static | |
116 | * legacy vector to irq mapping: | |
117 | */ | |
95d76acc | 118 | for (irq = 0; irq < nr_legacy_irqs(); irq++) |
36e9e1ea SS |
119 | per_cpu(vector_irq, cpu)[IRQ0_VECTOR + irq] = irq; |
120 | #endif | |
121 | ||
122 | __setup_vector_irq(cpu); | |
123 | } | |
124 | ||
36290d87 PE |
125 | static void __init smp_intr_init(void) |
126 | { | |
b0096bb0 PE |
127 | #ifdef CONFIG_SMP |
128 | #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) | |
2ae111cd CG |
129 | /* |
130 | * The reschedule interrupt is a CPU-to-CPU reschedule-helper | |
131 | * IPI, driven by wakeup. | |
132 | */ | |
133 | alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); | |
134 | ||
2ae111cd CG |
135 | /* IPI for generic function call */ |
136 | alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); | |
137 | ||
b0096bb0 | 138 | /* IPI for generic single function call */ |
b77b881f | 139 | alloc_intr_gate(CALL_FUNCTION_SINGLE_VECTOR, |
b0096bb0 | 140 | call_function_single_interrupt); |
497c9a19 YL |
141 | |
142 | /* Low priority IPI to cleanup after moving an irq */ | |
143 | set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt); | |
b77b881f | 144 | set_bit(IRQ_MOVE_CLEANUP_VECTOR, used_vectors); |
4ef702c1 AK |
145 | |
146 | /* IPI used for rebooting/stopping */ | |
147 | alloc_intr_gate(REBOOT_VECTOR, reboot_interrupt); | |
2ae111cd | 148 | #endif |
b0096bb0 | 149 | #endif /* CONFIG_SMP */ |
36290d87 PE |
150 | } |
151 | ||
22813c45 | 152 | static void __init apic_intr_init(void) |
1da177e4 | 153 | { |
36290d87 | 154 | smp_intr_init(); |
2ae111cd | 155 | |
48b1fddb | 156 | #ifdef CONFIG_X86_THERMAL_VECTOR |
ab19c25a | 157 | alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); |
48b1fddb | 158 | #endif |
6effa8f6 | 159 | #ifdef CONFIG_X86_MCE_THRESHOLD |
ab19c25a PE |
160 | alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt); |
161 | #endif | |
162 | ||
163 | #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) | |
2ae111cd CG |
164 | /* self generated IPI for local APIC timer */ |
165 | alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); | |
166 | ||
4a4de9c7 DS |
167 | /* IPI for X86 platform specific use */ |
168 | alloc_intr_gate(X86_PLATFORM_IPI_VECTOR, x86_platform_ipi); | |
d78f2664 YZ |
169 | #ifdef CONFIG_HAVE_KVM |
170 | /* IPI for KVM to deliver posted interrupt */ | |
171 | alloc_intr_gate(POSTED_INTR_VECTOR, kvm_posted_intr_ipi); | |
172 | #endif | |
acaabe79 | 173 | |
2ae111cd CG |
174 | /* IPI vectors for APIC spurious and error interrupts */ |
175 | alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); | |
176 | alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); | |
2ae111cd | 177 | |
e360adbe PZ |
178 | /* IRQ work interrupts: */ |
179 | # ifdef CONFIG_IRQ_WORK | |
180 | alloc_intr_gate(IRQ_WORK_VECTOR, irq_work_interrupt); | |
47f16ca7 IM |
181 | # endif |
182 | ||
2ae111cd | 183 | #endif |
22813c45 | 184 | } |
2ae111cd | 185 | |
22813c45 PE |
186 | void __init native_init_IRQ(void) |
187 | { | |
188 | int i; | |
189 | ||
190 | /* Execute any quirks before the call gates are initialised: */ | |
d9112f43 | 191 | x86_init.irqs.pre_vector_init(); |
22813c45 | 192 | |
77857dc0 YL |
193 | apic_intr_init(); |
194 | ||
22813c45 PE |
195 | /* |
196 | * Cover the whole vector space, no vector can escape | |
197 | * us. (some of these will be overridden and become | |
198 | * 'special' SMP interrupts) | |
199 | */ | |
0b2f4d4d AM |
200 | i = FIRST_EXTERNAL_VECTOR; |
201 | for_each_clear_bit_from(i, used_vectors, NR_VECTORS) { | |
77857dc0 | 202 | /* IA32_SYSCALL_VECTOR could be used in trap_init already. */ |
0b2f4d4d | 203 | set_intr_gate(i, interrupt[i - FIRST_EXTERNAL_VECTOR]); |
22813c45 | 204 | } |
7856f6cc | 205 | |
a90b858c | 206 | if (!acpi_ioapic && !of_ioapic && nr_legacy_irqs()) |
2ae111cd CG |
207 | setup_irq(2, &irq2); |
208 | ||
320fd996 | 209 | #ifdef CONFIG_X86_32 |
1da177e4 | 210 | irq_ctx_init(smp_processor_id()); |
320fd996 | 211 | #endif |
1da177e4 | 212 | } |