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) = { |
7276c6a2 | 55 | [0 ... NR_VECTORS - 1] = VECTOR_UNUSED, |
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) { | |
a782a7e4 | 63 | if (!IS_ERR_OR_NULL(per_cpu(vector_irq, cpu)[vector])) |
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 | /* | |
8b455e65 | 89 | * On cpu 0, Assign ISA_IRQ_VECTOR(irq) to IRQ 0..15. |
97943390 SS |
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++) |
a782a7e4 | 97 | per_cpu(vector_irq, 0)[ISA_IRQ_VECTOR(i)] = irq_to_desc(i); |
97943390 | 98 | |
66bcaf0b TG |
99 | x86_init.irqs.intr_init(); |
100 | } | |
2ae111cd | 101 | |
36290d87 PE |
102 | static void __init smp_intr_init(void) |
103 | { | |
b0096bb0 | 104 | #ifdef CONFIG_SMP |
2ae111cd CG |
105 | /* |
106 | * The reschedule interrupt is a CPU-to-CPU reschedule-helper | |
107 | * IPI, driven by wakeup. | |
108 | */ | |
109 | alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); | |
110 | ||
2ae111cd CG |
111 | /* IPI for generic function call */ |
112 | alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); | |
113 | ||
b0096bb0 | 114 | /* IPI for generic single function call */ |
b77b881f | 115 | alloc_intr_gate(CALL_FUNCTION_SINGLE_VECTOR, |
b0096bb0 | 116 | call_function_single_interrupt); |
497c9a19 YL |
117 | |
118 | /* Low priority IPI to cleanup after moving an irq */ | |
119 | set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt); | |
b77b881f | 120 | set_bit(IRQ_MOVE_CLEANUP_VECTOR, used_vectors); |
4ef702c1 AK |
121 | |
122 | /* IPI used for rebooting/stopping */ | |
123 | alloc_intr_gate(REBOOT_VECTOR, reboot_interrupt); | |
b0096bb0 | 124 | #endif /* CONFIG_SMP */ |
36290d87 PE |
125 | } |
126 | ||
22813c45 | 127 | static void __init apic_intr_init(void) |
1da177e4 | 128 | { |
36290d87 | 129 | smp_intr_init(); |
2ae111cd | 130 | |
48b1fddb | 131 | #ifdef CONFIG_X86_THERMAL_VECTOR |
ab19c25a | 132 | alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); |
48b1fddb | 133 | #endif |
6effa8f6 | 134 | #ifdef CONFIG_X86_MCE_THRESHOLD |
ab19c25a PE |
135 | alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt); |
136 | #endif | |
137 | ||
24fd78a8 AG |
138 | #ifdef CONFIG_X86_MCE_AMD |
139 | alloc_intr_gate(DEFERRED_ERROR_VECTOR, deferred_error_interrupt); | |
140 | #endif | |
141 | ||
2414e021 | 142 | #ifdef CONFIG_X86_LOCAL_APIC |
2ae111cd CG |
143 | /* self generated IPI for local APIC timer */ |
144 | alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); | |
145 | ||
4a4de9c7 DS |
146 | /* IPI for X86 platform specific use */ |
147 | alloc_intr_gate(X86_PLATFORM_IPI_VECTOR, x86_platform_ipi); | |
d78f2664 YZ |
148 | #ifdef CONFIG_HAVE_KVM |
149 | /* IPI for KVM to deliver posted interrupt */ | |
150 | alloc_intr_gate(POSTED_INTR_VECTOR, kvm_posted_intr_ipi); | |
f6b3c72c FW |
151 | /* IPI for KVM to deliver interrupt to wake up tasks */ |
152 | alloc_intr_gate(POSTED_INTR_WAKEUP_VECTOR, kvm_posted_intr_wakeup_ipi); | |
d78f2664 | 153 | #endif |
acaabe79 | 154 | |
2ae111cd CG |
155 | /* IPI vectors for APIC spurious and error interrupts */ |
156 | alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); | |
157 | alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); | |
2ae111cd | 158 | |
e360adbe PZ |
159 | /* IRQ work interrupts: */ |
160 | # ifdef CONFIG_IRQ_WORK | |
161 | alloc_intr_gate(IRQ_WORK_VECTOR, irq_work_interrupt); | |
47f16ca7 IM |
162 | # endif |
163 | ||
2ae111cd | 164 | #endif |
22813c45 | 165 | } |
2ae111cd | 166 | |
22813c45 PE |
167 | void __init native_init_IRQ(void) |
168 | { | |
169 | int i; | |
170 | ||
171 | /* Execute any quirks before the call gates are initialised: */ | |
d9112f43 | 172 | x86_init.irqs.pre_vector_init(); |
22813c45 | 173 | |
77857dc0 YL |
174 | apic_intr_init(); |
175 | ||
22813c45 PE |
176 | /* |
177 | * Cover the whole vector space, no vector can escape | |
178 | * us. (some of these will be overridden and become | |
179 | * 'special' SMP interrupts) | |
180 | */ | |
0b2f4d4d | 181 | i = FIRST_EXTERNAL_VECTOR; |
2414e021 JB |
182 | #ifndef CONFIG_X86_LOCAL_APIC |
183 | #define first_system_vector NR_VECTORS | |
184 | #endif | |
185 | for_each_clear_bit_from(i, used_vectors, first_system_vector) { | |
77857dc0 | 186 | /* IA32_SYSCALL_VECTOR could be used in trap_init already. */ |
3304c9c3 DV |
187 | set_intr_gate(i, irq_entries_start + |
188 | 8 * (i - FIRST_EXTERNAL_VECTOR)); | |
22813c45 | 189 | } |
2414e021 JB |
190 | #ifdef CONFIG_X86_LOCAL_APIC |
191 | for_each_clear_bit_from(i, used_vectors, NR_VECTORS) | |
192 | set_intr_gate(i, spurious_interrupt); | |
193 | #endif | |
7856f6cc | 194 | |
a90b858c | 195 | if (!acpi_ioapic && !of_ioapic && nr_legacy_irqs()) |
2ae111cd CG |
196 | setup_irq(2, &irq2); |
197 | ||
320fd996 | 198 | #ifdef CONFIG_X86_32 |
1da177e4 | 199 | irq_ctx_init(smp_processor_id()); |
320fd996 | 200 | #endif |
1da177e4 | 201 | } |