blob: 1870e0e86559157476266805978bd6c2b66a415c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#include <linux/linkage.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07002#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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#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>
Paul Jimenez2b8e05b2008-01-30 13:30:29 +010024#include <asm/i8259.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
Linus Torvalds1da177e2005-04-16 15:20:36 -070026/*
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
Thomas Gleixner0bc471d2008-05-02 21:55:12 +020037#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
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#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
Linus Torvalds1da177e2005-04-16 15:20:36 -070060/*
61 * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
Yinghai Luc97beb42007-03-28 23:10:29 -060062 * (these are usually mapped to vectors 0x30-0x3f)
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Linus Torvalds1da177e2005-04-16 15:20:36 -070065/*
Paul Jimenez2b8e05b2008-01-30 13:30:29 +010066 * The IO-APIC gives us many more interrupt sources. Most of these
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 * 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 */
Eric W. Biedermane500f572006-10-04 02:16:50 -070075 BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
Linus Torvalds1da177e2005-04-16 15:20:36 -070076BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)
77BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)
Eric W. Biedermane500f572006-10-04 02:16:50 -070078BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Linus Torvalds1da177e2005-04-16 15:20:36 -070080#undef BUILD_16_IRQS
Linus Torvalds1da177e2005-04-16 15:20:36 -070081#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
Yinghai Lu8fb6e5f2006-12-07 02:14:12 +010093/* for the irq vectors */
Jan Beulich3e7622f2008-01-30 13:31:23 +010094static void (*__initdata interrupt[NR_VECTORS - FIRST_EXTERNAL_VECTOR])(void) = {
Eric W. Biedermane500f572006-10-04 02:16:50 -070095 IRQLIST_16(0x2), IRQLIST_16(0x3),
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 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),
Eric W. Biedermane500f572006-10-04 02:16:50 -070098 IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070099};
100
101#undef IRQ
102#undef IRQLIST_16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
104/*
105 * This is the 'legacy' 8259A Programmable Interrupt Controller,
106 * present in the majority of PC/AT boxes.
107 * plus some generic x86 specific things if generic specifics makes
108 * any sense at all.
109 * this file should become arch/i386/kernel/irq.c when the old irq.c
110 * moves to arch independent land
111 */
112
Matthew Garrett35d534a2006-09-26 10:52:41 +0200113static int i8259A_auto_eoi;
Ingo Molnarf29bd1b2006-10-04 02:16:25 -0700114DEFINE_SPINLOCK(i8259A_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115static void mask_and_ack_8259A(unsigned int);
116
Ingo Molnarf29bd1b2006-10-04 02:16:25 -0700117static struct irq_chip i8259A_chip = {
118 .name = "XT-PIC",
119 .mask = disable_8259A_irq,
Ingo Molnar76d21602007-02-16 01:28:24 -0800120 .disable = disable_8259A_irq,
Ingo Molnarf29bd1b2006-10-04 02:16:25 -0700121 .unmask = enable_8259A_irq,
122 .mask_ack = mask_and_ack_8259A,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123};
124
125/*
126 * 8259A PIC functions to handle ISA devices:
127 */
128
129/*
130 * This contains the irq mask for both 8259A irq controllers,
131 */
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100132unsigned int cached_irq_mask = 0xffff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
134/*
135 * Not all IRQs can be routed through the IO-APIC, eg. on certain (older)
136 * boards the timer interrupt is not really connected to any IO-APIC pin,
137 * it's fed to the master 8259A's IR0 line only.
138 *
139 * Any '1' bit in this mask means the IRQ is routed through the IO-APIC.
140 * this 'mixed mode' IRQ handling costs nothing because it's only used
141 * at IRQ setup time.
142 */
143unsigned long io_apic_irqs;
144
145void disable_8259A_irq(unsigned int irq)
146{
147 unsigned int mask = 1 << irq;
148 unsigned long flags;
149
150 spin_lock_irqsave(&i8259A_lock, flags);
151 cached_irq_mask |= mask;
152 if (irq & 8)
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100153 outb(cached_slave_mask, PIC_SLAVE_IMR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 else
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100155 outb(cached_master_mask, PIC_MASTER_IMR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 spin_unlock_irqrestore(&i8259A_lock, flags);
157}
158
159void enable_8259A_irq(unsigned int irq)
160{
161 unsigned int mask = ~(1 << irq);
162 unsigned long flags;
163
164 spin_lock_irqsave(&i8259A_lock, flags);
165 cached_irq_mask &= mask;
166 if (irq & 8)
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100167 outb(cached_slave_mask, PIC_SLAVE_IMR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 else
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100169 outb(cached_master_mask, PIC_MASTER_IMR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 spin_unlock_irqrestore(&i8259A_lock, flags);
171}
172
173int i8259A_irq_pending(unsigned int irq)
174{
175 unsigned int mask = 1<<irq;
176 unsigned long flags;
177 int ret;
178
179 spin_lock_irqsave(&i8259A_lock, flags);
180 if (irq < 8)
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100181 ret = inb(PIC_MASTER_CMD) & mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 else
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100183 ret = inb(PIC_SLAVE_CMD) & (mask >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 spin_unlock_irqrestore(&i8259A_lock, flags);
185
186 return ret;
187}
188
189void make_8259A_irq(unsigned int irq)
190{
191 disable_irq_nosync(irq);
192 io_apic_irqs &= ~(1<<irq);
Ingo Molnara460e742006-10-17 00:10:03 -0700193 set_irq_chip_and_handler_name(irq, &i8259A_chip, handle_level_irq,
194 "XT");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 enable_irq(irq);
196}
197
198/*
199 * This function assumes to be called rarely. Switching between
200 * 8259A registers is slow.
201 * This has to be protected by the irq controller spinlock
202 * before being called.
203 */
204static inline int i8259A_irq_real(unsigned int irq)
205{
206 int value;
207 int irqmask = 1<<irq;
208
209 if (irq < 8) {
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100210 outb(0x0B,PIC_MASTER_CMD); /* ISR register */
211 value = inb(PIC_MASTER_CMD) & irqmask;
212 outb(0x0A,PIC_MASTER_CMD); /* back to the IRR register */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 return value;
214 }
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100215 outb(0x0B,PIC_SLAVE_CMD); /* ISR register */
216 value = inb(PIC_SLAVE_CMD) & (irqmask >> 8);
217 outb(0x0A,PIC_SLAVE_CMD); /* back to the IRR register */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 return value;
219}
220
221/*
222 * Careful! The 8259A is a fragile beast, it pretty
223 * much _has_ to be done exactly like this (mask it
224 * first, _then_ send the EOI, and the order of EOI
225 * to the two 8259s is important!
226 */
227static void mask_and_ack_8259A(unsigned int irq)
228{
229 unsigned int irqmask = 1 << irq;
230 unsigned long flags;
231
232 spin_lock_irqsave(&i8259A_lock, flags);
233 /*
234 * Lightweight spurious IRQ detection. We do not want
235 * to overdo spurious IRQ handling - it's usually a sign
236 * of hardware problems, so we only do the checks we can
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200237 * do without slowing down good hardware unnecessarily.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 *
239 * Note that IRQ7 and IRQ15 (the two spurious IRQs
240 * usually resulting from the 8259A-1|2 PICs) occur
241 * even if the IRQ is masked in the 8259A. Thus we
242 * can check spurious 8259A IRQs without doing the
243 * quite slow i8259A_irq_real() call for every IRQ.
244 * This does not cover 100% of spurious interrupts,
245 * but should be enough to warn the user that there
246 * is something bad going on ...
247 */
248 if (cached_irq_mask & irqmask)
249 goto spurious_8259A_irq;
250 cached_irq_mask |= irqmask;
251
252handle_real_irq:
253 if (irq & 8) {
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100254 inb(PIC_SLAVE_IMR); /* DUMMY - (do we need this?) */
255 outb(cached_slave_mask, PIC_SLAVE_IMR);
256 /* 'Specific EOI' to slave */
257 outb(0x60+(irq&7),PIC_SLAVE_CMD);
258 /* 'Specific EOI' to master-IRQ2 */
259 outb(0x60+PIC_CASCADE_IR,PIC_MASTER_CMD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 } else {
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100261 inb(PIC_MASTER_IMR); /* DUMMY - (do we need this?) */
262 outb(cached_master_mask, PIC_MASTER_IMR);
263 /* 'Specific EOI' to master */
264 outb(0x60+irq,PIC_MASTER_CMD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 }
266 spin_unlock_irqrestore(&i8259A_lock, flags);
267 return;
268
269spurious_8259A_irq:
270 /*
271 * this is the slow path - should happen rarely.
272 */
273 if (i8259A_irq_real(irq))
274 /*
275 * oops, the IRQ _is_ in service according to the
276 * 8259A - not spurious, go handle it.
277 */
278 goto handle_real_irq;
279
280 {
281 static int spurious_irq_mask;
282 /*
283 * At this point we can be sure the IRQ is spurious,
284 * lets ACK and report it. [once per IRQ]
285 */
286 if (!(spurious_irq_mask & irqmask)) {
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100287 printk(KERN_DEBUG
288 "spurious 8259A interrupt: IRQ%d.\n", irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 spurious_irq_mask |= irqmask;
290 }
291 atomic_inc(&irq_err_count);
292 /*
293 * Theoretically we do not have to handle this IRQ,
294 * but in Linux this does not cause problems and is
295 * simpler for us.
296 */
297 goto handle_real_irq;
298 }
299}
300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301static char irq_trigger[2];
302/**
303 * ELCR registers (0x4d0, 0x4d1) control edge/level of IRQ
304 */
305static void restore_ELCR(char *trigger)
306{
307 outb(trigger[0], 0x4d0);
308 outb(trigger[1], 0x4d1);
309}
310
311static void save_ELCR(char *trigger)
312{
313 /* IRQ 0,1,2,8,13 are marked as reserved */
314 trigger[0] = inb(0x4d0) & 0xF8;
315 trigger[1] = inb(0x4d1) & 0xDE;
316}
317
318static int i8259A_resume(struct sys_device *dev)
319{
Matthew Garrett35d534a2006-09-26 10:52:41 +0200320 init_8259A(i8259A_auto_eoi);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 restore_ELCR(irq_trigger);
322 return 0;
323}
324
Pavel Machek0b9c33a2005-04-16 15:25:31 -0700325static int i8259A_suspend(struct sys_device *dev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326{
327 save_ELCR(irq_trigger);
328 return 0;
329}
330
Eric W. Biederman719e7112005-06-25 14:57:43 -0700331static int i8259A_shutdown(struct sys_device *dev)
332{
333 /* Put the i8259A into a quiescent state that
334 * the kernel initialization code can get it
335 * out of.
336 */
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100337 outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */
338 outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-1 */
Eric W. Biederman719e7112005-06-25 14:57:43 -0700339 return 0;
340}
341
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342static struct sysdev_class i8259_sysdev_class = {
Kay Sieversaf5ca3f2007-12-20 02:09:39 +0100343 .name = "i8259",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 .suspend = i8259A_suspend,
345 .resume = i8259A_resume,
Eric W. Biederman719e7112005-06-25 14:57:43 -0700346 .shutdown = i8259A_shutdown,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347};
348
349static struct sys_device device_i8259A = {
350 .id = 0,
351 .cls = &i8259_sysdev_class,
352};
353
354static int __init i8259A_init_sysfs(void)
355{
356 int error = sysdev_class_register(&i8259_sysdev_class);
357 if (!error)
358 error = sysdev_register(&device_i8259A);
359 return error;
360}
361
362device_initcall(i8259A_init_sysfs);
363
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100364void init_8259A(int auto_eoi)
365{
366 unsigned long flags;
367
368 i8259A_auto_eoi = auto_eoi;
369
370 spin_lock_irqsave(&i8259A_lock, flags);
371
372 outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */
373 outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */
374
375 /*
Alan Cox466eed22008-01-30 13:33:14 +0100376 * outb_pic - this has to work on a wide range of PC hardware.
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100377 */
Alan Cox466eed22008-01-30 13:33:14 +0100378 outb_pic(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100379 /* ICW2: 8259A-1 IR0-7 mapped to 0x30-0x37 */
Alan Cox466eed22008-01-30 13:33:14 +0100380 outb_pic(IRQ0_VECTOR, PIC_MASTER_IMR);
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100381 /* 8259A-1 (the master) has a slave on IR2 */
Alan Cox466eed22008-01-30 13:33:14 +0100382 outb_pic(0x04, PIC_MASTER_IMR);
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100383 if (auto_eoi) /* master does Auto EOI */
Alan Cox466eed22008-01-30 13:33:14 +0100384 outb_pic(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR);
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100385 else /* master expects normal EOI */
Alan Cox466eed22008-01-30 13:33:14 +0100386 outb_pic(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR);
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100387
Alan Cox466eed22008-01-30 13:33:14 +0100388 outb_pic(0x11, PIC_SLAVE_CMD); /* ICW1: select 8259A-2 init */
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100389 /* ICW2: 8259A-2 IR0-7 mapped to 0x38-0x3f */
Alan Cox466eed22008-01-30 13:33:14 +0100390 outb_pic(IRQ8_VECTOR, PIC_SLAVE_IMR);
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100391 /* 8259A-2 is a slave on master's IR2 */
Alan Cox466eed22008-01-30 13:33:14 +0100392 outb_pic(PIC_CASCADE_IR, PIC_SLAVE_IMR);
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100393 /* (slave's support for AEOI in flat mode is to be investigated) */
Alan Cox466eed22008-01-30 13:33:14 +0100394 outb_pic(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR);
Paul Jimenez2b8e05b2008-01-30 13:30:29 +0100395
396 if (auto_eoi)
397 /*
398 * In AEOI mode we just have to mask the interrupt
399 * when acking.
400 */
401 i8259A_chip.mask_ack = disable_8259A_irq;
402 else
403 i8259A_chip.mask_ack = mask_and_ack_8259A;
404
405 udelay(100); /* wait for 8259A to initialize */
406
407 outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */
408 outb(cached_slave_mask, PIC_SLAVE_IMR); /* restore slave IRQ mask */
409
410 spin_unlock_irqrestore(&i8259A_lock, flags);
411}
412
413
414
415
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416/*
417 * IRQ2 is cascade interrupt to second interrupt controller
418 */
419
Thomas Gleixnerdf5ddf62007-10-17 18:04:36 +0200420static struct irqaction irq2 = {
421 .handler = no_action,
422 .mask = CPU_MASK_NONE,
423 .name = "cascade",
424};
Eric W. Biederman550f2292006-10-04 02:16:51 -0700425DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
Eric W. Biedermanbc5e81a2007-02-23 04:38:26 -0700426 [0 ... IRQ0_VECTOR - 1] = -1,
427 [IRQ0_VECTOR] = 0,
428 [IRQ1_VECTOR] = 1,
429 [IRQ2_VECTOR] = 2,
430 [IRQ3_VECTOR] = 3,
431 [IRQ4_VECTOR] = 4,
432 [IRQ5_VECTOR] = 5,
433 [IRQ6_VECTOR] = 6,
434 [IRQ7_VECTOR] = 7,
435 [IRQ8_VECTOR] = 8,
436 [IRQ9_VECTOR] = 9,
437 [IRQ10_VECTOR] = 10,
438 [IRQ11_VECTOR] = 11,
439 [IRQ12_VECTOR] = 12,
440 [IRQ13_VECTOR] = 13,
441 [IRQ14_VECTOR] = 14,
442 [IRQ15_VECTOR] = 15,
443 [IRQ15_VECTOR + 1 ... NR_VECTORS - 1] = -1
Eric W. Biedermane500f572006-10-04 02:16:50 -0700444};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
446void __init init_ISA_irqs (void)
447{
448 int i;
449
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 init_bsp_APIC();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 init_8259A(0);
452
453 for (i = 0; i < NR_IRQS; i++) {
454 irq_desc[i].status = IRQ_DISABLED;
455 irq_desc[i].action = NULL;
456 irq_desc[i].depth = 1;
457
458 if (i < 16) {
459 /*
460 * 16 old-style INTA-cycle interrupts:
461 */
Ingo Molnara460e742006-10-17 00:10:03 -0700462 set_irq_chip_and_handler_name(i, &i8259A_chip,
463 handle_level_irq, "XT");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 } else {
465 /*
466 * 'high' PCI IRQs filled in on demand
467 */
Ingo Molnarf29bd1b2006-10-04 02:16:25 -0700468 irq_desc[i].chip = &no_irq_chip;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 }
470 }
471}
472
Glauber de Oliveira Costab0387832008-01-30 13:33:19 +0100473void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ")));
474
475void __init native_init_IRQ(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476{
477 int i;
478
479 init_ISA_irqs();
480 /*
481 * Cover the whole vector space, no vector can escape
482 * us. (some of these will be overridden and become
483 * 'special' SMP interrupts)
484 */
485 for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
486 int vector = FIRST_EXTERNAL_VECTOR + i;
Andi Kleen915f34e2006-01-11 22:45:54 +0100487 if (vector != IA32_SYSCALL_VECTOR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 set_intr_gate(vector, interrupt[i]);
489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
491#ifdef CONFIG_SMP
492 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 * The reschedule interrupt is a CPU-to-CPU reschedule-helper
494 * IPI, driven by wakeup.
495 */
Alan Mayer305b92a2008-04-15 15:36:56 -0500496 alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
Andi Kleene5bc8b62005-09-12 18:49:24 +0200498 /* IPIs for invalidation */
Alan Mayer305b92a2008-04-15 15:36:56 -0500499 alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+0, invalidate_interrupt0);
500 alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+1, invalidate_interrupt1);
501 alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+2, invalidate_interrupt2);
502 alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+3, invalidate_interrupt3);
503 alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+4, invalidate_interrupt4);
504 alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+5, invalidate_interrupt5);
505 alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+6, invalidate_interrupt6);
506 alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+7, invalidate_interrupt7);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
508 /* IPI for generic function call */
Alan Mayer305b92a2008-04-15 15:36:56 -0500509 alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
Eric W. Biederman61014292007-02-23 04:40:58 -0700510
511 /* Low priority IPI to cleanup after moving an irq */
512 set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt);
513#endif
Alan Mayer305b92a2008-04-15 15:36:56 -0500514 alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
515 alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 /* self generated IPI for local APIC timer */
Alan Mayer305b92a2008-04-15 15:36:56 -0500518 alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
520 /* IPI vectors for APIC spurious and error interrupts */
Alan Mayer305b92a2008-04-15 15:36:56 -0500521 alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
522 alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 if (!acpi_ioapic)
525 setup_irq(2, &irq2);
526}