Blame view

arch/x86/kernel/irqinit.c 7.64 KB
778838600   Pekka Enberg   x86: unify trivia...
1
  #include <linux/linkage.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
  #include <linux/errno.h>
  #include <linux/signal.h>
  #include <linux/sched.h>
  #include <linux/ioport.h>
  #include <linux/interrupt.h>
778838600   Pekka Enberg   x86: unify trivia...
7
  #include <linux/timex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
  #include <linux/random.h>
47f16ca76   Ingo Molnar   x86, irqinit: pre...
9
  #include <linux/kprobes.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
  #include <linux/init.h>
  #include <linux/kernel_stat.h>
edbaa603e   Kay Sievers   driver-core: remo...
12
  #include <linux/device.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
  #include <linux/bitops.h>
778838600   Pekka Enberg   x86: unify trivia...
14
  #include <linux/acpi.h>
aa09e6cda   Jaswinder Singh Rajput   x86: irqinit_32.c...
15
16
  #include <linux/io.h>
  #include <linux/delay.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17

60063497a   Arun Sharma   atomic: use <linu...
18
  #include <linux/atomic.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
  #include <asm/system.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
  #include <asm/timer.h>
778838600   Pekka Enberg   x86: unify trivia...
21
  #include <asm/hw_irq.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  #include <asm/pgtable.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
  #include <asm/desc.h>
  #include <asm/apic.h>
8e6dafd6c   Ingo Molnar   x86: refactor x86...
25
  #include <asm/setup.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  #include <asm/i8259.h>
aa09e6cda   Jaswinder Singh Rajput   x86: irqinit_32.c...
27
  #include <asm/traps.h>
3879a6f32   Sebastian Andrzej Siewior   x86: dtb: Add ear...
28
  #include <asm/prom.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29

778838600   Pekka Enberg   x86: unify trivia...
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  /*
   * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
   * (these are usually mapped to vectors 0x30-0x3f)
   */
  
  /*
   * The IO-APIC gives us many more interrupt sources. Most of these
   * are unused but an SMP system is supposed to have enough memory ...
   * sometimes (mostly wrt. hw bugs) we get corrupted vectors all
   * across the spectrum, so we really want to be prepared to get all
   * of these. Plus, more powerful systems might have more than 64
   * IO-APIC registers.
   *
   * (these are usually mapped into the 0x30-0xff vector range)
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45

320fd9967   Pekka Enberg   x86: unify native...
46
  #ifdef CONFIG_X86_32
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
51
52
53
54
55
56
57
  /*
   * Note that on a 486, we don't want to do a SIGFPE on an irq13
   * as the irq is unreliable, and exception 16 works correctly
   * (ie as explained in the intel literature). On a 386, you
   * can't use exception 16 due to bad IBM design, so we have to
   * rely on the less exact irq13.
   *
   * Careful.. Not only is IRQ13 unreliable, but it is also
   * leads to races. IBM designers who came up with it should
   * be shot.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58

7d12e780e   David Howells   IRQ: Maintain reg...
59
  static irqreturn_t math_error_irq(int cpl, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
  {
aa09e6cda   Jaswinder Singh Rajput   x86: irqinit_32.c...
61
  	outb(0, 0xF0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
  	if (ignore_fpu_irq || !boot_cpu_data.hard_math)
  		return IRQ_NONE;
9b6dba9e0   Brian Gerst   x86: Merge simd_m...
64
  	math_error(get_irq_regs(), 0, 16);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
67
68
69
70
71
  	return IRQ_HANDLED;
  }
  
  /*
   * New motherboards sometimes make IRQ 13 be a PCI interrupt,
   * so allow interrupt sharing.
   */
6a61f6a55   Thomas Gleixner   x86: clean up str...
72
73
  static struct irqaction fpu_irq = {
  	.handler = math_error_irq,
6a61f6a55   Thomas Gleixner   x86: clean up str...
74
  	.name = "fpu",
9bbbff25b   Thomas Gleixner   x86: Mark low lev...
75
  	.flags = IRQF_NO_THREAD,
6a61f6a55   Thomas Gleixner   x86: clean up str...
76
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78

2ae111cdd   Cyrill Gorcunov   x86: apic interru...
79
80
81
82
83
  /*
   * IRQ2 is cascade interrupt to second interrupt controller
   */
  static struct irqaction irq2 = {
  	.handler = no_action,
2ae111cdd   Cyrill Gorcunov   x86: apic interru...
84
  	.name = "cascade",
9bbbff25b   Thomas Gleixner   x86: Mark low lev...
85
  	.flags = IRQF_NO_THREAD,
2ae111cdd   Cyrill Gorcunov   x86: apic interru...
86
  };
497c9a195   Yinghai Lu   x86: make 32bit s...
87
  DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
97943390b   Suresh Siddha   x86, irq: Don't b...
88
  	[0 ... NR_VECTORS - 1] = -1,
497c9a195   Yinghai Lu   x86: make 32bit s...
89
  };
b77b881f2   Yinghai Lu   x86: fix lguest u...
90
91
92
93
94
95
96
97
98
99
100
  int vector_used_by_percpu_irq(unsigned int vector)
  {
  	int cpu;
  
  	for_each_online_cpu(cpu) {
  		if (per_cpu(vector_irq, cpu)[vector] != -1)
  			return 1;
  	}
  
  	return 0;
  }
d9112f430   Thomas Gleixner   x86: Move pre_int...
101
  void __init init_ISA_irqs(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  {
011d578fd   Thomas Gleixner   x86: Remove usele...
103
104
  	struct irq_chip *chip = legacy_pic->chip;
  	const char *name = chip->name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  	int i;
598c73d25   Pekka Enberg   x86: unify init_I...
106
  #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
7371d9fcb   Pekka Enberg   x86: move init_IS...
107
108
  	init_bsp_APIC();
  #endif
b81bb373a   Jacob Pan   x86, pic: Make us...
109
  	legacy_pic->init(0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110

011d578fd   Thomas Gleixner   x86: Remove usele...
111
  	for (i = 0; i < legacy_pic->nr_legacy_irqs; i++)
2c778651f   Thomas Gleixner   x86: Cleanup the ...
112
  		irq_set_chip_and_handler_name(i, chip, handle_level_irq, name);
7371d9fcb   Pekka Enberg   x86: move init_IS...
113
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114

54e2603f1   Thomas Gleixner   x86: platform: Fi...
115
  void __init init_IRQ(void)
66bcaf0bd   Thomas Gleixner   x86: Move irq_ini...
116
  {
97943390b   Suresh Siddha   x86, irq: Don't b...
117
118
119
  	int i;
  
  	/*
bcc7c1244   Sebastian Andrzej Siewior   x86: ioapic: Add ...
120
121
122
123
124
125
  	 * We probably need a better place for this, but it works for
  	 * now ...
  	 */
  	x86_add_irq_domains();
  
  	/*
97943390b   Suresh Siddha   x86, irq: Don't b...
126
127
128
129
130
131
132
  	 * On cpu 0, Assign IRQ0_VECTOR..IRQ15_VECTOR's to IRQ 0..15.
  	 * If these IRQ's are handled by legacy interrupt-controllers like PIC,
  	 * then this configuration will likely be static after the boot. If
  	 * these IRQ's are handled by more mordern controllers like IO-APIC,
  	 * then this vector space can be freed and re-used dynamically as the
  	 * irq's migrate etc.
  	 */
28c6a0ba3   Yinghai Lu   x86, legacy_irq: ...
133
  	for (i = 0; i < legacy_pic->nr_legacy_irqs; i++)
97943390b   Suresh Siddha   x86, irq: Don't b...
134
  		per_cpu(vector_irq, 0)[IRQ0_VECTOR + i] = i;
66bcaf0bd   Thomas Gleixner   x86: Move irq_ini...
135
136
  	x86_init.irqs.intr_init();
  }
2ae111cdd   Cyrill Gorcunov   x86: apic interru...
137

36e9e1eab   Suresh Siddha   x86: Handle legac...
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  /*
   * Setup the vector to irq mappings.
   */
  void setup_vector_irq(int cpu)
  {
  #ifndef CONFIG_X86_IO_APIC
  	int irq;
  
  	/*
  	 * On most of the platforms, legacy PIC delivers the interrupts on the
  	 * boot cpu. But there are certain platforms where PIC interrupts are
  	 * delivered to multiple cpu's. If the legacy IRQ is handled by the
  	 * legacy PIC, for the new cpu that is coming online, setup the static
  	 * legacy vector to irq mapping:
  	 */
  	for (irq = 0; irq < legacy_pic->nr_legacy_irqs; irq++)
  		per_cpu(vector_irq, cpu)[IRQ0_VECTOR + irq] = irq;
  #endif
  
  	__setup_vector_irq(cpu);
  }
36290d87f   Pekka Enberg   x86: introduce sm...
159
160
  static void __init smp_intr_init(void)
  {
b0096bb0b   Pekka Enberg   x86: unify smp_in...
161
162
  #ifdef CONFIG_SMP
  #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
2ae111cdd   Cyrill Gorcunov   x86: apic interru...
163
164
165
166
167
  	/*
  	 * The reschedule interrupt is a CPU-to-CPU reschedule-helper
  	 * IPI, driven by wakeup.
  	 */
  	alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
02cf94c37   Tejun Heo   x86: make x86_32 ...
168
  	/* IPIs for invalidation */
3a09fb457   Shaohua Li   x86: Allocate 32 ...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
  #define ALLOC_INVTLB_VEC(NR) \
  	alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+NR, \
  		invalidate_interrupt##NR)
  
  	switch (NUM_INVALIDATE_TLB_VECTORS) {
  	default:
  		ALLOC_INVTLB_VEC(31);
  	case 31:
  		ALLOC_INVTLB_VEC(30);
  	case 30:
  		ALLOC_INVTLB_VEC(29);
  	case 29:
  		ALLOC_INVTLB_VEC(28);
  	case 28:
  		ALLOC_INVTLB_VEC(27);
  	case 27:
  		ALLOC_INVTLB_VEC(26);
  	case 26:
  		ALLOC_INVTLB_VEC(25);
  	case 25:
  		ALLOC_INVTLB_VEC(24);
  	case 24:
  		ALLOC_INVTLB_VEC(23);
  	case 23:
  		ALLOC_INVTLB_VEC(22);
  	case 22:
  		ALLOC_INVTLB_VEC(21);
  	case 21:
  		ALLOC_INVTLB_VEC(20);
  	case 20:
  		ALLOC_INVTLB_VEC(19);
  	case 19:
  		ALLOC_INVTLB_VEC(18);
  	case 18:
  		ALLOC_INVTLB_VEC(17);
  	case 17:
  		ALLOC_INVTLB_VEC(16);
  	case 16:
  		ALLOC_INVTLB_VEC(15);
  	case 15:
  		ALLOC_INVTLB_VEC(14);
  	case 14:
  		ALLOC_INVTLB_VEC(13);
  	case 13:
  		ALLOC_INVTLB_VEC(12);
  	case 12:
  		ALLOC_INVTLB_VEC(11);
  	case 11:
  		ALLOC_INVTLB_VEC(10);
  	case 10:
  		ALLOC_INVTLB_VEC(9);
  	case 9:
  		ALLOC_INVTLB_VEC(8);
  	case 8:
  		ALLOC_INVTLB_VEC(7);
  	case 7:
  		ALLOC_INVTLB_VEC(6);
  	case 6:
  		ALLOC_INVTLB_VEC(5);
  	case 5:
  		ALLOC_INVTLB_VEC(4);
  	case 4:
  		ALLOC_INVTLB_VEC(3);
  	case 3:
  		ALLOC_INVTLB_VEC(2);
  	case 2:
  		ALLOC_INVTLB_VEC(1);
  	case 1:
  		ALLOC_INVTLB_VEC(0);
  		break;
  	}
2ae111cdd   Cyrill Gorcunov   x86: apic interru...
240
241
242
  
  	/* IPI for generic function call */
  	alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
b0096bb0b   Pekka Enberg   x86: unify smp_in...
243
  	/* IPI for generic single function call */
b77b881f2   Yinghai Lu   x86: fix lguest u...
244
  	alloc_intr_gate(CALL_FUNCTION_SINGLE_VECTOR,
b0096bb0b   Pekka Enberg   x86: unify smp_in...
245
  			call_function_single_interrupt);
497c9a195   Yinghai Lu   x86: make 32bit s...
246
247
248
  
  	/* Low priority IPI to cleanup after moving an irq */
  	set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt);
b77b881f2   Yinghai Lu   x86: fix lguest u...
249
  	set_bit(IRQ_MOVE_CLEANUP_VECTOR, used_vectors);
4ef702c10   Andi Kleen   x86: fix panic wi...
250
251
252
  
  	/* IPI used for rebooting/stopping */
  	alloc_intr_gate(REBOOT_VECTOR, reboot_interrupt);
2ae111cdd   Cyrill Gorcunov   x86: apic interru...
253
  #endif
b0096bb0b   Pekka Enberg   x86: unify smp_in...
254
  #endif /* CONFIG_SMP */
36290d87f   Pekka Enberg   x86: introduce sm...
255
  }
22813c452   Pekka Enberg   x86: introduce ap...
256
  static void __init apic_intr_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
  {
36290d87f   Pekka Enberg   x86: introduce sm...
258
  	smp_intr_init();
2ae111cdd   Cyrill Gorcunov   x86: apic interru...
259

48b1fddbb   H. Peter Anvin   Merge branch 'irq...
260
  #ifdef CONFIG_X86_THERMAL_VECTOR
ab19c25ab   Pekka Enberg   x86: unify apic_i...
261
  	alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
48b1fddbb   H. Peter Anvin   Merge branch 'irq...
262
  #endif
6effa8f6f   Hidehiro Kawai   x86, mce: Rename ...
263
  #ifdef CONFIG_X86_MCE_THRESHOLD
ab19c25ab   Pekka Enberg   x86: unify apic_i...
264
265
266
267
  	alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
  #endif
  
  #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
2ae111cdd   Cyrill Gorcunov   x86: apic interru...
268
269
  	/* self generated IPI for local APIC timer */
  	alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
4a4de9c7d   Dimitri Sivanich   x86: UV RTC: Rena...
270
271
  	/* IPI for X86 platform specific use */
  	alloc_intr_gate(X86_PLATFORM_IPI_VECTOR, x86_platform_ipi);
acaabe795   Dimitri Sivanich   x86: UV, SGI RTC:...
272

2ae111cdd   Cyrill Gorcunov   x86: apic interru...
273
274
275
  	/* IPI vectors for APIC spurious and error interrupts */
  	alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
  	alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
2ae111cdd   Cyrill Gorcunov   x86: apic interru...
276

e360adbe2   Peter Zijlstra   irq_work: Add gen...
277
278
279
  	/* IRQ work interrupts: */
  # ifdef CONFIG_IRQ_WORK
  	alloc_intr_gate(IRQ_WORK_VECTOR, irq_work_interrupt);
47f16ca76   Ingo Molnar   x86, irqinit: pre...
280
  # endif
2ae111cdd   Cyrill Gorcunov   x86: apic interru...
281
  #endif
22813c452   Pekka Enberg   x86: introduce ap...
282
  }
2ae111cdd   Cyrill Gorcunov   x86: apic interru...
283

22813c452   Pekka Enberg   x86: introduce ap...
284
285
286
287
288
  void __init native_init_IRQ(void)
  {
  	int i;
  
  	/* Execute any quirks before the call gates are initialised: */
d9112f430   Thomas Gleixner   x86: Move pre_int...
289
  	x86_init.irqs.pre_vector_init();
22813c452   Pekka Enberg   x86: introduce ap...
290

77857dc07   Yinghai Lu   x86: use used_vec...
291
  	apic_intr_init();
22813c452   Pekka Enberg   x86: introduce ap...
292
293
294
295
296
  	/*
  	 * Cover the whole vector space, no vector can escape
  	 * us. (some of these will be overridden and become
  	 * 'special' SMP interrupts)
  	 */
d3496c85c   Pekka Enberg   x86: use identica...
297
  	for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) {
77857dc07   Yinghai Lu   x86: use used_vec...
298
299
  		/* IA32_SYSCALL_VECTOR could be used in trap_init already. */
  		if (!test_bit(i, used_vectors))
320fd9967   Pekka Enberg   x86: unify native...
300
  			set_intr_gate(i, interrupt[i-FIRST_EXTERNAL_VECTOR]);
22813c452   Pekka Enberg   x86: introduce ap...
301
  	}
7856f6cce   Andi Kleen   x86, mce: enable ...
302

3879a6f32   Sebastian Andrzej Siewior   x86: dtb: Add ear...
303
  	if (!acpi_ioapic && !of_ioapic)
2ae111cdd   Cyrill Gorcunov   x86: apic interru...
304
  		setup_irq(2, &irq2);
320fd9967   Pekka Enberg   x86: unify native...
305
  #ifdef CONFIG_X86_32
8e6dafd6c   Ingo Molnar   x86: refactor x86...
306
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
309
310
311
312
313
  	 * External FPU? Set up irq13 if so, for
  	 * original braindamaged IBM FERR coupling.
  	 */
  	if (boot_cpu_data.hard_math && !cpu_has_fpu)
  		setup_irq(FPU_IRQ, &fpu_irq);
  
  	irq_ctx_init(smp_processor_id());
320fd9967   Pekka Enberg   x86: unify native...
314
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
  }