diff options
Diffstat (limited to 'arch/x86/kernel/irqinit_64.c')
-rw-r--r-- | arch/x86/kernel/irqinit_64.c | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/arch/x86/kernel/irqinit_64.c b/arch/x86/kernel/irqinit_64.c new file mode 100644 index 000000000000..31f49e8f46a7 --- /dev/null +++ b/arch/x86/kernel/irqinit_64.c | |||
@@ -0,0 +1,217 @@ | |||
1 | #include <linux/linkage.h> | ||
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> | ||
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> | ||
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> | ||
24 | #include <asm/i8259.h> | ||
25 | |||
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 | |||
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 | |||
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 | |||
60 | /* | ||
61 | * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts: | ||
62 | * (these are usually mapped to vectors 0x30-0x3f) | ||
63 | */ | ||
64 | |||
65 | /* | ||
66 | * The IO-APIC gives us many more interrupt sources. Most of these | ||
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 | */ | ||
75 | BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3) | ||
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) | ||
78 | BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf) | ||
79 | |||
80 | #undef BUILD_16_IRQS | ||
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 | |||
93 | /* for the irq vectors */ | ||
94 | static void (*__initdata interrupt[NR_VECTORS - FIRST_EXTERNAL_VECTOR])(void) = { | ||
95 | IRQLIST_16(0x2), IRQLIST_16(0x3), | ||
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), | ||
98 | IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf) | ||
99 | }; | ||
100 | |||
101 | #undef IRQ | ||
102 | #undef IRQLIST_16 | ||
103 | |||
104 | |||
105 | |||
106 | |||
107 | /* | ||
108 | * IRQ2 is cascade interrupt to second interrupt controller | ||
109 | */ | ||
110 | |||
111 | static struct irqaction irq2 = { | ||
112 | .handler = no_action, | ||
113 | .mask = CPU_MASK_NONE, | ||
114 | .name = "cascade", | ||
115 | }; | ||
116 | DEFINE_PER_CPU(vector_irq_t, vector_irq) = { | ||
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 | ||
135 | }; | ||
136 | |||
137 | static void __init init_ISA_irqs (void) | ||
138 | { | ||
139 | int i; | ||
140 | |||
141 | init_bsp_APIC(); | ||
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 | */ | ||
153 | set_irq_chip_and_handler_name(i, &i8259A_chip, | ||
154 | handle_level_irq, "XT"); | ||
155 | } else { | ||
156 | /* | ||
157 | * 'high' PCI IRQs filled in on demand | ||
158 | */ | ||
159 | irq_desc[i].chip = &no_irq_chip; | ||
160 | } | ||
161 | } | ||
162 | } | ||
163 | |||
164 | void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ"))); | ||
165 | |||
166 | void __init native_init_IRQ(void) | ||
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; | ||
178 | if (vector != IA32_SYSCALL_VECTOR) | ||
179 | set_intr_gate(vector, interrupt[i]); | ||
180 | } | ||
181 | |||
182 | #ifdef CONFIG_SMP | ||
183 | /* | ||
184 | * The reschedule interrupt is a CPU-to-CPU reschedule-helper | ||
185 | * IPI, driven by wakeup. | ||
186 | */ | ||
187 | alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); | ||
188 | |||
189 | /* IPIs for invalidation */ | ||
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); | ||
198 | |||
199 | /* IPI for generic function call */ | ||
200 | alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); | ||
201 | |||
202 | /* Low priority IPI to cleanup after moving an irq */ | ||
203 | set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt); | ||
204 | #endif | ||
205 | alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); | ||
206 | alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt); | ||
207 | |||
208 | /* self generated IPI for local APIC timer */ | ||
209 | alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); | ||
210 | |||
211 | /* IPI vectors for APIC spurious and error interrupts */ | ||
212 | alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); | ||
213 | alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); | ||
214 | |||
215 | if (!acpi_ioapic) | ||
216 | setup_irq(2, &irq2); | ||
217 | } | ||