diff options
Diffstat (limited to 'arch/x86/kernel/irqinit_64.c')
-rw-r--r-- | arch/x86/kernel/irqinit_64.c | 203 |
1 files changed, 203 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..64bc0f14285f --- /dev/null +++ b/arch/x86/kernel/irqinit_64.c | |||
@@ -0,0 +1,203 @@ | |||
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 BI(x,y) \ | ||
38 | BUILD_IRQ(x##y) | ||
39 | |||
40 | #define BUILD_16_IRQS(x) \ | ||
41 | BI(x,0) BI(x,1) BI(x,2) BI(x,3) \ | ||
42 | BI(x,4) BI(x,5) BI(x,6) BI(x,7) \ | ||
43 | BI(x,8) BI(x,9) BI(x,a) BI(x,b) \ | ||
44 | BI(x,c) BI(x,d) BI(x,e) BI(x,f) | ||
45 | |||
46 | /* | ||
47 | * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts: | ||
48 | * (these are usually mapped to vectors 0x30-0x3f) | ||
49 | */ | ||
50 | |||
51 | /* | ||
52 | * The IO-APIC gives us many more interrupt sources. Most of these | ||
53 | * are unused but an SMP system is supposed to have enough memory ... | ||
54 | * sometimes (mostly wrt. hw bugs) we get corrupted vectors all | ||
55 | * across the spectrum, so we really want to be prepared to get all | ||
56 | * of these. Plus, more powerful systems might have more than 64 | ||
57 | * IO-APIC registers. | ||
58 | * | ||
59 | * (these are usually mapped into the 0x30-0xff vector range) | ||
60 | */ | ||
61 | BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3) | ||
62 | BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7) | ||
63 | BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb) | ||
64 | BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf) | ||
65 | |||
66 | #undef BUILD_16_IRQS | ||
67 | #undef BI | ||
68 | |||
69 | |||
70 | #define IRQ(x,y) \ | ||
71 | IRQ##x##y##_interrupt | ||
72 | |||
73 | #define IRQLIST_16(x) \ | ||
74 | IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \ | ||
75 | IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \ | ||
76 | IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \ | ||
77 | IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f) | ||
78 | |||
79 | /* for the irq vectors */ | ||
80 | static void (*__initdata interrupt[NR_VECTORS - FIRST_EXTERNAL_VECTOR])(void) = { | ||
81 | IRQLIST_16(0x2), IRQLIST_16(0x3), | ||
82 | IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7), | ||
83 | IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb), | ||
84 | IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf) | ||
85 | }; | ||
86 | |||
87 | #undef IRQ | ||
88 | #undef IRQLIST_16 | ||
89 | |||
90 | |||
91 | |||
92 | |||
93 | /* | ||
94 | * IRQ2 is cascade interrupt to second interrupt controller | ||
95 | */ | ||
96 | |||
97 | static struct irqaction irq2 = { | ||
98 | .handler = no_action, | ||
99 | .mask = CPU_MASK_NONE, | ||
100 | .name = "cascade", | ||
101 | }; | ||
102 | DEFINE_PER_CPU(vector_irq_t, vector_irq) = { | ||
103 | [0 ... IRQ0_VECTOR - 1] = -1, | ||
104 | [IRQ0_VECTOR] = 0, | ||
105 | [IRQ1_VECTOR] = 1, | ||
106 | [IRQ2_VECTOR] = 2, | ||
107 | [IRQ3_VECTOR] = 3, | ||
108 | [IRQ4_VECTOR] = 4, | ||
109 | [IRQ5_VECTOR] = 5, | ||
110 | [IRQ6_VECTOR] = 6, | ||
111 | [IRQ7_VECTOR] = 7, | ||
112 | [IRQ8_VECTOR] = 8, | ||
113 | [IRQ9_VECTOR] = 9, | ||
114 | [IRQ10_VECTOR] = 10, | ||
115 | [IRQ11_VECTOR] = 11, | ||
116 | [IRQ12_VECTOR] = 12, | ||
117 | [IRQ13_VECTOR] = 13, | ||
118 | [IRQ14_VECTOR] = 14, | ||
119 | [IRQ15_VECTOR] = 15, | ||
120 | [IRQ15_VECTOR + 1 ... NR_VECTORS - 1] = -1 | ||
121 | }; | ||
122 | |||
123 | static void __init init_ISA_irqs (void) | ||
124 | { | ||
125 | int i; | ||
126 | |||
127 | init_bsp_APIC(); | ||
128 | init_8259A(0); | ||
129 | |||
130 | for (i = 0; i < NR_IRQS; i++) { | ||
131 | irq_desc[i].status = IRQ_DISABLED; | ||
132 | irq_desc[i].action = NULL; | ||
133 | irq_desc[i].depth = 1; | ||
134 | |||
135 | if (i < 16) { | ||
136 | /* | ||
137 | * 16 old-style INTA-cycle interrupts: | ||
138 | */ | ||
139 | set_irq_chip_and_handler_name(i, &i8259A_chip, | ||
140 | handle_level_irq, "XT"); | ||
141 | } else { | ||
142 | /* | ||
143 | * 'high' PCI IRQs filled in on demand | ||
144 | */ | ||
145 | irq_desc[i].chip = &no_irq_chip; | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | |||
150 | void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ"))); | ||
151 | |||
152 | void __init native_init_IRQ(void) | ||
153 | { | ||
154 | int i; | ||
155 | |||
156 | init_ISA_irqs(); | ||
157 | /* | ||
158 | * Cover the whole vector space, no vector can escape | ||
159 | * us. (some of these will be overridden and become | ||
160 | * 'special' SMP interrupts) | ||
161 | */ | ||
162 | for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) { | ||
163 | int vector = FIRST_EXTERNAL_VECTOR + i; | ||
164 | if (vector != IA32_SYSCALL_VECTOR) | ||
165 | set_intr_gate(vector, interrupt[i]); | ||
166 | } | ||
167 | |||
168 | #ifdef CONFIG_SMP | ||
169 | /* | ||
170 | * The reschedule interrupt is a CPU-to-CPU reschedule-helper | ||
171 | * IPI, driven by wakeup. | ||
172 | */ | ||
173 | set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); | ||
174 | |||
175 | /* IPIs for invalidation */ | ||
176 | set_intr_gate(INVALIDATE_TLB_VECTOR_START+0, invalidate_interrupt0); | ||
177 | set_intr_gate(INVALIDATE_TLB_VECTOR_START+1, invalidate_interrupt1); | ||
178 | set_intr_gate(INVALIDATE_TLB_VECTOR_START+2, invalidate_interrupt2); | ||
179 | set_intr_gate(INVALIDATE_TLB_VECTOR_START+3, invalidate_interrupt3); | ||
180 | set_intr_gate(INVALIDATE_TLB_VECTOR_START+4, invalidate_interrupt4); | ||
181 | set_intr_gate(INVALIDATE_TLB_VECTOR_START+5, invalidate_interrupt5); | ||
182 | set_intr_gate(INVALIDATE_TLB_VECTOR_START+6, invalidate_interrupt6); | ||
183 | set_intr_gate(INVALIDATE_TLB_VECTOR_START+7, invalidate_interrupt7); | ||
184 | |||
185 | /* IPI for generic function call */ | ||
186 | set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); | ||
187 | |||
188 | /* Low priority IPI to cleanup after moving an irq */ | ||
189 | set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt); | ||
190 | #endif | ||
191 | set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); | ||
192 | set_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt); | ||
193 | |||
194 | /* self generated IPI for local APIC timer */ | ||
195 | set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); | ||
196 | |||
197 | /* IPI vectors for APIC spurious and error interrupts */ | ||
198 | set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); | ||
199 | set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); | ||
200 | |||
201 | if (!acpi_ioapic) | ||
202 | setup_irq(2, &irq2); | ||
203 | } | ||