blob: 339cf6f926dc96875e23b65815f3d98d582b946d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Intel IO-APIC support for multi-Pentium hosts.
3 *
4 * Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar, Hajnalka Szabo
5 *
6 * Many thanks to Stig Venaas for trying out countless experimental
7 * patches and reporting/debugging problems patiently!
8 *
9 * (c) 1999, Multiple IO-APIC support, developed by
10 * Ken-ichi Yaku <yaku@css1.kbnes.nec.co.jp> and
11 * Hidemi Kishimoto <kisimoto@css1.kbnes.nec.co.jp>,
12 * further tested and cleaned up by Zach Brown <zab@redhat.com>
13 * and Ingo Molnar <mingo@redhat.com>
14 *
15 * Fixes
16 * Maciej W. Rozycki : Bits for genuine 82489DX APICs;
17 * thanks to Eric Gilmore
18 * and Rolf G. Tews
19 * for testing these extensively
20 * Paul Diefenbaugh : Added full ACPI support
21 */
22
23#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/interrupt.h>
25#include <linux/init.h>
26#include <linux/delay.h>
27#include <linux/sched.h>
Eric W. Biederman589e3672006-10-04 02:16:42 -070028#include <linux/pci.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/mc146818rtc.h>
30#include <linux/acpi.h>
31#include <linux/sysdev.h>
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070032#include <linux/msi.h>
Eric W. Biederman95d77882006-10-04 02:17:01 -070033#include <linux/htirq.h>
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -070034#include <linux/dmar.h>
Julia Lawall1d16b532008-01-30 13:32:19 +010035#include <linux/jiffies.h>
Andi Kleenab688052006-02-16 23:42:04 +010036#ifdef CONFIG_ACPI
37#include <acpi/acpi_bus.h>
38#endif
Thomas Gleixner3e35a0e2008-01-30 13:30:19 +010039#include <linux/bootmem.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
Eric W. Biederman61014292007-02-23 04:40:58 -070041#include <asm/idle.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <asm/io.h>
43#include <asm/smp.h>
44#include <asm/desc.h>
45#include <asm/proto.h>
Andi Kleen8d916402005-05-31 14:39:26 -070046#include <asm/acpi.h>
Andi Kleenca8642f2006-01-11 22:44:27 +010047#include <asm/dma.h>
Don Zickus3e4ff112006-06-26 13:57:01 +020048#include <asm/nmi.h>
Eric W. Biederman589e3672006-10-04 02:16:42 -070049#include <asm/msidef.h>
Eric W. Biederman8b955b02006-10-04 02:16:55 -070050#include <asm/hypertransport.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
Glauber Costa5af55732008-03-25 13:28:56 -030052#include <mach_ipi.h>
Glauber Costadd46e3c2008-03-25 18:10:46 -030053#include <mach_apic.h>
Glauber Costa5af55732008-03-25 13:28:56 -030054
Eric W. Biederman13a79502007-02-23 04:32:47 -070055struct irq_cfg {
56 cpumask_t domain;
Eric W. Biederman61014292007-02-23 04:40:58 -070057 cpumask_t old_domain;
58 unsigned move_cleanup_count;
Eric W. Biederman13a79502007-02-23 04:32:47 -070059 u8 vector;
Eric W. Biederman61014292007-02-23 04:40:58 -070060 u8 move_in_progress : 1;
Eric W. Biederman13a79502007-02-23 04:32:47 -070061};
62
63/* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
64struct irq_cfg irq_cfg[NR_IRQS] __read_mostly = {
Eric W. Biedermanbc5e81a2007-02-23 04:38:26 -070065 [0] = { .domain = CPU_MASK_ALL, .vector = IRQ0_VECTOR, },
66 [1] = { .domain = CPU_MASK_ALL, .vector = IRQ1_VECTOR, },
67 [2] = { .domain = CPU_MASK_ALL, .vector = IRQ2_VECTOR, },
68 [3] = { .domain = CPU_MASK_ALL, .vector = IRQ3_VECTOR, },
69 [4] = { .domain = CPU_MASK_ALL, .vector = IRQ4_VECTOR, },
70 [5] = { .domain = CPU_MASK_ALL, .vector = IRQ5_VECTOR, },
71 [6] = { .domain = CPU_MASK_ALL, .vector = IRQ6_VECTOR, },
72 [7] = { .domain = CPU_MASK_ALL, .vector = IRQ7_VECTOR, },
73 [8] = { .domain = CPU_MASK_ALL, .vector = IRQ8_VECTOR, },
74 [9] = { .domain = CPU_MASK_ALL, .vector = IRQ9_VECTOR, },
75 [10] = { .domain = CPU_MASK_ALL, .vector = IRQ10_VECTOR, },
76 [11] = { .domain = CPU_MASK_ALL, .vector = IRQ11_VECTOR, },
77 [12] = { .domain = CPU_MASK_ALL, .vector = IRQ12_VECTOR, },
78 [13] = { .domain = CPU_MASK_ALL, .vector = IRQ13_VECTOR, },
79 [14] = { .domain = CPU_MASK_ALL, .vector = IRQ14_VECTOR, },
80 [15] = { .domain = CPU_MASK_ALL, .vector = IRQ15_VECTOR, },
Eric W. Biederman13a79502007-02-23 04:32:47 -070081};
82
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -070083static int assign_irq_vector(int irq, cpumask_t mask);
Eric W. Biederman04b92672006-10-04 02:16:46 -070084
Linus Torvalds1da177e2005-04-16 15:20:36 -070085#define __apicdebuginit __init
86
87int sis_apic_bug; /* not actually supported, dummy for compile */
88
Andi Kleen14d98ca2005-05-20 14:27:59 -070089static int no_timer_check;
90
Linus Torvaldsfea5f1e2007-01-08 15:04:46 -080091static int disable_timer_pin_1 __initdata;
92
93int timer_over_8254 __initdata = 1;
94
Eric W. Biederman1008fdd2006-01-11 22:46:06 +010095/* Where if anywhere is the i8259 connect in external int mode */
96static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
97
Linus Torvalds1da177e2005-04-16 15:20:36 -070098static DEFINE_SPINLOCK(ioapic_lock);
Eric W. Biederman70a0a532006-10-25 01:00:23 +020099DEFINE_SPINLOCK(vector_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
101/*
102 * # of IRQ routing registers
103 */
104int nr_ioapic_registers[MAX_IO_APICS];
105
Alexey Starikovskiy9c7408f32008-04-04 23:41:19 +0400106/* I/O APIC entries */
Alexey Starikovskiyec2cd0a2008-05-14 19:03:10 +0400107struct mp_config_ioapic mp_ioapics[MAX_IO_APICS];
Alexey Starikovskiy9c7408f32008-04-04 23:41:19 +0400108int nr_ioapics;
109
Alexey Starikovskiy350bae12008-04-04 23:41:38 +0400110/* MP IRQ source entries */
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400111struct mp_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
Alexey Starikovskiy350bae12008-04-04 23:41:38 +0400112
113/* # of MP IRQ source entries */
114int mp_irq_entries;
115
Alexey Starikovskiy8732fc42008-05-19 19:47:16 +0400116DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES);
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118/*
119 * Rough estimation of how many shared IRQs there are, can
120 * be changed anytime.
121 */
Eric W. Biedermane273d142007-02-23 04:26:53 -0700122#define MAX_PLUS_SHARED_IRQS NR_IRQS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
124
125/*
126 * This is performance-critical, we want to do it O(1)
127 *
128 * the indexing order of this array favors 1:1 mappings
129 * between pins and IRQs.
130 */
131
132static struct irq_pin_list {
133 short apic, pin, next;
134} irq_2_pin[PIN_MAP_SIZE];
135
Linus Torvalds6c0ffb92006-11-08 10:23:03 -0800136struct io_apic {
137 unsigned int index;
138 unsigned int unused[3];
139 unsigned int data;
140};
141
142static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx)
143{
144 return (void __iomem *) __fix_to_virt(FIX_IO_APIC_BASE_0 + idx)
Alexey Starikovskiyec2cd0a2008-05-14 19:03:10 +0400145 + (mp_ioapics[idx].mp_apicaddr & ~PAGE_MASK);
Linus Torvalds6c0ffb92006-11-08 10:23:03 -0800146}
147
148static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
149{
150 struct io_apic __iomem *io_apic = io_apic_base(apic);
151 writel(reg, &io_apic->index);
152 return readl(&io_apic->data);
153}
154
155static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
156{
157 struct io_apic __iomem *io_apic = io_apic_base(apic);
158 writel(reg, &io_apic->index);
159 writel(value, &io_apic->data);
160}
161
162/*
163 * Re-write a value: to be used for read-modify-write
164 * cycles where the read already set up the index register.
165 */
166static inline void io_apic_modify(unsigned int apic, unsigned int value)
167{
168 struct io_apic __iomem *io_apic = io_apic_base(apic);
169 writel(value, &io_apic->data);
170}
171
Akinobu Mita9d25cb02008-04-05 22:39:04 +0900172static bool io_apic_level_ack_pending(unsigned int irq)
Eric W. Biedermanef3e28c2007-07-21 17:10:45 +0200173{
174 struct irq_pin_list *entry;
175 unsigned long flags;
Eric W. Biedermanef3e28c2007-07-21 17:10:45 +0200176
177 spin_lock_irqsave(&ioapic_lock, flags);
178 entry = irq_2_pin + irq;
179 for (;;) {
180 unsigned int reg;
181 int pin;
182
183 pin = entry->pin;
184 if (pin == -1)
185 break;
186 reg = io_apic_read(entry->apic, 0x10 + pin*2);
187 /* Is the remote IRR bit set? */
Akinobu Mita9d25cb02008-04-05 22:39:04 +0900188 if ((reg >> 14) & 1) {
189 spin_unlock_irqrestore(&ioapic_lock, flags);
190 return true;
191 }
Eric W. Biedermanef3e28c2007-07-21 17:10:45 +0200192 if (!entry->next)
193 break;
194 entry = irq_2_pin + entry->next;
195 }
196 spin_unlock_irqrestore(&ioapic_lock, flags);
Akinobu Mita9d25cb02008-04-05 22:39:04 +0900197
198 return false;
Eric W. Biedermanef3e28c2007-07-21 17:10:45 +0200199}
200
Linus Torvalds6c0ffb92006-11-08 10:23:03 -0800201/*
202 * Synchronize the IO-APIC and the CPU by doing
203 * a dummy read from the IO-APIC
204 */
205static inline void io_apic_sync(unsigned int apic)
206{
207 struct io_apic __iomem *io_apic = io_apic_base(apic);
208 readl(&io_apic->data);
209}
210
Ashok Raj54d5d422005-09-06 15:16:15 -0700211#define __DO_ACTION(R, ACTION, FINAL) \
212 \
213{ \
214 int pin; \
215 struct irq_pin_list *entry = irq_2_pin + irq; \
216 \
James Cleverdon6004e1b2005-11-05 17:25:53 +0100217 BUG_ON(irq >= NR_IRQS); \
Ashok Raj54d5d422005-09-06 15:16:15 -0700218 for (;;) { \
219 unsigned int reg; \
220 pin = entry->pin; \
221 if (pin == -1) \
222 break; \
223 reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \
224 reg ACTION; \
225 io_apic_modify(entry->apic, reg); \
Eric W. Biedermanf45bcd72007-02-23 04:23:52 -0700226 FINAL; \
Ashok Raj54d5d422005-09-06 15:16:15 -0700227 if (!entry->next) \
228 break; \
229 entry = irq_2_pin + entry->next; \
230 } \
Ashok Raj54d5d422005-09-06 15:16:15 -0700231}
232
Andi Kleeneea0e112006-09-26 10:52:30 +0200233union entry_union {
234 struct { u32 w1, w2; };
235 struct IO_APIC_route_entry entry;
236};
237
238static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin)
239{
240 union entry_union eu;
241 unsigned long flags;
242 spin_lock_irqsave(&ioapic_lock, flags);
243 eu.w1 = io_apic_read(apic, 0x10 + 2 * pin);
244 eu.w2 = io_apic_read(apic, 0x11 + 2 * pin);
245 spin_unlock_irqrestore(&ioapic_lock, flags);
246 return eu.entry;
247}
248
Linus Torvalds48797eb2006-11-08 10:27:54 -0800249/*
250 * When we write a new IO APIC routing entry, we need to write the high
251 * word first! If the mask bit in the low word is clear, we will enable
252 * the interrupt, and we need to make sure the entry is fully populated
253 * before that happens.
254 */
Andi Kleen516d2832006-12-07 02:14:07 +0100255static void
256__ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
257{
258 union entry_union eu;
259 eu.entry = e;
260 io_apic_write(apic, 0x11 + 2*pin, eu.w2);
261 io_apic_write(apic, 0x10 + 2*pin, eu.w1);
262}
263
Andi Kleeneea0e112006-09-26 10:52:30 +0200264static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
265{
266 unsigned long flags;
Andi Kleeneea0e112006-09-26 10:52:30 +0200267 spin_lock_irqsave(&ioapic_lock, flags);
Andi Kleen516d2832006-12-07 02:14:07 +0100268 __ioapic_write_entry(apic, pin, e);
Linus Torvalds48797eb2006-11-08 10:27:54 -0800269 spin_unlock_irqrestore(&ioapic_lock, flags);
270}
271
272/*
273 * When we mask an IO APIC routing entry, we need to write the low
274 * word first, in order to set the mask bit before we change the
275 * high bits!
276 */
277static void ioapic_mask_entry(int apic, int pin)
278{
279 unsigned long flags;
280 union entry_union eu = { .entry.mask = 1 };
281
282 spin_lock_irqsave(&ioapic_lock, flags);
Andi Kleeneea0e112006-09-26 10:52:30 +0200283 io_apic_write(apic, 0x10 + 2*pin, eu.w1);
284 io_apic_write(apic, 0x11 + 2*pin, eu.w2);
285 spin_unlock_irqrestore(&ioapic_lock, flags);
286}
287
Ashok Raj54d5d422005-09-06 15:16:15 -0700288#ifdef CONFIG_SMP
Eric W. Biederman550f2292006-10-04 02:16:51 -0700289static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector)
290{
291 int apic, pin;
292 struct irq_pin_list *entry = irq_2_pin + irq;
293
294 BUG_ON(irq >= NR_IRQS);
295 for (;;) {
296 unsigned int reg;
297 apic = entry->apic;
298 pin = entry->pin;
299 if (pin == -1)
300 break;
301 io_apic_write(apic, 0x11 + pin*2, dest);
302 reg = io_apic_read(apic, 0x10 + pin*2);
303 reg &= ~0x000000ff;
304 reg |= vector;
305 io_apic_modify(apic, reg);
306 if (!entry->next)
307 break;
308 entry = irq_2_pin + entry->next;
309 }
310}
311
Ashok Raj54d5d422005-09-06 15:16:15 -0700312static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
313{
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -0700314 struct irq_cfg *cfg = irq_cfg + irq;
Ashok Raj54d5d422005-09-06 15:16:15 -0700315 unsigned long flags;
316 unsigned int dest;
317 cpumask_t tmp;
318
319 cpus_and(tmp, mask, cpu_online_map);
320 if (cpus_empty(tmp))
Eric W. Biederman5ff51152007-02-23 04:20:59 -0700321 return;
Ashok Raj54d5d422005-09-06 15:16:15 -0700322
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -0700323 if (assign_irq_vector(irq, mask))
Eric W. Biederman550f2292006-10-04 02:16:51 -0700324 return;
325
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -0700326 cpus_and(tmp, cfg->domain, mask);
Eric W. Biederman550f2292006-10-04 02:16:51 -0700327 dest = cpu_mask_to_apicid(tmp);
Ashok Raj54d5d422005-09-06 15:16:15 -0700328
329 /*
330 * Only the high 8 bits are valid.
331 */
332 dest = SET_APIC_LOGICAL_ID(dest);
333
334 spin_lock_irqsave(&ioapic_lock, flags);
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -0700335 __target_IO_APIC_irq(irq, dest, cfg->vector);
Eric W. Biederman9f0a5ba2007-02-23 04:13:55 -0700336 irq_desc[irq].affinity = mask;
Ashok Raj54d5d422005-09-06 15:16:15 -0700337 spin_unlock_irqrestore(&ioapic_lock, flags);
338}
339#endif
340
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341/*
342 * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
343 * shared ISA-space IRQs, so we have to support them. We are super
344 * fast in the common case, and fast for shared ISA-space IRQs.
345 */
346static void add_pin_to_irq(unsigned int irq, int apic, int pin)
347{
348 static int first_free_entry = NR_IRQS;
349 struct irq_pin_list *entry = irq_2_pin + irq;
350
James Cleverdon6004e1b2005-11-05 17:25:53 +0100351 BUG_ON(irq >= NR_IRQS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 while (entry->next)
353 entry = irq_2_pin + entry->next;
354
355 if (entry->pin != -1) {
356 entry->next = first_free_entry;
357 entry = irq_2_pin + entry->next;
358 if (++first_free_entry >= PIN_MAP_SIZE)
James Cleverdon6004e1b2005-11-05 17:25:53 +0100359 panic("io_apic.c: ran out of irq_2_pin entries!");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 }
361 entry->apic = apic;
362 entry->pin = pin;
363}
364
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366#define DO_ACTION(name,R,ACTION, FINAL) \
367 \
368 static void name##_IO_APIC_irq (unsigned int irq) \
369 __DO_ACTION(R, ACTION, FINAL)
370
371DO_ACTION( __mask, 0, |= 0x00010000, io_apic_sync(entry->apic) )
372 /* mask = 1 */
373DO_ACTION( __unmask, 0, &= 0xfffeffff, )
374 /* mask = 0 */
375
376static void mask_IO_APIC_irq (unsigned int irq)
377{
378 unsigned long flags;
379
380 spin_lock_irqsave(&ioapic_lock, flags);
381 __mask_IO_APIC_irq(irq);
382 spin_unlock_irqrestore(&ioapic_lock, flags);
383}
384
385static void unmask_IO_APIC_irq (unsigned int irq)
386{
387 unsigned long flags;
388
389 spin_lock_irqsave(&ioapic_lock, flags);
390 __unmask_IO_APIC_irq(irq);
391 spin_unlock_irqrestore(&ioapic_lock, flags);
392}
393
394static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
395{
396 struct IO_APIC_route_entry entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
398 /* Check delivery_mode to be sure we're not clearing an SMI pin */
Andi Kleeneea0e112006-09-26 10:52:30 +0200399 entry = ioapic_read_entry(apic, pin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 if (entry.delivery_mode == dest_SMI)
401 return;
402 /*
403 * Disable it in the IO-APIC irq-routing table:
404 */
Linus Torvalds48797eb2006-11-08 10:27:54 -0800405 ioapic_mask_entry(apic, pin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406}
407
408static void clear_IO_APIC (void)
409{
410 int apic, pin;
411
412 for (apic = 0; apic < nr_ioapics; apic++)
413 for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
414 clear_IO_APIC_pin(apic, pin);
415}
416
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417int skip_ioapic_setup;
418int ioapic_force;
419
Len Brown61ec7562007-08-16 03:34:22 -0400420static int __init parse_noapic(char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421{
Len Brown61ec7562007-08-16 03:34:22 -0400422 disable_ioapic_setup();
Andi Kleen2c8c0e62006-09-26 10:52:32 +0200423 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424}
Len Brown61ec7562007-08-16 03:34:22 -0400425early_param("noapic", parse_noapic);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
Linus Torvaldsfea5f1e2007-01-08 15:04:46 -0800427/* Actually the next is obsolete, but keep it for paranoid reasons -AK */
428static int __init disable_timer_pin_setup(char *arg)
429{
430 disable_timer_pin_1 = 1;
431 return 1;
432}
433__setup("disable_timer_pin_1", disable_timer_pin_setup);
434
435static int __init setup_disable_8254_timer(char *s)
436{
437 timer_over_8254 = -1;
438 return 1;
439}
440static int __init setup_enable_8254_timer(char *s)
441{
442 timer_over_8254 = 2;
443 return 1;
444}
445
446__setup("disable_8254_timer", setup_disable_8254_timer);
447__setup("enable_8254_timer", setup_enable_8254_timer);
448
449
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450/*
451 * Find the IRQ entry number of a certain pin.
452 */
453static int find_irq_entry(int apic, int pin, int type)
454{
455 int i;
456
457 for (i = 0; i < mp_irq_entries; i++)
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400458 if (mp_irqs[i].mp_irqtype == type &&
459 (mp_irqs[i].mp_dstapic == mp_ioapics[apic].mp_apicid ||
460 mp_irqs[i].mp_dstapic == MP_APIC_ALL) &&
461 mp_irqs[i].mp_dstirq == pin)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 return i;
463
464 return -1;
465}
466
467/*
468 * Find the pin to which IRQ[irq] (ISA) is connected
469 */
Eric W. Biederman1008fdd2006-01-11 22:46:06 +0100470static int __init find_isa_irq_pin(int irq, int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471{
472 int i;
473
474 for (i = 0; i < mp_irq_entries; i++) {
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400475 int lbus = mp_irqs[i].mp_srcbus;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
Andi Kleen55f05ff2006-09-26 10:52:30 +0200477 if (test_bit(lbus, mp_bus_not_pci) &&
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400478 (mp_irqs[i].mp_irqtype == type) &&
479 (mp_irqs[i].mp_srcbusirq == irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400481 return mp_irqs[i].mp_dstirq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 }
483 return -1;
484}
485
Eric W. Biederman1008fdd2006-01-11 22:46:06 +0100486static int __init find_isa_irq_apic(int irq, int type)
487{
488 int i;
489
490 for (i = 0; i < mp_irq_entries; i++) {
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400491 int lbus = mp_irqs[i].mp_srcbus;
Eric W. Biederman1008fdd2006-01-11 22:46:06 +0100492
Andi Kleen55f05ff2006-09-26 10:52:30 +0200493 if (test_bit(lbus, mp_bus_not_pci) &&
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400494 (mp_irqs[i].mp_irqtype == type) &&
495 (mp_irqs[i].mp_srcbusirq == irq))
Eric W. Biederman1008fdd2006-01-11 22:46:06 +0100496 break;
497 }
498 if (i < mp_irq_entries) {
499 int apic;
500 for(apic = 0; apic < nr_ioapics; apic++) {
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400501 if (mp_ioapics[apic].mp_apicid == mp_irqs[i].mp_dstapic)
Eric W. Biederman1008fdd2006-01-11 22:46:06 +0100502 return apic;
503 }
504 }
505
506 return -1;
507}
508
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509/*
510 * Find a specific PCI IRQ entry.
511 * Not an __init, possibly needed by modules
512 */
513static int pin_2_irq(int idx, int apic, int pin);
514
515int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
516{
517 int apic, i, best_guess = -1;
518
519 apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",
520 bus, slot, pin);
Alexey Starikovskiyce6444d2008-05-19 19:47:09 +0400521 if (test_bit(bus, mp_bus_not_pci)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 apic_printk(APIC_VERBOSE, "PCI BIOS passed nonexistent PCI bus %d!\n", bus);
523 return -1;
524 }
525 for (i = 0; i < mp_irq_entries; i++) {
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400526 int lbus = mp_irqs[i].mp_srcbus;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
528 for (apic = 0; apic < nr_ioapics; apic++)
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400529 if (mp_ioapics[apic].mp_apicid == mp_irqs[i].mp_dstapic ||
530 mp_irqs[i].mp_dstapic == MP_APIC_ALL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 break;
532
Andi Kleen55f05ff2006-09-26 10:52:30 +0200533 if (!test_bit(lbus, mp_bus_not_pci) &&
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400534 !mp_irqs[i].mp_irqtype &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 (bus == lbus) &&
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400536 (slot == ((mp_irqs[i].mp_srcbusirq >> 2) & 0x1f))) {
537 int irq = pin_2_irq(i,apic,mp_irqs[i].mp_dstirq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
539 if (!(apic || IO_APIC_IRQ(irq)))
540 continue;
541
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400542 if (pin == (mp_irqs[i].mp_srcbusirq & 3))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 return irq;
544 /*
545 * Use the first all-but-pin matching entry as a
546 * best-guess fuzzy result for broken mptables.
547 */
548 if (best_guess < 0)
549 best_guess = irq;
550 }
551 }
James Cleverdon6004e1b2005-11-05 17:25:53 +0100552 BUG_ON(best_guess >= NR_IRQS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 return best_guess;
554}
555
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556/* ISA interrupts are always polarity zero edge triggered,
557 * when listed as conforming in the MP table. */
558
559#define default_ISA_trigger(idx) (0)
560#define default_ISA_polarity(idx) (0)
561
562/* PCI interrupts are always polarity one level triggered,
563 * when listed as conforming in the MP table. */
564
565#define default_PCI_trigger(idx) (1)
566#define default_PCI_polarity(idx) (1)
567
Shaohua Li61fd47e2007-11-17 01:05:28 -0500568static int MPBIOS_polarity(int idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569{
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400570 int bus = mp_irqs[idx].mp_srcbus;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 int polarity;
572
573 /*
574 * Determine IRQ line polarity (high active or low active):
575 */
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400576 switch (mp_irqs[idx].mp_irqflag & 3)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 {
578 case 0: /* conforms, ie. bus-type dependent polarity */
Andi Kleen55f05ff2006-09-26 10:52:30 +0200579 if (test_bit(bus, mp_bus_not_pci))
580 polarity = default_ISA_polarity(idx);
581 else
582 polarity = default_PCI_polarity(idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 case 1: /* high active */
585 {
586 polarity = 0;
587 break;
588 }
589 case 2: /* reserved */
590 {
591 printk(KERN_WARNING "broken BIOS!!\n");
592 polarity = 1;
593 break;
594 }
595 case 3: /* low active */
596 {
597 polarity = 1;
598 break;
599 }
600 default: /* invalid */
601 {
602 printk(KERN_WARNING "broken BIOS!!\n");
603 polarity = 1;
604 break;
605 }
606 }
607 return polarity;
608}
609
610static int MPBIOS_trigger(int idx)
611{
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400612 int bus = mp_irqs[idx].mp_srcbus;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 int trigger;
614
615 /*
616 * Determine IRQ trigger mode (edge or level sensitive):
617 */
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400618 switch ((mp_irqs[idx].mp_irqflag>>2) & 3)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 {
620 case 0: /* conforms, ie. bus-type dependent */
Andi Kleen55f05ff2006-09-26 10:52:30 +0200621 if (test_bit(bus, mp_bus_not_pci))
622 trigger = default_ISA_trigger(idx);
623 else
624 trigger = default_PCI_trigger(idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 case 1: /* edge */
627 {
628 trigger = 0;
629 break;
630 }
631 case 2: /* reserved */
632 {
633 printk(KERN_WARNING "broken BIOS!!\n");
634 trigger = 1;
635 break;
636 }
637 case 3: /* level */
638 {
639 trigger = 1;
640 break;
641 }
642 default: /* invalid */
643 {
644 printk(KERN_WARNING "broken BIOS!!\n");
645 trigger = 0;
646 break;
647 }
648 }
649 return trigger;
650}
651
652static inline int irq_polarity(int idx)
653{
654 return MPBIOS_polarity(idx);
655}
656
657static inline int irq_trigger(int idx)
658{
659 return MPBIOS_trigger(idx);
660}
661
662static int pin_2_irq(int idx, int apic, int pin)
663{
664 int irq, i;
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400665 int bus = mp_irqs[idx].mp_srcbus;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
667 /*
668 * Debugging check, we are in big trouble if this message pops up!
669 */
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400670 if (mp_irqs[idx].mp_dstirq != pin)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n");
672
Andi Kleen55f05ff2006-09-26 10:52:30 +0200673 if (test_bit(bus, mp_bus_not_pci)) {
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +0400674 irq = mp_irqs[idx].mp_srcbusirq;
Andi Kleen55f05ff2006-09-26 10:52:30 +0200675 } else {
676 /*
677 * PCI IRQs are mapped in order
678 */
679 i = irq = 0;
680 while (i < apic)
681 irq += nr_ioapic_registers[i++];
682 irq += pin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 }
James Cleverdon6004e1b2005-11-05 17:25:53 +0100684 BUG_ON(irq >= NR_IRQS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 return irq;
686}
687
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -0700688static int __assign_irq_vector(int irq, cpumask_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689{
Eric W. Biederman550f2292006-10-04 02:16:51 -0700690 /*
691 * NOTE! The local APIC isn't very good at handling
692 * multiple interrupts at the same interrupt level.
693 * As the interrupt level is determined by taking the
694 * vector number and shifting that right by 4, we
695 * want to spread these out a bit so that they don't
696 * all fall in the same interrupt level.
697 *
698 * Also, we've got to be careful not to trash gate
699 * 0x80, because int 0x80 is hm, kind of importantish. ;)
700 */
Eric W. Biedermand1752aa2006-10-25 01:00:22 +0200701 static int current_vector = FIRST_DEVICE_VECTOR, current_offset = 0;
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -0700702 unsigned int old_vector;
Eric W. Biederman550f2292006-10-04 02:16:51 -0700703 int cpu;
Eric W. Biederman13a79502007-02-23 04:32:47 -0700704 struct irq_cfg *cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
Eric W. Biedermane273d142007-02-23 04:26:53 -0700706 BUG_ON((unsigned)irq >= NR_IRQS);
Eric W. Biederman13a79502007-02-23 04:32:47 -0700707 cfg = &irq_cfg[irq];
Jan Beulich0a1ad602006-06-26 13:56:43 +0200708
Eric W. Biederman70a0a532006-10-25 01:00:23 +0200709 /* Only try and allocate irqs on cpus that are present */
710 cpus_and(mask, mask, cpu_online_map);
711
Eric W. Biederman61014292007-02-23 04:40:58 -0700712 if ((cfg->move_in_progress) || cfg->move_cleanup_count)
713 return -EBUSY;
714
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -0700715 old_vector = cfg->vector;
716 if (old_vector) {
717 cpumask_t tmp;
718 cpus_and(tmp, cfg->domain, mask);
719 if (!cpus_empty(tmp))
720 return 0;
Jan Beulich0a1ad602006-06-26 13:56:43 +0200721 }
Eric W. Biederman550f2292006-10-04 02:16:51 -0700722
723 for_each_cpu_mask(cpu, mask) {
Eric W. Biederman70a0a532006-10-25 01:00:23 +0200724 cpumask_t domain, new_mask;
Eric W. Biederman61014292007-02-23 04:40:58 -0700725 int new_cpu;
Eric W. Biederman550f2292006-10-04 02:16:51 -0700726 int vector, offset;
Eric W. Biedermanc7111c132006-10-08 07:47:55 -0600727
728 domain = vector_allocation_domain(cpu);
Eric W. Biederman70a0a532006-10-25 01:00:23 +0200729 cpus_and(new_mask, domain, cpu_online_map);
Eric W. Biedermanc7111c132006-10-08 07:47:55 -0600730
Eric W. Biedermand1752aa2006-10-25 01:00:22 +0200731 vector = current_vector;
732 offset = current_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733next:
Eric W. Biederman550f2292006-10-04 02:16:51 -0700734 vector += 8;
735 if (vector >= FIRST_SYSTEM_VECTOR) {
736 /* If we run out of vectors on large boxen, must share them. */
737 offset = (offset + 1) % 8;
738 vector = FIRST_DEVICE_VECTOR + offset;
739 }
Eric W. Biedermand1752aa2006-10-25 01:00:22 +0200740 if (unlikely(current_vector == vector))
Eric W. Biederman550f2292006-10-04 02:16:51 -0700741 continue;
742 if (vector == IA32_SYSCALL_VECTOR)
743 goto next;
Eric W. Biederman70a0a532006-10-25 01:00:23 +0200744 for_each_cpu_mask(new_cpu, new_mask)
Yinghai Lu45edfd12006-10-21 18:37:01 +0200745 if (per_cpu(vector_irq, new_cpu)[vector] != -1)
Eric W. Biedermanc7111c132006-10-08 07:47:55 -0600746 goto next;
Eric W. Biederman550f2292006-10-04 02:16:51 -0700747 /* Found one! */
Eric W. Biedermand1752aa2006-10-25 01:00:22 +0200748 current_vector = vector;
749 current_offset = offset;
Eric W. Biederman61014292007-02-23 04:40:58 -0700750 if (old_vector) {
751 cfg->move_in_progress = 1;
752 cfg->old_domain = cfg->domain;
753 }
Eric W. Biederman70a0a532006-10-25 01:00:23 +0200754 for_each_cpu_mask(new_cpu, new_mask)
Eric W. Biedermanc7111c132006-10-08 07:47:55 -0600755 per_cpu(vector_irq, new_cpu)[vector] = irq;
Eric W. Biederman13a79502007-02-23 04:32:47 -0700756 cfg->vector = vector;
757 cfg->domain = domain;
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -0700758 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 }
Eric W. Biederman550f2292006-10-04 02:16:51 -0700760 return -ENOSPC;
Eric W. Biederman04b92672006-10-04 02:16:46 -0700761}
762
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -0700763static int assign_irq_vector(int irq, cpumask_t mask)
Eric W. Biederman04b92672006-10-04 02:16:46 -0700764{
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -0700765 int err;
Eric W. Biederman04b92672006-10-04 02:16:46 -0700766 unsigned long flags;
767
768 spin_lock_irqsave(&vector_lock, flags);
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -0700769 err = __assign_irq_vector(irq, mask);
Ingo Molnar26a3c492006-06-26 13:57:16 +0200770 spin_unlock_irqrestore(&vector_lock, flags);
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -0700771 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772}
773
Yinghai Lu5df02872006-12-07 02:14:05 +0100774static void __clear_irq_vector(int irq)
775{
Eric W. Biederman13a79502007-02-23 04:32:47 -0700776 struct irq_cfg *cfg;
Yinghai Lu5df02872006-12-07 02:14:05 +0100777 cpumask_t mask;
778 int cpu, vector;
779
Eric W. Biederman13a79502007-02-23 04:32:47 -0700780 BUG_ON((unsigned)irq >= NR_IRQS);
781 cfg = &irq_cfg[irq];
782 BUG_ON(!cfg->vector);
Yinghai Lu5df02872006-12-07 02:14:05 +0100783
Eric W. Biederman13a79502007-02-23 04:32:47 -0700784 vector = cfg->vector;
785 cpus_and(mask, cfg->domain, cpu_online_map);
Yinghai Lu5df02872006-12-07 02:14:05 +0100786 for_each_cpu_mask(cpu, mask)
787 per_cpu(vector_irq, cpu)[vector] = -1;
788
Eric W. Biederman13a79502007-02-23 04:32:47 -0700789 cfg->vector = 0;
Mike Travisd366f8c2008-04-04 18:11:12 -0700790 cpus_clear(cfg->domain);
Yinghai Lu5df02872006-12-07 02:14:05 +0100791}
792
Eric W. Biederman70a0a532006-10-25 01:00:23 +0200793void __setup_vector_irq(int cpu)
794{
795 /* Initialize vector_irq on a new cpu */
796 /* This function must be called with vector_lock held */
Eric W. Biederman70a0a532006-10-25 01:00:23 +0200797 int irq, vector;
798
Eric W. Biederman70a0a532006-10-25 01:00:23 +0200799 /* Mark the inuse vectors */
Eric W. Biedermane273d142007-02-23 04:26:53 -0700800 for (irq = 0; irq < NR_IRQS; ++irq) {
Eric W. Biederman13a79502007-02-23 04:32:47 -0700801 if (!cpu_isset(cpu, irq_cfg[irq].domain))
Eric W. Biederman70a0a532006-10-25 01:00:23 +0200802 continue;
Eric W. Biederman13a79502007-02-23 04:32:47 -0700803 vector = irq_cfg[irq].vector;
Eric W. Biederman70a0a532006-10-25 01:00:23 +0200804 per_cpu(vector_irq, cpu)[vector] = irq;
805 }
806 /* Mark the free vectors */
807 for (vector = 0; vector < NR_VECTORS; ++vector) {
808 irq = per_cpu(vector_irq, cpu)[vector];
809 if (irq < 0)
810 continue;
Eric W. Biederman13a79502007-02-23 04:32:47 -0700811 if (!cpu_isset(cpu, irq_cfg[irq].domain))
Eric W. Biederman70a0a532006-10-25 01:00:23 +0200812 per_cpu(vector_irq, cpu)[vector] = -1;
813 }
814}
815
816
Ingo Molnarf29bd1b2006-10-04 02:16:25 -0700817static struct irq_chip ioapic_chip;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818
Eric W. Biedermana27bc062007-02-23 04:16:31 -0700819static void ioapic_register_intr(int irq, unsigned long trigger)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820{
Thomas Gleixnercc75b922007-08-12 15:46:36 +0000821 if (trigger) {
822 irq_desc[irq].status |= IRQ_LEVEL;
Ingo Molnara460e742006-10-17 00:10:03 -0700823 set_irq_chip_and_handler_name(irq, &ioapic_chip,
824 handle_fasteoi_irq, "fasteoi");
Thomas Gleixnercc75b922007-08-12 15:46:36 +0000825 } else {
826 irq_desc[irq].status &= ~IRQ_LEVEL;
Ingo Molnara460e742006-10-17 00:10:03 -0700827 set_irq_chip_and_handler_name(irq, &ioapic_chip,
828 handle_edge_irq, "edge");
Thomas Gleixnercc75b922007-08-12 15:46:36 +0000829 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830}
Eric W. Biedermana8c8a362007-02-23 04:19:08 -0700831
832static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq,
833 int trigger, int polarity)
Yinghai Luad892f52006-12-07 02:14:19 +0100834{
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -0700835 struct irq_cfg *cfg = irq_cfg + irq;
Yinghai Luad892f52006-12-07 02:14:19 +0100836 struct IO_APIC_route_entry entry;
Eric W. Biedermana8c8a362007-02-23 04:19:08 -0700837 cpumask_t mask;
Yinghai Luad892f52006-12-07 02:14:19 +0100838
Eric W. Biedermana8c8a362007-02-23 04:19:08 -0700839 if (!IO_APIC_IRQ(irq))
840 return;
841
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -0700842 mask = TARGET_CPUS;
843 if (assign_irq_vector(irq, mask))
Eric W. Biedermana8c8a362007-02-23 04:19:08 -0700844 return;
845
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -0700846 cpus_and(mask, cfg->domain, mask);
847
Eric W. Biedermana8c8a362007-02-23 04:19:08 -0700848 apic_printk(APIC_VERBOSE,KERN_DEBUG
849 "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> "
850 "IRQ %d Mode:%i Active:%i)\n",
Alexey Starikovskiyec2cd0a2008-05-14 19:03:10 +0400851 apic, mp_ioapics[apic].mp_apicid, pin, cfg->vector,
Eric W. Biedermana8c8a362007-02-23 04:19:08 -0700852 irq, trigger, polarity);
Yinghai Luad892f52006-12-07 02:14:19 +0100853
854 /*
855 * add it to the IO-APIC irq-routing table:
856 */
857 memset(&entry,0,sizeof(entry));
858
859 entry.delivery_mode = INT_DELIVERY_MODE;
860 entry.dest_mode = INT_DEST_MODE;
Eric W. Biedermana8c8a362007-02-23 04:19:08 -0700861 entry.dest = cpu_mask_to_apicid(mask);
Yinghai Luad892f52006-12-07 02:14:19 +0100862 entry.mask = 0; /* enable IRQ */
Eric W. Biedermana8c8a362007-02-23 04:19:08 -0700863 entry.trigger = trigger;
864 entry.polarity = polarity;
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -0700865 entry.vector = cfg->vector;
Yinghai Luad892f52006-12-07 02:14:19 +0100866
Eric W. Biedermana8c8a362007-02-23 04:19:08 -0700867 /* Mask level triggered irqs.
868 * Use IRQ_DELAYED_DISABLE for edge triggered irqs.
869 */
870 if (trigger)
Yinghai Luad892f52006-12-07 02:14:19 +0100871 entry.mask = 1;
Yinghai Luad892f52006-12-07 02:14:19 +0100872
Eric W. Biedermana8c8a362007-02-23 04:19:08 -0700873 ioapic_register_intr(irq, trigger);
874 if (irq < 16)
875 disable_8259A_irq(irq);
Yinghai Luad892f52006-12-07 02:14:19 +0100876
877 ioapic_write_entry(apic, pin, entry);
Yinghai Luad892f52006-12-07 02:14:19 +0100878}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879
880static void __init setup_IO_APIC_irqs(void)
881{
Yinghai Luad892f52006-12-07 02:14:19 +0100882 int apic, pin, idx, irq, first_notcon = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
884 apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n");
885
886 for (apic = 0; apic < nr_ioapics; apic++) {
887 for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
888
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 idx = find_irq_entry(apic,pin,mp_INT);
890 if (idx == -1) {
891 if (first_notcon) {
Alexey Starikovskiyec2cd0a2008-05-14 19:03:10 +0400892 apic_printk(APIC_VERBOSE, KERN_DEBUG " IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mp_apicid, pin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 first_notcon = 0;
894 } else
Alexey Starikovskiyec2cd0a2008-05-14 19:03:10 +0400895 apic_printk(APIC_VERBOSE, ", %d-%d", mp_ioapics[apic].mp_apicid, pin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 continue;
897 }
Yinghai Lu20d225b2007-10-17 18:04:41 +0200898 if (!first_notcon) {
899 apic_printk(APIC_VERBOSE, " not connected.\n");
900 first_notcon = 1;
901 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 irq = pin_2_irq(idx, apic, pin);
904 add_pin_to_irq(irq, apic, pin);
905
Eric W. Biedermana8c8a362007-02-23 04:19:08 -0700906 setup_IO_APIC_irq(apic, pin, irq,
907 irq_trigger(idx), irq_polarity(idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 }
909 }
910
911 if (!first_notcon)
Yinghai Lu20d225b2007-10-17 18:04:41 +0200912 apic_printk(APIC_VERBOSE, " not connected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913}
914
915/*
916 * Set up the 8259A-master output pin as broadcast to all
917 * CPUs.
918 */
Eric W. Biederman1008fdd2006-01-11 22:46:06 +0100919static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, int vector)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920{
921 struct IO_APIC_route_entry entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
Akinobu Mitaa2249cb2008-04-05 22:39:05 +0900923 memset(&entry, 0, sizeof(entry));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
925 disable_8259A_irq(0);
926
927 /* mask LVT0 */
Andi Kleen11a8e772006-01-11 22:46:51 +0100928 apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929
930 /*
931 * We use logical delivery to get the timer IRQ
932 * to the first CPU.
933 */
934 entry.dest_mode = INT_DEST_MODE;
935 entry.mask = 0; /* unmask IRQ now */
Benjamin Romeree4eff62007-02-13 13:26:25 +0100936 entry.dest = cpu_mask_to_apicid(TARGET_CPUS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 entry.delivery_mode = INT_DELIVERY_MODE;
938 entry.polarity = 0;
939 entry.trigger = 0;
940 entry.vector = vector;
941
942 /*
943 * The timer IRQ doesn't have to know that behind the
944 * scene we have a 8259A-master in AEOI mode ...
945 */
Ingo Molnara460e742006-10-17 00:10:03 -0700946 set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
948 /*
949 * Add it to the IO-APIC irq-routing table:
950 */
Akinobu Mitaa2249cb2008-04-05 22:39:05 +0900951 ioapic_write_entry(apic, pin, entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
953 enable_8259A_irq(0);
954}
955
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956void __apicdebuginit print_IO_APIC(void)
957{
958 int apic, i;
959 union IO_APIC_reg_00 reg_00;
960 union IO_APIC_reg_01 reg_01;
961 union IO_APIC_reg_02 reg_02;
962 unsigned long flags;
963
964 if (apic_verbosity == APIC_QUIET)
965 return;
966
967 printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
968 for (i = 0; i < nr_ioapics; i++)
969 printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n",
Alexey Starikovskiyec2cd0a2008-05-14 19:03:10 +0400970 mp_ioapics[i].mp_apicid, nr_ioapic_registers[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
972 /*
973 * We are a bit conservative about what we expect. We have to
974 * know about every hardware change ASAP.
975 */
976 printk(KERN_INFO "testing the IO APIC.......................\n");
977
978 for (apic = 0; apic < nr_ioapics; apic++) {
979
980 spin_lock_irqsave(&ioapic_lock, flags);
981 reg_00.raw = io_apic_read(apic, 0);
982 reg_01.raw = io_apic_read(apic, 1);
983 if (reg_01.bits.version >= 0x10)
984 reg_02.raw = io_apic_read(apic, 2);
985 spin_unlock_irqrestore(&ioapic_lock, flags);
986
987 printk("\n");
Alexey Starikovskiyec2cd0a2008-05-14 19:03:10 +0400988 printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mp_apicid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw);
990 printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
992 printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)&reg_01);
993 printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.bits.entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994
995 printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ);
996 printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.bits.version);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
998 if (reg_01.bits.version >= 0x10) {
999 printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw);
1000 printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.bits.arbitration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 }
1002
1003 printk(KERN_DEBUG ".... IRQ redirection table:\n");
1004
Benjamin Romeree4eff62007-02-13 13:26:25 +01001005 printk(KERN_DEBUG " NR Dst Mask Trig IRR Pol"
1006 " Stat Dmod Deli Vect: \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
1008 for (i = 0; i <= reg_01.bits.entries; i++) {
1009 struct IO_APIC_route_entry entry;
1010
Andi Kleeneea0e112006-09-26 10:52:30 +02001011 entry = ioapic_read_entry(apic, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
Benjamin Romeree4eff62007-02-13 13:26:25 +01001013 printk(KERN_DEBUG " %02x %03X ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 i,
Benjamin Romeree4eff62007-02-13 13:26:25 +01001015 entry.dest
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 );
1017
1018 printk("%1d %1d %1d %1d %1d %1d %1d %02X\n",
1019 entry.mask,
1020 entry.trigger,
1021 entry.irr,
1022 entry.polarity,
1023 entry.delivery_status,
1024 entry.dest_mode,
1025 entry.delivery_mode,
1026 entry.vector
1027 );
1028 }
1029 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 printk(KERN_DEBUG "IRQ to pin mappings:\n");
1031 for (i = 0; i < NR_IRQS; i++) {
1032 struct irq_pin_list *entry = irq_2_pin + i;
1033 if (entry->pin < 0)
1034 continue;
Eric W. Biederman04b92672006-10-04 02:16:46 -07001035 printk(KERN_DEBUG "IRQ%d ", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 for (;;) {
1037 printk("-> %d:%d", entry->apic, entry->pin);
1038 if (!entry->next)
1039 break;
1040 entry = irq_2_pin + entry->next;
1041 }
1042 printk("\n");
1043 }
1044
1045 printk(KERN_INFO ".................................... done.\n");
1046
1047 return;
1048}
1049
1050#if 0
1051
1052static __apicdebuginit void print_APIC_bitfield (int base)
1053{
1054 unsigned int v;
1055 int i, j;
1056
1057 if (apic_verbosity == APIC_QUIET)
1058 return;
1059
1060 printk(KERN_DEBUG "0123456789abcdef0123456789abcdef\n" KERN_DEBUG);
1061 for (i = 0; i < 8; i++) {
1062 v = apic_read(base + i*0x10);
1063 for (j = 0; j < 32; j++) {
1064 if (v & (1<<j))
1065 printk("1");
1066 else
1067 printk("0");
1068 }
1069 printk("\n");
1070 }
1071}
1072
1073void __apicdebuginit print_local_APIC(void * dummy)
1074{
1075 unsigned int v, ver, maxlvt;
1076
1077 if (apic_verbosity == APIC_QUIET)
1078 return;
1079
1080 printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",
1081 smp_processor_id(), hard_smp_processor_id());
Jack Steiner05f2d122008-03-28 14:12:02 -05001082 printk(KERN_INFO "... APIC ID: %08x (%01x)\n", v, GET_APIC_ID(read_apic_id()));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 v = apic_read(APIC_LVR);
1084 printk(KERN_INFO "... APIC VERSION: %08x\n", v);
1085 ver = GET_APIC_VERSION(v);
Thomas Gleixner37e650c2008-01-30 13:30:14 +01001086 maxlvt = lapic_get_maxlvt();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087
1088 v = apic_read(APIC_TASKPRI);
1089 printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK);
1090
Andi Kleen5a40b7c2005-09-12 18:49:24 +02001091 v = apic_read(APIC_ARBPRI);
1092 printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v,
1093 v & APIC_ARBPRI_MASK);
1094 v = apic_read(APIC_PROCPRI);
1095 printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096
1097 v = apic_read(APIC_EOI);
1098 printk(KERN_DEBUG "... APIC EOI: %08x\n", v);
1099 v = apic_read(APIC_RRR);
1100 printk(KERN_DEBUG "... APIC RRR: %08x\n", v);
1101 v = apic_read(APIC_LDR);
1102 printk(KERN_DEBUG "... APIC LDR: %08x\n", v);
1103 v = apic_read(APIC_DFR);
1104 printk(KERN_DEBUG "... APIC DFR: %08x\n", v);
1105 v = apic_read(APIC_SPIV);
1106 printk(KERN_DEBUG "... APIC SPIV: %08x\n", v);
1107
1108 printk(KERN_DEBUG "... APIC ISR field:\n");
1109 print_APIC_bitfield(APIC_ISR);
1110 printk(KERN_DEBUG "... APIC TMR field:\n");
1111 print_APIC_bitfield(APIC_TMR);
1112 printk(KERN_DEBUG "... APIC IRR field:\n");
1113 print_APIC_bitfield(APIC_IRR);
1114
Andi Kleen5a40b7c2005-09-12 18:49:24 +02001115 v = apic_read(APIC_ESR);
1116 printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117
1118 v = apic_read(APIC_ICR);
1119 printk(KERN_DEBUG "... APIC ICR: %08x\n", v);
1120 v = apic_read(APIC_ICR2);
1121 printk(KERN_DEBUG "... APIC ICR2: %08x\n", v);
1122
1123 v = apic_read(APIC_LVTT);
1124 printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);
1125
1126 if (maxlvt > 3) { /* PC is LVT#4. */
1127 v = apic_read(APIC_LVTPC);
1128 printk(KERN_DEBUG "... APIC LVTPC: %08x\n", v);
1129 }
1130 v = apic_read(APIC_LVT0);
1131 printk(KERN_DEBUG "... APIC LVT0: %08x\n", v);
1132 v = apic_read(APIC_LVT1);
1133 printk(KERN_DEBUG "... APIC LVT1: %08x\n", v);
1134
1135 if (maxlvt > 2) { /* ERR is LVT#3. */
1136 v = apic_read(APIC_LVTERR);
1137 printk(KERN_DEBUG "... APIC LVTERR: %08x\n", v);
1138 }
1139
1140 v = apic_read(APIC_TMICT);
1141 printk(KERN_DEBUG "... APIC TMICT: %08x\n", v);
1142 v = apic_read(APIC_TMCCT);
1143 printk(KERN_DEBUG "... APIC TMCCT: %08x\n", v);
1144 v = apic_read(APIC_TDCR);
1145 printk(KERN_DEBUG "... APIC TDCR: %08x\n", v);
1146 printk("\n");
1147}
1148
1149void print_all_local_APICs (void)
1150{
1151 on_each_cpu(print_local_APIC, NULL, 1, 1);
1152}
1153
1154void __apicdebuginit print_PIC(void)
1155{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 unsigned int v;
1157 unsigned long flags;
1158
1159 if (apic_verbosity == APIC_QUIET)
1160 return;
1161
1162 printk(KERN_DEBUG "\nprinting PIC contents\n");
1163
1164 spin_lock_irqsave(&i8259A_lock, flags);
1165
1166 v = inb(0xa1) << 8 | inb(0x21);
1167 printk(KERN_DEBUG "... PIC IMR: %04x\n", v);
1168
1169 v = inb(0xa0) << 8 | inb(0x20);
1170 printk(KERN_DEBUG "... PIC IRR: %04x\n", v);
1171
1172 outb(0x0b,0xa0);
1173 outb(0x0b,0x20);
1174 v = inb(0xa0) << 8 | inb(0x20);
1175 outb(0x0a,0xa0);
1176 outb(0x0a,0x20);
1177
1178 spin_unlock_irqrestore(&i8259A_lock, flags);
1179
1180 printk(KERN_DEBUG "... PIC ISR: %04x\n", v);
1181
1182 v = inb(0x4d1) << 8 | inb(0x4d0);
1183 printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
1184}
1185
1186#endif /* 0 */
1187
Yinghai Lu1c695242008-01-30 13:30:39 +01001188void __init enable_IO_APIC(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189{
1190 union IO_APIC_reg_01 reg_01;
Eric W. Biederman1008fdd2006-01-11 22:46:06 +01001191 int i8259_apic, i8259_pin;
1192 int i, apic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 unsigned long flags;
1194
1195 for (i = 0; i < PIN_MAP_SIZE; i++) {
1196 irq_2_pin[i].pin = -1;
1197 irq_2_pin[i].next = 0;
1198 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199
1200 /*
1201 * The number of IO-APIC IRQ registers (== #pins):
1202 */
Eric W. Biederman1008fdd2006-01-11 22:46:06 +01001203 for (apic = 0; apic < nr_ioapics; apic++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 spin_lock_irqsave(&ioapic_lock, flags);
Eric W. Biederman1008fdd2006-01-11 22:46:06 +01001205 reg_01.raw = io_apic_read(apic, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 spin_unlock_irqrestore(&ioapic_lock, flags);
Eric W. Biederman1008fdd2006-01-11 22:46:06 +01001207 nr_ioapic_registers[apic] = reg_01.bits.entries+1;
1208 }
1209 for(apic = 0; apic < nr_ioapics; apic++) {
1210 int pin;
1211 /* See if any of the pins is in ExtINT mode */
1212 for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
1213 struct IO_APIC_route_entry entry;
Andi Kleeneea0e112006-09-26 10:52:30 +02001214 entry = ioapic_read_entry(apic, pin);
Eric W. Biederman1008fdd2006-01-11 22:46:06 +01001215
1216 /* If the interrupt line is enabled and in ExtInt mode
1217 * I have found the pin where the i8259 is connected.
1218 */
1219 if ((entry.mask == 0) && (entry.delivery_mode == dest_ExtINT)) {
1220 ioapic_i8259.apic = apic;
1221 ioapic_i8259.pin = pin;
1222 goto found_i8259;
1223 }
1224 }
1225 }
1226 found_i8259:
1227 /* Look to see what if the MP table has reported the ExtINT */
1228 i8259_pin = find_isa_irq_pin(0, mp_ExtINT);
1229 i8259_apic = find_isa_irq_apic(0, mp_ExtINT);
1230 /* Trust the MP table if nothing is setup in the hardware */
1231 if ((ioapic_i8259.pin == -1) && (i8259_pin >= 0)) {
1232 printk(KERN_WARNING "ExtINT not setup in hardware but reported by MP table\n");
1233 ioapic_i8259.pin = i8259_pin;
1234 ioapic_i8259.apic = i8259_apic;
1235 }
1236 /* Complain if the MP table and the hardware disagree */
1237 if (((ioapic_i8259.apic != i8259_apic) || (ioapic_i8259.pin != i8259_pin)) &&
1238 (i8259_pin >= 0) && (ioapic_i8259.pin >= 0))
1239 {
1240 printk(KERN_WARNING "ExtINT in hardware and MP table differ\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 }
1242
1243 /*
1244 * Do not trust the IO-APIC being empty at bootup
1245 */
1246 clear_IO_APIC();
1247}
1248
1249/*
1250 * Not an __init, needed by the reboot code
1251 */
1252void disable_IO_APIC(void)
1253{
1254 /*
1255 * Clear the IO-APIC before rebooting:
1256 */
1257 clear_IO_APIC();
1258
Eric W. Biederman208fb932005-06-25 14:57:45 -07001259 /*
Karsten Wiese0b968d22005-09-09 12:59:04 +02001260 * If the i8259 is routed through an IOAPIC
Eric W. Biederman208fb932005-06-25 14:57:45 -07001261 * Put that IOAPIC in virtual wire mode
Karsten Wiese0b968d22005-09-09 12:59:04 +02001262 * so legacy interrupts can be delivered.
Eric W. Biederman208fb932005-06-25 14:57:45 -07001263 */
Eric W. Biederman1008fdd2006-01-11 22:46:06 +01001264 if (ioapic_i8259.pin != -1) {
Eric W. Biederman208fb932005-06-25 14:57:45 -07001265 struct IO_APIC_route_entry entry;
Eric W. Biederman208fb932005-06-25 14:57:45 -07001266
1267 memset(&entry, 0, sizeof(entry));
1268 entry.mask = 0; /* Enabled */
1269 entry.trigger = 0; /* Edge */
1270 entry.irr = 0;
1271 entry.polarity = 0; /* High */
1272 entry.delivery_status = 0;
1273 entry.dest_mode = 0; /* Physical */
Eric W. Biederman1008fdd2006-01-11 22:46:06 +01001274 entry.delivery_mode = dest_ExtINT; /* ExtInt */
Eric W. Biederman208fb932005-06-25 14:57:45 -07001275 entry.vector = 0;
Jack Steiner05f2d122008-03-28 14:12:02 -05001276 entry.dest = GET_APIC_ID(read_apic_id());
Eric W. Biederman208fb932005-06-25 14:57:45 -07001277
Eric W. Biederman208fb932005-06-25 14:57:45 -07001278 /*
1279 * Add it to the IO-APIC irq-routing table:
1280 */
Andi Kleeneea0e112006-09-26 10:52:30 +02001281 ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry);
Eric W. Biederman208fb932005-06-25 14:57:45 -07001282 }
1283
Eric W. Biederman1008fdd2006-01-11 22:46:06 +01001284 disconnect_bsp_APIC(ioapic_i8259.pin != -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285}
1286
1287/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 * There is a nasty bug in some older SMP boards, their mptable lies
1289 * about the timer IRQ. We do the following to work around the situation:
1290 *
1291 * - timer IRQ defaults to IO-APIC IRQ
1292 * - if this function detects that timer IRQs are defunct, then we fall
1293 * back to ISA timer IRQs
1294 */
1295static int __init timer_irq_works(void)
1296{
1297 unsigned long t1 = jiffies;
Ingo Molnar4aae0702007-12-18 18:05:58 +01001298 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
Ingo Molnar4aae0702007-12-18 18:05:58 +01001300 local_save_flags(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 local_irq_enable();
1302 /* Let ten ticks pass... */
1303 mdelay((10 * 1000) / HZ);
Ingo Molnar4aae0702007-12-18 18:05:58 +01001304 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305
1306 /*
1307 * Expect a few ticks at least, to be sure some possible
1308 * glue logic does not lock up after one or two first
1309 * ticks in a non-ExtINT mode. Also the local APIC
1310 * might have cached one ExtINT interrupt. Finally, at
1311 * least one tick may be lost due to delays.
1312 */
1313
1314 /* jiffies wrap? */
Julia Lawall1d16b532008-01-30 13:32:19 +01001315 if (time_after(jiffies, t1 + 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 return 1;
1317 return 0;
1318}
1319
1320/*
1321 * In the SMP+IOAPIC case it might happen that there are an unspecified
1322 * number of pending IRQ events unhandled. These cases are very rare,
1323 * so we 'resend' these IRQs via IPIs, to the same CPU. It's much
1324 * better to do it this way as thus we do not have to be aware of
1325 * 'pending' interrupts in the IRQ path, except at this point.
1326 */
1327/*
1328 * Edge triggered needs to resend any interrupt
1329 * that was delayed but this is now handled in the device
1330 * independent code.
1331 */
1332
1333/*
1334 * Starting up a edge-triggered IO-APIC interrupt is
1335 * nasty - we need to make sure that we get the edge.
1336 * If it is already asserted for some reason, we need
1337 * return 1 to indicate that is was pending.
1338 *
1339 * This is not complete - we should be able to fake
1340 * an edge even if it isn't on the 8259A...
1341 */
1342
Ingo Molnarf29bd1b2006-10-04 02:16:25 -07001343static unsigned int startup_ioapic_irq(unsigned int irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344{
1345 int was_pending = 0;
1346 unsigned long flags;
1347
1348 spin_lock_irqsave(&ioapic_lock, flags);
1349 if (irq < 16) {
1350 disable_8259A_irq(irq);
1351 if (i8259A_irq_pending(irq))
1352 was_pending = 1;
1353 }
1354 __unmask_IO_APIC_irq(irq);
1355 spin_unlock_irqrestore(&ioapic_lock, flags);
1356
1357 return was_pending;
1358}
1359
Eric W. Biederman04b92672006-10-04 02:16:46 -07001360static int ioapic_retrigger_irq(unsigned int irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361{
Eric W. Biederman13a79502007-02-23 04:32:47 -07001362 struct irq_cfg *cfg = &irq_cfg[irq];
Eric W. Biederman550f2292006-10-04 02:16:51 -07001363 cpumask_t mask;
Eric W. Biederman6bf2daf2006-10-21 18:37:02 +02001364 unsigned long flags;
Eric W. Biederman550f2292006-10-04 02:16:51 -07001365
Eric W. Biederman6bf2daf2006-10-21 18:37:02 +02001366 spin_lock_irqsave(&vector_lock, flags);
Akinobu Mita7281c962008-04-05 22:39:08 +09001367 mask = cpumask_of_cpu(first_cpu(cfg->domain));
Eric W. Biederman13a79502007-02-23 04:32:47 -07001368 send_IPI_mask(mask, cfg->vector);
Eric W. Biederman6bf2daf2006-10-21 18:37:02 +02001369 spin_unlock_irqrestore(&vector_lock, flags);
Ingo Molnarc0ad90a2006-06-29 02:24:44 -07001370
1371 return 1;
1372}
1373
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374/*
1375 * Level and edge triggered IO-APIC interrupts need different handling,
1376 * so we use two separate IRQ descriptors. Edge triggered IRQs can be
1377 * handled with the level-triggered descriptor, but that one has slightly
1378 * more overhead. Level-triggered interrupts cannot be handled with the
1379 * edge-triggered handler, without risking IRQ storms and other ugly
1380 * races.
1381 */
1382
Eric W. Biederman61014292007-02-23 04:40:58 -07001383#ifdef CONFIG_SMP
1384asmlinkage void smp_irq_move_cleanup_interrupt(void)
1385{
1386 unsigned vector, me;
1387 ack_APIC_irq();
1388 exit_idle();
1389 irq_enter();
1390
1391 me = smp_processor_id();
1392 for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
1393 unsigned int irq;
1394 struct irq_desc *desc;
1395 struct irq_cfg *cfg;
1396 irq = __get_cpu_var(vector_irq)[vector];
1397 if (irq >= NR_IRQS)
1398 continue;
1399
1400 desc = irq_desc + irq;
1401 cfg = irq_cfg + irq;
1402 spin_lock(&desc->lock);
1403 if (!cfg->move_cleanup_count)
1404 goto unlock;
1405
1406 if ((vector == cfg->vector) && cpu_isset(me, cfg->domain))
1407 goto unlock;
1408
1409 __get_cpu_var(vector_irq)[vector] = -1;
1410 cfg->move_cleanup_count--;
1411unlock:
1412 spin_unlock(&desc->lock);
1413 }
1414
1415 irq_exit();
1416}
1417
1418static void irq_complete_move(unsigned int irq)
1419{
1420 struct irq_cfg *cfg = irq_cfg + irq;
1421 unsigned vector, me;
1422
1423 if (likely(!cfg->move_in_progress))
1424 return;
1425
H. Peter Anvin65ea5b02008-01-30 13:30:56 +01001426 vector = ~get_irq_regs()->orig_ax;
Eric W. Biederman61014292007-02-23 04:40:58 -07001427 me = smp_processor_id();
Yinghai Luf0e13ae2007-05-02 19:27:08 +02001428 if ((vector == cfg->vector) && cpu_isset(me, cfg->domain)) {
Eric W. Biederman61014292007-02-23 04:40:58 -07001429 cpumask_t cleanup_mask;
1430
1431 cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map);
1432 cfg->move_cleanup_count = cpus_weight(cleanup_mask);
1433 send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
1434 cfg->move_in_progress = 0;
1435 }
1436}
1437#else
1438static inline void irq_complete_move(unsigned int irq) {}
1439#endif
1440
Eric W. Biederman0be66522006-10-04 02:16:30 -07001441static void ack_apic_edge(unsigned int irq)
1442{
Eric W. Biederman61014292007-02-23 04:40:58 -07001443 irq_complete_move(irq);
Eric W. Biederman0be66522006-10-04 02:16:30 -07001444 move_native_irq(irq);
1445 ack_APIC_irq();
1446}
1447
1448static void ack_apic_level(unsigned int irq)
1449{
1450 int do_unmask_irq = 0;
1451
Eric W. Biederman61014292007-02-23 04:40:58 -07001452 irq_complete_move(irq);
Hiroshi Shimamoto52e3d902008-01-30 13:30:30 +01001453#ifdef CONFIG_GENERIC_PENDING_IRQ
Eric W. Biederman0be66522006-10-04 02:16:30 -07001454 /* If we are moving the irq we need to mask it */
1455 if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) {
1456 do_unmask_irq = 1;
1457 mask_IO_APIC_irq(irq);
1458 }
1459#endif
1460
1461 /*
1462 * We must acknowledge the irq before we move it or the acknowledge will
Robert P. J. Daybeb7dd82007-05-09 07:14:03 +02001463 * not propagate properly.
Eric W. Biederman0be66522006-10-04 02:16:30 -07001464 */
1465 ack_APIC_irq();
1466
1467 /* Now we can move and renable the irq */
Eric W. Biedermanef3e28c2007-07-21 17:10:45 +02001468 if (unlikely(do_unmask_irq)) {
1469 /* Only migrate the irq if the ack has been received.
1470 *
1471 * On rare occasions the broadcast level triggered ack gets
1472 * delayed going to ioapics, and if we reprogram the
1473 * vector while Remote IRR is still set the irq will never
1474 * fire again.
1475 *
1476 * To prevent this scenario we read the Remote IRR bit
1477 * of the ioapic. This has two effects.
1478 * - On any sane system the read of the ioapic will
1479 * flush writes (and acks) going to the ioapic from
1480 * this cpu.
1481 * - We get to see if the ACK has actually been delivered.
1482 *
1483 * Based on failed experiments of reprogramming the
1484 * ioapic entry from outside of irq context starting
1485 * with masking the ioapic entry and then polling until
1486 * Remote IRR was clear before reprogramming the
1487 * ioapic I don't trust the Remote IRR bit to be
1488 * completey accurate.
1489 *
1490 * However there appears to be no other way to plug
1491 * this race, so if the Remote IRR bit is not
1492 * accurate and is causing problems then it is a hardware bug
1493 * and you can go talk to the chipset vendor about it.
1494 */
1495 if (!io_apic_level_ack_pending(irq))
1496 move_masked_irq(irq);
Eric W. Biederman0be66522006-10-04 02:16:30 -07001497 unmask_IO_APIC_irq(irq);
Eric W. Biedermanef3e28c2007-07-21 17:10:45 +02001498 }
Eric W. Biederman0be66522006-10-04 02:16:30 -07001499}
1500
Ingo Molnarf29bd1b2006-10-04 02:16:25 -07001501static struct irq_chip ioapic_chip __read_mostly = {
1502 .name = "IO-APIC",
Eric W. Biederman04b92672006-10-04 02:16:46 -07001503 .startup = startup_ioapic_irq,
1504 .mask = mask_IO_APIC_irq,
1505 .unmask = unmask_IO_APIC_irq,
Eric W. Biederman0be66522006-10-04 02:16:30 -07001506 .ack = ack_apic_edge,
1507 .eoi = ack_apic_level,
Ashok Raj54d5d422005-09-06 15:16:15 -07001508#ifdef CONFIG_SMP
Eric W. Biederman04b92672006-10-04 02:16:46 -07001509 .set_affinity = set_ioapic_affinity_irq,
Ashok Raj54d5d422005-09-06 15:16:15 -07001510#endif
Eric W. Biederman04b92672006-10-04 02:16:46 -07001511 .retrigger = ioapic_retrigger_irq,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512};
1513
1514static inline void init_IO_APIC_traps(void)
1515{
1516 int irq;
1517
1518 /*
1519 * NOTE! The local APIC isn't very good at handling
1520 * multiple interrupts at the same interrupt level.
1521 * As the interrupt level is determined by taking the
1522 * vector number and shifting that right by 4, we
1523 * want to spread these out a bit so that they don't
1524 * all fall in the same interrupt level.
1525 *
1526 * Also, we've got to be careful not to trash gate
1527 * 0x80, because int 0x80 is hm, kind of importantish. ;)
1528 */
1529 for (irq = 0; irq < NR_IRQS ; irq++) {
Akinobu Mitaaddfc662008-04-05 22:39:07 +09001530 if (IO_APIC_IRQ(irq) && !irq_cfg[irq].vector) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 /*
1532 * Hmm.. We don't have an entry for this,
1533 * so default to an old-fashioned 8259
1534 * interrupt if we can..
1535 */
1536 if (irq < 16)
1537 make_8259A_irq(irq);
1538 else
1539 /* Strange. Oh, well.. */
Ingo Molnarf29bd1b2006-10-04 02:16:25 -07001540 irq_desc[irq].chip = &no_irq_chip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 }
1542 }
1543}
1544
1545static void enable_lapic_irq (unsigned int irq)
1546{
1547 unsigned long v;
1548
1549 v = apic_read(APIC_LVT0);
Andi Kleen11a8e772006-01-11 22:46:51 +01001550 apic_write(APIC_LVT0, v & ~APIC_LVT_MASKED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551}
1552
1553static void disable_lapic_irq (unsigned int irq)
1554{
1555 unsigned long v;
1556
1557 v = apic_read(APIC_LVT0);
Andi Kleen11a8e772006-01-11 22:46:51 +01001558 apic_write(APIC_LVT0, v | APIC_LVT_MASKED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559}
1560
1561static void ack_lapic_irq (unsigned int irq)
1562{
1563 ack_APIC_irq();
1564}
1565
1566static void end_lapic_irq (unsigned int i) { /* nothing */ }
1567
Ravikiran G Thirumalai6c231b72005-09-06 15:17:45 -07001568static struct hw_interrupt_type lapic_irq_type __read_mostly = {
Suresh Siddhac47e2852007-06-25 15:31:37 -07001569 .name = "local-APIC",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 .typename = "local-APIC-edge",
1571 .startup = NULL, /* startup_irq() not used for IRQ0 */
1572 .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */
1573 .enable = enable_lapic_irq,
1574 .disable = disable_lapic_irq,
1575 .ack = ack_lapic_irq,
1576 .end = end_lapic_irq,
1577};
1578
Jan Beuliche9427102008-01-30 13:31:24 +01001579static void __init setup_nmi(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580{
1581 /*
1582 * Dirty trick to enable the NMI watchdog ...
1583 * We put the 8259A master into AEOI mode and
1584 * unmask on all local APICs LVT0 as NMI.
1585 *
1586 * The idea to use the 8259A in AEOI mode ('8259A Virtual Wire')
1587 * is from Maciej W. Rozycki - so we do not have to EOI from
1588 * the NMI handler or the timer interrupt.
1589 */
1590 printk(KERN_INFO "activating NMI Watchdog ...");
1591
Jan Beuliche9427102008-01-30 13:31:24 +01001592 enable_NMI_through_LVT0();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593
1594 printk(" done.\n");
1595}
1596
1597/*
1598 * This looks a bit hackish but it's about the only one way of sending
1599 * a few INTA cycles to 8259As and any associated glue logic. ICR does
1600 * not support the ExtINT mode, unfortunately. We need to send these
1601 * cycles as some i82489DX-based boards have glue logic that keeps the
1602 * 8259A interrupt line asserted until INTA. --macro
1603 */
Jacek Luczak5afca332008-04-11 13:29:04 +02001604static inline void __init unlock_ExtINT_logic(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605{
Eric W. Biederman1008fdd2006-01-11 22:46:06 +01001606 int apic, pin, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 struct IO_APIC_route_entry entry0, entry1;
1608 unsigned char save_control, save_freq_select;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609
Eric W. Biederman1008fdd2006-01-11 22:46:06 +01001610 pin = find_isa_irq_pin(8, mp_INT);
1611 apic = find_isa_irq_apic(8, mp_INT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 if (pin == -1)
1613 return;
1614
Akinobu Mitaa2249cb2008-04-05 22:39:05 +09001615 entry0 = ioapic_read_entry(apic, pin);
1616
Eric W. Biederman1008fdd2006-01-11 22:46:06 +01001617 clear_IO_APIC_pin(apic, pin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618
1619 memset(&entry1, 0, sizeof(entry1));
1620
1621 entry1.dest_mode = 0; /* physical delivery */
1622 entry1.mask = 0; /* unmask IRQ now */
Benjamin Romeree4eff62007-02-13 13:26:25 +01001623 entry1.dest = hard_smp_processor_id();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 entry1.delivery_mode = dest_ExtINT;
1625 entry1.polarity = entry0.polarity;
1626 entry1.trigger = 0;
1627 entry1.vector = 0;
1628
Akinobu Mitaa2249cb2008-04-05 22:39:05 +09001629 ioapic_write_entry(apic, pin, entry1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630
1631 save_control = CMOS_READ(RTC_CONTROL);
1632 save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
1633 CMOS_WRITE((save_freq_select & ~RTC_RATE_SELECT) | 0x6,
1634 RTC_FREQ_SELECT);
1635 CMOS_WRITE(save_control | RTC_PIE, RTC_CONTROL);
1636
1637 i = 100;
1638 while (i-- > 0) {
1639 mdelay(10);
1640 if ((CMOS_READ(RTC_INTR_FLAGS) & RTC_PF) == RTC_PF)
1641 i -= 10;
1642 }
1643
1644 CMOS_WRITE(save_control, RTC_CONTROL);
1645 CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
Eric W. Biederman1008fdd2006-01-11 22:46:06 +01001646 clear_IO_APIC_pin(apic, pin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647
Akinobu Mitaa2249cb2008-04-05 22:39:05 +09001648 ioapic_write_entry(apic, pin, entry0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649}
1650
1651/*
1652 * This code may look a bit paranoid, but it's supposed to cooperate with
1653 * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ
1654 * is so screwy. Thanks to Brian Perkins for testing/hacking this beast
1655 * fanatically on his truly buggy board.
Linus Torvaldsfea5f1e2007-01-08 15:04:46 -08001656 *
1657 * FIXME: really need to revamp this for modern platforms only.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 */
Jan Beuliche9427102008-01-30 13:31:24 +01001659static inline void __init check_timer(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660{
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07001661 struct irq_cfg *cfg = irq_cfg + 0;
Eric W. Biederman1008fdd2006-01-11 22:46:06 +01001662 int apic1, pin1, apic2, pin2;
Ingo Molnar4aae0702007-12-18 18:05:58 +01001663 unsigned long flags;
1664
1665 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666
1667 /*
1668 * get/set the timer IRQ vector:
1669 */
1670 disable_8259A_irq(0);
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07001671 assign_irq_vector(0, TARGET_CPUS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672
1673 /*
1674 * Subtle, code in do_timer_interrupt() expects an AEOI
1675 * mode for the 8259A whenever interrupts are routed
1676 * through I/O APICs. Also IRQ0 has to be enabled in
1677 * the 8259A which implies the virtual wire has to be
1678 * disabled in the local APIC.
1679 */
Andi Kleen11a8e772006-01-11 22:46:51 +01001680 apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 init_8259A(1);
Linus Torvaldsfea5f1e2007-01-08 15:04:46 -08001682 if (timer_over_8254 > 0)
1683 enable_8259A_irq(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
Eric W. Biederman1008fdd2006-01-11 22:46:06 +01001685 pin1 = find_isa_irq_pin(0, mp_INT);
1686 apic1 = find_isa_irq_apic(0, mp_INT);
1687 pin2 = ioapic_i8259.pin;
1688 apic2 = ioapic_i8259.apic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
Linus Torvaldsfea5f1e2007-01-08 15:04:46 -08001690 apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07001691 cfg->vector, apic1, pin1, apic2, pin2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
Linus Torvaldsfea5f1e2007-01-08 15:04:46 -08001693 if (pin1 != -1) {
1694 /*
1695 * Ok, does IRQ0 through the IOAPIC work?
1696 */
1697 unmask_IO_APIC_irq(0);
1698 if (!no_timer_check && timer_irq_works()) {
1699 nmi_watchdog_default();
1700 if (nmi_watchdog == NMI_IO_APIC) {
1701 disable_8259A_irq(0);
1702 setup_nmi();
1703 enable_8259A_irq(0);
1704 }
1705 if (disable_timer_pin_1 > 0)
1706 clear_IO_APIC_pin(0, pin1);
Ingo Molnar4aae0702007-12-18 18:05:58 +01001707 goto out;
Linus Torvaldsfea5f1e2007-01-08 15:04:46 -08001708 }
1709 clear_IO_APIC_pin(apic1, pin1);
1710 apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: 8254 timer not "
1711 "connected to IO-APIC\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 }
Andi Kleenb0268722006-12-07 02:14:06 +01001713
Linus Torvaldsfea5f1e2007-01-08 15:04:46 -08001714 apic_printk(APIC_VERBOSE,KERN_INFO "...trying to set up timer (IRQ0) "
1715 "through the 8259A ... ");
1716 if (pin2 != -1) {
1717 apic_printk(APIC_VERBOSE,"\n..... (found apic %d pin %d) ...",
1718 apic2, pin2);
1719 /*
1720 * legacy devices should be connected to IO APIC #0
1721 */
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07001722 setup_ExtINT_IRQ0_pin(apic2, pin2, cfg->vector);
Linus Torvaldsfea5f1e2007-01-08 15:04:46 -08001723 if (timer_irq_works()) {
1724 apic_printk(APIC_VERBOSE," works.\n");
1725 nmi_watchdog_default();
1726 if (nmi_watchdog == NMI_IO_APIC) {
1727 setup_nmi();
1728 }
Ingo Molnar4aae0702007-12-18 18:05:58 +01001729 goto out;
Linus Torvaldsfea5f1e2007-01-08 15:04:46 -08001730 }
1731 /*
1732 * Cleanup, just in case ...
1733 */
1734 clear_IO_APIC_pin(apic2, pin2);
1735 }
1736 apic_printk(APIC_VERBOSE," failed.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737
Chris McDermott1f992152006-02-26 04:18:40 +01001738 if (nmi_watchdog == NMI_IO_APIC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n");
1740 nmi_watchdog = 0;
1741 }
1742
1743 apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
1744
1745 disable_8259A_irq(0);
Ingo Molnard1bef4e2006-06-29 02:24:36 -07001746 irq_desc[0].chip = &lapic_irq_type;
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07001747 apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector); /* Fixed mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 enable_8259A_irq(0);
1749
1750 if (timer_irq_works()) {
Chuck Ebbert5b922cd2006-03-25 16:30:55 +01001751 apic_printk(APIC_VERBOSE," works.\n");
Ingo Molnar4aae0702007-12-18 18:05:58 +01001752 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 }
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07001754 apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 apic_printk(APIC_VERBOSE," failed.\n");
1756
1757 apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as ExtINT IRQ...");
1758
1759 init_8259A(0);
1760 make_8259A_irq(0);
Andi Kleen11a8e772006-01-11 22:46:51 +01001761 apic_write(APIC_LVT0, APIC_DM_EXTINT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762
1763 unlock_ExtINT_logic();
1764
1765 if (timer_irq_works()) {
1766 apic_printk(APIC_VERBOSE," works.\n");
Ingo Molnar4aae0702007-12-18 18:05:58 +01001767 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 }
1769 apic_printk(APIC_VERBOSE," failed :(.\n");
1770 panic("IO-APIC + timer doesn't work! Try using the 'noapic' kernel parameter\n");
Ingo Molnar4aae0702007-12-18 18:05:58 +01001771out:
1772 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773}
1774
Andi Kleen14d98ca2005-05-20 14:27:59 -07001775static int __init notimercheck(char *s)
1776{
1777 no_timer_check = 1;
1778 return 1;
1779}
1780__setup("no_timer_check", notimercheck);
1781
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782/*
1783 *
Simon Arlott676b1852007-10-20 01:25:36 +02001784 * IRQs that are handled by the PIC in the MPS IOAPIC case.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 * - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ.
1786 * Linux doesn't really care, as it's not actually used
1787 * for any interrupt handling anyway.
1788 */
1789#define PIC_IRQS (1<<2)
1790
1791void __init setup_IO_APIC(void)
1792{
Yinghai Lu1c695242008-01-30 13:30:39 +01001793
1794 /*
1795 * calling enable_IO_APIC() is moved to setup_local_APIC for BP
1796 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797
1798 if (acpi_ioapic)
1799 io_apic_irqs = ~0; /* all IRQs go through IOAPIC */
1800 else
1801 io_apic_irqs = ~PIC_IRQS;
1802
1803 apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n");
1804
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 sync_Arb_IDs();
1806 setup_IO_APIC_irqs();
1807 init_IO_APIC_traps();
1808 check_timer();
1809 if (!acpi_ioapic)
1810 print_IO_APIC();
1811}
1812
1813struct sysfs_ioapic_data {
1814 struct sys_device dev;
1815 struct IO_APIC_route_entry entry[0];
1816};
1817static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS];
1818
Pavel Machek0b9c33a2005-04-16 15:25:31 -07001819static int ioapic_suspend(struct sys_device *dev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820{
1821 struct IO_APIC_route_entry *entry;
1822 struct sysfs_ioapic_data *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 int i;
1824
1825 data = container_of(dev, struct sysfs_ioapic_data, dev);
1826 entry = data->entry;
Andi Kleeneea0e112006-09-26 10:52:30 +02001827 for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ )
1828 *entry = ioapic_read_entry(dev->id, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
1830 return 0;
1831}
1832
1833static int ioapic_resume(struct sys_device *dev)
1834{
1835 struct IO_APIC_route_entry *entry;
1836 struct sysfs_ioapic_data *data;
1837 unsigned long flags;
1838 union IO_APIC_reg_00 reg_00;
1839 int i;
1840
1841 data = container_of(dev, struct sysfs_ioapic_data, dev);
1842 entry = data->entry;
1843
1844 spin_lock_irqsave(&ioapic_lock, flags);
1845 reg_00.raw = io_apic_read(dev->id, 0);
Alexey Starikovskiyec2cd0a2008-05-14 19:03:10 +04001846 if (reg_00.bits.ID != mp_ioapics[dev->id].mp_apicid) {
1847 reg_00.bits.ID = mp_ioapics[dev->id].mp_apicid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 io_apic_write(dev->id, 0, reg_00.raw);
1849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 spin_unlock_irqrestore(&ioapic_lock, flags);
Andi Kleeneea0e112006-09-26 10:52:30 +02001851 for (i = 0; i < nr_ioapic_registers[dev->id]; i++)
1852 ioapic_write_entry(dev->id, i, entry[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853
1854 return 0;
1855}
1856
1857static struct sysdev_class ioapic_sysdev_class = {
Kay Sieversaf5ca3f42007-12-20 02:09:39 +01001858 .name = "ioapic",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 .suspend = ioapic_suspend,
1860 .resume = ioapic_resume,
1861};
1862
1863static int __init ioapic_init_sysfs(void)
1864{
1865 struct sys_device * dev;
Mariusz Kozlowskicddf7ff2007-10-17 18:04:38 +02001866 int i, size, error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867
1868 error = sysdev_class_register(&ioapic_sysdev_class);
1869 if (error)
1870 return error;
1871
1872 for (i = 0; i < nr_ioapics; i++ ) {
1873 size = sizeof(struct sys_device) + nr_ioapic_registers[i]
1874 * sizeof(struct IO_APIC_route_entry);
Mariusz Kozlowskicddf7ff2007-10-17 18:04:38 +02001875 mp_ioapic_data[i] = kzalloc(size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 if (!mp_ioapic_data[i]) {
1877 printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i);
1878 continue;
1879 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 dev = &mp_ioapic_data[i]->dev;
1881 dev->id = i;
1882 dev->cls = &ioapic_sysdev_class;
1883 error = sysdev_register(dev);
1884 if (error) {
1885 kfree(mp_ioapic_data[i]);
1886 mp_ioapic_data[i] = NULL;
1887 printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i);
1888 continue;
1889 }
1890 }
1891
1892 return 0;
1893}
1894
1895device_initcall(ioapic_init_sysfs);
1896
Eric W. Biedermanc4fa0bbf2006-10-04 02:16:40 -07001897/*
Eric W. Biederman04b92672006-10-04 02:16:46 -07001898 * Dynamic irq allocate and deallocation
Eric W. Biedermanc4fa0bbf2006-10-04 02:16:40 -07001899 */
1900int create_irq(void)
1901{
Eric W. Biederman04b92672006-10-04 02:16:46 -07001902 /* Allocate an unused irq */
1903 int irq;
1904 int new;
Eric W. Biedermanc4fa0bbf2006-10-04 02:16:40 -07001905 unsigned long flags;
Eric W. Biedermanc4fa0bbf2006-10-04 02:16:40 -07001906
Eric W. Biederman04b92672006-10-04 02:16:46 -07001907 irq = -ENOSPC;
1908 spin_lock_irqsave(&vector_lock, flags);
1909 for (new = (NR_IRQS - 1); new >= 0; new--) {
1910 if (platform_legacy_irq(new))
1911 continue;
Eric W. Biederman13a79502007-02-23 04:32:47 -07001912 if (irq_cfg[new].vector != 0)
Eric W. Biederman04b92672006-10-04 02:16:46 -07001913 continue;
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07001914 if (__assign_irq_vector(new, TARGET_CPUS) == 0)
Eric W. Biederman04b92672006-10-04 02:16:46 -07001915 irq = new;
1916 break;
1917 }
1918 spin_unlock_irqrestore(&vector_lock, flags);
Eric W. Biedermanc4fa0bbf2006-10-04 02:16:40 -07001919
Eric W. Biederman04b92672006-10-04 02:16:46 -07001920 if (irq >= 0) {
Eric W. Biedermanc4fa0bbf2006-10-04 02:16:40 -07001921 dynamic_irq_init(irq);
1922 }
1923 return irq;
1924}
1925
1926void destroy_irq(unsigned int irq)
1927{
1928 unsigned long flags;
Eric W. Biedermanc4fa0bbf2006-10-04 02:16:40 -07001929
1930 dynamic_irq_cleanup(irq);
1931
1932 spin_lock_irqsave(&vector_lock, flags);
Yinghai Lu5df02872006-12-07 02:14:05 +01001933 __clear_irq_vector(irq);
Eric W. Biedermanc4fa0bbf2006-10-04 02:16:40 -07001934 spin_unlock_irqrestore(&vector_lock, flags);
1935}
Eric W. Biedermanc4fa0bbf2006-10-04 02:16:40 -07001936
Eric W. Biederman589e3672006-10-04 02:16:42 -07001937/*
Simon Arlott676b1852007-10-20 01:25:36 +02001938 * MSI message composition
Eric W. Biederman589e3672006-10-04 02:16:42 -07001939 */
1940#ifdef CONFIG_PCI_MSI
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07001941static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
Eric W. Biederman589e3672006-10-04 02:16:42 -07001942{
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07001943 struct irq_cfg *cfg = irq_cfg + irq;
1944 int err;
Eric W. Biederman589e3672006-10-04 02:16:42 -07001945 unsigned dest;
Eric W. Biedermanc7111c132006-10-08 07:47:55 -06001946 cpumask_t tmp;
Eric W. Biederman589e3672006-10-04 02:16:42 -07001947
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07001948 tmp = TARGET_CPUS;
1949 err = assign_irq_vector(irq, tmp);
1950 if (!err) {
1951 cpus_and(tmp, cfg->domain, tmp);
Eric W. Biederman589e3672006-10-04 02:16:42 -07001952 dest = cpu_mask_to_apicid(tmp);
1953
1954 msg->address_hi = MSI_ADDR_BASE_HI;
1955 msg->address_lo =
1956 MSI_ADDR_BASE_LO |
1957 ((INT_DEST_MODE == 0) ?
1958 MSI_ADDR_DEST_MODE_PHYSICAL:
1959 MSI_ADDR_DEST_MODE_LOGICAL) |
1960 ((INT_DELIVERY_MODE != dest_LowestPrio) ?
1961 MSI_ADDR_REDIRECTION_CPU:
1962 MSI_ADDR_REDIRECTION_LOWPRI) |
1963 MSI_ADDR_DEST_ID(dest);
1964
1965 msg->data =
1966 MSI_DATA_TRIGGER_EDGE |
1967 MSI_DATA_LEVEL_ASSERT |
1968 ((INT_DELIVERY_MODE != dest_LowestPrio) ?
1969 MSI_DATA_DELIVERY_FIXED:
1970 MSI_DATA_DELIVERY_LOWPRI) |
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07001971 MSI_DATA_VECTOR(cfg->vector);
Eric W. Biederman589e3672006-10-04 02:16:42 -07001972 }
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07001973 return err;
Eric W. Biederman589e3672006-10-04 02:16:42 -07001974}
1975
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07001976#ifdef CONFIG_SMP
1977static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
1978{
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07001979 struct irq_cfg *cfg = irq_cfg + irq;
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07001980 struct msi_msg msg;
1981 unsigned int dest;
1982 cpumask_t tmp;
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07001983
1984 cpus_and(tmp, mask, cpu_online_map);
1985 if (cpus_empty(tmp))
Eric W. Biederman5ff51152007-02-23 04:20:59 -07001986 return;
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07001987
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07001988 if (assign_irq_vector(irq, mask))
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07001989 return;
1990
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07001991 cpus_and(tmp, cfg->domain, mask);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07001992 dest = cpu_mask_to_apicid(tmp);
1993
1994 read_msi_msg(irq, &msg);
1995
1996 msg.data &= ~MSI_DATA_VECTOR_MASK;
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07001997 msg.data |= MSI_DATA_VECTOR(cfg->vector);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07001998 msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
1999 msg.address_lo |= MSI_ADDR_DEST_ID(dest);
2000
2001 write_msi_msg(irq, &msg);
Eric W. Biederman9f0a5ba2007-02-23 04:13:55 -07002002 irq_desc[irq].affinity = mask;
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07002003}
2004#endif /* CONFIG_SMP */
2005
2006/*
2007 * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
2008 * which implement the MSI or MSI-X Capability Structure.
2009 */
2010static struct irq_chip msi_chip = {
2011 .name = "PCI-MSI",
2012 .unmask = unmask_msi_irq,
2013 .mask = mask_msi_irq,
2014 .ack = ack_apic_edge,
2015#ifdef CONFIG_SMP
2016 .set_affinity = set_msi_irq_affinity,
2017#endif
2018 .retrigger = ioapic_retrigger_irq,
2019};
2020
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -07002021int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07002022{
2023 struct msi_msg msg;
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -07002024 int irq, ret;
2025 irq = create_irq();
2026 if (irq < 0)
2027 return irq;
2028
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07002029 ret = msi_compose_msg(dev, irq, &msg);
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -07002030 if (ret < 0) {
2031 destroy_irq(irq);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07002032 return ret;
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -07002033 }
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07002034
Michael Ellerman7fe37302007-04-18 19:39:21 +10002035 set_irq_msi(irq, desc);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07002036 write_msi_msg(irq, &msg);
2037
Ingo Molnara460e742006-10-17 00:10:03 -07002038 set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07002039
Michael Ellerman7fe37302007-04-18 19:39:21 +10002040 return 0;
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07002041}
2042
2043void arch_teardown_msi_irq(unsigned int irq)
Eric W. Biederman589e3672006-10-04 02:16:42 -07002044{
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -07002045 destroy_irq(irq);
Eric W. Biederman589e3672006-10-04 02:16:42 -07002046}
2047
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002048#ifdef CONFIG_DMAR
2049#ifdef CONFIG_SMP
2050static void dmar_msi_set_affinity(unsigned int irq, cpumask_t mask)
2051{
2052 struct irq_cfg *cfg = irq_cfg + irq;
2053 struct msi_msg msg;
2054 unsigned int dest;
2055 cpumask_t tmp;
Eric W. Biederman589e3672006-10-04 02:16:42 -07002056
Keshavamurthy, Anil S3460a6d2007-10-21 16:41:54 -07002057 cpus_and(tmp, mask, cpu_online_map);
2058 if (cpus_empty(tmp))
2059 return;
2060
2061 if (assign_irq_vector(irq, mask))
2062 return;
2063
2064 cpus_and(tmp, cfg->domain, mask);
2065 dest = cpu_mask_to_apicid(tmp);
2066
2067 dmar_msi_read(irq, &msg);
2068
2069 msg.data &= ~MSI_DATA_VECTOR_MASK;
2070 msg.data |= MSI_DATA_VECTOR(cfg->vector);
2071 msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
2072 msg.address_lo |= MSI_ADDR_DEST_ID(dest);
2073
2074 dmar_msi_write(irq, &msg);
2075 irq_desc[irq].affinity = mask;
2076}
2077#endif /* CONFIG_SMP */
2078
2079struct irq_chip dmar_msi_type = {
2080 .name = "DMAR_MSI",
2081 .unmask = dmar_msi_unmask,
2082 .mask = dmar_msi_mask,
2083 .ack = ack_apic_edge,
2084#ifdef CONFIG_SMP
2085 .set_affinity = dmar_msi_set_affinity,
2086#endif
2087 .retrigger = ioapic_retrigger_irq,
2088};
2089
2090int arch_setup_dmar_msi(unsigned int irq)
2091{
2092 int ret;
2093 struct msi_msg msg;
2094
2095 ret = msi_compose_msg(NULL, irq, &msg);
2096 if (ret < 0)
2097 return ret;
2098 dmar_msi_write(irq, &msg);
2099 set_irq_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
2100 "edge");
2101 return 0;
2102}
2103#endif
2104
2105#endif /* CONFIG_PCI_MSI */
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002106/*
2107 * Hypertransport interrupt support
2108 */
2109#ifdef CONFIG_HT_IRQ
2110
2111#ifdef CONFIG_SMP
2112
2113static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
2114{
Eric W. Biedermanec683072006-11-08 17:44:57 -08002115 struct ht_irq_msg msg;
2116 fetch_ht_irq_msg(irq, &msg);
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002117
Eric W. Biedermanec683072006-11-08 17:44:57 -08002118 msg.address_lo &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK);
2119 msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002120
Eric W. Biedermanec683072006-11-08 17:44:57 -08002121 msg.address_lo |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest);
2122 msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest);
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002123
Eric W. Biedermanec683072006-11-08 17:44:57 -08002124 write_ht_irq_msg(irq, &msg);
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002125}
2126
2127static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
2128{
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07002129 struct irq_cfg *cfg = irq_cfg + irq;
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002130 unsigned int dest;
2131 cpumask_t tmp;
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002132
2133 cpus_and(tmp, mask, cpu_online_map);
2134 if (cpus_empty(tmp))
Eric W. Biederman5ff51152007-02-23 04:20:59 -07002135 return;
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002136
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07002137 if (assign_irq_vector(irq, mask))
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002138 return;
2139
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07002140 cpus_and(tmp, cfg->domain, mask);
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002141 dest = cpu_mask_to_apicid(tmp);
2142
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07002143 target_ht_irq(irq, dest, cfg->vector);
Eric W. Biederman9f0a5ba2007-02-23 04:13:55 -07002144 irq_desc[irq].affinity = mask;
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002145}
2146#endif
2147
Aneesh Kumar K.Vc37e1082006-10-11 01:20:43 -07002148static struct irq_chip ht_irq_chip = {
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002149 .name = "PCI-HT",
2150 .mask = mask_ht_irq,
2151 .unmask = unmask_ht_irq,
2152 .ack = ack_apic_edge,
2153#ifdef CONFIG_SMP
2154 .set_affinity = set_ht_irq_affinity,
2155#endif
2156 .retrigger = ioapic_retrigger_irq,
2157};
2158
2159int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
2160{
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07002161 struct irq_cfg *cfg = irq_cfg + irq;
2162 int err;
Eric W. Biedermanc7111c132006-10-08 07:47:55 -06002163 cpumask_t tmp;
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002164
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07002165 tmp = TARGET_CPUS;
2166 err = assign_irq_vector(irq, tmp);
2167 if (!err) {
Eric W. Biedermanec683072006-11-08 17:44:57 -08002168 struct ht_irq_msg msg;
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002169 unsigned dest;
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002170
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07002171 cpus_and(tmp, cfg->domain, tmp);
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002172 dest = cpu_mask_to_apicid(tmp);
2173
Eric W. Biedermanec683072006-11-08 17:44:57 -08002174 msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest);
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002175
Eric W. Biedermanec683072006-11-08 17:44:57 -08002176 msg.address_lo =
2177 HT_IRQ_LOW_BASE |
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002178 HT_IRQ_LOW_DEST_ID(dest) |
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07002179 HT_IRQ_LOW_VECTOR(cfg->vector) |
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002180 ((INT_DEST_MODE == 0) ?
2181 HT_IRQ_LOW_DM_PHYSICAL :
2182 HT_IRQ_LOW_DM_LOGICAL) |
2183 HT_IRQ_LOW_RQEOI_EDGE |
2184 ((INT_DELIVERY_MODE != dest_LowestPrio) ?
2185 HT_IRQ_LOW_MT_FIXED :
Eric W. Biedermanec683072006-11-08 17:44:57 -08002186 HT_IRQ_LOW_MT_ARBITRATED) |
2187 HT_IRQ_LOW_IRQ_MASKED;
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002188
Eric W. Biedermanec683072006-11-08 17:44:57 -08002189 write_ht_irq_msg(irq, &msg);
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002190
Ingo Molnara460e742006-10-17 00:10:03 -07002191 set_irq_chip_and_handler_name(irq, &ht_irq_chip,
2192 handle_edge_irq, "edge");
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002193 }
Eric W. Biedermandfbffdd2007-02-23 04:35:05 -07002194 return err;
Eric W. Biederman8b955b02006-10-04 02:16:55 -07002195}
2196#endif /* CONFIG_HT_IRQ */
2197
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198/* --------------------------------------------------------------------------
2199 ACPI-based IOAPIC Configuration
2200 -------------------------------------------------------------------------- */
2201
Len Brown888ba6c2005-08-24 12:07:20 -04002202#ifdef CONFIG_ACPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203
2204#define IO_APIC_MAX_ID 0xFE
2205
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206int __init io_apic_get_redir_entries (int ioapic)
2207{
2208 union IO_APIC_reg_01 reg_01;
2209 unsigned long flags;
2210
2211 spin_lock_irqsave(&ioapic_lock, flags);
2212 reg_01.raw = io_apic_read(ioapic, 1);
2213 spin_unlock_irqrestore(&ioapic_lock, flags);
2214
2215 return reg_01.bits.entries;
2216}
2217
2218
Bob Moore50eca3e2005-09-30 19:03:00 -04002219int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int polarity)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 if (!IO_APIC_IRQ(irq)) {
2222 apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
2223 ioapic);
2224 return -EINVAL;
2225 }
2226
Eric W. Biederman550f2292006-10-04 02:16:51 -07002227 /*
2228 * IRQs < 16 are already in the irq_2_pin[] map
2229 */
2230 if (irq >= 16)
2231 add_pin_to_irq(irq, ioapic, pin);
2232
Eric W. Biedermana8c8a362007-02-23 04:19:08 -07002233 setup_IO_APIC_irq(ioapic, pin, irq, triggering, polarity);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
2235 return 0;
2236}
2237
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238
Shaohua Li61fd47e2007-11-17 01:05:28 -05002239int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity)
2240{
2241 int i;
2242
2243 if (skip_ioapic_setup)
2244 return -1;
2245
2246 for (i = 0; i < mp_irq_entries; i++)
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +04002247 if (mp_irqs[i].mp_irqtype == mp_INT &&
2248 mp_irqs[i].mp_srcbusirq == bus_irq)
Shaohua Li61fd47e2007-11-17 01:05:28 -05002249 break;
2250 if (i >= mp_irq_entries)
2251 return -1;
2252
2253 *trigger = irq_trigger(i);
2254 *polarity = irq_polarity(i);
2255 return 0;
2256}
2257
2258#endif /* CONFIG_ACPI */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259
2260/*
2261 * This function currently is only a helper for the i386 smp boot process where
2262 * we need to reprogram the ioredtbls to cater for the cpus which have come online
2263 * so mask in all cases should simply be TARGET_CPUS
2264 */
Ashok Raj54d5d422005-09-06 15:16:15 -07002265#ifdef CONFIG_SMP
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266void __init setup_ioapic_dest(void)
2267{
2268 int pin, ioapic, irq, irq_entry;
2269
2270 if (skip_ioapic_setup == 1)
2271 return;
2272
2273 for (ioapic = 0; ioapic < nr_ioapics; ioapic++) {
2274 for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) {
2275 irq_entry = find_irq_entry(ioapic, pin, mp_INT);
2276 if (irq_entry == -1)
2277 continue;
2278 irq = pin_2_irq(irq_entry, ioapic, pin);
Yinghai Luad892f52006-12-07 02:14:19 +01002279
2280 /* setup_IO_APIC_irqs could fail to get vector for some device
2281 * when you have too many devices, because at that time only boot
2282 * cpu is online.
2283 */
Eric W. Biederman13a79502007-02-23 04:32:47 -07002284 if (!irq_cfg[irq].vector)
Eric W. Biedermana8c8a362007-02-23 04:19:08 -07002285 setup_IO_APIC_irq(ioapic, pin, irq,
2286 irq_trigger(irq_entry),
2287 irq_polarity(irq_entry));
Yinghai Luad892f52006-12-07 02:14:19 +01002288 else
2289 set_ioapic_affinity_irq(irq, TARGET_CPUS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 }
2291
2292 }
2293}
Ashok Raj54d5d422005-09-06 15:16:15 -07002294#endif
Shaohua Li61fd47e2007-11-17 01:05:28 -05002295
Thomas Gleixner3e35a0e2008-01-30 13:30:19 +01002296#define IOAPIC_RESOURCE_NAME_SIZE 11
2297
2298static struct resource *ioapic_resources;
2299
2300static struct resource * __init ioapic_setup_resources(void)
2301{
2302 unsigned long n;
2303 struct resource *res;
2304 char *mem;
2305 int i;
2306
2307 if (nr_ioapics <= 0)
2308 return NULL;
2309
2310 n = IOAPIC_RESOURCE_NAME_SIZE + sizeof(struct resource);
2311 n *= nr_ioapics;
2312
2313 mem = alloc_bootmem(n);
2314 res = (void *)mem;
2315
2316 if (mem != NULL) {
Thomas Gleixner3e35a0e2008-01-30 13:30:19 +01002317 mem += sizeof(struct resource) * nr_ioapics;
2318
2319 for (i = 0; i < nr_ioapics; i++) {
2320 res[i].name = mem;
2321 res[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY;
2322 sprintf(mem, "IOAPIC %u", i);
2323 mem += IOAPIC_RESOURCE_NAME_SIZE;
2324 }
2325 }
2326
2327 ioapic_resources = res;
2328
2329 return res;
2330}
2331
2332void __init ioapic_init_mappings(void)
2333{
2334 unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
2335 struct resource *ioapic_res;
2336 int i;
2337
2338 ioapic_res = ioapic_setup_resources();
2339 for (i = 0; i < nr_ioapics; i++) {
2340 if (smp_found_config) {
Alexey Starikovskiyec2cd0a2008-05-14 19:03:10 +04002341 ioapic_phys = mp_ioapics[i].mp_apicaddr;
Thomas Gleixner3e35a0e2008-01-30 13:30:19 +01002342 } else {
2343 ioapic_phys = (unsigned long)
2344 alloc_bootmem_pages(PAGE_SIZE);
2345 ioapic_phys = __pa(ioapic_phys);
2346 }
2347 set_fixmap_nocache(idx, ioapic_phys);
2348 apic_printk(APIC_VERBOSE,
2349 "mapped IOAPIC to %016lx (%016lx)\n",
2350 __fix_to_virt(idx), ioapic_phys);
2351 idx++;
2352
2353 if (ioapic_res != NULL) {
2354 ioapic_res->start = ioapic_phys;
2355 ioapic_res->end = ioapic_phys + (4 * 1024) - 1;
2356 ioapic_res++;
2357 }
2358 }
2359}
2360
2361static int __init ioapic_insert_resources(void)
2362{
2363 int i;
2364 struct resource *r = ioapic_resources;
2365
2366 if (!r) {
2367 printk(KERN_ERR
2368 "IO APIC resources could be not be allocated.\n");
2369 return -1;
2370 }
2371
2372 for (i = 0; i < nr_ioapics; i++) {
2373 insert_resource(&iomem_resource, r);
2374 r++;
2375 }
2376
2377 return 0;
2378}
2379
2380/* Insert the IO APIC resources after PCI initialization has occured to handle
2381 * IO APICS that are mapped in on a BAR in PCI space. */
2382late_initcall(ioapic_insert_resources);
2383