]>
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 | 72 | struct irq_chip *chip = legacy_pic->chip; |
1da177e4 LT |
73 | int i; |
74 | ||
598c73d2 | 75 | #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) |
7371d9fc PE |
76 | init_bsp_APIC(); |
77 | #endif | |
b81bb373 | 78 | legacy_pic->init(0); |
1da177e4 | 79 | |
95d76acc | 80 | for (i = 0; i < nr_legacy_irqs(); i++) |
60e684f0 | 81 | irq_set_chip_and_handler(i, chip, handle_level_irq); |
7371d9fc | 82 | } |
1da177e4 | 83 | |
54e2603f | 84 | void __init init_IRQ(void) |
66bcaf0b | 85 | { |
97943390 SS |
86 | int i; |
87 | ||
88 | /* | |
89 | * On cpu 0, Assign IRQ0_VECTOR..IRQ15_VECTOR's to IRQ 0..15. | |
90 | * If these IRQ's are handled by legacy interrupt-controllers like PIC, | |
91 | * then this configuration will likely be static after the boot. If | |
92 | * these IRQ's are handled by more mordern controllers like IO-APIC, | |
93 | * then this vector space can be freed and re-used dynamically as the | |
94 | * irq's migrate etc. | |
95 | */ | |
95d76acc | 96 | for (i = 0; i < nr_legacy_irqs(); i++) |
97943390 SS |
97 | per_cpu(vector_irq, 0)[IRQ0_VECTOR + i] = i; |
98 | ||
66bcaf0b TG |
99 | x86_init.irqs.intr_init(); |
100 | } | |
2ae111cd | 101 | |
36e9e1ea SS |
102 | /* |
103 | * Setup the vector to irq mappings. | |
104 | */ | |
105 | void setup_vector_irq(int cpu) | |
106 | { | |
107 | #ifndef CONFIG_X86_IO_APIC | |
108 | int irq; | |
109 | ||
110 | /* | |
111 | * On most of the platforms, legacy PIC delivers the interrupts on the | |
112 | * boot cpu. But there are certain platforms where PIC interrupts are | |
113 | * delivered to multiple cpu's. If the legacy IRQ is handled by the | |
114 | * legacy PIC, for the new cpu that is coming online, setup the static | |
115 | * legacy vector to irq mapping: | |
116 | */ | |
95d76acc | 117 | for (irq = 0; irq < nr_legacy_irqs(); irq++) |
36e9e1ea SS |
118 | per_cpu(vector_irq, cpu)[IRQ0_VECTOR + irq] = irq; |
119 | #endif | |
120 | ||
121 | __setup_vector_irq(cpu); | |
122 | } | |
123 | ||
36290d87 PE |
124 | static void __init smp_intr_init(void) |
125 | { | |
b0096bb0 PE |
126 | #ifdef CONFIG_SMP |
127 | #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) | |
2ae111cd CG |
128 | /* |
129 | * The reschedule interrupt is a CPU-to-CPU reschedule-helper | |
130 | * IPI, driven by wakeup. | |
131 | */ | |
132 | alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); | |
133 | ||
2ae111cd CG |
134 | /* IPI for generic function call */ |
135 | alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); | |
136 | ||
b0096bb0 | 137 | /* IPI for generic single function call */ |
b77b881f | 138 | alloc_intr_gate(CALL_FUNCTION_SINGLE_VECTOR, |
b0096bb0 | 139 | call_function_single_interrupt); |
497c9a19 YL |
140 | |
141 | /* Low priority IPI to cleanup after moving an irq */ | |
142 | set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt); | |
b77b881f | 143 | set_bit(IRQ_MOVE_CLEANUP_VECTOR, used_vectors); |
4ef702c1 AK |
144 | |
145 | /* IPI used for rebooting/stopping */ | |
146 | alloc_intr_gate(REBOOT_VECTOR, reboot_interrupt); | |
2ae111cd | 147 | #endif |
b0096bb0 | 148 | #endif /* CONFIG_SMP */ |
36290d87 PE |
149 | } |
150 | ||
22813c45 | 151 | static void __init apic_intr_init(void) |
1da177e4 | 152 | { |
36290d87 | 153 | smp_intr_init(); |
2ae111cd | 154 | |
48b1fddb | 155 | #ifdef CONFIG_X86_THERMAL_VECTOR |
ab19c25a | 156 | alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); |
48b1fddb | 157 | #endif |
6effa8f6 | 158 | #ifdef CONFIG_X86_MCE_THRESHOLD |
ab19c25a PE |
159 | alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt); |
160 | #endif | |
161 | ||
162 | #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) | |
2ae111cd CG |
163 | /* self generated IPI for local APIC timer */ |
164 | alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); | |
165 | ||
4a4de9c7 DS |
166 | /* IPI for X86 platform specific use */ |
167 | alloc_intr_gate(X86_PLATFORM_IPI_VECTOR, x86_platform_ipi); | |
d78f2664 YZ |
168 | #ifdef CONFIG_HAVE_KVM |
169 | /* IPI for KVM to deliver posted interrupt */ | |
170 | alloc_intr_gate(POSTED_INTR_VECTOR, kvm_posted_intr_ipi); | |
171 | #endif | |
acaabe79 | 172 | |
2ae111cd CG |
173 | /* IPI vectors for APIC spurious and error interrupts */ |
174 | alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); | |
175 | alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); | |
2ae111cd | 176 | |
e360adbe PZ |
177 | /* IRQ work interrupts: */ |
178 | # ifdef CONFIG_IRQ_WORK | |
179 | alloc_intr_gate(IRQ_WORK_VECTOR, irq_work_interrupt); | |
47f16ca7 IM |
180 | # endif |
181 | ||
2ae111cd | 182 | #endif |
22813c45 | 183 | } |
2ae111cd | 184 | |
22813c45 PE |
185 | void __init native_init_IRQ(void) |
186 | { | |
187 | int i; | |
188 | ||
189 | /* Execute any quirks before the call gates are initialised: */ | |
d9112f43 | 190 | x86_init.irqs.pre_vector_init(); |
22813c45 | 191 | |
77857dc0 YL |
192 | apic_intr_init(); |
193 | ||
22813c45 PE |
194 | /* |
195 | * Cover the whole vector space, no vector can escape | |
196 | * us. (some of these will be overridden and become | |
197 | * 'special' SMP interrupts) | |
198 | */ | |
0b2f4d4d AM |
199 | i = FIRST_EXTERNAL_VECTOR; |
200 | for_each_clear_bit_from(i, used_vectors, NR_VECTORS) { | |
77857dc0 | 201 | /* IA32_SYSCALL_VECTOR could be used in trap_init already. */ |
0b2f4d4d | 202 | set_intr_gate(i, interrupt[i - FIRST_EXTERNAL_VECTOR]); |
22813c45 | 203 | } |
7856f6cc | 204 | |
a90b858c | 205 | if (!acpi_ioapic && !of_ioapic && nr_legacy_irqs()) |
2ae111cd CG |
206 | setup_irq(2, &irq2); |
207 | ||
320fd996 | 208 | #ifdef CONFIG_X86_32 |
1da177e4 | 209 | irq_ctx_init(smp_processor_id()); |
320fd996 | 210 | #endif |
1da177e4 | 211 | } |