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