blob: 5aee1d1a306dcad5f4edde1283a6517ee3a4f11c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Intel IO-APIC support for multi-Pentium hosts.
3 *
Ingo Molnar8f47e162009-01-31 02:03:42 +01004 * Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
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>
Yinghai Lud4057bd2008-08-19 20:50:38 -070028#include <linux/pci.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/mc146818rtc.h>
30#include <linux/compiler.h>
31#include <linux/acpi.h>
Alexey Dobriyan129f6942005-06-23 00:08:33 -070032#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/sysdev.h>
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070034#include <linux/msi.h>
Eric W. Biederman95d77882006-10-04 02:17:01 -070035#include <linux/htirq.h>
Nigel Cunningham7dfb7102006-12-06 20:34:23 -080036#include <linux/freezer.h>
Eric W. Biedermanf26d6a22007-05-02 19:27:19 +020037#include <linux/kthread.h>
Ingo Molnar54168ed2008-08-20 09:07:45 +020038#include <linux/jiffies.h> /* time_after() */
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090039#include <linux/slab.h>
Yinghai Lud4057bd2008-08-19 20:50:38 -070040#ifdef CONFIG_ACPI
41#include <acpi/acpi_bus.h>
42#endif
43#include <linux/bootmem.h>
44#include <linux/dmar.h>
venkatesh.pallipadi@intel.com58ac1e72008-09-05 18:02:17 -070045#include <linux/hpet.h>
Ashok Raj54d5d422005-09-06 15:16:15 -070046
Yinghai Lud4057bd2008-08-19 20:50:38 -070047#include <asm/idle.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <asm/io.h>
49#include <asm/smp.h>
Jaswinder Singh Rajput6d652ea2009-01-07 21:38:59 +053050#include <asm/cpu.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <asm/desc.h>
Yinghai Lud4057bd2008-08-19 20:50:38 -070052#include <asm/proto.h>
53#include <asm/acpi.h>
54#include <asm/dma.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#include <asm/timer.h>
Ingo Molnar306e4402005-06-30 02:58:55 -070056#include <asm/i8259.h>
Don Zickus3e4ff112006-06-26 13:57:01 +020057#include <asm/nmi.h>
Eric W. Biederman2d3fcc12006-10-04 02:16:43 -070058#include <asm/msidef.h>
Eric W. Biederman8b955b02006-10-04 02:16:55 -070059#include <asm/hypertransport.h>
Yinghai Lua4dbc342008-07-25 02:14:28 -070060#include <asm/setup.h>
Yinghai Lud4057bd2008-08-19 20:50:38 -070061#include <asm/irq_remapping.h>
venkatesh.pallipadi@intel.com58ac1e72008-09-05 18:02:17 -070062#include <asm/hpet.h>
Jaswinder Singh Rajput2c1b2842009-04-11 00:03:10 +053063#include <asm/hw_irq.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Ingo Molnar7b6aa332009-02-17 13:58:15 +010065#include <asm/apic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
Maciej W. Rozycki32f71af2008-07-21 00:52:49 +010067#define __apicdebuginit(type) static type __init
Cyrill Gorcunov2977fb32009-08-01 11:47:59 +040068#define for_each_irq_pin(entry, head) \
69 for (entry = head; entry; entry = entry->next)
Maciej W. Rozycki32f71af2008-07-21 00:52:49 +010070
Linus Torvalds1da177e2005-04-16 15:20:36 -070071/*
Ingo Molnar54168ed2008-08-20 09:07:45 +020072 * Is the SiS APIC rmw bug present ?
73 * -1 = don't know, 0 = no, 1 = yes
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 */
75int sis_apic_bug = -1;
76
Thomas Gleixnerdade7712009-07-25 18:39:36 +020077static DEFINE_RAW_SPINLOCK(ioapic_lock);
78static DEFINE_RAW_SPINLOCK(vector_lock);
Yinghai Luefa25592008-08-19 20:50:36 -070079
Yinghai Luefa25592008-08-19 20:50:36 -070080/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 * # of IRQ routing registers
82 */
83int nr_ioapic_registers[MAX_IO_APICS];
84
Alexey Starikovskiy9f640cc2008-04-04 23:41:13 +040085/* I/O APIC entries */
Jaswinder Singh Rajputb5ba7e62009-01-12 17:46:17 +053086struct mpc_ioapic mp_ioapics[MAX_IO_APICS];
Alexey Starikovskiy9f640cc2008-04-04 23:41:13 +040087int nr_ioapics;
88
Feng Tang2a4ab642009-07-07 23:01:15 -040089/* IO APIC gsi routing info */
90struct mp_ioapic_gsi mp_gsi_routing[MAX_IO_APICS];
91
Eric W. Biedermana4384df2010-06-08 11:44:32 -070092/* The one past the highest gsi number used */
93u32 gsi_top;
Eric W. Biederman57773722010-03-30 01:07:10 -070094
Alexey Starikovskiy584f7342008-04-04 23:41:32 +040095/* MP IRQ source entries */
Jaswinder Singh Rajputc2c21742009-01-12 17:47:22 +053096struct mpc_intsrc mp_irqs[MAX_IRQ_SOURCES];
Alexey Starikovskiy584f7342008-04-04 23:41:32 +040097
98/* # of MP IRQ source entries */
99int mp_irq_entries;
100
Thomas Gleixnerbc078442009-08-29 18:09:57 +0200101/* GSI interrupts */
102static int nr_irqs_gsi = NR_IRQS_LEGACY;
103
Alexey Starikovskiy8732fc42008-05-19 19:47:16 +0400104#if defined (CONFIG_MCA) || defined (CONFIG_EISA)
105int mp_bus_id_to_type[MAX_MP_BUSSES];
106#endif
107
108DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES);
109
Yinghai Luefa25592008-08-19 20:50:36 -0700110int skip_ioapic_setup;
111
Ingo Molnar65a4e572009-01-31 03:36:17 +0100112void arch_disable_smp_support(void)
113{
114#ifdef CONFIG_PCI
115 noioapicquirk = 1;
116 noioapicreroute = -1;
117#endif
118 skip_ioapic_setup = 1;
119}
120
Ingo Molnar54168ed2008-08-20 09:07:45 +0200121static int __init parse_noapic(char *str)
Yinghai Luefa25592008-08-19 20:50:36 -0700122{
123 /* disable IO-APIC */
Ingo Molnar65a4e572009-01-31 03:36:17 +0100124 arch_disable_smp_support();
Yinghai Luefa25592008-08-19 20:50:36 -0700125 return 0;
126}
127early_param("noapic", parse_noapic);
Chuck Ebbert66759a02005-09-12 18:49:25 +0200128
Yinghai Lu0f978f42008-08-19 20:50:26 -0700129struct irq_pin_list {
130 int apic, pin;
131 struct irq_pin_list *next;
132};
Yinghai Lu301e6192008-08-19 20:50:02 -0700133
Yinghai Lu85ac16d2009-04-27 18:00:38 -0700134static struct irq_pin_list *get_one_free_irq_2_pin(int node)
Yinghai Lu0f978f42008-08-19 20:50:26 -0700135{
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800136 struct irq_pin_list *pin;
Yinghai Lu0f978f42008-08-19 20:50:26 -0700137
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800138 pin = kzalloc_node(sizeof(*pin), GFP_ATOMIC, node);
Yinghai Lu0f978f42008-08-19 20:50:26 -0700139
Yinghai Lu0f978f42008-08-19 20:50:26 -0700140 return pin;
141}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800143/* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
144#ifdef CONFIG_SPARSE_IRQ
Suresh Siddha97943392010-01-19 12:20:54 -0800145static struct irq_cfg irq_cfgx[NR_IRQS_LEGACY];
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800146#else
Suresh Siddha97943392010-01-19 12:20:54 -0800147static struct irq_cfg irq_cfgx[NR_IRQS];
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800148#endif
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800149
Yinghai Lu13a0c3c2008-12-26 02:05:47 -0800150int __init arch_early_irq_init(void)
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800151{
152 struct irq_cfg *cfg;
153 struct irq_desc *desc;
154 int count;
Yinghai Ludad213ae2009-05-28 18:14:40 -0700155 int node;
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800156 int i;
157
Jacob Pan1f912332010-02-05 04:06:56 -0800158 if (!legacy_pic->nr_legacy_irqs) {
159 nr_irqs_gsi = 0;
160 io_apic_irqs = ~0UL;
161 }
162
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800163 cfg = irq_cfgx;
164 count = ARRAY_SIZE(irq_cfgx);
Yinghai Ludad213ae2009-05-28 18:14:40 -0700165 node= cpu_to_node(boot_cpu_id);
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800166
167 for (i = 0; i < count; i++) {
168 desc = irq_to_desc(i);
169 desc->chip_data = &cfg[i];
Yinghai Lu12274e92009-06-11 15:07:48 -0700170 zalloc_cpumask_var_node(&cfg[i].domain, GFP_NOWAIT, node);
171 zalloc_cpumask_var_node(&cfg[i].old_domain, GFP_NOWAIT, node);
Suresh Siddha97943392010-01-19 12:20:54 -0800172 /*
173 * For legacy IRQ's, start with assigning irq0 to irq15 to
174 * IRQ0_VECTOR to IRQ15_VECTOR on cpu 0.
175 */
H. Peter Anvin54b56172010-02-22 16:25:18 -0800176 if (i < legacy_pic->nr_legacy_irqs) {
Suresh Siddha97943392010-01-19 12:20:54 -0800177 cfg[i].vector = IRQ0_VECTOR + i;
178 cpumask_set_cpu(0, cfg[i].domain);
179 }
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800180 }
Yinghai Lu13a0c3c2008-12-26 02:05:47 -0800181
182 return 0;
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800183}
184
185#ifdef CONFIG_SPARSE_IRQ
Dimitri Sivanich9338ad62009-10-13 15:32:36 -0500186struct irq_cfg *irq_cfg(unsigned int irq)
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800187{
188 struct irq_cfg *cfg = NULL;
189 struct irq_desc *desc;
190
191 desc = irq_to_desc(irq);
192 if (desc)
193 cfg = desc->chip_data;
194
195 return cfg;
196}
197
Yinghai Lu85ac16d2009-04-27 18:00:38 -0700198static struct irq_cfg *get_one_free_irq_cfg(int node)
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800199{
200 struct irq_cfg *cfg;
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800201
202 cfg = kzalloc_node(sizeof(*cfg), GFP_ATOMIC, node);
Mike Travis22f65d32008-12-16 17:33:56 -0800203 if (cfg) {
Li Zefan79f55992009-06-15 14:58:26 +0800204 if (!zalloc_cpumask_var_node(&cfg->domain, GFP_ATOMIC, node)) {
Mike Travis22f65d32008-12-16 17:33:56 -0800205 kfree(cfg);
206 cfg = NULL;
Li Zefan79f55992009-06-15 14:58:26 +0800207 } else if (!zalloc_cpumask_var_node(&cfg->old_domain,
Mike Travis80855f72008-12-31 18:08:47 -0800208 GFP_ATOMIC, node)) {
Mike Travis22f65d32008-12-16 17:33:56 -0800209 free_cpumask_var(cfg->domain);
210 kfree(cfg);
211 cfg = NULL;
Mike Travis22f65d32008-12-16 17:33:56 -0800212 }
213 }
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800214
215 return cfg;
216}
217
Yinghai Lu85ac16d2009-04-27 18:00:38 -0700218int arch_init_chip_data(struct irq_desc *desc, int node)
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800219{
220 struct irq_cfg *cfg;
221
222 cfg = desc->chip_data;
223 if (!cfg) {
Yinghai Lu85ac16d2009-04-27 18:00:38 -0700224 desc->chip_data = get_one_free_irq_cfg(node);
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800225 if (!desc->chip_data) {
226 printk(KERN_ERR "can not alloc irq_cfg\n");
227 BUG_ON(1);
228 }
229 }
Yinghai Lu13a0c3c2008-12-26 02:05:47 -0800230
231 return 0;
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800232}
233
Yinghai Lufcef5912009-04-27 17:58:23 -0700234/* for move_irq_desc */
Yinghai Lu48a1b102008-12-11 00:15:01 -0800235static void
Yinghai Lu85ac16d2009-04-27 18:00:38 -0700236init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int node)
Yinghai Lu48a1b102008-12-11 00:15:01 -0800237{
238 struct irq_pin_list *old_entry, *head, *tail, *entry;
239
240 cfg->irq_2_pin = NULL;
241 old_entry = old_cfg->irq_2_pin;
242 if (!old_entry)
243 return;
244
Yinghai Lu85ac16d2009-04-27 18:00:38 -0700245 entry = get_one_free_irq_2_pin(node);
Yinghai Lu48a1b102008-12-11 00:15:01 -0800246 if (!entry)
247 return;
248
249 entry->apic = old_entry->apic;
250 entry->pin = old_entry->pin;
251 head = entry;
252 tail = entry;
253 old_entry = old_entry->next;
254 while (old_entry) {
Yinghai Lu85ac16d2009-04-27 18:00:38 -0700255 entry = get_one_free_irq_2_pin(node);
Yinghai Lu48a1b102008-12-11 00:15:01 -0800256 if (!entry) {
257 entry = head;
258 while (entry) {
259 head = entry->next;
260 kfree(entry);
261 entry = head;
262 }
263 /* still use the old one */
264 return;
265 }
266 entry->apic = old_entry->apic;
267 entry->pin = old_entry->pin;
268 tail->next = entry;
269 tail = entry;
270 old_entry = old_entry->next;
271 }
272
273 tail->next = NULL;
274 cfg->irq_2_pin = head;
275}
276
277static void free_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg)
278{
279 struct irq_pin_list *entry, *next;
280
281 if (old_cfg->irq_2_pin == cfg->irq_2_pin)
282 return;
283
284 entry = old_cfg->irq_2_pin;
285
286 while (entry) {
287 next = entry->next;
288 kfree(entry);
289 entry = next;
290 }
291 old_cfg->irq_2_pin = NULL;
292}
293
294void arch_init_copy_chip_data(struct irq_desc *old_desc,
Yinghai Lu85ac16d2009-04-27 18:00:38 -0700295 struct irq_desc *desc, int node)
Yinghai Lu48a1b102008-12-11 00:15:01 -0800296{
297 struct irq_cfg *cfg;
298 struct irq_cfg *old_cfg;
299
Yinghai Lu85ac16d2009-04-27 18:00:38 -0700300 cfg = get_one_free_irq_cfg(node);
Yinghai Lu48a1b102008-12-11 00:15:01 -0800301
302 if (!cfg)
303 return;
304
305 desc->chip_data = cfg;
306
307 old_cfg = old_desc->chip_data;
308
309 memcpy(cfg, old_cfg, sizeof(struct irq_cfg));
310
Yinghai Lu85ac16d2009-04-27 18:00:38 -0700311 init_copy_irq_2_pin(old_cfg, cfg, node);
Yinghai Lu48a1b102008-12-11 00:15:01 -0800312}
313
314static void free_irq_cfg(struct irq_cfg *old_cfg)
315{
316 kfree(old_cfg);
317}
318
319void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc)
320{
321 struct irq_cfg *old_cfg, *cfg;
322
323 old_cfg = old_desc->chip_data;
324 cfg = desc->chip_data;
325
326 if (old_cfg == cfg)
327 return;
328
329 if (old_cfg) {
330 free_irq_2_pin(old_cfg, cfg);
331 free_irq_cfg(old_cfg);
332 old_desc->chip_data = NULL;
333 }
334}
Yinghai Lufcef5912009-04-27 17:58:23 -0700335/* end for move_irq_desc */
Yinghai Lu48a1b102008-12-11 00:15:01 -0800336
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800337#else
Dimitri Sivanich9338ad62009-10-13 15:32:36 -0500338struct irq_cfg *irq_cfg(unsigned int irq)
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -0800339{
340 return irq < nr_irqs ? irq_cfgx + irq : NULL;
341}
342
343#endif
344
Linus Torvalds130fe052006-11-01 09:11:00 -0800345struct io_apic {
346 unsigned int index;
347 unsigned int unused[3];
348 unsigned int data;
Suresh Siddha0280f7c2009-03-16 17:05:01 -0700349 unsigned int unused2[11];
350 unsigned int eoi;
Linus Torvalds130fe052006-11-01 09:11:00 -0800351};
352
353static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx)
354{
355 return (void __iomem *) __fix_to_virt(FIX_IO_APIC_BASE_0 + idx)
Jaswinder Singh Rajputb5ba7e62009-01-12 17:46:17 +0530356 + (mp_ioapics[idx].apicaddr & ~PAGE_MASK);
Linus Torvalds130fe052006-11-01 09:11:00 -0800357}
358
Suresh Siddha0280f7c2009-03-16 17:05:01 -0700359static inline void io_apic_eoi(unsigned int apic, unsigned int vector)
360{
361 struct io_apic __iomem *io_apic = io_apic_base(apic);
362 writel(vector, &io_apic->eoi);
363}
364
Linus Torvalds130fe052006-11-01 09:11:00 -0800365static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
366{
367 struct io_apic __iomem *io_apic = io_apic_base(apic);
368 writel(reg, &io_apic->index);
369 return readl(&io_apic->data);
370}
371
372static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
373{
374 struct io_apic __iomem *io_apic = io_apic_base(apic);
375 writel(reg, &io_apic->index);
376 writel(value, &io_apic->data);
377}
378
379/*
380 * Re-write a value: to be used for read-modify-write
381 * cycles where the read already set up the index register.
382 *
383 * Older SiS APIC requires we rewrite the index register
384 */
385static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
386{
Ingo Molnar54168ed2008-08-20 09:07:45 +0200387 struct io_apic __iomem *io_apic = io_apic_base(apic);
Thomas Gleixnerd6c88a52008-10-15 15:27:23 +0200388
389 if (sis_apic_bug)
390 writel(reg, &io_apic->index);
Linus Torvalds130fe052006-11-01 09:11:00 -0800391 writel(value, &io_apic->data);
392}
393
Yinghai Lu3145e942008-12-05 18:58:34 -0800394static bool io_apic_level_ack_pending(struct irq_cfg *cfg)
Yinghai Lu047c8fd2008-08-19 20:50:41 -0700395{
396 struct irq_pin_list *entry;
397 unsigned long flags;
Yinghai Lu047c8fd2008-08-19 20:50:41 -0700398
Thomas Gleixnerdade7712009-07-25 18:39:36 +0200399 raw_spin_lock_irqsave(&ioapic_lock, flags);
Cyrill Gorcunov2977fb32009-08-01 11:47:59 +0400400 for_each_irq_pin(entry, cfg->irq_2_pin) {
Yinghai Lu047c8fd2008-08-19 20:50:41 -0700401 unsigned int reg;
402 int pin;
403
Yinghai Lu047c8fd2008-08-19 20:50:41 -0700404 pin = entry->pin;
405 reg = io_apic_read(entry->apic, 0x10 + pin*2);
406 /* Is the remote IRR bit set? */
407 if (reg & IO_APIC_REDIR_REMOTE_IRR) {
Thomas Gleixnerdade7712009-07-25 18:39:36 +0200408 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Yinghai Lu047c8fd2008-08-19 20:50:41 -0700409 return true;
410 }
Yinghai Lu047c8fd2008-08-19 20:50:41 -0700411 }
Thomas Gleixnerdade7712009-07-25 18:39:36 +0200412 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Yinghai Lu047c8fd2008-08-19 20:50:41 -0700413
414 return false;
415}
Yinghai Lu047c8fd2008-08-19 20:50:41 -0700416
Andi Kleencf4c6a22006-09-26 10:52:30 +0200417union entry_union {
418 struct { u32 w1, w2; };
419 struct IO_APIC_route_entry entry;
420};
421
422static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin)
423{
424 union entry_union eu;
425 unsigned long flags;
Thomas Gleixnerdade7712009-07-25 18:39:36 +0200426 raw_spin_lock_irqsave(&ioapic_lock, flags);
Andi Kleencf4c6a22006-09-26 10:52:30 +0200427 eu.w1 = io_apic_read(apic, 0x10 + 2 * pin);
428 eu.w2 = io_apic_read(apic, 0x11 + 2 * pin);
Thomas Gleixnerdade7712009-07-25 18:39:36 +0200429 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Andi Kleencf4c6a22006-09-26 10:52:30 +0200430 return eu.entry;
431}
432
Linus Torvaldsf9dadfa2006-11-01 10:05:35 -0800433/*
434 * When we write a new IO APIC routing entry, we need to write the high
435 * word first! If the mask bit in the low word is clear, we will enable
436 * the interrupt, and we need to make sure the entry is fully populated
437 * before that happens.
438 */
Andi Kleend15512f2006-12-07 02:14:07 +0100439static void
440__ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
441{
Figo.zhang50a8d4d2009-06-17 22:25:20 +0800442 union entry_union eu = {{0, 0}};
443
Andi Kleend15512f2006-12-07 02:14:07 +0100444 eu.entry = e;
445 io_apic_write(apic, 0x11 + 2*pin, eu.w2);
446 io_apic_write(apic, 0x10 + 2*pin, eu.w1);
447}
448
Jeremy Fitzhardingeca97ab92009-02-09 12:05:47 -0800449void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
Andi Kleencf4c6a22006-09-26 10:52:30 +0200450{
451 unsigned long flags;
Thomas Gleixnerdade7712009-07-25 18:39:36 +0200452 raw_spin_lock_irqsave(&ioapic_lock, flags);
Andi Kleend15512f2006-12-07 02:14:07 +0100453 __ioapic_write_entry(apic, pin, e);
Thomas Gleixnerdade7712009-07-25 18:39:36 +0200454 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Linus Torvaldsf9dadfa2006-11-01 10:05:35 -0800455}
456
457/*
458 * When we mask an IO APIC routing entry, we need to write the low
459 * word first, in order to set the mask bit before we change the
460 * high bits!
461 */
462static void ioapic_mask_entry(int apic, int pin)
463{
464 unsigned long flags;
465 union entry_union eu = { .entry.mask = 1 };
466
Thomas Gleixnerdade7712009-07-25 18:39:36 +0200467 raw_spin_lock_irqsave(&ioapic_lock, flags);
Andi Kleencf4c6a22006-09-26 10:52:30 +0200468 io_apic_write(apic, 0x10 + 2*pin, eu.w1);
469 io_apic_write(apic, 0x11 + 2*pin, eu.w2);
Thomas Gleixnerdade7712009-07-25 18:39:36 +0200470 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Andi Kleencf4c6a22006-09-26 10:52:30 +0200471}
472
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473/*
474 * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
475 * shared ISA-space IRQs, so we have to support them. We are super
476 * fast in the common case, and fast for shared ISA-space IRQs.
477 */
Cyrill Gorcunovf3d19152009-08-06 00:09:31 +0400478static int
479add_pin_to_irq_node_nopanic(struct irq_cfg *cfg, int node, int apic, int pin)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480{
Cyrill Gorcunov2977fb32009-08-01 11:47:59 +0400481 struct irq_pin_list **last, *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
Cyrill Gorcunov2977fb32009-08-01 11:47:59 +0400483 /* don't allow duplicates */
484 last = &cfg->irq_2_pin;
485 for_each_irq_pin(entry, cfg->irq_2_pin) {
Yinghai Lu0f978f42008-08-19 20:50:26 -0700486 if (entry->apic == apic && entry->pin == pin)
Cyrill Gorcunovf3d19152009-08-06 00:09:31 +0400487 return 0;
Cyrill Gorcunov2977fb32009-08-01 11:47:59 +0400488 last = &entry->next;
Yinghai Lu0f978f42008-08-19 20:50:26 -0700489 }
490
Jeremy Fitzhardinge875e68e2009-06-08 03:24:11 -0700491 entry = get_one_free_irq_2_pin(node);
Cyrill Gorcunova7428cd2009-08-01 11:48:00 +0400492 if (!entry) {
Cyrill Gorcunovf3d19152009-08-06 00:09:31 +0400493 printk(KERN_ERR "can not alloc irq_pin_list (%d,%d,%d)\n",
494 node, apic, pin);
495 return -ENOMEM;
Cyrill Gorcunova7428cd2009-08-01 11:48:00 +0400496 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 entry->apic = apic;
498 entry->pin = pin;
Jeremy Fitzhardinge875e68e2009-06-08 03:24:11 -0700499
Cyrill Gorcunov2977fb32009-08-01 11:47:59 +0400500 *last = entry;
Cyrill Gorcunovf3d19152009-08-06 00:09:31 +0400501 return 0;
502}
503
504static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin)
505{
506 if (add_pin_to_irq_node_nopanic(cfg, node, apic, pin))
507 panic("IO-APIC: failed to add irq-pin. Can not proceed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508}
509
510/*
511 * Reroute an IRQ to a different pin.
512 */
Yinghai Lu85ac16d2009-04-27 18:00:38 -0700513static void __init replace_pin_at_irq_node(struct irq_cfg *cfg, int node,
Jeremy Fitzhardinge4eea6ff2009-06-08 03:32:15 -0700514 int oldapic, int oldpin,
515 int newapic, int newpin)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516{
Jeremy Fitzhardinge535b6422009-06-08 03:29:26 -0700517 struct irq_pin_list *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
Cyrill Gorcunov2977fb32009-08-01 11:47:59 +0400519 for_each_irq_pin(entry, cfg->irq_2_pin) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 if (entry->apic == oldapic && entry->pin == oldpin) {
521 entry->apic = newapic;
522 entry->pin = newpin;
Yinghai Lu0f978f42008-08-19 20:50:26 -0700523 /* every one is different, right? */
Jeremy Fitzhardinge4eea6ff2009-06-08 03:32:15 -0700524 return;
Yinghai Lu0f978f42008-08-19 20:50:26 -0700525 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 }
Yinghai Lu0f978f42008-08-19 20:50:26 -0700527
Jeremy Fitzhardinge4eea6ff2009-06-08 03:32:15 -0700528 /* old apic/pin didn't exist, so just add new ones */
529 add_pin_to_irq_node(cfg, node, newapic, newpin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530}
531
Suresh Siddhac29d9db2009-12-01 15:31:16 -0800532static void __io_apic_modify_irq(struct irq_pin_list *entry,
533 int mask_and, int mask_or,
534 void (*final)(struct irq_pin_list *entry))
535{
536 unsigned int reg, pin;
537
538 pin = entry->pin;
539 reg = io_apic_read(entry->apic, 0x10 + pin * 2);
540 reg &= mask_and;
541 reg |= mask_or;
542 io_apic_modify(entry->apic, 0x10 + pin * 2, reg);
543 if (final)
544 final(entry);
545}
546
Jeremy Fitzhardinge2f210de2009-06-08 02:55:22 -0700547static void io_apic_modify_irq(struct irq_cfg *cfg,
548 int mask_and, int mask_or,
549 void (*final)(struct irq_pin_list *entry))
Cyrill Gorcunov87783be2008-09-10 22:19:50 +0400550{
Cyrill Gorcunov87783be2008-09-10 22:19:50 +0400551 struct irq_pin_list *entry;
552
Suresh Siddhac29d9db2009-12-01 15:31:16 -0800553 for_each_irq_pin(entry, cfg->irq_2_pin)
554 __io_apic_modify_irq(entry, mask_and, mask_or, final);
555}
556
557static void __mask_and_edge_IO_APIC_irq(struct irq_pin_list *entry)
558{
559 __io_apic_modify_irq(entry, ~IO_APIC_REDIR_LEVEL_TRIGGER,
560 IO_APIC_REDIR_MASKED, NULL);
561}
562
563static void __unmask_and_level_IO_APIC_irq(struct irq_pin_list *entry)
564{
565 __io_apic_modify_irq(entry, ~IO_APIC_REDIR_MASKED,
566 IO_APIC_REDIR_LEVEL_TRIGGER, NULL);
Yinghai Lu047c8fd2008-08-19 20:50:41 -0700567}
568
Yinghai Lu3145e942008-12-05 18:58:34 -0800569static void __unmask_IO_APIC_irq(struct irq_cfg *cfg)
Cyrill Gorcunov87783be2008-09-10 22:19:50 +0400570{
Yinghai Lu3145e942008-12-05 18:58:34 -0800571 io_apic_modify_irq(cfg, ~IO_APIC_REDIR_MASKED, 0, NULL);
Cyrill Gorcunov87783be2008-09-10 22:19:50 +0400572}
Yinghai Lu4e738e22008-08-19 20:50:47 -0700573
Jaswinder Singh Rajput7f3e6322008-12-29 20:34:35 +0530574static void io_apic_sync(struct irq_pin_list *entry)
Yinghai Lu4e738e22008-08-19 20:50:47 -0700575{
Cyrill Gorcunov87783be2008-09-10 22:19:50 +0400576 /*
577 * Synchronize the IO-APIC and the CPU by doing
578 * a dummy read from the IO-APIC
579 */
580 struct io_apic __iomem *io_apic;
581 io_apic = io_apic_base(entry->apic);
Yinghai Lu4e738e22008-08-19 20:50:47 -0700582 readl(&io_apic->data);
583}
584
Yinghai Lu3145e942008-12-05 18:58:34 -0800585static void __mask_IO_APIC_irq(struct irq_cfg *cfg)
Cyrill Gorcunov87783be2008-09-10 22:19:50 +0400586{
Yinghai Lu3145e942008-12-05 18:58:34 -0800587 io_apic_modify_irq(cfg, ~0, IO_APIC_REDIR_MASKED, &io_apic_sync);
Cyrill Gorcunov87783be2008-09-10 22:19:50 +0400588}
Yinghai Lu047c8fd2008-08-19 20:50:41 -0700589
Yinghai Lu3145e942008-12-05 18:58:34 -0800590static void mask_IO_APIC_irq_desc(struct irq_desc *desc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591{
Yinghai Lu3145e942008-12-05 18:58:34 -0800592 struct irq_cfg *cfg = desc->chip_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 unsigned long flags;
594
Yinghai Lu3145e942008-12-05 18:58:34 -0800595 BUG_ON(!cfg);
596
Thomas Gleixnerdade7712009-07-25 18:39:36 +0200597 raw_spin_lock_irqsave(&ioapic_lock, flags);
Yinghai Lu3145e942008-12-05 18:58:34 -0800598 __mask_IO_APIC_irq(cfg);
Thomas Gleixnerdade7712009-07-25 18:39:36 +0200599 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600}
601
Yinghai Lu3145e942008-12-05 18:58:34 -0800602static void unmask_IO_APIC_irq_desc(struct irq_desc *desc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603{
Yinghai Lu3145e942008-12-05 18:58:34 -0800604 struct irq_cfg *cfg = desc->chip_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 unsigned long flags;
606
Thomas Gleixnerdade7712009-07-25 18:39:36 +0200607 raw_spin_lock_irqsave(&ioapic_lock, flags);
Yinghai Lu3145e942008-12-05 18:58:34 -0800608 __unmask_IO_APIC_irq(cfg);
Thomas Gleixnerdade7712009-07-25 18:39:36 +0200609 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610}
611
Yinghai Lu3145e942008-12-05 18:58:34 -0800612static void mask_IO_APIC_irq(unsigned int irq)
613{
614 struct irq_desc *desc = irq_to_desc(irq);
615
616 mask_IO_APIC_irq_desc(desc);
617}
618static void unmask_IO_APIC_irq(unsigned int irq)
619{
620 struct irq_desc *desc = irq_to_desc(irq);
621
622 unmask_IO_APIC_irq_desc(desc);
623}
624
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
626{
627 struct IO_APIC_route_entry entry;
Paolo Ciarrocchi36062442008-06-08 13:07:18 +0200628
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 /* Check delivery_mode to be sure we're not clearing an SMI pin */
Andi Kleencf4c6a22006-09-26 10:52:30 +0200630 entry = ioapic_read_entry(apic, pin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 if (entry.delivery_mode == dest_SMI)
632 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 /*
634 * Disable it in the IO-APIC irq-routing table:
635 */
Linus Torvaldsf9dadfa2006-11-01 10:05:35 -0800636 ioapic_mask_entry(apic, pin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637}
638
Ingo Molnar54168ed2008-08-20 09:07:45 +0200639static void clear_IO_APIC (void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640{
641 int apic, pin;
642
643 for (apic = 0; apic < nr_ioapics; apic++)
644 for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
645 clear_IO_APIC_pin(apic, pin);
646}
647
Ingo Molnar54168ed2008-08-20 09:07:45 +0200648#ifdef CONFIG_X86_32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649/*
650 * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to
651 * specific CPU-side IRQs.
652 */
653
654#define MAX_PIRQS 8
Yinghai Lu3bd25d02009-02-15 02:54:03 -0800655static int pirq_entries[MAX_PIRQS] = {
656 [0 ... MAX_PIRQS - 1] = -1
657};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659static int __init ioapic_pirq_setup(char *str)
660{
661 int i, max;
662 int ints[MAX_PIRQS+1];
663
664 get_options(str, ARRAY_SIZE(ints), ints);
665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 apic_printk(APIC_VERBOSE, KERN_INFO
667 "PIRQ redirection, working around broken MP-BIOS.\n");
668 max = MAX_PIRQS;
669 if (ints[0] < MAX_PIRQS)
670 max = ints[0];
671
672 for (i = 0; i < max; i++) {
673 apic_printk(APIC_VERBOSE, KERN_DEBUG
674 "... PIRQ%d -> IRQ %d\n", i, ints[i+1]);
675 /*
676 * PIRQs are mapped upside down, usually.
677 */
678 pirq_entries[MAX_PIRQS-i-1] = ints[i+1];
679 }
680 return 1;
681}
682
683__setup("pirq=", ioapic_pirq_setup);
Ingo Molnar54168ed2008-08-20 09:07:45 +0200684#endif /* CONFIG_X86_32 */
685
Fenghua Yub24696b2009-03-27 14:22:44 -0700686struct IO_APIC_route_entry **alloc_ioapic_entries(void)
687{
688 int apic;
689 struct IO_APIC_route_entry **ioapic_entries;
690
691 ioapic_entries = kzalloc(sizeof(*ioapic_entries) * nr_ioapics,
692 GFP_ATOMIC);
693 if (!ioapic_entries)
694 return 0;
695
696 for (apic = 0; apic < nr_ioapics; apic++) {
697 ioapic_entries[apic] =
698 kzalloc(sizeof(struct IO_APIC_route_entry) *
699 nr_ioapic_registers[apic], GFP_ATOMIC);
700 if (!ioapic_entries[apic])
701 goto nomem;
702 }
703
704 return ioapic_entries;
705
706nomem:
707 while (--apic >= 0)
708 kfree(ioapic_entries[apic]);
709 kfree(ioapic_entries);
710
711 return 0;
712}
Ingo Molnar54168ed2008-08-20 09:07:45 +0200713
714/*
Suresh Siddha05c3dc22009-03-16 17:05:03 -0700715 * Saves all the IO-APIC RTE's
Ingo Molnar54168ed2008-08-20 09:07:45 +0200716 */
Fenghua Yub24696b2009-03-27 14:22:44 -0700717int save_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
Ingo Molnar54168ed2008-08-20 09:07:45 +0200718{
Ingo Molnar54168ed2008-08-20 09:07:45 +0200719 int apic, pin;
720
Fenghua Yub24696b2009-03-27 14:22:44 -0700721 if (!ioapic_entries)
722 return -ENOMEM;
Ingo Molnar54168ed2008-08-20 09:07:45 +0200723
724 for (apic = 0; apic < nr_ioapics; apic++) {
Fenghua Yub24696b2009-03-27 14:22:44 -0700725 if (!ioapic_entries[apic])
726 return -ENOMEM;
Ingo Molnar54168ed2008-08-20 09:07:45 +0200727
Suresh Siddha05c3dc22009-03-16 17:05:03 -0700728 for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
Fenghua Yub24696b2009-03-27 14:22:44 -0700729 ioapic_entries[apic][pin] =
Ingo Molnar54168ed2008-08-20 09:07:45 +0200730 ioapic_read_entry(apic, pin);
Fenghua Yub24696b2009-03-27 14:22:44 -0700731 }
Cyrill Gorcunov5ffa4eb2008-09-18 23:37:57 +0400732
Ingo Molnar54168ed2008-08-20 09:07:45 +0200733 return 0;
734}
735
Fenghua Yub24696b2009-03-27 14:22:44 -0700736/*
737 * Mask all IO APIC entries.
738 */
739void mask_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
Suresh Siddha05c3dc22009-03-16 17:05:03 -0700740{
741 int apic, pin;
742
Fenghua Yub24696b2009-03-27 14:22:44 -0700743 if (!ioapic_entries)
744 return;
745
Suresh Siddha05c3dc22009-03-16 17:05:03 -0700746 for (apic = 0; apic < nr_ioapics; apic++) {
Fenghua Yub24696b2009-03-27 14:22:44 -0700747 if (!ioapic_entries[apic])
Suresh Siddha05c3dc22009-03-16 17:05:03 -0700748 break;
Fenghua Yub24696b2009-03-27 14:22:44 -0700749
Suresh Siddha05c3dc22009-03-16 17:05:03 -0700750 for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
751 struct IO_APIC_route_entry entry;
752
Fenghua Yub24696b2009-03-27 14:22:44 -0700753 entry = ioapic_entries[apic][pin];
Suresh Siddha05c3dc22009-03-16 17:05:03 -0700754 if (!entry.mask) {
755 entry.mask = 1;
756 ioapic_write_entry(apic, pin, entry);
757 }
758 }
759 }
760}
761
Fenghua Yub24696b2009-03-27 14:22:44 -0700762/*
763 * Restore IO APIC entries which was saved in ioapic_entries.
764 */
765int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
Ingo Molnar54168ed2008-08-20 09:07:45 +0200766{
767 int apic, pin;
768
Fenghua Yub24696b2009-03-27 14:22:44 -0700769 if (!ioapic_entries)
770 return -ENOMEM;
771
Cyrill Gorcunov5ffa4eb2008-09-18 23:37:57 +0400772 for (apic = 0; apic < nr_ioapics; apic++) {
Fenghua Yub24696b2009-03-27 14:22:44 -0700773 if (!ioapic_entries[apic])
774 return -ENOMEM;
775
Ingo Molnar54168ed2008-08-20 09:07:45 +0200776 for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
777 ioapic_write_entry(apic, pin,
Fenghua Yub24696b2009-03-27 14:22:44 -0700778 ioapic_entries[apic][pin]);
Cyrill Gorcunov5ffa4eb2008-09-18 23:37:57 +0400779 }
Fenghua Yub24696b2009-03-27 14:22:44 -0700780 return 0;
Ingo Molnar54168ed2008-08-20 09:07:45 +0200781}
782
Fenghua Yub24696b2009-03-27 14:22:44 -0700783void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries)
784{
785 int apic;
786
787 for (apic = 0; apic < nr_ioapics; apic++)
788 kfree(ioapic_entries[apic]);
789
790 kfree(ioapic_entries);
Ingo Molnar54168ed2008-08-20 09:07:45 +0200791}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
793/*
794 * Find the IRQ entry number of a certain pin.
795 */
796static int find_irq_entry(int apic, int pin, int type)
797{
798 int i;
799
800 for (i = 0; i < mp_irq_entries; i++)
Jaswinder Singh Rajputc2c21742009-01-12 17:47:22 +0530801 if (mp_irqs[i].irqtype == type &&
802 (mp_irqs[i].dstapic == mp_ioapics[apic].apicid ||
803 mp_irqs[i].dstapic == MP_APIC_ALL) &&
804 mp_irqs[i].dstirq == pin)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 return i;
806
807 return -1;
808}
809
810/*
811 * Find the pin to which IRQ[irq] (ISA) is connected
812 */
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -0800813static int __init find_isa_irq_pin(int irq, int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814{
815 int i;
816
817 for (i = 0; i < mp_irq_entries; i++) {
Jaswinder Singh Rajputc2c21742009-01-12 17:47:22 +0530818 int lbus = mp_irqs[i].srcbus;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
Alexey Starikovskiyd27e2b82008-03-20 14:54:18 +0300820 if (test_bit(lbus, mp_bus_not_pci) &&
Jaswinder Singh Rajputc2c21742009-01-12 17:47:22 +0530821 (mp_irqs[i].irqtype == type) &&
822 (mp_irqs[i].srcbusirq == irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
Jaswinder Singh Rajputc2c21742009-01-12 17:47:22 +0530824 return mp_irqs[i].dstirq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 }
826 return -1;
827}
828
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -0800829static int __init find_isa_irq_apic(int irq, int type)
830{
831 int i;
832
833 for (i = 0; i < mp_irq_entries; i++) {
Jaswinder Singh Rajputc2c21742009-01-12 17:47:22 +0530834 int lbus = mp_irqs[i].srcbus;
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -0800835
Alexey Starikovskiy73b29612008-03-20 14:54:24 +0300836 if (test_bit(lbus, mp_bus_not_pci) &&
Jaswinder Singh Rajputc2c21742009-01-12 17:47:22 +0530837 (mp_irqs[i].irqtype == type) &&
838 (mp_irqs[i].srcbusirq == irq))
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -0800839 break;
840 }
841 if (i < mp_irq_entries) {
842 int apic;
Ingo Molnar54168ed2008-08-20 09:07:45 +0200843 for(apic = 0; apic < nr_ioapics; apic++) {
Jaswinder Singh Rajputc2c21742009-01-12 17:47:22 +0530844 if (mp_ioapics[apic].apicid == mp_irqs[i].dstapic)
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -0800845 return apic;
846 }
847 }
848
849 return -1;
850}
851
Alexey Starikovskiyc0a282c2008-03-20 14:55:02 +0300852#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853/*
854 * EISA Edge/Level control register, ELCR
855 */
856static int EISA_ELCR(unsigned int irq)
857{
Jacob Panb81bb372009-11-09 11:27:04 -0800858 if (irq < legacy_pic->nr_legacy_irqs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 unsigned int port = 0x4d0 + (irq >> 3);
860 return (inb(port) >> (irq & 7)) & 1;
861 }
862 apic_printk(APIC_VERBOSE, KERN_INFO
863 "Broken MPtable reports ISA irq %d\n", irq);
864 return 0;
865}
Ingo Molnar54168ed2008-08-20 09:07:45 +0200866
Alexey Starikovskiyc0a282c2008-03-20 14:55:02 +0300867#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868
Alexey Starikovskiy67288012008-03-20 14:54:36 +0300869/* ISA interrupts are always polarity zero edge triggered,
870 * when listed as conforming in the MP table. */
871
872#define default_ISA_trigger(idx) (0)
873#define default_ISA_polarity(idx) (0)
874
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875/* EISA interrupts are always polarity zero and can be edge or level
876 * trigger depending on the ELCR value. If an interrupt is listed as
877 * EISA conforming in the MP table, that means its trigger type must
878 * be read in from the ELCR */
879
Jaswinder Singh Rajputc2c21742009-01-12 17:47:22 +0530880#define default_EISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].srcbusirq))
Alexey Starikovskiy67288012008-03-20 14:54:36 +0300881#define default_EISA_polarity(idx) default_ISA_polarity(idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882
883/* PCI interrupts are always polarity one level triggered,
884 * when listed as conforming in the MP table. */
885
886#define default_PCI_trigger(idx) (1)
887#define default_PCI_polarity(idx) (1)
888
889/* MCA interrupts are always polarity zero level triggered,
890 * when listed as conforming in the MP table. */
891
892#define default_MCA_trigger(idx) (1)
Alexey Starikovskiy67288012008-03-20 14:54:36 +0300893#define default_MCA_polarity(idx) default_ISA_polarity(idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
Shaohua Li61fd47e2007-11-17 01:05:28 -0500895static int MPBIOS_polarity(int idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896{
Jaswinder Singh Rajputc2c21742009-01-12 17:47:22 +0530897 int bus = mp_irqs[idx].srcbus;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 int polarity;
899
900 /*
901 * Determine IRQ line polarity (high active or low active):
902 */
Jaswinder Singh Rajputc2c21742009-01-12 17:47:22 +0530903 switch (mp_irqs[idx].irqflag & 3)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 {
Ingo Molnar54168ed2008-08-20 09:07:45 +0200905 case 0: /* conforms, ie. bus-type dependent polarity */
906 if (test_bit(bus, mp_bus_not_pci))
907 polarity = default_ISA_polarity(idx);
908 else
909 polarity = default_PCI_polarity(idx);
910 break;
911 case 1: /* high active */
912 {
913 polarity = 0;
914 break;
915 }
916 case 2: /* reserved */
917 {
918 printk(KERN_WARNING "broken BIOS!!\n");
919 polarity = 1;
920 break;
921 }
922 case 3: /* low active */
923 {
924 polarity = 1;
925 break;
926 }
927 default: /* invalid */
928 {
929 printk(KERN_WARNING "broken BIOS!!\n");
930 polarity = 1;
931 break;
932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 }
934 return polarity;
935}
936
937static int MPBIOS_trigger(int idx)
938{
Jaswinder Singh Rajputc2c21742009-01-12 17:47:22 +0530939 int bus = mp_irqs[idx].srcbus;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 int trigger;
941
942 /*
943 * Determine IRQ trigger mode (edge or level sensitive):
944 */
Jaswinder Singh Rajputc2c21742009-01-12 17:47:22 +0530945 switch ((mp_irqs[idx].irqflag>>2) & 3)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 {
Ingo Molnar54168ed2008-08-20 09:07:45 +0200947 case 0: /* conforms, ie. bus-type dependent */
948 if (test_bit(bus, mp_bus_not_pci))
949 trigger = default_ISA_trigger(idx);
950 else
951 trigger = default_PCI_trigger(idx);
Alexey Starikovskiyc0a282c2008-03-20 14:55:02 +0300952#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
Ingo Molnar54168ed2008-08-20 09:07:45 +0200953 switch (mp_bus_id_to_type[bus]) {
954 case MP_BUS_ISA: /* ISA pin */
955 {
956 /* set before the switch */
957 break;
958 }
959 case MP_BUS_EISA: /* EISA pin */
960 {
961 trigger = default_EISA_trigger(idx);
962 break;
963 }
964 case MP_BUS_PCI: /* PCI pin */
965 {
966 /* set before the switch */
967 break;
968 }
969 case MP_BUS_MCA: /* MCA pin */
970 {
971 trigger = default_MCA_trigger(idx);
972 break;
973 }
974 default:
975 {
976 printk(KERN_WARNING "broken BIOS!!\n");
977 trigger = 1;
978 break;
979 }
980 }
981#endif
982 break;
983 case 1: /* edge */
Paolo Ciarrocchi36062442008-06-08 13:07:18 +0200984 {
Ingo Molnar54168ed2008-08-20 09:07:45 +0200985 trigger = 0;
Paolo Ciarrocchi36062442008-06-08 13:07:18 +0200986 break;
987 }
Ingo Molnar54168ed2008-08-20 09:07:45 +0200988 case 2: /* reserved */
Paolo Ciarrocchi36062442008-06-08 13:07:18 +0200989 {
990 printk(KERN_WARNING "broken BIOS!!\n");
991 trigger = 1;
992 break;
993 }
Ingo Molnar54168ed2008-08-20 09:07:45 +0200994 case 3: /* level */
995 {
996 trigger = 1;
997 break;
998 }
999 default: /* invalid */
1000 {
1001 printk(KERN_WARNING "broken BIOS!!\n");
1002 trigger = 0;
1003 break;
1004 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 }
1006 return trigger;
1007}
1008
1009static inline int irq_polarity(int idx)
1010{
1011 return MPBIOS_polarity(idx);
1012}
1013
1014static inline int irq_trigger(int idx)
1015{
1016 return MPBIOS_trigger(idx);
1017}
1018
1019static int pin_2_irq(int idx, int apic, int pin)
1020{
Eric W. Biedermand4642072010-03-30 01:07:13 -07001021 int irq;
Jaswinder Singh Rajputc2c21742009-01-12 17:47:22 +05301022 int bus = mp_irqs[idx].srcbus;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
1024 /*
1025 * Debugging check, we are in big trouble if this message pops up!
1026 */
Jaswinder Singh Rajputc2c21742009-01-12 17:47:22 +05301027 if (mp_irqs[idx].dstirq != pin)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n");
1029
Ingo Molnar54168ed2008-08-20 09:07:45 +02001030 if (test_bit(bus, mp_bus_not_pci)) {
Jaswinder Singh Rajputc2c21742009-01-12 17:47:22 +05301031 irq = mp_irqs[idx].srcbusirq;
Ingo Molnar54168ed2008-08-20 09:07:45 +02001032 } else {
Eric W. Biedermand4642072010-03-30 01:07:13 -07001033 u32 gsi = mp_gsi_routing[apic].gsi_base + pin;
Eric W. Biederman988856e2010-03-30 01:07:15 -07001034
1035 if (gsi >= NR_IRQS_LEGACY)
1036 irq = gsi;
1037 else
Eric W. Biedermana4384df2010-06-08 11:44:32 -07001038 irq = gsi_top + gsi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 }
1040
Ingo Molnar54168ed2008-08-20 09:07:45 +02001041#ifdef CONFIG_X86_32
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 /*
1043 * PCI IRQ command line redirection. Yes, limits are hardcoded.
1044 */
1045 if ((pin >= 16) && (pin <= 23)) {
1046 if (pirq_entries[pin-16] != -1) {
1047 if (!pirq_entries[pin-16]) {
1048 apic_printk(APIC_VERBOSE, KERN_DEBUG
1049 "disabling PIRQ%d\n", pin-16);
1050 } else {
1051 irq = pirq_entries[pin-16];
1052 apic_printk(APIC_VERBOSE, KERN_DEBUG
1053 "using PIRQ%d -> IRQ %d\n",
1054 pin-16, irq);
1055 }
1056 }
1057 }
Ingo Molnar54168ed2008-08-20 09:07:45 +02001058#endif
1059
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 return irq;
1061}
1062
Yinghai Lue20c06f2009-05-06 10:08:22 -07001063/*
1064 * Find a specific PCI IRQ entry.
1065 * Not an __init, possibly needed by modules
1066 */
1067int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin,
Yinghai Lue5198072009-05-15 13:05:16 -07001068 struct io_apic_irq_attr *irq_attr)
Yinghai Lue20c06f2009-05-06 10:08:22 -07001069{
1070 int apic, i, best_guess = -1;
1071
1072 apic_printk(APIC_DEBUG,
1073 "querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",
1074 bus, slot, pin);
1075 if (test_bit(bus, mp_bus_not_pci)) {
1076 apic_printk(APIC_VERBOSE,
1077 "PCI BIOS passed nonexistent PCI bus %d!\n", bus);
1078 return -1;
1079 }
1080 for (i = 0; i < mp_irq_entries; i++) {
1081 int lbus = mp_irqs[i].srcbus;
1082
1083 for (apic = 0; apic < nr_ioapics; apic++)
1084 if (mp_ioapics[apic].apicid == mp_irqs[i].dstapic ||
1085 mp_irqs[i].dstapic == MP_APIC_ALL)
1086 break;
1087
1088 if (!test_bit(lbus, mp_bus_not_pci) &&
1089 !mp_irqs[i].irqtype &&
1090 (bus == lbus) &&
1091 (slot == ((mp_irqs[i].srcbusirq >> 2) & 0x1f))) {
1092 int irq = pin_2_irq(i, apic, mp_irqs[i].dstirq);
1093
1094 if (!(apic || IO_APIC_IRQ(irq)))
1095 continue;
1096
1097 if (pin == (mp_irqs[i].srcbusirq & 3)) {
Yinghai Lue5198072009-05-15 13:05:16 -07001098 set_io_apic_irq_attr(irq_attr, apic,
1099 mp_irqs[i].dstirq,
1100 irq_trigger(i),
1101 irq_polarity(i));
Yinghai Lue20c06f2009-05-06 10:08:22 -07001102 return irq;
1103 }
1104 /*
1105 * Use the first all-but-pin matching entry as a
1106 * best-guess fuzzy result for broken mptables.
1107 */
1108 if (best_guess < 0) {
Yinghai Lue5198072009-05-15 13:05:16 -07001109 set_io_apic_irq_attr(irq_attr, apic,
1110 mp_irqs[i].dstirq,
1111 irq_trigger(i),
1112 irq_polarity(i));
Yinghai Lue20c06f2009-05-06 10:08:22 -07001113 best_guess = irq;
1114 }
1115 }
1116 }
1117 return best_guess;
1118}
1119EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
1120
Yinghai Lu497c9a12008-08-19 20:50:28 -07001121void lock_vector_lock(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122{
Yinghai Lu497c9a12008-08-19 20:50:28 -07001123 /* Used to the online set of cpus does not change
1124 * during assign_irq_vector.
1125 */
Thomas Gleixnerdade7712009-07-25 18:39:36 +02001126 raw_spin_lock(&vector_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127}
1128
Yinghai Lu497c9a12008-08-19 20:50:28 -07001129void unlock_vector_lock(void)
Eric W. Biedermanace80ab2006-10-04 02:16:47 -07001130{
Thomas Gleixnerdade7712009-07-25 18:39:36 +02001131 raw_spin_unlock(&vector_lock);
Yinghai Lu497c9a12008-08-19 20:50:28 -07001132}
1133
Mike Travise7986732008-12-16 17:33:52 -08001134static int
1135__assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
Yinghai Lu497c9a12008-08-19 20:50:28 -07001136{
Yinghai Lu047c8fd2008-08-19 20:50:41 -07001137 /*
1138 * NOTE! The local APIC isn't very good at handling
1139 * multiple interrupts at the same interrupt level.
1140 * As the interrupt level is determined by taking the
1141 * vector number and shifting that right by 4, we
1142 * want to spread these out a bit so that they don't
1143 * all fall in the same interrupt level.
1144 *
1145 * Also, we've got to be careful not to trash gate
1146 * 0x80, because int 0x80 is hm, kind of importantish. ;)
1147 */
Suresh Siddha6579b472010-01-13 16:19:11 -08001148 static int current_vector = FIRST_EXTERNAL_VECTOR + VECTOR_OFFSET_START;
H. Peter Anvinea943962010-01-04 21:14:41 -08001149 static int current_offset = VECTOR_OFFSET_START % 8;
Ingo Molnar54168ed2008-08-20 09:07:45 +02001150 unsigned int old_vector;
Mike Travis22f65d32008-12-16 17:33:56 -08001151 int cpu, err;
1152 cpumask_var_t tmp_mask;
Yinghai Lu497c9a12008-08-19 20:50:28 -07001153
Suresh Siddha23359a82009-10-26 14:24:33 -08001154 if (cfg->move_in_progress)
Ingo Molnar54168ed2008-08-20 09:07:45 +02001155 return -EBUSY;
Yinghai Lu497c9a12008-08-19 20:50:28 -07001156
Mike Travis22f65d32008-12-16 17:33:56 -08001157 if (!alloc_cpumask_var(&tmp_mask, GFP_ATOMIC))
1158 return -ENOMEM;
Yinghai Lu3145e942008-12-05 18:58:34 -08001159
Ingo Molnar54168ed2008-08-20 09:07:45 +02001160 old_vector = cfg->vector;
1161 if (old_vector) {
Mike Travis22f65d32008-12-16 17:33:56 -08001162 cpumask_and(tmp_mask, mask, cpu_online_mask);
1163 cpumask_and(tmp_mask, cfg->domain, tmp_mask);
1164 if (!cpumask_empty(tmp_mask)) {
1165 free_cpumask_var(tmp_mask);
Ingo Molnar54168ed2008-08-20 09:07:45 +02001166 return 0;
Mike Travis22f65d32008-12-16 17:33:56 -08001167 }
Ingo Molnar54168ed2008-08-20 09:07:45 +02001168 }
Yinghai Lu497c9a12008-08-19 20:50:28 -07001169
Mike Travise7986732008-12-16 17:33:52 -08001170 /* Only try and allocate irqs on cpus that are present */
Mike Travis22f65d32008-12-16 17:33:56 -08001171 err = -ENOSPC;
1172 for_each_cpu_and(cpu, mask, cpu_online_mask) {
Ingo Molnar54168ed2008-08-20 09:07:45 +02001173 int new_cpu;
1174 int vector, offset;
Yinghai Lu497c9a12008-08-19 20:50:28 -07001175
Ingo Molnare2d40b12009-01-28 06:50:47 +01001176 apic->vector_allocation_domain(cpu, tmp_mask);
Yinghai Lu497c9a12008-08-19 20:50:28 -07001177
Ingo Molnar54168ed2008-08-20 09:07:45 +02001178 vector = current_vector;
1179 offset = current_offset;
Yinghai Lu497c9a12008-08-19 20:50:28 -07001180next:
Ingo Molnar54168ed2008-08-20 09:07:45 +02001181 vector += 8;
1182 if (vector >= first_system_vector) {
Mike Travise7986732008-12-16 17:33:52 -08001183 /* If out of vectors on large boxen, must share them. */
Ingo Molnar54168ed2008-08-20 09:07:45 +02001184 offset = (offset + 1) % 8;
Suresh Siddha6579b472010-01-13 16:19:11 -08001185 vector = FIRST_EXTERNAL_VECTOR + offset;
Yinghai Lu7a959cf2008-08-19 20:50:32 -07001186 }
Ingo Molnar54168ed2008-08-20 09:07:45 +02001187 if (unlikely(current_vector == vector))
1188 continue;
Yinghai Lub77b8812008-12-19 15:23:44 -08001189
1190 if (test_bit(vector, used_vectors))
Ingo Molnar54168ed2008-08-20 09:07:45 +02001191 goto next;
Yinghai Lub77b8812008-12-19 15:23:44 -08001192
Mike Travis22f65d32008-12-16 17:33:56 -08001193 for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask)
Ingo Molnar54168ed2008-08-20 09:07:45 +02001194 if (per_cpu(vector_irq, new_cpu)[vector] != -1)
1195 goto next;
1196 /* Found one! */
1197 current_vector = vector;
1198 current_offset = offset;
1199 if (old_vector) {
1200 cfg->move_in_progress = 1;
Mike Travis22f65d32008-12-16 17:33:56 -08001201 cpumask_copy(cfg->old_domain, cfg->domain);
Ingo Molnar54168ed2008-08-20 09:07:45 +02001202 }
Mike Travis22f65d32008-12-16 17:33:56 -08001203 for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask)
Ingo Molnar54168ed2008-08-20 09:07:45 +02001204 per_cpu(vector_irq, new_cpu)[vector] = irq;
1205 cfg->vector = vector;
Mike Travis22f65d32008-12-16 17:33:56 -08001206 cpumask_copy(cfg->domain, tmp_mask);
1207 err = 0;
1208 break;
Ingo Molnar54168ed2008-08-20 09:07:45 +02001209 }
Mike Travis22f65d32008-12-16 17:33:56 -08001210 free_cpumask_var(tmp_mask);
1211 return err;
Yinghai Lu497c9a12008-08-19 20:50:28 -07001212}
1213
Dimitri Sivanich9338ad62009-10-13 15:32:36 -05001214int assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
Yinghai Lu497c9a12008-08-19 20:50:28 -07001215{
1216 int err;
Eric W. Biedermanace80ab2006-10-04 02:16:47 -07001217 unsigned long flags;
Eric W. Biedermanace80ab2006-10-04 02:16:47 -07001218
Thomas Gleixnerdade7712009-07-25 18:39:36 +02001219 raw_spin_lock_irqsave(&vector_lock, flags);
Yinghai Lu3145e942008-12-05 18:58:34 -08001220 err = __assign_irq_vector(irq, cfg, mask);
Thomas Gleixnerdade7712009-07-25 18:39:36 +02001221 raw_spin_unlock_irqrestore(&vector_lock, flags);
Yinghai Lu497c9a12008-08-19 20:50:28 -07001222 return err;
1223}
1224
Yinghai Lu3145e942008-12-05 18:58:34 -08001225static void __clear_irq_vector(int irq, struct irq_cfg *cfg)
Yinghai Lu497c9a12008-08-19 20:50:28 -07001226{
Yinghai Lu497c9a12008-08-19 20:50:28 -07001227 int cpu, vector;
1228
Yinghai Lu497c9a12008-08-19 20:50:28 -07001229 BUG_ON(!cfg->vector);
1230
1231 vector = cfg->vector;
Mike Travis22f65d32008-12-16 17:33:56 -08001232 for_each_cpu_and(cpu, cfg->domain, cpu_online_mask)
Yinghai Lu497c9a12008-08-19 20:50:28 -07001233 per_cpu(vector_irq, cpu)[vector] = -1;
1234
1235 cfg->vector = 0;
Mike Travis22f65d32008-12-16 17:33:56 -08001236 cpumask_clear(cfg->domain);
Matthew Wilcox0ca4b6b2008-11-20 14:09:33 -07001237
1238 if (likely(!cfg->move_in_progress))
1239 return;
Mike Travis22f65d32008-12-16 17:33:56 -08001240 for_each_cpu_and(cpu, cfg->old_domain, cpu_online_mask) {
Matthew Wilcox0ca4b6b2008-11-20 14:09:33 -07001241 for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS;
1242 vector++) {
1243 if (per_cpu(vector_irq, cpu)[vector] != irq)
1244 continue;
1245 per_cpu(vector_irq, cpu)[vector] = -1;
1246 break;
1247 }
1248 }
1249 cfg->move_in_progress = 0;
Yinghai Lu497c9a12008-08-19 20:50:28 -07001250}
1251
1252void __setup_vector_irq(int cpu)
1253{
1254 /* Initialize vector_irq on a new cpu */
Yinghai Lu497c9a12008-08-19 20:50:28 -07001255 int irq, vector;
1256 struct irq_cfg *cfg;
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08001257 struct irq_desc *desc;
Yinghai Lu497c9a12008-08-19 20:50:28 -07001258
Suresh Siddha9d133e52010-01-29 11:42:21 -08001259 /*
1260 * vector_lock will make sure that we don't run into irq vector
1261 * assignments that might be happening on another cpu in parallel,
1262 * while we setup our initial vector to irq mappings.
1263 */
Thomas Gleixnerdade7712009-07-25 18:39:36 +02001264 raw_spin_lock(&vector_lock);
Yinghai Lu497c9a12008-08-19 20:50:28 -07001265 /* Mark the inuse vectors */
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08001266 for_each_irq_desc(irq, desc) {
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08001267 cfg = desc->chip_data;
Suresh Siddha36e9e1e2010-03-15 14:33:06 -08001268
1269 /*
1270 * If it is a legacy IRQ handled by the legacy PIC, this cpu
1271 * will be part of the irq_cfg's domain.
1272 */
1273 if (irq < legacy_pic->nr_legacy_irqs && !IO_APIC_IRQ(irq))
1274 cpumask_set_cpu(cpu, cfg->domain);
1275
Mike Travis22f65d32008-12-16 17:33:56 -08001276 if (!cpumask_test_cpu(cpu, cfg->domain))
Yinghai Lu497c9a12008-08-19 20:50:28 -07001277 continue;
1278 vector = cfg->vector;
Yinghai Lu497c9a12008-08-19 20:50:28 -07001279 per_cpu(vector_irq, cpu)[vector] = irq;
1280 }
1281 /* Mark the free vectors */
1282 for (vector = 0; vector < NR_VECTORS; ++vector) {
1283 irq = per_cpu(vector_irq, cpu)[vector];
1284 if (irq < 0)
1285 continue;
1286
1287 cfg = irq_cfg(irq);
Mike Travis22f65d32008-12-16 17:33:56 -08001288 if (!cpumask_test_cpu(cpu, cfg->domain))
Yinghai Lu497c9a12008-08-19 20:50:28 -07001289 per_cpu(vector_irq, cpu)[vector] = -1;
Ingo Molnar54168ed2008-08-20 09:07:45 +02001290 }
Thomas Gleixnerdade7712009-07-25 18:39:36 +02001291 raw_spin_unlock(&vector_lock);
Eric W. Biedermanace80ab2006-10-04 02:16:47 -07001292}
Glauber Costa3fde6902008-05-28 20:34:19 -07001293
Ingo Molnarf5b9ed72006-10-04 02:16:26 -07001294static struct irq_chip ioapic_chip;
Ingo Molnar54168ed2008-08-20 09:07:45 +02001295static struct irq_chip ir_ioapic_chip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296
Ingo Molnar54168ed2008-08-20 09:07:45 +02001297#define IOAPIC_AUTO -1
1298#define IOAPIC_EDGE 0
1299#define IOAPIC_LEVEL 1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
Yinghai Lu047c8fd2008-08-19 20:50:41 -07001301#ifdef CONFIG_X86_32
Yinghai Lu1d025192008-08-19 20:50:34 -07001302static inline int IO_APIC_irq_trigger(int irq)
1303{
Thomas Gleixnerd6c88a52008-10-15 15:27:23 +02001304 int apic, idx, pin;
Yinghai Lu1d025192008-08-19 20:50:34 -07001305
Thomas Gleixnerd6c88a52008-10-15 15:27:23 +02001306 for (apic = 0; apic < nr_ioapics; apic++) {
1307 for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
1308 idx = find_irq_entry(apic, pin, mp_INT);
1309 if ((idx != -1) && (irq == pin_2_irq(idx, apic, pin)))
1310 return irq_trigger(idx);
1311 }
1312 }
1313 /*
Ingo Molnar54168ed2008-08-20 09:07:45 +02001314 * nonexistent IRQs are edge default
1315 */
Thomas Gleixnerd6c88a52008-10-15 15:27:23 +02001316 return 0;
Yinghai Lu1d025192008-08-19 20:50:34 -07001317}
Yinghai Lu047c8fd2008-08-19 20:50:41 -07001318#else
1319static inline int IO_APIC_irq_trigger(int irq)
1320{
Ingo Molnar54168ed2008-08-20 09:07:45 +02001321 return 1;
Yinghai Lu047c8fd2008-08-19 20:50:41 -07001322}
1323#endif
Yinghai Lu1d025192008-08-19 20:50:34 -07001324
Yinghai Lu3145e942008-12-05 18:58:34 -08001325static void ioapic_register_intr(int irq, struct irq_desc *desc, unsigned long trigger)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326{
Yinghai Lu199751d2008-08-19 20:50:27 -07001327
Jan Beulich6ebcc002006-06-26 13:56:46 +02001328 if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
Yinghai Lu047c8fd2008-08-19 20:50:41 -07001329 trigger == IOAPIC_LEVEL)
Yinghai Lu08678b02008-08-19 20:50:05 -07001330 desc->status |= IRQ_LEVEL;
Yinghai Lu047c8fd2008-08-19 20:50:41 -07001331 else
1332 desc->status &= ~IRQ_LEVEL;
1333
Ingo Molnar54168ed2008-08-20 09:07:45 +02001334 if (irq_remapped(irq)) {
1335 desc->status |= IRQ_MOVE_PCNTXT;
1336 if (trigger)
1337 set_irq_chip_and_handler_name(irq, &ir_ioapic_chip,
1338 handle_fasteoi_irq,
1339 "fasteoi");
1340 else
1341 set_irq_chip_and_handler_name(irq, &ir_ioapic_chip,
1342 handle_edge_irq, "edge");
1343 return;
1344 }
Suresh Siddha29b61be2009-03-16 17:05:02 -07001345
Yinghai Lu047c8fd2008-08-19 20:50:41 -07001346 if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
1347 trigger == IOAPIC_LEVEL)
Ingo Molnara460e742006-10-17 00:10:03 -07001348 set_irq_chip_and_handler_name(irq, &ioapic_chip,
Ingo Molnar54168ed2008-08-20 09:07:45 +02001349 handle_fasteoi_irq,
1350 "fasteoi");
Yinghai Lu047c8fd2008-08-19 20:50:41 -07001351 else
Ingo Molnara460e742006-10-17 00:10:03 -07001352 set_irq_chip_and_handler_name(irq, &ioapic_chip,
Ingo Molnar54168ed2008-08-20 09:07:45 +02001353 handle_edge_irq, "edge");
Yinghai Lu497c9a12008-08-19 20:50:28 -07001354}
1355
Jeremy Fitzhardingeca97ab92009-02-09 12:05:47 -08001356int setup_ioapic_entry(int apic_id, int irq,
1357 struct IO_APIC_route_entry *entry,
1358 unsigned int destination, int trigger,
Suresh Siddha0280f7c2009-03-16 17:05:01 -07001359 int polarity, int vector, int pin)
Yinghai Lu497c9a12008-08-19 20:50:28 -07001360{
1361 /*
1362 * add it to the IO-APIC irq-routing table:
1363 */
1364 memset(entry,0,sizeof(*entry));
1365
Ingo Molnar54168ed2008-08-20 09:07:45 +02001366 if (intr_remapping_enabled) {
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01001367 struct intel_iommu *iommu = map_ioapic_to_ir(apic_id);
Ingo Molnar54168ed2008-08-20 09:07:45 +02001368 struct irte irte;
1369 struct IR_IO_APIC_route_entry *ir_entry =
1370 (struct IR_IO_APIC_route_entry *) entry;
1371 int index;
Yinghai Lu497c9a12008-08-19 20:50:28 -07001372
Ingo Molnar54168ed2008-08-20 09:07:45 +02001373 if (!iommu)
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01001374 panic("No mapping iommu for ioapic %d\n", apic_id);
Ingo Molnar54168ed2008-08-20 09:07:45 +02001375
1376 index = alloc_irte(iommu, irq, 1);
1377 if (index < 0)
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01001378 panic("Failed to allocate IRTE for ioapic %d\n", apic_id);
Ingo Molnar54168ed2008-08-20 09:07:45 +02001379
1380 memset(&irte, 0, sizeof(irte));
1381
1382 irte.present = 1;
Ingo Molnar9b5bc8d2009-01-28 04:09:58 +01001383 irte.dst_mode = apic->irq_dest_mode;
Suresh Siddha0280f7c2009-03-16 17:05:01 -07001384 /*
1385 * Trigger mode in the IRTE will always be edge, and the
1386 * actual level or edge trigger will be setup in the IO-APIC
1387 * RTE. This will help simplify level triggered irq migration.
1388 * For more details, see the comments above explainig IO-APIC
1389 * irq migration in the presence of interrupt-remapping.
1390 */
1391 irte.trigger_mode = 0;
Ingo Molnar9b5bc8d2009-01-28 04:09:58 +01001392 irte.dlvry_mode = apic->irq_delivery_mode;
Ingo Molnar54168ed2008-08-20 09:07:45 +02001393 irte.vector = vector;
1394 irte.dest_id = IRTE_DEST(destination);
1395
Weidong Hanf007e992009-05-23 00:41:15 +08001396 /* Set source-id of interrupt request */
1397 set_ioapic_sid(&irte, apic_id);
1398
Ingo Molnar54168ed2008-08-20 09:07:45 +02001399 modify_irte(irq, &irte);
1400
1401 ir_entry->index2 = (index >> 15) & 0x1;
1402 ir_entry->zero = 0;
1403 ir_entry->format = 1;
1404 ir_entry->index = (index & 0x7fff);
Suresh Siddha0280f7c2009-03-16 17:05:01 -07001405 /*
1406 * IO-APIC RTE will be configured with virtual vector.
1407 * irq handler will do the explicit EOI to the io-apic.
1408 */
1409 ir_entry->vector = pin;
Suresh Siddha29b61be2009-03-16 17:05:02 -07001410 } else {
Ingo Molnar9b5bc8d2009-01-28 04:09:58 +01001411 entry->delivery_mode = apic->irq_delivery_mode;
1412 entry->dest_mode = apic->irq_dest_mode;
Ingo Molnar54168ed2008-08-20 09:07:45 +02001413 entry->dest = destination;
Suresh Siddha0280f7c2009-03-16 17:05:01 -07001414 entry->vector = vector;
Ingo Molnar54168ed2008-08-20 09:07:45 +02001415 }
1416
1417 entry->mask = 0; /* enable IRQ */
Yinghai Lu497c9a12008-08-19 20:50:28 -07001418 entry->trigger = trigger;
1419 entry->polarity = polarity;
Yinghai Lu497c9a12008-08-19 20:50:28 -07001420
1421 /* Mask level triggered irqs.
1422 * Use IRQ_DELAYED_DISABLE for edge triggered irqs.
1423 */
1424 if (trigger)
1425 entry->mask = 1;
Yinghai Lu497c9a12008-08-19 20:50:28 -07001426 return 0;
1427}
1428
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01001429static void setup_IO_APIC_irq(int apic_id, int pin, unsigned int irq, struct irq_desc *desc,
Ingo Molnar54168ed2008-08-20 09:07:45 +02001430 int trigger, int polarity)
Yinghai Lu497c9a12008-08-19 20:50:28 -07001431{
1432 struct irq_cfg *cfg;
1433 struct IO_APIC_route_entry entry;
Mike Travis22f65d32008-12-16 17:33:56 -08001434 unsigned int dest;
Yinghai Lu497c9a12008-08-19 20:50:28 -07001435
1436 if (!IO_APIC_IRQ(irq))
1437 return;
1438
Yinghai Lu3145e942008-12-05 18:58:34 -08001439 cfg = desc->chip_data;
Yinghai Lu497c9a12008-08-19 20:50:28 -07001440
Suresh Siddha69c89ef2010-01-29 11:42:20 -08001441 /*
1442 * For legacy irqs, cfg->domain starts with cpu 0 for legacy
1443 * controllers like 8259. Now that IO-APIC can handle this irq, update
1444 * the cfg->domain.
1445 */
Yinghai Lu28c6a0b2010-02-23 20:27:48 -08001446 if (irq < legacy_pic->nr_legacy_irqs && cpumask_test_cpu(0, cfg->domain))
Suresh Siddha69c89ef2010-01-29 11:42:20 -08001447 apic->vector_allocation_domain(0, cfg->domain);
1448
Ingo Molnarfe402e12009-01-28 04:32:51 +01001449 if (assign_irq_vector(irq, cfg, apic->target_cpus()))
Yinghai Lu497c9a12008-08-19 20:50:28 -07001450 return;
1451
Ingo Molnardebccb32009-01-28 15:20:18 +01001452 dest = apic->cpu_mask_to_apicid_and(cfg->domain, apic->target_cpus());
Yinghai Lu497c9a12008-08-19 20:50:28 -07001453
1454 apic_printk(APIC_VERBOSE,KERN_DEBUG
1455 "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> "
1456 "IRQ %d Mode:%i Active:%i)\n",
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01001457 apic_id, mp_ioapics[apic_id].apicid, pin, cfg->vector,
Yinghai Lu497c9a12008-08-19 20:50:28 -07001458 irq, trigger, polarity);
1459
1460
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01001461 if (setup_ioapic_entry(mp_ioapics[apic_id].apicid, irq, &entry,
Suresh Siddha0280f7c2009-03-16 17:05:01 -07001462 dest, trigger, polarity, cfg->vector, pin)) {
Yinghai Lu497c9a12008-08-19 20:50:28 -07001463 printk("Failed to setup ioapic entry for ioapic %d, pin %d\n",
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01001464 mp_ioapics[apic_id].apicid, pin);
Yinghai Lu3145e942008-12-05 18:58:34 -08001465 __clear_irq_vector(irq, cfg);
Yinghai Lu497c9a12008-08-19 20:50:28 -07001466 return;
1467 }
1468
Yinghai Lu3145e942008-12-05 18:58:34 -08001469 ioapic_register_intr(irq, desc, trigger);
Jacob Panb81bb372009-11-09 11:27:04 -08001470 if (irq < legacy_pic->nr_legacy_irqs)
1471 legacy_pic->chip->mask(irq);
Yinghai Lu497c9a12008-08-19 20:50:28 -07001472
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01001473 ioapic_write_entry(apic_id, pin, entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474}
1475
Yinghai Lub9c61b702009-05-06 10:10:06 -07001476static struct {
1477 DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1);
1478} mp_ioapic_routing[MAX_IO_APICS];
1479
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480static void __init setup_IO_APIC_irqs(void)
1481{
Eric W. Biedermanfad53992010-02-28 01:06:34 -08001482 int apic_id, pin, idx, irq;
Cyrill Gorcunov3c2cbd22008-09-06 14:15:33 +04001483 int notcon = 0;
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08001484 struct irq_desc *desc;
Yinghai Lu3145e942008-12-05 18:58:34 -08001485 struct irq_cfg *cfg;
Yinghai Lu85ac16d2009-04-27 18:00:38 -07001486 int node = cpu_to_node(boot_cpu_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487
1488 apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n");
1489
Eric W. Biedermanfad53992010-02-28 01:06:34 -08001490 for (apic_id = 0; apic_id < nr_ioapics; apic_id++)
Yinghai Lub9c61b702009-05-06 10:10:06 -07001491 for (pin = 0; pin < nr_ioapic_registers[apic_id]; pin++) {
1492 idx = find_irq_entry(apic_id, pin, mp_INT);
1493 if (idx == -1) {
1494 if (!notcon) {
1495 notcon = 1;
Cyrill Gorcunov56ffa1a2008-09-13 13:11:16 +04001496 apic_printk(APIC_VERBOSE,
Yinghai Lub9c61b702009-05-06 10:10:06 -07001497 KERN_DEBUG " %d-%d",
1498 mp_ioapics[apic_id].apicid, pin);
1499 } else
1500 apic_printk(APIC_VERBOSE, " %d-%d",
1501 mp_ioapics[apic_id].apicid, pin);
1502 continue;
Cyrill Gorcunov3c2cbd22008-09-06 14:15:33 +04001503 }
Yinghai Lub9c61b702009-05-06 10:10:06 -07001504 if (notcon) {
1505 apic_printk(APIC_VERBOSE,
1506 " (apicid-pin) not connected\n");
1507 notcon = 0;
1508 }
1509
1510 irq = pin_2_irq(idx, apic_id, pin);
1511
Eric W. Biedermanfad53992010-02-28 01:06:34 -08001512 if ((apic_id > 0) && (irq > 16))
1513 continue;
1514
Yinghai Lub9c61b702009-05-06 10:10:06 -07001515 /*
1516 * Skip the timer IRQ if there's a quirk handler
1517 * installed and if it returns 1:
1518 */
1519 if (apic->multi_timer_check &&
1520 apic->multi_timer_check(apic_id, irq))
1521 continue;
1522
1523 desc = irq_to_desc_alloc_node(irq, node);
1524 if (!desc) {
1525 printk(KERN_INFO "can not get irq_desc for %d\n", irq);
1526 continue;
1527 }
1528 cfg = desc->chip_data;
1529 add_pin_to_irq_node(cfg, node, apic_id, pin);
Yinghai Lu4c6f18f2009-05-18 10:23:28 -07001530 /*
1531 * don't mark it in pin_programmed, so later acpi could
1532 * set it correctly when irq < 16
1533 */
Yinghai Lub9c61b702009-05-06 10:10:06 -07001534 setup_IO_APIC_irq(apic_id, pin, irq, desc,
1535 irq_trigger(idx), irq_polarity(idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 }
1537
Cyrill Gorcunov3c2cbd22008-09-06 14:15:33 +04001538 if (notcon)
1539 apic_printk(APIC_VERBOSE,
Cyrill Gorcunov2a554fb2008-09-08 19:38:06 +04001540 " (apicid-pin) not connected\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541}
1542
1543/*
Yinghai Lu18dce6b2010-02-10 01:20:05 -08001544 * for the gsit that is not in first ioapic
1545 * but could not use acpi_register_gsi()
1546 * like some special sci in IBM x3330
1547 */
1548void setup_IO_APIC_irq_extra(u32 gsi)
1549{
1550 int apic_id = 0, pin, idx, irq;
1551 int node = cpu_to_node(boot_cpu_id);
1552 struct irq_desc *desc;
1553 struct irq_cfg *cfg;
1554
1555 /*
1556 * Convert 'gsi' to 'ioapic.pin'.
1557 */
1558 apic_id = mp_find_ioapic(gsi);
1559 if (apic_id < 0)
1560 return;
1561
1562 pin = mp_find_ioapic_pin(apic_id, gsi);
1563 idx = find_irq_entry(apic_id, pin, mp_INT);
1564 if (idx == -1)
1565 return;
1566
1567 irq = pin_2_irq(idx, apic_id, pin);
1568#ifdef CONFIG_SPARSE_IRQ
1569 desc = irq_to_desc(irq);
1570 if (desc)
1571 return;
1572#endif
1573 desc = irq_to_desc_alloc_node(irq, node);
1574 if (!desc) {
1575 printk(KERN_INFO "can not get irq_desc for %d\n", irq);
1576 return;
1577 }
1578
1579 cfg = desc->chip_data;
1580 add_pin_to_irq_node(cfg, node, apic_id, pin);
1581
1582 if (test_bit(pin, mp_ioapic_routing[apic_id].pin_programmed)) {
1583 pr_debug("Pin %d-%d already programmed\n",
1584 mp_ioapics[apic_id].apicid, pin);
1585 return;
1586 }
1587 set_bit(pin, mp_ioapic_routing[apic_id].pin_programmed);
1588
1589 setup_IO_APIC_irq(apic_id, pin, irq, desc,
1590 irq_trigger(idx), irq_polarity(idx));
1591}
1592
1593/*
Maciej W. Rozyckif7633ce2008-05-27 21:19:34 +01001594 * Set up the timer pin, possibly with the 8259A-master behind.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 */
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01001596static void __init setup_timer_IRQ0_pin(unsigned int apic_id, unsigned int pin,
Maciej W. Rozyckif7633ce2008-05-27 21:19:34 +01001597 int vector)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598{
1599 struct IO_APIC_route_entry entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600
Ingo Molnar54168ed2008-08-20 09:07:45 +02001601 if (intr_remapping_enabled)
1602 return;
Ingo Molnar54168ed2008-08-20 09:07:45 +02001603
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02001604 memset(&entry, 0, sizeof(entry));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605
1606 /*
1607 * We use logical delivery to get the timer IRQ
1608 * to the first CPU.
1609 */
Ingo Molnar9b5bc8d2009-01-28 04:09:58 +01001610 entry.dest_mode = apic->irq_dest_mode;
Yinghai Luf72dcca2009-02-08 16:18:03 -08001611 entry.mask = 0; /* don't mask IRQ for edge */
Ingo Molnardebccb32009-01-28 15:20:18 +01001612 entry.dest = apic->cpu_mask_to_apicid(apic->target_cpus());
Ingo Molnar9b5bc8d2009-01-28 04:09:58 +01001613 entry.delivery_mode = apic->irq_delivery_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 entry.polarity = 0;
1615 entry.trigger = 0;
1616 entry.vector = vector;
1617
1618 /*
1619 * The timer IRQ doesn't have to know that behind the
Maciej W. Rozyckif7633ce2008-05-27 21:19:34 +01001620 * scene we may have a 8259A-master in AEOI mode ...
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 */
Ingo Molnar54168ed2008-08-20 09:07:45 +02001622 set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623
1624 /*
1625 * Add it to the IO-APIC irq-routing table:
1626 */
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01001627 ioapic_write_entry(apic_id, pin, entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628}
1629
Maciej W. Rozycki32f71af2008-07-21 00:52:49 +01001630
1631__apicdebuginit(void) print_IO_APIC(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632{
1633 int apic, i;
1634 union IO_APIC_reg_00 reg_00;
1635 union IO_APIC_reg_01 reg_01;
1636 union IO_APIC_reg_02 reg_02;
1637 union IO_APIC_reg_03 reg_03;
1638 unsigned long flags;
Yinghai Lu0f978f42008-08-19 20:50:26 -07001639 struct irq_cfg *cfg;
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08001640 struct irq_desc *desc;
Yinghai Lu8f09cd22008-08-19 20:50:51 -07001641 unsigned int irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02001643 printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 for (i = 0; i < nr_ioapics; i++)
1645 printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n",
Jaswinder Singh Rajputb5ba7e62009-01-12 17:46:17 +05301646 mp_ioapics[i].apicid, nr_ioapic_registers[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647
1648 /*
1649 * We are a bit conservative about what we expect. We have to
1650 * know about every hardware change ASAP.
1651 */
1652 printk(KERN_INFO "testing the IO APIC.......................\n");
1653
1654 for (apic = 0; apic < nr_ioapics; apic++) {
1655
Thomas Gleixnerdade7712009-07-25 18:39:36 +02001656 raw_spin_lock_irqsave(&ioapic_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 reg_00.raw = io_apic_read(apic, 0);
1658 reg_01.raw = io_apic_read(apic, 1);
1659 if (reg_01.bits.version >= 0x10)
1660 reg_02.raw = io_apic_read(apic, 2);
Thomas Gleixnerd6c88a52008-10-15 15:27:23 +02001661 if (reg_01.bits.version >= 0x20)
1662 reg_03.raw = io_apic_read(apic, 3);
Thomas Gleixnerdade7712009-07-25 18:39:36 +02001663 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664
Ingo Molnar54168ed2008-08-20 09:07:45 +02001665 printk("\n");
Jaswinder Singh Rajputb5ba7e62009-01-12 17:46:17 +05301666 printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].apicid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw);
1668 printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID);
1669 printk(KERN_DEBUG "....... : Delivery Type: %X\n", reg_00.bits.delivery_type);
1670 printk(KERN_DEBUG "....... : LTS : %X\n", reg_00.bits.LTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
Ingo Molnar54168ed2008-08-20 09:07:45 +02001672 printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)&reg_01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.bits.entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
1675 printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ);
1676 printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.bits.version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677
1678 /*
1679 * Some Intel chipsets with IO APIC VERSION of 0x1? don't have reg_02,
1680 * but the value of reg_02 is read as the previous read register
1681 * value, so ignore it if reg_02 == reg_01.
1682 */
1683 if (reg_01.bits.version >= 0x10 && reg_02.raw != reg_01.raw) {
1684 printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw);
1685 printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.bits.arbitration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 }
1687
1688 /*
1689 * Some Intel chipsets with IO APIC VERSION of 0x2? don't have reg_02
1690 * or reg_03, but the value of reg_0[23] is read as the previous read
1691 * register value, so ignore it if reg_03 == reg_0[12].
1692 */
1693 if (reg_01.bits.version >= 0x20 && reg_03.raw != reg_02.raw &&
1694 reg_03.raw != reg_01.raw) {
1695 printk(KERN_DEBUG ".... register #03: %08X\n", reg_03.raw);
1696 printk(KERN_DEBUG "....... : Boot DT : %X\n", reg_03.bits.boot_DT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 }
1698
1699 printk(KERN_DEBUG ".... IRQ redirection table:\n");
1700
Yinghai Lud83e94a2008-08-19 20:50:33 -07001701 printk(KERN_DEBUG " NR Dst Mask Trig IRR Pol"
Frans Pop3235dc32010-02-06 18:47:17 +01001702 " Stat Dmod Deli Vect:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703
1704 for (i = 0; i <= reg_01.bits.entries; i++) {
1705 struct IO_APIC_route_entry entry;
1706
Andi Kleencf4c6a22006-09-26 10:52:30 +02001707 entry = ioapic_read_entry(apic, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708
Ingo Molnar54168ed2008-08-20 09:07:45 +02001709 printk(KERN_DEBUG " %02x %03X ",
1710 i,
1711 entry.dest
1712 );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713
1714 printk("%1d %1d %1d %1d %1d %1d %1d %02X\n",
1715 entry.mask,
1716 entry.trigger,
1717 entry.irr,
1718 entry.polarity,
1719 entry.delivery_status,
1720 entry.dest_mode,
1721 entry.delivery_mode,
1722 entry.vector
1723 );
1724 }
1725 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 printk(KERN_DEBUG "IRQ to pin mappings:\n");
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08001727 for_each_irq_desc(irq, desc) {
1728 struct irq_pin_list *entry;
1729
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08001730 cfg = desc->chip_data;
Daniel Kiper05e40762010-08-20 00:46:16 +02001731 if (!cfg)
1732 continue;
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08001733 entry = cfg->irq_2_pin;
Yinghai Lu0f978f42008-08-19 20:50:26 -07001734 if (!entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 continue;
Yinghai Lu8f09cd22008-08-19 20:50:51 -07001736 printk(KERN_DEBUG "IRQ%d ", irq);
Cyrill Gorcunov2977fb32009-08-01 11:47:59 +04001737 for_each_irq_pin(entry, cfg->irq_2_pin)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 printk("-> %d:%d", entry->apic, entry->pin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 printk("\n");
1740 }
1741
1742 printk(KERN_INFO ".................................... done.\n");
1743
1744 return;
1745}
1746
Ingo Molnar251e1e42009-07-02 08:54:01 +02001747__apicdebuginit(void) print_APIC_field(int base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748{
Ingo Molnar251e1e42009-07-02 08:54:01 +02001749 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750
Ingo Molnar251e1e42009-07-02 08:54:01 +02001751 printk(KERN_DEBUG);
1752
1753 for (i = 0; i < 8; i++)
1754 printk(KERN_CONT "%08x", apic_read(base + i*0x10));
1755
1756 printk(KERN_CONT "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757}
1758
Maciej W. Rozycki32f71af2008-07-21 00:52:49 +01001759__apicdebuginit(void) print_local_APIC(void *dummy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760{
Andreas Herrmann97a52712009-05-08 18:23:50 +02001761 unsigned int i, v, ver, maxlvt;
Hiroshi Shimamoto7ab6af72008-07-30 17:36:48 -07001762 u64 icr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763
Ingo Molnar251e1e42009-07-02 08:54:01 +02001764 printk(KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 smp_processor_id(), hard_smp_processor_id());
Andreas Herrmann66823112008-06-05 16:35:10 +02001766 v = apic_read(APIC_ID);
Ingo Molnar54168ed2008-08-20 09:07:45 +02001767 printk(KERN_INFO "... APIC ID: %08x (%01x)\n", v, read_apic_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 v = apic_read(APIC_LVR);
1769 printk(KERN_INFO "... APIC VERSION: %08x\n", v);
1770 ver = GET_APIC_VERSION(v);
Thomas Gleixnere05d7232007-02-16 01:27:58 -08001771 maxlvt = lapic_get_maxlvt();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772
1773 v = apic_read(APIC_TASKPRI);
1774 printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK);
1775
Ingo Molnar54168ed2008-08-20 09:07:45 +02001776 if (APIC_INTEGRATED(ver)) { /* !82489DX */
Yinghai Lua11b5ab2008-09-03 16:58:31 -07001777 if (!APIC_XAPIC(ver)) {
1778 v = apic_read(APIC_ARBPRI);
1779 printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v,
1780 v & APIC_ARBPRI_MASK);
1781 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 v = apic_read(APIC_PROCPRI);
1783 printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v);
1784 }
1785
Yinghai Lua11b5ab2008-09-03 16:58:31 -07001786 /*
1787 * Remote read supported only in the 82489DX and local APIC for
1788 * Pentium processors.
1789 */
1790 if (!APIC_INTEGRATED(ver) || maxlvt == 3) {
1791 v = apic_read(APIC_RRR);
1792 printk(KERN_DEBUG "... APIC RRR: %08x\n", v);
1793 }
1794
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 v = apic_read(APIC_LDR);
1796 printk(KERN_DEBUG "... APIC LDR: %08x\n", v);
Yinghai Lua11b5ab2008-09-03 16:58:31 -07001797 if (!x2apic_enabled()) {
1798 v = apic_read(APIC_DFR);
1799 printk(KERN_DEBUG "... APIC DFR: %08x\n", v);
1800 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 v = apic_read(APIC_SPIV);
1802 printk(KERN_DEBUG "... APIC SPIV: %08x\n", v);
1803
1804 printk(KERN_DEBUG "... APIC ISR field:\n");
Ingo Molnar251e1e42009-07-02 08:54:01 +02001805 print_APIC_field(APIC_ISR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 printk(KERN_DEBUG "... APIC TMR field:\n");
Ingo Molnar251e1e42009-07-02 08:54:01 +02001807 print_APIC_field(APIC_TMR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 printk(KERN_DEBUG "... APIC IRR field:\n");
Ingo Molnar251e1e42009-07-02 08:54:01 +02001809 print_APIC_field(APIC_IRR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810
Ingo Molnar54168ed2008-08-20 09:07:45 +02001811 if (APIC_INTEGRATED(ver)) { /* !82489DX */
1812 if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 apic_write(APIC_ESR, 0);
Ingo Molnar54168ed2008-08-20 09:07:45 +02001814
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 v = apic_read(APIC_ESR);
1816 printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
1817 }
1818
Hiroshi Shimamoto7ab6af72008-07-30 17:36:48 -07001819 icr = apic_icr_read();
Ingo Molnar0c425ce2008-08-18 13:04:26 +02001820 printk(KERN_DEBUG "... APIC ICR: %08x\n", (u32)icr);
1821 printk(KERN_DEBUG "... APIC ICR2: %08x\n", (u32)(icr >> 32));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822
1823 v = apic_read(APIC_LVTT);
1824 printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);
1825
1826 if (maxlvt > 3) { /* PC is LVT#4. */
1827 v = apic_read(APIC_LVTPC);
1828 printk(KERN_DEBUG "... APIC LVTPC: %08x\n", v);
1829 }
1830 v = apic_read(APIC_LVT0);
1831 printk(KERN_DEBUG "... APIC LVT0: %08x\n", v);
1832 v = apic_read(APIC_LVT1);
1833 printk(KERN_DEBUG "... APIC LVT1: %08x\n", v);
1834
1835 if (maxlvt > 2) { /* ERR is LVT#3. */
1836 v = apic_read(APIC_LVTERR);
1837 printk(KERN_DEBUG "... APIC LVTERR: %08x\n", v);
1838 }
1839
1840 v = apic_read(APIC_TMICT);
1841 printk(KERN_DEBUG "... APIC TMICT: %08x\n", v);
1842 v = apic_read(APIC_TMCCT);
1843 printk(KERN_DEBUG "... APIC TMCCT: %08x\n", v);
1844 v = apic_read(APIC_TDCR);
1845 printk(KERN_DEBUG "... APIC TDCR: %08x\n", v);
Andreas Herrmann97a52712009-05-08 18:23:50 +02001846
1847 if (boot_cpu_has(X86_FEATURE_EXTAPIC)) {
1848 v = apic_read(APIC_EFEAT);
1849 maxlvt = (v >> 16) & 0xff;
1850 printk(KERN_DEBUG "... APIC EFEAT: %08x\n", v);
1851 v = apic_read(APIC_ECTRL);
1852 printk(KERN_DEBUG "... APIC ECTRL: %08x\n", v);
1853 for (i = 0; i < maxlvt; i++) {
1854 v = apic_read(APIC_EILVTn(i));
1855 printk(KERN_DEBUG "... APIC EILVT%d: %08x\n", i, v);
1856 }
1857 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 printk("\n");
1859}
1860
Cyrill Gorcunov2626eb22009-10-14 00:07:05 +04001861__apicdebuginit(void) print_local_APICs(int maxcpu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862{
Yinghai Luffd5aae2008-08-19 20:50:50 -07001863 int cpu;
1864
Cyrill Gorcunov2626eb22009-10-14 00:07:05 +04001865 if (!maxcpu)
1866 return;
1867
Yinghai Luffd5aae2008-08-19 20:50:50 -07001868 preempt_disable();
Cyrill Gorcunov2626eb22009-10-14 00:07:05 +04001869 for_each_online_cpu(cpu) {
1870 if (cpu >= maxcpu)
1871 break;
Yinghai Luffd5aae2008-08-19 20:50:50 -07001872 smp_call_function_single(cpu, print_local_APIC, NULL, 1);
Cyrill Gorcunov2626eb22009-10-14 00:07:05 +04001873 }
Yinghai Luffd5aae2008-08-19 20:50:50 -07001874 preempt_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875}
1876
Maciej W. Rozycki32f71af2008-07-21 00:52:49 +01001877__apicdebuginit(void) print_PIC(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 unsigned int v;
1880 unsigned long flags;
1881
Jacob Panb81bb372009-11-09 11:27:04 -08001882 if (!legacy_pic->nr_legacy_irqs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 return;
1884
1885 printk(KERN_DEBUG "\nprinting PIC contents\n");
1886
Thomas Gleixner5619c282009-07-25 18:35:11 +02001887 raw_spin_lock_irqsave(&i8259A_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888
1889 v = inb(0xa1) << 8 | inb(0x21);
1890 printk(KERN_DEBUG "... PIC IMR: %04x\n", v);
1891
1892 v = inb(0xa0) << 8 | inb(0x20);
1893 printk(KERN_DEBUG "... PIC IRR: %04x\n", v);
1894
Ingo Molnar54168ed2008-08-20 09:07:45 +02001895 outb(0x0b,0xa0);
1896 outb(0x0b,0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 v = inb(0xa0) << 8 | inb(0x20);
Ingo Molnar54168ed2008-08-20 09:07:45 +02001898 outb(0x0a,0xa0);
1899 outb(0x0a,0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
Thomas Gleixner5619c282009-07-25 18:35:11 +02001901 raw_spin_unlock_irqrestore(&i8259A_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902
1903 printk(KERN_DEBUG "... PIC ISR: %04x\n", v);
1904
1905 v = inb(0x4d1) << 8 | inb(0x4d0);
1906 printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
1907}
1908
Cyrill Gorcunov2626eb22009-10-14 00:07:05 +04001909static int __initdata show_lapic = 1;
1910static __init int setup_show_lapic(char *arg)
Maciej W. Rozycki32f71af2008-07-21 00:52:49 +01001911{
Cyrill Gorcunov2626eb22009-10-14 00:07:05 +04001912 int num = -1;
1913
1914 if (strcmp(arg, "all") == 0) {
1915 show_lapic = CONFIG_NR_CPUS;
1916 } else {
1917 get_option(&arg, &num);
1918 if (num >= 0)
1919 show_lapic = num;
1920 }
1921
1922 return 1;
1923}
1924__setup("show_lapic=", setup_show_lapic);
1925
1926__apicdebuginit(int) print_ICs(void)
1927{
1928 if (apic_verbosity == APIC_QUIET)
1929 return 0;
1930
Maciej W. Rozycki32f71af2008-07-21 00:52:49 +01001931 print_PIC();
Yinghai Lu4797f6b2009-05-02 10:40:57 -07001932
1933 /* don't print out if apic is not there */
Cyrill Gorcunov83121362009-09-15 11:12:30 +04001934 if (!cpu_has_apic && !apic_from_smp_config())
Yinghai Lu4797f6b2009-05-02 10:40:57 -07001935 return 0;
1936
Cyrill Gorcunov2626eb22009-10-14 00:07:05 +04001937 print_local_APICs(show_lapic);
Maciej W. Rozycki32f71af2008-07-21 00:52:49 +01001938 print_IO_APIC();
1939
1940 return 0;
1941}
1942
Cyrill Gorcunov2626eb22009-10-14 00:07:05 +04001943fs_initcall(print_ICs);
Maciej W. Rozycki32f71af2008-07-21 00:52:49 +01001944
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945
Yinghai Luefa25592008-08-19 20:50:36 -07001946/* Where if anywhere is the i8259 connect in external int mode */
1947static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
1948
Ingo Molnar54168ed2008-08-20 09:07:45 +02001949void __init enable_IO_APIC(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950{
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -08001951 int i8259_apic, i8259_pin;
Ingo Molnar54168ed2008-08-20 09:07:45 +02001952 int apic;
Thomas Gleixnerbc078442009-08-29 18:09:57 +02001953
Jacob Panb81bb372009-11-09 11:27:04 -08001954 if (!legacy_pic->nr_legacy_irqs)
Thomas Gleixnerbc078442009-08-29 18:09:57 +02001955 return;
1956
Ingo Molnar54168ed2008-08-20 09:07:45 +02001957 for(apic = 0; apic < nr_ioapics; apic++) {
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -08001958 int pin;
1959 /* See if any of the pins is in ExtINT mode */
Eric W. Biederman1008fdd2006-01-11 22:46:06 +01001960 for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -08001961 struct IO_APIC_route_entry entry;
Andi Kleencf4c6a22006-09-26 10:52:30 +02001962 entry = ioapic_read_entry(apic, pin);
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -08001963
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -08001964 /* If the interrupt line is enabled and in ExtInt mode
1965 * I have found the pin where the i8259 is connected.
1966 */
1967 if ((entry.mask == 0) && (entry.delivery_mode == dest_ExtINT)) {
1968 ioapic_i8259.apic = apic;
1969 ioapic_i8259.pin = pin;
1970 goto found_i8259;
1971 }
1972 }
1973 }
1974 found_i8259:
1975 /* Look to see what if the MP table has reported the ExtINT */
1976 /* If we could not find the appropriate pin by looking at the ioapic
1977 * the i8259 probably is not connected the ioapic but give the
1978 * mptable a chance anyway.
1979 */
1980 i8259_pin = find_isa_irq_pin(0, mp_ExtINT);
1981 i8259_apic = find_isa_irq_apic(0, mp_ExtINT);
1982 /* Trust the MP table if nothing is setup in the hardware */
1983 if ((ioapic_i8259.pin == -1) && (i8259_pin >= 0)) {
1984 printk(KERN_WARNING "ExtINT not setup in hardware but reported by MP table\n");
1985 ioapic_i8259.pin = i8259_pin;
1986 ioapic_i8259.apic = i8259_apic;
1987 }
1988 /* Complain if the MP table and the hardware disagree */
1989 if (((ioapic_i8259.apic != i8259_apic) || (ioapic_i8259.pin != i8259_pin)) &&
1990 (i8259_pin >= 0) && (ioapic_i8259.pin >= 0))
1991 {
1992 printk(KERN_WARNING "ExtINT in hardware and MP table differ\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 }
1994
1995 /*
1996 * Do not trust the IO-APIC being empty at bootup
1997 */
1998 clear_IO_APIC();
1999}
2000
2001/*
2002 * Not an __init, needed by the reboot code
2003 */
2004void disable_IO_APIC(void)
2005{
2006 /*
2007 * Clear the IO-APIC before rebooting:
2008 */
2009 clear_IO_APIC();
2010
Jacob Panb81bb372009-11-09 11:27:04 -08002011 if (!legacy_pic->nr_legacy_irqs)
Thomas Gleixnerbc078442009-08-29 18:09:57 +02002012 return;
2013
Eric W. Biederman650927e2005-06-25 14:57:44 -07002014 /*
Karsten Wiese0b968d22005-09-09 12:59:04 +02002015 * If the i8259 is routed through an IOAPIC
Eric W. Biederman650927e2005-06-25 14:57:44 -07002016 * Put that IOAPIC in virtual wire mode
Karsten Wiese0b968d22005-09-09 12:59:04 +02002017 * so legacy interrupts can be delivered.
Suresh Siddha7c6d9f92009-03-16 17:04:59 -07002018 *
2019 * With interrupt-remapping, for now we will use virtual wire A mode,
2020 * as virtual wire B is little complex (need to configure both
2021 * IOAPIC RTE aswell as interrupt-remapping table entry).
2022 * As this gets called during crash dump, keep this simple for now.
Eric W. Biederman650927e2005-06-25 14:57:44 -07002023 */
Suresh Siddha7c6d9f92009-03-16 17:04:59 -07002024 if (ioapic_i8259.pin != -1 && !intr_remapping_enabled) {
Eric W. Biederman650927e2005-06-25 14:57:44 -07002025 struct IO_APIC_route_entry entry;
Eric W. Biederman650927e2005-06-25 14:57:44 -07002026
2027 memset(&entry, 0, sizeof(entry));
2028 entry.mask = 0; /* Enabled */
2029 entry.trigger = 0; /* Edge */
2030 entry.irr = 0;
2031 entry.polarity = 0; /* High */
2032 entry.delivery_status = 0;
2033 entry.dest_mode = 0; /* Physical */
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -08002034 entry.delivery_mode = dest_ExtINT; /* ExtInt */
Eric W. Biederman650927e2005-06-25 14:57:44 -07002035 entry.vector = 0;
Ingo Molnar54168ed2008-08-20 09:07:45 +02002036 entry.dest = read_apic_id();
Eric W. Biederman650927e2005-06-25 14:57:44 -07002037
2038 /*
2039 * Add it to the IO-APIC irq-routing table:
2040 */
Andi Kleencf4c6a22006-09-26 10:52:30 +02002041 ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry);
Eric W. Biederman650927e2005-06-25 14:57:44 -07002042 }
Ingo Molnar54168ed2008-08-20 09:07:45 +02002043
Suresh Siddha7c6d9f92009-03-16 17:04:59 -07002044 /*
2045 * Use virtual wire A mode when interrupt remapping is enabled.
2046 */
Cyrill Gorcunov83121362009-09-15 11:12:30 +04002047 if (cpu_has_apic || apic_from_smp_config())
Cyrill Gorcunov3f4c3952009-06-17 22:13:22 +04002048 disconnect_bsp_APIC(!intr_remapping_enabled &&
2049 ioapic_i8259.pin != -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050}
2051
Ingo Molnar54168ed2008-08-20 09:07:45 +02002052#ifdef CONFIG_X86_32
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053/*
2054 * function to set the IO-APIC physical IDs based on the
2055 * values stored in the MPC table.
2056 *
2057 * by Matt Domsch <Matt_Domsch@dell.com> Tue Dec 21 12:25:05 CST 1999
2058 */
2059
Thomas Gleixnerde934102009-08-20 09:27:29 +02002060void __init setup_ioapic_ids_from_mpc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061{
2062 union IO_APIC_reg_00 reg_00;
2063 physid_mask_t phys_id_present_map;
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01002064 int apic_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 int i;
2066 unsigned char old_id;
2067 unsigned long flags;
2068
Thomas Gleixnerde934102009-08-20 09:27:29 +02002069 if (acpi_ioapic)
Yinghai Lud49c4282008-06-08 18:31:54 -07002070 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 /*
Natalie Protasevichca05fea2005-06-23 00:08:22 -07002072 * Don't check I/O APIC IDs for xAPIC systems. They have
2073 * no meaning without the serial APIC bus.
2074 */
Shaohua Li7c5c1e42006-03-23 02:59:53 -08002075 if (!(boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
2076 || APIC_XAPIC(apic_version[boot_cpu_physical_apicid]))
Natalie Protasevichca05fea2005-06-23 00:08:22 -07002077 return;
2078 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 * This is broken; anything with a real cpu count has to
2080 * circumvent this idiocy regardless.
2081 */
Cyrill Gorcunov7abc0752009-11-10 01:06:59 +03002082 apic->ioapic_phys_id_map(&phys_cpu_present_map, &phys_id_present_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083
2084 /*
2085 * Set the IOAPIC ID to the value stored in the MPC table.
2086 */
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01002087 for (apic_id = 0; apic_id < nr_ioapics; apic_id++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088
2089 /* Read the register 0 value */
Thomas Gleixnerdade7712009-07-25 18:39:36 +02002090 raw_spin_lock_irqsave(&ioapic_lock, flags);
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01002091 reg_00.raw = io_apic_read(apic_id, 0);
Thomas Gleixnerdade7712009-07-25 18:39:36 +02002092 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02002093
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01002094 old_id = mp_ioapics[apic_id].apicid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01002096 if (mp_ioapics[apic_id].apicid >= get_physical_broadcast()) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01002098 apic_id, mp_ioapics[apic_id].apicid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
2100 reg_00.bits.ID);
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01002101 mp_ioapics[apic_id].apicid = reg_00.bits.ID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 }
2103
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 /*
2105 * Sanity check, is the ID really free? Every APIC in a
2106 * system must have a unique ID or we get lots of nice
2107 * 'stuck on smp_invalidate_needed IPI wait' messages.
2108 */
Cyrill Gorcunov7abc0752009-11-10 01:06:59 +03002109 if (apic->check_apicid_used(&phys_id_present_map,
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01002110 mp_ioapics[apic_id].apicid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01002112 apic_id, mp_ioapics[apic_id].apicid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 for (i = 0; i < get_physical_broadcast(); i++)
2114 if (!physid_isset(i, phys_id_present_map))
2115 break;
2116 if (i >= get_physical_broadcast())
2117 panic("Max APIC ID exceeded!\n");
2118 printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
2119 i);
2120 physid_set(i, phys_id_present_map);
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01002121 mp_ioapics[apic_id].apicid = i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 } else {
2123 physid_mask_t tmp;
Cyrill Gorcunov7abc0752009-11-10 01:06:59 +03002124 apic->apicid_to_cpu_present(mp_ioapics[apic_id].apicid, &tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 apic_printk(APIC_VERBOSE, "Setting %d in the "
2126 "phys_id_present_map\n",
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01002127 mp_ioapics[apic_id].apicid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 physids_or(phys_id_present_map, phys_id_present_map, tmp);
2129 }
2130
2131
2132 /*
2133 * We need to adjust the IRQ routing table
2134 * if the ID changed.
2135 */
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01002136 if (old_id != mp_ioapics[apic_id].apicid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 for (i = 0; i < mp_irq_entries; i++)
Jaswinder Singh Rajputc2c21742009-01-12 17:47:22 +05302138 if (mp_irqs[i].dstapic == old_id)
2139 mp_irqs[i].dstapic
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01002140 = mp_ioapics[apic_id].apicid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141
2142 /*
2143 * Read the right value from the MPC table and
2144 * write it into the ID register.
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02002145 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 apic_printk(APIC_VERBOSE, KERN_INFO
2147 "...changing IO-APIC physical APIC ID to %d ...",
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01002148 mp_ioapics[apic_id].apicid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01002150 reg_00.bits.ID = mp_ioapics[apic_id].apicid;
Thomas Gleixnerdade7712009-07-25 18:39:36 +02002151 raw_spin_lock_irqsave(&ioapic_lock, flags);
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01002152 io_apic_write(apic_id, 0, reg_00.raw);
Thomas Gleixnerdade7712009-07-25 18:39:36 +02002153 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154
2155 /*
2156 * Sanity check
2157 */
Thomas Gleixnerdade7712009-07-25 18:39:36 +02002158 raw_spin_lock_irqsave(&ioapic_lock, flags);
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01002159 reg_00.raw = io_apic_read(apic_id, 0);
Thomas Gleixnerdade7712009-07-25 18:39:36 +02002160 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Ingo Molnarc8d46cf2009-01-28 00:14:11 +01002161 if (reg_00.bits.ID != mp_ioapics[apic_id].apicid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 printk("could not set ID!\n");
2163 else
2164 apic_printk(APIC_VERBOSE, " ok.\n");
2165 }
2166}
Ingo Molnar54168ed2008-08-20 09:07:45 +02002167#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168
Zachary Amsden7ce0bcf2007-02-13 13:26:21 +01002169int no_timer_check __initdata;
Zachary Amsden8542b202006-12-07 02:14:09 +01002170
2171static int __init notimercheck(char *s)
2172{
2173 no_timer_check = 1;
2174 return 1;
2175}
2176__setup("no_timer_check", notimercheck);
2177
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178/*
2179 * There is a nasty bug in some older SMP boards, their mptable lies
2180 * about the timer IRQ. We do the following to work around the situation:
2181 *
2182 * - timer IRQ defaults to IO-APIC IRQ
2183 * - if this function detects that timer IRQs are defunct, then we fall
2184 * back to ISA timer IRQs
2185 */
Adrian Bunkf0a7a5c2007-07-21 17:10:29 +02002186static int __init timer_irq_works(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187{
2188 unsigned long t1 = jiffies;
Ingo Molnar4aae0702007-12-18 18:05:58 +01002189 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190
Zachary Amsden8542b202006-12-07 02:14:09 +01002191 if (no_timer_check)
2192 return 1;
2193
Ingo Molnar4aae0702007-12-18 18:05:58 +01002194 local_save_flags(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 local_irq_enable();
2196 /* Let ten ticks pass... */
2197 mdelay((10 * 1000) / HZ);
Ingo Molnar4aae0702007-12-18 18:05:58 +01002198 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199
2200 /*
2201 * Expect a few ticks at least, to be sure some possible
2202 * glue logic does not lock up after one or two first
2203 * ticks in a non-ExtINT mode. Also the local APIC
2204 * might have cached one ExtINT interrupt. Finally, at
2205 * least one tick may be lost due to delays.
2206 */
Ingo Molnar54168ed2008-08-20 09:07:45 +02002207
2208 /* jiffies wrap? */
Julia Lawall1d16b532008-01-30 13:32:19 +01002209 if (time_after(jiffies, t1 + 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 return 0;
2212}
2213
2214/*
2215 * In the SMP+IOAPIC case it might happen that there are an unspecified
2216 * number of pending IRQ events unhandled. These cases are very rare,
2217 * so we 'resend' these IRQs via IPIs, to the same CPU. It's much
2218 * better to do it this way as thus we do not have to be aware of
2219 * 'pending' interrupts in the IRQ path, except at this point.
2220 */
2221/*
2222 * Edge triggered needs to resend any interrupt
2223 * that was delayed but this is now handled in the device
2224 * independent code.
2225 */
2226
2227/*
2228 * Starting up a edge-triggered IO-APIC interrupt is
2229 * nasty - we need to make sure that we get the edge.
2230 * If it is already asserted for some reason, we need
2231 * return 1 to indicate that is was pending.
2232 *
2233 * This is not complete - we should be able to fake
2234 * an edge even if it isn't on the 8259A...
2235 */
Ingo Molnar54168ed2008-08-20 09:07:45 +02002236
Ingo Molnarf5b9ed72006-10-04 02:16:26 -07002237static unsigned int startup_ioapic_irq(unsigned int irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238{
2239 int was_pending = 0;
2240 unsigned long flags;
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08002241 struct irq_cfg *cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242
Thomas Gleixnerdade7712009-07-25 18:39:36 +02002243 raw_spin_lock_irqsave(&ioapic_lock, flags);
Jacob Panb81bb372009-11-09 11:27:04 -08002244 if (irq < legacy_pic->nr_legacy_irqs) {
2245 legacy_pic->chip->mask(irq);
2246 if (legacy_pic->irq_pending(irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 was_pending = 1;
2248 }
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08002249 cfg = irq_cfg(irq);
Yinghai Lu3145e942008-12-05 18:58:34 -08002250 __unmask_IO_APIC_irq(cfg);
Thomas Gleixnerdade7712009-07-25 18:39:36 +02002251 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252
2253 return was_pending;
2254}
2255
Eric W. Biedermanace80ab2006-10-04 02:16:47 -07002256static int ioapic_retrigger_irq(unsigned int irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257{
Ingo Molnar54168ed2008-08-20 09:07:45 +02002258
2259 struct irq_cfg *cfg = irq_cfg(irq);
2260 unsigned long flags;
2261
Thomas Gleixnerdade7712009-07-25 18:39:36 +02002262 raw_spin_lock_irqsave(&vector_lock, flags);
Ingo Molnardac5f412009-01-28 15:42:24 +01002263 apic->send_IPI_mask(cpumask_of(cpumask_first(cfg->domain)), cfg->vector);
Thomas Gleixnerdade7712009-07-25 18:39:36 +02002264 raw_spin_unlock_irqrestore(&vector_lock, flags);
Ingo Molnarc0ad90a2006-06-29 02:24:44 -07002265
2266 return 1;
2267}
Ingo Molnar54168ed2008-08-20 09:07:45 +02002268
2269/*
2270 * Level and edge triggered IO-APIC interrupts need different handling,
2271 * so we use two separate IRQ descriptors. Edge triggered IRQs can be
2272 * handled with the level-triggered descriptor, but that one has slightly
2273 * more overhead. Level-triggered interrupts cannot be handled with the
2274 * edge-triggered handler, without risking IRQ storms and other ugly
2275 * races.
2276 */
Ingo Molnarc0ad90a2006-06-29 02:24:44 -07002277
Yinghai Lu497c9a12008-08-19 20:50:28 -07002278#ifdef CONFIG_SMP
Dimitri Sivanich9338ad62009-10-13 15:32:36 -05002279void send_cleanup_vector(struct irq_cfg *cfg)
Gary Hadee85abf82009-04-08 14:07:25 -07002280{
2281 cpumask_var_t cleanup_mask;
2282
2283 if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) {
2284 unsigned int i;
Gary Hadee85abf82009-04-08 14:07:25 -07002285 for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
2286 apic->send_IPI_mask(cpumask_of(i), IRQ_MOVE_CLEANUP_VECTOR);
2287 } else {
2288 cpumask_and(cleanup_mask, cfg->old_domain, cpu_online_mask);
Gary Hadee85abf82009-04-08 14:07:25 -07002289 apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
2290 free_cpumask_var(cleanup_mask);
2291 }
2292 cfg->move_in_progress = 0;
2293}
2294
Ingo Molnar44204712009-05-01 19:02:50 +02002295static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg)
Gary Hadee85abf82009-04-08 14:07:25 -07002296{
2297 int apic, pin;
2298 struct irq_pin_list *entry;
2299 u8 vector = cfg->vector;
2300
Cyrill Gorcunov2977fb32009-08-01 11:47:59 +04002301 for_each_irq_pin(entry, cfg->irq_2_pin) {
Gary Hadee85abf82009-04-08 14:07:25 -07002302 unsigned int reg;
2303
Gary Hadee85abf82009-04-08 14:07:25 -07002304 apic = entry->apic;
2305 pin = entry->pin;
2306 /*
2307 * With interrupt-remapping, destination information comes
2308 * from interrupt-remapping table entry.
2309 */
2310 if (!irq_remapped(irq))
2311 io_apic_write(apic, 0x11 + pin*2, dest);
2312 reg = io_apic_read(apic, 0x10 + pin*2);
2313 reg &= ~IO_APIC_REDIR_VECTOR_MASK;
2314 reg |= vector;
2315 io_apic_modify(apic, 0x10 + pin*2, reg);
Gary Hadee85abf82009-04-08 14:07:25 -07002316 }
2317}
2318
2319/*
2320 * Either sets desc->affinity to a valid value, and returns
Suresh Siddha18374d82009-12-17 18:29:46 -08002321 * ->cpu_mask_to_apicid of that in dest_id, or returns -1 and
Gary Hadee85abf82009-04-08 14:07:25 -07002322 * leaves desc->affinity untouched.
2323 */
Dimitri Sivanich9338ad62009-10-13 15:32:36 -05002324unsigned int
Suresh Siddha18374d82009-12-17 18:29:46 -08002325set_desc_affinity(struct irq_desc *desc, const struct cpumask *mask,
2326 unsigned int *dest_id)
Gary Hadee85abf82009-04-08 14:07:25 -07002327{
2328 struct irq_cfg *cfg;
2329 unsigned int irq;
2330
2331 if (!cpumask_intersects(mask, cpu_online_mask))
Suresh Siddha18374d82009-12-17 18:29:46 -08002332 return -1;
Gary Hadee85abf82009-04-08 14:07:25 -07002333
2334 irq = desc->irq;
2335 cfg = desc->chip_data;
2336 if (assign_irq_vector(irq, cfg, mask))
Suresh Siddha18374d82009-12-17 18:29:46 -08002337 return -1;
Gary Hadee85abf82009-04-08 14:07:25 -07002338
Gary Hadee85abf82009-04-08 14:07:25 -07002339 cpumask_copy(desc->affinity, mask);
2340
Suresh Siddha18374d82009-12-17 18:29:46 -08002341 *dest_id = apic->cpu_mask_to_apicid_and(desc->affinity, cfg->domain);
2342 return 0;
Gary Hadee85abf82009-04-08 14:07:25 -07002343}
2344
Ingo Molnar44204712009-05-01 19:02:50 +02002345static int
Gary Hadee85abf82009-04-08 14:07:25 -07002346set_ioapic_affinity_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
2347{
2348 struct irq_cfg *cfg;
2349 unsigned long flags;
2350 unsigned int dest;
2351 unsigned int irq;
Ingo Molnar44204712009-05-01 19:02:50 +02002352 int ret = -1;
Gary Hadee85abf82009-04-08 14:07:25 -07002353
2354 irq = desc->irq;
2355 cfg = desc->chip_data;
2356
Thomas Gleixnerdade7712009-07-25 18:39:36 +02002357 raw_spin_lock_irqsave(&ioapic_lock, flags);
Suresh Siddha18374d82009-12-17 18:29:46 -08002358 ret = set_desc_affinity(desc, mask, &dest);
2359 if (!ret) {
Gary Hadee85abf82009-04-08 14:07:25 -07002360 /* Only the high 8 bits are valid. */
2361 dest = SET_APIC_LOGICAL_ID(dest);
2362 __target_IO_APIC_irq(irq, dest, cfg);
2363 }
Thomas Gleixnerdade7712009-07-25 18:39:36 +02002364 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Ingo Molnar44204712009-05-01 19:02:50 +02002365
2366 return ret;
Gary Hadee85abf82009-04-08 14:07:25 -07002367}
2368
Ingo Molnar44204712009-05-01 19:02:50 +02002369static int
Gary Hadee85abf82009-04-08 14:07:25 -07002370set_ioapic_affinity_irq(unsigned int irq, const struct cpumask *mask)
2371{
2372 struct irq_desc *desc;
2373
2374 desc = irq_to_desc(irq);
2375
Ingo Molnar44204712009-05-01 19:02:50 +02002376 return set_ioapic_affinity_irq_desc(desc, mask);
Gary Hadee85abf82009-04-08 14:07:25 -07002377}
Ingo Molnar54168ed2008-08-20 09:07:45 +02002378
2379#ifdef CONFIG_INTR_REMAP
Ingo Molnar54168ed2008-08-20 09:07:45 +02002380
2381/*
2382 * Migrate the IO-APIC irq in the presence of intr-remapping.
2383 *
Suresh Siddha0280f7c2009-03-16 17:05:01 -07002384 * For both level and edge triggered, irq migration is a simple atomic
2385 * update(of vector and cpu destination) of IRTE and flush the hardware cache.
Ingo Molnar54168ed2008-08-20 09:07:45 +02002386 *
Suresh Siddha0280f7c2009-03-16 17:05:01 -07002387 * For level triggered, we eliminate the io-apic RTE modification (with the
2388 * updated vector information), by using a virtual vector (io-apic pin number).
2389 * Real vector that is used for interrupting cpu will be coming from
2390 * the interrupt-remapping table entry.
Ingo Molnar54168ed2008-08-20 09:07:45 +02002391 */
Yinghai Lud5dedd42009-04-27 17:59:21 -07002392static int
Mike Travise7986732008-12-16 17:33:52 -08002393migrate_ioapic_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
Ingo Molnar54168ed2008-08-20 09:07:45 +02002394{
2395 struct irq_cfg *cfg;
Ingo Molnar54168ed2008-08-20 09:07:45 +02002396 struct irte irte;
Ingo Molnar54168ed2008-08-20 09:07:45 +02002397 unsigned int dest;
Yinghai Lu3145e942008-12-05 18:58:34 -08002398 unsigned int irq;
Yinghai Lud5dedd42009-04-27 17:59:21 -07002399 int ret = -1;
Ingo Molnar54168ed2008-08-20 09:07:45 +02002400
Mike Travis22f65d32008-12-16 17:33:56 -08002401 if (!cpumask_intersects(mask, cpu_online_mask))
Yinghai Lud5dedd42009-04-27 17:59:21 -07002402 return ret;
Ingo Molnar54168ed2008-08-20 09:07:45 +02002403
Yinghai Lu3145e942008-12-05 18:58:34 -08002404 irq = desc->irq;
Ingo Molnar54168ed2008-08-20 09:07:45 +02002405 if (get_irte(irq, &irte))
Yinghai Lud5dedd42009-04-27 17:59:21 -07002406 return ret;
Ingo Molnar54168ed2008-08-20 09:07:45 +02002407
Yinghai Lu3145e942008-12-05 18:58:34 -08002408 cfg = desc->chip_data;
2409 if (assign_irq_vector(irq, cfg, mask))
Yinghai Lud5dedd42009-04-27 17:59:21 -07002410 return ret;
Ingo Molnar54168ed2008-08-20 09:07:45 +02002411
Ingo Molnardebccb32009-01-28 15:20:18 +01002412 dest = apic->cpu_mask_to_apicid_and(cfg->domain, mask);
Ingo Molnar54168ed2008-08-20 09:07:45 +02002413
Ingo Molnar54168ed2008-08-20 09:07:45 +02002414 irte.vector = cfg->vector;
2415 irte.dest_id = IRTE_DEST(dest);
2416
2417 /*
2418 * Modified the IRTE and flushes the Interrupt entry cache.
2419 */
2420 modify_irte(irq, &irte);
2421
Mike Travis22f65d32008-12-16 17:33:56 -08002422 if (cfg->move_in_progress)
2423 send_cleanup_vector(cfg);
Ingo Molnar54168ed2008-08-20 09:07:45 +02002424
Mike Travis7f7ace02009-01-10 21:58:08 -08002425 cpumask_copy(desc->affinity, mask);
Yinghai Lud5dedd42009-04-27 17:59:21 -07002426
2427 return 0;
Ingo Molnar54168ed2008-08-20 09:07:45 +02002428}
2429
Ingo Molnar54168ed2008-08-20 09:07:45 +02002430/*
2431 * Migrates the IRQ destination in the process context.
2432 */
Yinghai Lud5dedd42009-04-27 17:59:21 -07002433static int set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc,
Rusty Russell968ea6d2008-12-13 21:55:51 +10302434 const struct cpumask *mask)
Ingo Molnar54168ed2008-08-20 09:07:45 +02002435{
Yinghai Lud5dedd42009-04-27 17:59:21 -07002436 return migrate_ioapic_irq_desc(desc, mask);
Yinghai Lu3145e942008-12-05 18:58:34 -08002437}
Yinghai Lud5dedd42009-04-27 17:59:21 -07002438static int set_ir_ioapic_affinity_irq(unsigned int irq,
Rusty Russell0de26522008-12-13 21:20:26 +10302439 const struct cpumask *mask)
Ingo Molnar54168ed2008-08-20 09:07:45 +02002440{
2441 struct irq_desc *desc = irq_to_desc(irq);
2442
Yinghai Lud5dedd42009-04-27 17:59:21 -07002443 return set_ir_ioapic_affinity_irq_desc(desc, mask);
Ingo Molnar54168ed2008-08-20 09:07:45 +02002444}
Suresh Siddha29b61be2009-03-16 17:05:02 -07002445#else
Yinghai Lud5dedd42009-04-27 17:59:21 -07002446static inline int set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc,
Suresh Siddha29b61be2009-03-16 17:05:02 -07002447 const struct cpumask *mask)
2448{
Yinghai Lud5dedd42009-04-27 17:59:21 -07002449 return 0;
Suresh Siddha29b61be2009-03-16 17:05:02 -07002450}
Ingo Molnar54168ed2008-08-20 09:07:45 +02002451#endif
2452
Yinghai Lu497c9a12008-08-19 20:50:28 -07002453asmlinkage void smp_irq_move_cleanup_interrupt(void)
2454{
2455 unsigned vector, me;
Hiroshi Shimamoto8f2466f2008-12-08 19:19:07 -08002456
Yinghai Lu497c9a12008-08-19 20:50:28 -07002457 ack_APIC_irq();
Ingo Molnar54168ed2008-08-20 09:07:45 +02002458 exit_idle();
Yinghai Lu497c9a12008-08-19 20:50:28 -07002459 irq_enter();
2460
2461 me = smp_processor_id();
2462 for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
2463 unsigned int irq;
Suresh Siddha68a8ca52009-03-16 17:05:04 -07002464 unsigned int irr;
Yinghai Lu497c9a12008-08-19 20:50:28 -07002465 struct irq_desc *desc;
2466 struct irq_cfg *cfg;
2467 irq = __get_cpu_var(vector_irq)[vector];
2468
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08002469 if (irq == -1)
2470 continue;
2471
Yinghai Lu497c9a12008-08-19 20:50:28 -07002472 desc = irq_to_desc(irq);
2473 if (!desc)
2474 continue;
2475
2476 cfg = irq_cfg(irq);
Thomas Gleixner239007b2009-11-17 16:46:45 +01002477 raw_spin_lock(&desc->lock);
Yinghai Lu497c9a12008-08-19 20:50:28 -07002478
Suresh Siddha7f41c2e2010-01-06 10:56:31 -08002479 /*
2480 * Check if the irq migration is in progress. If so, we
2481 * haven't received the cleanup request yet for this irq.
2482 */
2483 if (cfg->move_in_progress)
2484 goto unlock;
2485
Mike Travis22f65d32008-12-16 17:33:56 -08002486 if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
Yinghai Lu497c9a12008-08-19 20:50:28 -07002487 goto unlock;
2488
Suresh Siddha68a8ca52009-03-16 17:05:04 -07002489 irr = apic_read(APIC_IRR + (vector / 32 * 0x10));
2490 /*
2491 * Check if the vector that needs to be cleanedup is
2492 * registered at the cpu's IRR. If so, then this is not
2493 * the best time to clean it up. Lets clean it up in the
2494 * next attempt by sending another IRQ_MOVE_CLEANUP_VECTOR
2495 * to myself.
2496 */
2497 if (irr & (1 << (vector % 32))) {
2498 apic->send_IPI_self(IRQ_MOVE_CLEANUP_VECTOR);
2499 goto unlock;
2500 }
Yinghai Lu497c9a12008-08-19 20:50:28 -07002501 __get_cpu_var(vector_irq)[vector] = -1;
Yinghai Lu497c9a12008-08-19 20:50:28 -07002502unlock:
Thomas Gleixner239007b2009-11-17 16:46:45 +01002503 raw_spin_unlock(&desc->lock);
Yinghai Lu497c9a12008-08-19 20:50:28 -07002504 }
2505
2506 irq_exit();
2507}
2508
Suresh Siddhaa5e74b82009-10-26 14:24:34 -08002509static void __irq_complete_move(struct irq_desc **descp, unsigned vector)
Yinghai Lu497c9a12008-08-19 20:50:28 -07002510{
Yinghai Lu3145e942008-12-05 18:58:34 -08002511 struct irq_desc *desc = *descp;
2512 struct irq_cfg *cfg = desc->chip_data;
Suresh Siddhaa5e74b82009-10-26 14:24:34 -08002513 unsigned me;
Yinghai Lu497c9a12008-08-19 20:50:28 -07002514
Yinghai Lufcef5912009-04-27 17:58:23 -07002515 if (likely(!cfg->move_in_progress))
Yinghai Lu497c9a12008-08-19 20:50:28 -07002516 return;
2517
Yinghai Lu497c9a12008-08-19 20:50:28 -07002518 me = smp_processor_id();
Yinghai Lu10b888d2009-01-31 14:50:07 -08002519
Yinghai Lufcef5912009-04-27 17:58:23 -07002520 if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
Mike Travis22f65d32008-12-16 17:33:56 -08002521 send_cleanup_vector(cfg);
Yinghai Lu497c9a12008-08-19 20:50:28 -07002522}
Suresh Siddhaa5e74b82009-10-26 14:24:34 -08002523
2524static void irq_complete_move(struct irq_desc **descp)
2525{
2526 __irq_complete_move(descp, ~get_irq_regs()->orig_ax);
2527}
2528
2529void irq_force_complete_move(int irq)
2530{
2531 struct irq_desc *desc = irq_to_desc(irq);
2532 struct irq_cfg *cfg = desc->chip_data;
2533
Prarit Bhargavabbd391a2010-04-27 11:24:42 -04002534 if (!cfg)
2535 return;
2536
Suresh Siddhaa5e74b82009-10-26 14:24:34 -08002537 __irq_complete_move(&desc, cfg->vector);
2538}
Yinghai Lu497c9a12008-08-19 20:50:28 -07002539#else
Yinghai Lu3145e942008-12-05 18:58:34 -08002540static inline void irq_complete_move(struct irq_desc **descp) {}
Yinghai Lu497c9a12008-08-19 20:50:28 -07002541#endif
Yinghai Lu3145e942008-12-05 18:58:34 -08002542
Yinghai Lu1d025192008-08-19 20:50:34 -07002543static void ack_apic_edge(unsigned int irq)
2544{
Yinghai Lu3145e942008-12-05 18:58:34 -08002545 struct irq_desc *desc = irq_to_desc(irq);
2546
2547 irq_complete_move(&desc);
Yinghai Lu1d025192008-08-19 20:50:34 -07002548 move_native_irq(irq);
2549 ack_APIC_irq();
2550}
2551
Yinghai Lu3eb2cce2008-08-19 20:50:48 -07002552atomic_t irq_mis_count;
Yinghai Lu3eb2cce2008-08-19 20:50:48 -07002553
Suresh Siddhac29d9db2009-12-01 15:31:16 -08002554/*
2555 * IO-APIC versions below 0x20 don't support EOI register.
2556 * For the record, here is the information about various versions:
2557 * 0Xh 82489DX
2558 * 1Xh I/OAPIC or I/O(x)APIC which are not PCI 2.2 Compliant
2559 * 2Xh I/O(x)APIC which is PCI 2.2 Compliant
2560 * 30h-FFh Reserved
2561 *
2562 * Some of the Intel ICH Specs (ICH2 to ICH5) documents the io-apic
2563 * version as 0x2. This is an error with documentation and these ICH chips
2564 * use io-apic's of version 0x20.
2565 *
2566 * For IO-APIC's with EOI register, we use that to do an explicit EOI.
2567 * Otherwise, we simulate the EOI message manually by changing the trigger
2568 * mode to edge and then back to level, with RTE being masked during this.
2569*/
Suresh Siddhab3ec0a32009-10-26 14:24:35 -08002570static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
2571{
2572 struct irq_pin_list *entry;
2573
2574 for_each_irq_pin(entry, cfg->irq_2_pin) {
Suresh Siddhac29d9db2009-12-01 15:31:16 -08002575 if (mp_ioapics[entry->apic].apicver >= 0x20) {
2576 /*
2577 * Intr-remapping uses pin number as the virtual vector
2578 * in the RTE. Actual vector is programmed in
2579 * intr-remapping table entry. Hence for the io-apic
2580 * EOI we use the pin number.
2581 */
2582 if (irq_remapped(irq))
2583 io_apic_eoi(entry->apic, entry->pin);
2584 else
2585 io_apic_eoi(entry->apic, cfg->vector);
2586 } else {
2587 __mask_and_edge_IO_APIC_irq(entry);
2588 __unmask_and_level_IO_APIC_irq(entry);
2589 }
Suresh Siddhab3ec0a32009-10-26 14:24:35 -08002590 }
2591}
2592
2593static void eoi_ioapic_irq(struct irq_desc *desc)
2594{
2595 struct irq_cfg *cfg;
2596 unsigned long flags;
2597 unsigned int irq;
2598
2599 irq = desc->irq;
2600 cfg = desc->chip_data;
2601
Thomas Gleixnerdade7712009-07-25 18:39:36 +02002602 raw_spin_lock_irqsave(&ioapic_lock, flags);
Suresh Siddhab3ec0a32009-10-26 14:24:35 -08002603 __eoi_ioapic_irq(irq, cfg);
Thomas Gleixnerdade7712009-07-25 18:39:36 +02002604 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Suresh Siddhab3ec0a32009-10-26 14:24:35 -08002605}
2606
Yinghai Lu047c8fd2008-08-19 20:50:41 -07002607static void ack_apic_level(unsigned int irq)
2608{
Yinghai Lu3145e942008-12-05 18:58:34 -08002609 struct irq_desc *desc = irq_to_desc(irq);
Yinghai Lu3eb2cce2008-08-19 20:50:48 -07002610 unsigned long v;
2611 int i;
Yinghai Lu3145e942008-12-05 18:58:34 -08002612 struct irq_cfg *cfg;
Ingo Molnar54168ed2008-08-20 09:07:45 +02002613 int do_unmask_irq = 0;
Yinghai Lu047c8fd2008-08-19 20:50:41 -07002614
Yinghai Lu3145e942008-12-05 18:58:34 -08002615 irq_complete_move(&desc);
Yinghai Lu047c8fd2008-08-19 20:50:41 -07002616#ifdef CONFIG_GENERIC_PENDING_IRQ
Ingo Molnar54168ed2008-08-20 09:07:45 +02002617 /* If we are moving the irq we need to mask it */
Yinghai Lu3145e942008-12-05 18:58:34 -08002618 if (unlikely(desc->status & IRQ_MOVE_PENDING)) {
Ingo Molnar54168ed2008-08-20 09:07:45 +02002619 do_unmask_irq = 1;
Yinghai Lu3145e942008-12-05 18:58:34 -08002620 mask_IO_APIC_irq_desc(desc);
Ingo Molnar54168ed2008-08-20 09:07:45 +02002621 }
Yinghai Lu047c8fd2008-08-19 20:50:41 -07002622#endif
2623
Yinghai Lu3eb2cce2008-08-19 20:50:48 -07002624 /*
Jeremy Fitzhardinge916a0fe2009-06-08 03:00:22 -07002625 * It appears there is an erratum which affects at least version 0x11
2626 * of I/O APIC (that's the 82093AA and cores integrated into various
2627 * chipsets). Under certain conditions a level-triggered interrupt is
2628 * erroneously delivered as edge-triggered one but the respective IRR
2629 * bit gets set nevertheless. As a result the I/O unit expects an EOI
2630 * message but it will never arrive and further interrupts are blocked
2631 * from the source. The exact reason is so far unknown, but the
2632 * phenomenon was observed when two consecutive interrupt requests
2633 * from a given source get delivered to the same CPU and the source is
2634 * temporarily disabled in between.
2635 *
2636 * A workaround is to simulate an EOI message manually. We achieve it
2637 * by setting the trigger mode to edge and then to level when the edge
2638 * trigger mode gets detected in the TMR of a local APIC for a
2639 * level-triggered interrupt. We mask the source for the time of the
2640 * operation to prevent an edge-triggered interrupt escaping meanwhile.
2641 * The idea is from Manfred Spraul. --macro
Suresh Siddha1c839952009-12-01 15:31:17 -08002642 *
2643 * Also in the case when cpu goes offline, fixup_irqs() will forward
2644 * any unhandled interrupt on the offlined cpu to the new cpu
2645 * destination that is handling the corresponding interrupt. This
2646 * interrupt forwarding is done via IPI's. Hence, in this case also
2647 * level-triggered io-apic interrupt will be seen as an edge
2648 * interrupt in the IRR. And we can't rely on the cpu's EOI
2649 * to be broadcasted to the IO-APIC's which will clear the remoteIRR
2650 * corresponding to the level-triggered interrupt. Hence on IO-APIC's
2651 * supporting EOI register, we do an explicit EOI to clear the
2652 * remote IRR and on IO-APIC's which don't have an EOI register,
2653 * we use the above logic (mask+edge followed by unmask+level) from
2654 * Manfred Spraul to clear the remote IRR.
Jeremy Fitzhardinge916a0fe2009-06-08 03:00:22 -07002655 */
Yinghai Lu3145e942008-12-05 18:58:34 -08002656 cfg = desc->chip_data;
2657 i = cfg->vector;
Yinghai Lu3eb2cce2008-08-19 20:50:48 -07002658 v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
Yinghai Lu3eb2cce2008-08-19 20:50:48 -07002659
Ingo Molnar54168ed2008-08-20 09:07:45 +02002660 /*
2661 * We must acknowledge the irq before we move it or the acknowledge will
2662 * not propagate properly.
2663 */
2664 ack_APIC_irq();
Yinghai Lu047c8fd2008-08-19 20:50:41 -07002665
Suresh Siddha1c839952009-12-01 15:31:17 -08002666 /*
2667 * Tail end of clearing remote IRR bit (either by delivering the EOI
2668 * message via io-apic EOI register write or simulating it using
2669 * mask+edge followed by unnask+level logic) manually when the
2670 * level triggered interrupt is seen as the edge triggered interrupt
2671 * at the cpu.
2672 */
Maciej W. Rozyckica64c472009-12-01 15:31:15 -08002673 if (!(v & (1 << (i & 0x1f)))) {
2674 atomic_inc(&irq_mis_count);
2675
Suresh Siddhac29d9db2009-12-01 15:31:16 -08002676 eoi_ioapic_irq(desc);
Maciej W. Rozyckica64c472009-12-01 15:31:15 -08002677 }
2678
Ingo Molnar54168ed2008-08-20 09:07:45 +02002679 /* Now we can move and renable the irq */
2680 if (unlikely(do_unmask_irq)) {
2681 /* Only migrate the irq if the ack has been received.
2682 *
2683 * On rare occasions the broadcast level triggered ack gets
2684 * delayed going to ioapics, and if we reprogram the
2685 * vector while Remote IRR is still set the irq will never
2686 * fire again.
2687 *
2688 * To prevent this scenario we read the Remote IRR bit
2689 * of the ioapic. This has two effects.
2690 * - On any sane system the read of the ioapic will
2691 * flush writes (and acks) going to the ioapic from
2692 * this cpu.
2693 * - We get to see if the ACK has actually been delivered.
2694 *
2695 * Based on failed experiments of reprogramming the
2696 * ioapic entry from outside of irq context starting
2697 * with masking the ioapic entry and then polling until
2698 * Remote IRR was clear before reprogramming the
2699 * ioapic I don't trust the Remote IRR bit to be
2700 * completey accurate.
2701 *
2702 * However there appears to be no other way to plug
2703 * this race, so if the Remote IRR bit is not
2704 * accurate and is causing problems then it is a hardware bug
2705 * and you can go talk to the chipset vendor about it.
2706 */
Yinghai Lu3145e942008-12-05 18:58:34 -08002707 cfg = desc->chip_data;
2708 if (!io_apic_level_ack_pending(cfg))
Ingo Molnar54168ed2008-08-20 09:07:45 +02002709 move_masked_irq(irq);
Yinghai Lu3145e942008-12-05 18:58:34 -08002710 unmask_IO_APIC_irq_desc(desc);
Ingo Molnar54168ed2008-08-20 09:07:45 +02002711 }
Yinghai Lu3eb2cce2008-08-19 20:50:48 -07002712}
Yinghai Lu1d025192008-08-19 20:50:34 -07002713
Han, Weidongd0b03bd2009-04-03 17:15:50 +08002714#ifdef CONFIG_INTR_REMAP
2715static void ir_ack_apic_edge(unsigned int irq)
2716{
Weidong Han5d0ae2d2009-04-17 16:42:13 +08002717 ack_APIC_irq();
Han, Weidongd0b03bd2009-04-03 17:15:50 +08002718}
2719
2720static void ir_ack_apic_level(unsigned int irq)
2721{
Weidong Han5d0ae2d2009-04-17 16:42:13 +08002722 struct irq_desc *desc = irq_to_desc(irq);
2723
2724 ack_APIC_irq();
2725 eoi_ioapic_irq(desc);
Han, Weidongd0b03bd2009-04-03 17:15:50 +08002726}
2727#endif /* CONFIG_INTR_REMAP */
2728
Ingo Molnarf5b9ed72006-10-04 02:16:26 -07002729static struct irq_chip ioapic_chip __read_mostly = {
Thomas Gleixnerd6c88a52008-10-15 15:27:23 +02002730 .name = "IO-APIC",
2731 .startup = startup_ioapic_irq,
2732 .mask = mask_IO_APIC_irq,
2733 .unmask = unmask_IO_APIC_irq,
2734 .ack = ack_apic_edge,
2735 .eoi = ack_apic_level,
Ashok Raj54d5d422005-09-06 15:16:15 -07002736#ifdef CONFIG_SMP
Thomas Gleixnerd6c88a52008-10-15 15:27:23 +02002737 .set_affinity = set_ioapic_affinity_irq,
Ashok Raj54d5d422005-09-06 15:16:15 -07002738#endif
Eric W. Biedermanace80ab2006-10-04 02:16:47 -07002739 .retrigger = ioapic_retrigger_irq,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740};
2741
Ingo Molnar54168ed2008-08-20 09:07:45 +02002742static struct irq_chip ir_ioapic_chip __read_mostly = {
Thomas Gleixnerd6c88a52008-10-15 15:27:23 +02002743 .name = "IR-IO-APIC",
2744 .startup = startup_ioapic_irq,
2745 .mask = mask_IO_APIC_irq,
2746 .unmask = unmask_IO_APIC_irq,
Jaswinder Singh Rajputa1e38ca2009-03-23 02:11:25 +05302747#ifdef CONFIG_INTR_REMAP
Han, Weidongd0b03bd2009-04-03 17:15:50 +08002748 .ack = ir_ack_apic_edge,
2749 .eoi = ir_ack_apic_level,
Ingo Molnar54168ed2008-08-20 09:07:45 +02002750#ifdef CONFIG_SMP
Thomas Gleixnerd6c88a52008-10-15 15:27:23 +02002751 .set_affinity = set_ir_ioapic_affinity_irq,
Ingo Molnar54168ed2008-08-20 09:07:45 +02002752#endif
Jaswinder Singh Rajputa1e38ca2009-03-23 02:11:25 +05302753#endif
Ingo Molnar54168ed2008-08-20 09:07:45 +02002754 .retrigger = ioapic_retrigger_irq,
2755};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756
2757static inline void init_IO_APIC_traps(void)
2758{
2759 int irq;
Yinghai Lu08678b02008-08-19 20:50:05 -07002760 struct irq_desc *desc;
Yinghai Luda51a822008-08-19 20:50:25 -07002761 struct irq_cfg *cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762
2763 /*
2764 * NOTE! The local APIC isn't very good at handling
2765 * multiple interrupts at the same interrupt level.
2766 * As the interrupt level is determined by taking the
2767 * vector number and shifting that right by 4, we
2768 * want to spread these out a bit so that they don't
2769 * all fall in the same interrupt level.
2770 *
2771 * Also, we've got to be careful not to trash gate
2772 * 0x80, because int 0x80 is hm, kind of importantish. ;)
2773 */
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08002774 for_each_irq_desc(irq, desc) {
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08002775 cfg = desc->chip_data;
2776 if (IO_APIC_IRQ(irq) && cfg && !cfg->vector) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 /*
2778 * Hmm.. We don't have an entry for this,
2779 * so default to an old-fashioned 8259
2780 * interrupt if we can..
2781 */
Jacob Panb81bb372009-11-09 11:27:04 -08002782 if (irq < legacy_pic->nr_legacy_irqs)
2783 legacy_pic->make_irq(irq);
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08002784 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 /* Strange. Oh, well.. */
Yinghai Lu08678b02008-08-19 20:50:05 -07002786 desc->chip = &no_irq_chip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 }
2788 }
2789}
2790
Ingo Molnarf5b9ed72006-10-04 02:16:26 -07002791/*
2792 * The local APIC irq-chip implementation:
2793 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02002795static void mask_lapic_irq(unsigned int irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796{
2797 unsigned long v;
2798
2799 v = apic_read(APIC_LVT0);
Maciej W. Rozycki593f4a72008-07-16 19:15:30 +01002800 apic_write(APIC_LVT0, v | APIC_LVT_MASKED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801}
2802
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02002803static void unmask_lapic_irq(unsigned int irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804{
Ingo Molnarf5b9ed72006-10-04 02:16:26 -07002805 unsigned long v;
2806
2807 v = apic_read(APIC_LVT0);
Maciej W. Rozycki593f4a72008-07-16 19:15:30 +01002808 apic_write(APIC_LVT0, v & ~APIC_LVT_MASKED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809}
2810
Yinghai Lu3145e942008-12-05 18:58:34 -08002811static void ack_lapic_irq(unsigned int irq)
Yinghai Lu1d025192008-08-19 20:50:34 -07002812{
2813 ack_APIC_irq();
2814}
2815
Ingo Molnarf5b9ed72006-10-04 02:16:26 -07002816static struct irq_chip lapic_chip __read_mostly = {
Maciej W. Rozycki9a1c6192008-05-27 21:19:09 +01002817 .name = "local-APIC",
Ingo Molnarf5b9ed72006-10-04 02:16:26 -07002818 .mask = mask_lapic_irq,
2819 .unmask = unmask_lapic_irq,
Maciej W. Rozyckic88ac1d2008-07-11 19:35:17 +01002820 .ack = ack_lapic_irq,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821};
2822
Yinghai Lu3145e942008-12-05 18:58:34 -08002823static void lapic_register_intr(int irq, struct irq_desc *desc)
Maciej W. Rozyckic88ac1d2008-07-11 19:35:17 +01002824{
Yinghai Lu08678b02008-08-19 20:50:05 -07002825 desc->status &= ~IRQ_LEVEL;
Maciej W. Rozyckic88ac1d2008-07-11 19:35:17 +01002826 set_irq_chip_and_handler_name(irq, &lapic_chip, handle_edge_irq,
2827 "edge");
Maciej W. Rozyckic88ac1d2008-07-11 19:35:17 +01002828}
2829
Jan Beuliche9427102008-01-30 13:31:24 +01002830static void __init setup_nmi(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831{
2832 /*
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02002833 * Dirty trick to enable the NMI watchdog ...
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 * We put the 8259A master into AEOI mode and
2835 * unmask on all local APICs LVT0 as NMI.
2836 *
2837 * The idea to use the 8259A in AEOI mode ('8259A Virtual Wire')
2838 * is from Maciej W. Rozycki - so we do not have to EOI from
2839 * the NMI handler or the timer interrupt.
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02002840 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 apic_printk(APIC_VERBOSE, KERN_INFO "activating NMI Watchdog ...");
2842
Jan Beuliche9427102008-01-30 13:31:24 +01002843 enable_NMI_through_LVT0();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844
2845 apic_printk(APIC_VERBOSE, " done.\n");
2846}
2847
2848/*
2849 * This looks a bit hackish but it's about the only one way of sending
2850 * a few INTA cycles to 8259As and any associated glue logic. ICR does
2851 * not support the ExtINT mode, unfortunately. We need to send these
2852 * cycles as some i82489DX-based boards have glue logic that keeps the
2853 * 8259A interrupt line asserted until INTA. --macro
2854 */
Jacek Luczak28acf282008-04-12 17:41:12 +02002855static inline void __init unlock_ExtINT_logic(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856{
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -08002857 int apic, pin, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 struct IO_APIC_route_entry entry0, entry1;
2859 unsigned char save_control, save_freq_select;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -08002861 pin = find_isa_irq_pin(8, mp_INT);
Adrian Bunk956fb532006-12-07 02:14:11 +01002862 if (pin == -1) {
2863 WARN_ON_ONCE(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 return;
Adrian Bunk956fb532006-12-07 02:14:11 +01002865 }
2866 apic = find_isa_irq_apic(8, mp_INT);
2867 if (apic == -1) {
2868 WARN_ON_ONCE(1);
2869 return;
2870 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871
Andi Kleencf4c6a22006-09-26 10:52:30 +02002872 entry0 = ioapic_read_entry(apic, pin);
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -08002873 clear_IO_APIC_pin(apic, pin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874
2875 memset(&entry1, 0, sizeof(entry1));
2876
2877 entry1.dest_mode = 0; /* physical delivery */
2878 entry1.mask = 0; /* unmask IRQ now */
Yinghai Lud83e94a2008-08-19 20:50:33 -07002879 entry1.dest = hard_smp_processor_id();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 entry1.delivery_mode = dest_ExtINT;
2881 entry1.polarity = entry0.polarity;
2882 entry1.trigger = 0;
2883 entry1.vector = 0;
2884
Andi Kleencf4c6a22006-09-26 10:52:30 +02002885 ioapic_write_entry(apic, pin, entry1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886
2887 save_control = CMOS_READ(RTC_CONTROL);
2888 save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
2889 CMOS_WRITE((save_freq_select & ~RTC_RATE_SELECT) | 0x6,
2890 RTC_FREQ_SELECT);
2891 CMOS_WRITE(save_control | RTC_PIE, RTC_CONTROL);
2892
2893 i = 100;
2894 while (i-- > 0) {
2895 mdelay(10);
2896 if ((CMOS_READ(RTC_INTR_FLAGS) & RTC_PF) == RTC_PF)
2897 i -= 10;
2898 }
2899
2900 CMOS_WRITE(save_control, RTC_CONTROL);
2901 CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -08002902 clear_IO_APIC_pin(apic, pin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903
Andi Kleencf4c6a22006-09-26 10:52:30 +02002904 ioapic_write_entry(apic, pin, entry0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905}
2906
Yinghai Luefa25592008-08-19 20:50:36 -07002907static int disable_timer_pin_1 __initdata;
Yinghai Lu047c8fd2008-08-19 20:50:41 -07002908/* Actually the next is obsolete, but keep it for paranoid reasons -AK */
Ingo Molnar54168ed2008-08-20 09:07:45 +02002909static int __init disable_timer_pin_setup(char *arg)
Yinghai Luefa25592008-08-19 20:50:36 -07002910{
2911 disable_timer_pin_1 = 1;
2912 return 0;
2913}
Ingo Molnar54168ed2008-08-20 09:07:45 +02002914early_param("disable_timer_pin_1", disable_timer_pin_setup);
Yinghai Luefa25592008-08-19 20:50:36 -07002915
2916int timer_through_8259 __initdata;
2917
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918/*
2919 * This code may look a bit paranoid, but it's supposed to cooperate with
2920 * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ
2921 * is so screwy. Thanks to Brian Perkins for testing/hacking this beast
2922 * fanatically on his truly buggy board.
Ingo Molnar54168ed2008-08-20 09:07:45 +02002923 *
2924 * FIXME: really need to revamp this for all platforms.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 */
Zachary Amsden8542b202006-12-07 02:14:09 +01002926static inline void __init check_timer(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927{
Yinghai Lu3145e942008-12-05 18:58:34 -08002928 struct irq_desc *desc = irq_to_desc(0);
2929 struct irq_cfg *cfg = desc->chip_data;
Yinghai Lu85ac16d2009-04-27 18:00:38 -07002930 int node = cpu_to_node(boot_cpu_id);
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -08002931 int apic1, pin1, apic2, pin2;
Ingo Molnar4aae0702007-12-18 18:05:58 +01002932 unsigned long flags;
Yinghai Lu047c8fd2008-08-19 20:50:41 -07002933 int no_pin1 = 0;
Ingo Molnar4aae0702007-12-18 18:05:58 +01002934
2935 local_irq_save(flags);
Maciej W. Rozyckid4d25de2007-11-26 20:42:19 +01002936
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 /*
2938 * get/set the timer IRQ vector:
2939 */
Jacob Panb81bb372009-11-09 11:27:04 -08002940 legacy_pic->chip->mask(0);
Ingo Molnarfe402e12009-01-28 04:32:51 +01002941 assign_irq_vector(0, cfg, apic->target_cpus());
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942
2943 /*
Maciej W. Rozyckid11d5792008-05-21 22:09:11 +01002944 * As IRQ0 is to be enabled in the 8259A, the virtual
2945 * wire has to be disabled in the local APIC. Also
2946 * timer interrupts need to be acknowledged manually in
2947 * the 8259A for the i82489DX when using the NMI
2948 * watchdog as that APIC treats NMIs as level-triggered.
2949 * The AEOI mode will finish them in the 8259A
2950 * automatically.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 */
Maciej W. Rozycki593f4a72008-07-16 19:15:30 +01002952 apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
Jacob Panb81bb372009-11-09 11:27:04 -08002953 legacy_pic->init(1);
Ingo Molnar54168ed2008-08-20 09:07:45 +02002954#ifdef CONFIG_X86_32
Yinghai Luf72dcca2009-02-08 16:18:03 -08002955 {
2956 unsigned int ver;
2957
2958 ver = apic_read(APIC_LVR);
2959 ver = GET_APIC_VERSION(ver);
2960 timer_ack = (nmi_watchdog == NMI_IO_APIC && !APIC_INTEGRATED(ver));
2961 }
Ingo Molnar54168ed2008-08-20 09:07:45 +02002962#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -08002964 pin1 = find_isa_irq_pin(0, mp_INT);
2965 apic1 = find_isa_irq_apic(0, mp_INT);
2966 pin2 = ioapic_i8259.pin;
2967 apic2 = ioapic_i8259.apic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968
Maciej W. Rozycki49a66a0b2008-07-14 19:08:13 +01002969 apic_printk(APIC_QUIET, KERN_INFO "..TIMER: vector=0x%02X "
2970 "apic1=%d pin1=%d apic2=%d pin2=%d\n",
Yinghai Lu497c9a12008-08-19 20:50:28 -07002971 cfg->vector, apic1, pin1, apic2, pin2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972
Maciej W. Rozycki691874f2008-05-27 21:19:51 +01002973 /*
2974 * Some BIOS writers are clueless and report the ExtINTA
2975 * I/O APIC input from the cascaded 8259A as the timer
2976 * interrupt input. So just in case, if only one pin
2977 * was found above, try it both directly and through the
2978 * 8259A.
2979 */
2980 if (pin1 == -1) {
Ingo Molnar54168ed2008-08-20 09:07:45 +02002981 if (intr_remapping_enabled)
2982 panic("BIOS bug: timer not connected to IO-APIC");
Maciej W. Rozycki691874f2008-05-27 21:19:51 +01002983 pin1 = pin2;
2984 apic1 = apic2;
2985 no_pin1 = 1;
2986 } else if (pin2 == -1) {
2987 pin2 = pin1;
2988 apic2 = apic1;
2989 }
2990
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 if (pin1 != -1) {
2992 /*
2993 * Ok, does IRQ0 through the IOAPIC work?
2994 */
Maciej W. Rozycki691874f2008-05-27 21:19:51 +01002995 if (no_pin1) {
Yinghai Lu85ac16d2009-04-27 18:00:38 -07002996 add_pin_to_irq_node(cfg, node, apic1, pin1);
Yinghai Lu497c9a12008-08-19 20:50:28 -07002997 setup_timer_IRQ0_pin(apic1, pin1, cfg->vector);
Yinghai Luf72dcca2009-02-08 16:18:03 -08002998 } else {
2999 /* for edge trigger, setup_IO_APIC_irq already
3000 * leave it unmasked.
3001 * so only need to unmask if it is level-trigger
3002 * do we really have level trigger timer?
3003 */
3004 int idx;
3005 idx = find_irq_entry(apic1, pin1, mp_INT);
3006 if (idx != -1 && irq_trigger(idx))
3007 unmask_IO_APIC_irq_desc(desc);
Maciej W. Rozycki691874f2008-05-27 21:19:51 +01003008 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 if (timer_irq_works()) {
3010 if (nmi_watchdog == NMI_IO_APIC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 setup_nmi();
Jacob Panb81bb372009-11-09 11:27:04 -08003012 legacy_pic->chip->unmask(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 }
Chuck Ebbert66759a02005-09-12 18:49:25 +02003014 if (disable_timer_pin_1 > 0)
3015 clear_IO_APIC_pin(0, pin1);
Ingo Molnar4aae0702007-12-18 18:05:58 +01003016 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 }
Ingo Molnar54168ed2008-08-20 09:07:45 +02003018 if (intr_remapping_enabled)
3019 panic("timer doesn't work through Interrupt-remapped IO-APIC");
Yinghai Luf72dcca2009-02-08 16:18:03 -08003020 local_irq_disable();
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -08003021 clear_IO_APIC_pin(apic1, pin1);
Maciej W. Rozycki691874f2008-05-27 21:19:51 +01003022 if (!no_pin1)
Maciej W. Rozycki49a66a0b2008-07-14 19:08:13 +01003023 apic_printk(APIC_QUIET, KERN_ERR "..MP-BIOS bug: "
3024 "8254 timer not connected to IO-APIC\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025
Maciej W. Rozycki49a66a0b2008-07-14 19:08:13 +01003026 apic_printk(APIC_QUIET, KERN_INFO "...trying to set up timer "
3027 "(IRQ0) through the 8259A ...\n");
3028 apic_printk(APIC_QUIET, KERN_INFO
3029 "..... (found apic %d pin %d) ...\n", apic2, pin2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 /*
3031 * legacy devices should be connected to IO APIC #0
3032 */
Yinghai Lu85ac16d2009-04-27 18:00:38 -07003033 replace_pin_at_irq_node(cfg, node, apic1, pin1, apic2, pin2);
Yinghai Lu497c9a12008-08-19 20:50:28 -07003034 setup_timer_IRQ0_pin(apic2, pin2, cfg->vector);
Jacob Panb81bb372009-11-09 11:27:04 -08003035 legacy_pic->chip->unmask(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 if (timer_irq_works()) {
Maciej W. Rozycki49a66a0b2008-07-14 19:08:13 +01003037 apic_printk(APIC_QUIET, KERN_INFO "....... works.\n");
Maciej W. Rozycki35542c52008-05-21 22:10:22 +01003038 timer_through_8259 = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 if (nmi_watchdog == NMI_IO_APIC) {
Jacob Panb81bb372009-11-09 11:27:04 -08003040 legacy_pic->chip->mask(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 setup_nmi();
Jacob Panb81bb372009-11-09 11:27:04 -08003042 legacy_pic->chip->unmask(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 }
Ingo Molnar4aae0702007-12-18 18:05:58 +01003044 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 }
3046 /*
3047 * Cleanup, just in case ...
3048 */
Yinghai Luf72dcca2009-02-08 16:18:03 -08003049 local_irq_disable();
Jacob Panb81bb372009-11-09 11:27:04 -08003050 legacy_pic->chip->mask(0);
Eric W. Biedermanfcfd6362005-10-30 14:59:39 -08003051 clear_IO_APIC_pin(apic2, pin2);
Maciej W. Rozycki49a66a0b2008-07-14 19:08:13 +01003052 apic_printk(APIC_QUIET, KERN_INFO "....... failed.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054
3055 if (nmi_watchdog == NMI_IO_APIC) {
Maciej W. Rozycki49a66a0b2008-07-14 19:08:13 +01003056 apic_printk(APIC_QUIET, KERN_WARNING "timer doesn't work "
3057 "through the IO-APIC - disabling NMI Watchdog!\n");
Cyrill Gorcunov067fa0f2008-05-29 22:32:30 +04003058 nmi_watchdog = NMI_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 }
Ingo Molnar54168ed2008-08-20 09:07:45 +02003060#ifdef CONFIG_X86_32
Maciej W. Rozyckid11d5792008-05-21 22:09:11 +01003061 timer_ack = 0;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003062#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063
Maciej W. Rozycki49a66a0b2008-07-14 19:08:13 +01003064 apic_printk(APIC_QUIET, KERN_INFO
3065 "...trying to set up timer as Virtual Wire IRQ...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066
Yinghai Lu3145e942008-12-05 18:58:34 -08003067 lapic_register_intr(0, desc);
Yinghai Lu497c9a12008-08-19 20:50:28 -07003068 apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector); /* Fixed mode */
Jacob Panb81bb372009-11-09 11:27:04 -08003069 legacy_pic->chip->unmask(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070
3071 if (timer_irq_works()) {
Maciej W. Rozycki49a66a0b2008-07-14 19:08:13 +01003072 apic_printk(APIC_QUIET, KERN_INFO "..... works.\n");
Ingo Molnar4aae0702007-12-18 18:05:58 +01003073 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 }
Yinghai Luf72dcca2009-02-08 16:18:03 -08003075 local_irq_disable();
Jacob Panb81bb372009-11-09 11:27:04 -08003076 legacy_pic->chip->mask(0);
Yinghai Lu497c9a12008-08-19 20:50:28 -07003077 apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector);
Maciej W. Rozycki49a66a0b2008-07-14 19:08:13 +01003078 apic_printk(APIC_QUIET, KERN_INFO "..... failed.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079
Maciej W. Rozycki49a66a0b2008-07-14 19:08:13 +01003080 apic_printk(APIC_QUIET, KERN_INFO
3081 "...trying to set up timer as ExtINT IRQ...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082
Jacob Panb81bb372009-11-09 11:27:04 -08003083 legacy_pic->init(0);
3084 legacy_pic->make_irq(0);
Maciej W. Rozycki593f4a72008-07-16 19:15:30 +01003085 apic_write(APIC_LVT0, APIC_DM_EXTINT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086
3087 unlock_ExtINT_logic();
3088
3089 if (timer_irq_works()) {
Maciej W. Rozycki49a66a0b2008-07-14 19:08:13 +01003090 apic_printk(APIC_QUIET, KERN_INFO "..... works.\n");
Ingo Molnar4aae0702007-12-18 18:05:58 +01003091 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 }
Yinghai Luf72dcca2009-02-08 16:18:03 -08003093 local_irq_disable();
Maciej W. Rozycki49a66a0b2008-07-14 19:08:13 +01003094 apic_printk(APIC_QUIET, KERN_INFO "..... failed :(.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 panic("IO-APIC + timer doesn't work! Boot with apic=debug and send a "
Maciej W. Rozycki49a66a0b2008-07-14 19:08:13 +01003096 "report. Then try booting with the 'noapic' option.\n");
Ingo Molnar4aae0702007-12-18 18:05:58 +01003097out:
3098 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099}
3100
3101/*
Maciej W. Rozyckiaf174782008-07-11 19:35:23 +01003102 * Traditionally ISA IRQ2 is the cascade IRQ, and is not available
3103 * to devices. However there may be an I/O APIC pin available for
3104 * this interrupt regardless. The pin may be left unconnected, but
3105 * typically it will be reused as an ExtINT cascade interrupt for
3106 * the master 8259A. In the MPS case such a pin will normally be
3107 * reported as an ExtINT interrupt in the MP table. With ACPI
3108 * there is no provision for ExtINT interrupts, and in the absence
3109 * of an override it would be treated as an ordinary ISA I/O APIC
3110 * interrupt, that is edge-triggered and unmasked by default. We
3111 * used to do this, but it caused problems on some systems because
3112 * of the NMI watchdog and sometimes IRQ0 of the 8254 timer using
3113 * the same ExtINT cascade interrupt to drive the local APIC of the
3114 * bootstrap processor. Therefore we refrain from routing IRQ2 to
3115 * the I/O APIC in all cases now. No actual device should request
3116 * it anyway. --macro
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 */
Thomas Gleixnerbc078442009-08-29 18:09:57 +02003118#define PIC_IRQS (1UL << PIC_CASCADE_IR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119
3120void __init setup_IO_APIC(void)
3121{
Ingo Molnar54168ed2008-08-20 09:07:45 +02003122
Ingo Molnar54168ed2008-08-20 09:07:45 +02003123 /*
3124 * calling enable_IO_APIC() is moved to setup_local_APIC for BP
3125 */
Jacob Panb81bb372009-11-09 11:27:04 -08003126 io_apic_irqs = legacy_pic->nr_legacy_irqs ? ~PIC_IRQS : ~0UL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127
Ingo Molnar54168ed2008-08-20 09:07:45 +02003128 apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n");
Thomas Gleixnerd6c88a52008-10-15 15:27:23 +02003129 /*
Ingo Molnar54168ed2008-08-20 09:07:45 +02003130 * Set up IO-APIC IRQ routing.
3131 */
Thomas Gleixnerde934102009-08-20 09:27:29 +02003132 x86_init.mpparse.setup_ioapic_ids();
3133
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 sync_Arb_IDs();
3135 setup_IO_APIC_irqs();
3136 init_IO_APIC_traps();
Jacob Panb81bb372009-11-09 11:27:04 -08003137 if (legacy_pic->nr_legacy_irqs)
Thomas Gleixnerbc078442009-08-29 18:09:57 +02003138 check_timer();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139}
3140
3141/*
Ingo Molnar54168ed2008-08-20 09:07:45 +02003142 * Called after all the initialization is done. If we didnt find any
3143 * APIC bugs then we can allow the modify fast path
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 */
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02003145
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146static int __init io_apic_bug_finalize(void)
3147{
Thomas Gleixnerd6c88a52008-10-15 15:27:23 +02003148 if (sis_apic_bug == -1)
3149 sis_apic_bug = 0;
3150 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151}
3152
3153late_initcall(io_apic_bug_finalize);
3154
3155struct sysfs_ioapic_data {
3156 struct sys_device dev;
3157 struct IO_APIC_route_entry entry[0];
3158};
Ingo Molnar54168ed2008-08-20 09:07:45 +02003159static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160
Pavel Machek438510f2005-04-16 15:25:24 -07003161static int ioapic_suspend(struct sys_device *dev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162{
3163 struct IO_APIC_route_entry *entry;
3164 struct sysfs_ioapic_data *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 int i;
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02003166
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 data = container_of(dev, struct sysfs_ioapic_data, dev);
3168 entry = data->entry;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003169 for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ )
3170 *entry = ioapic_read_entry(dev->id, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171
3172 return 0;
3173}
3174
3175static int ioapic_resume(struct sys_device *dev)
3176{
3177 struct IO_APIC_route_entry *entry;
3178 struct sysfs_ioapic_data *data;
3179 unsigned long flags;
3180 union IO_APIC_reg_00 reg_00;
3181 int i;
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02003182
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 data = container_of(dev, struct sysfs_ioapic_data, dev);
3184 entry = data->entry;
3185
Thomas Gleixnerdade7712009-07-25 18:39:36 +02003186 raw_spin_lock_irqsave(&ioapic_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 reg_00.raw = io_apic_read(dev->id, 0);
Jaswinder Singh Rajputb5ba7e62009-01-12 17:46:17 +05303188 if (reg_00.bits.ID != mp_ioapics[dev->id].apicid) {
3189 reg_00.bits.ID = mp_ioapics[dev->id].apicid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 io_apic_write(dev->id, 0, reg_00.raw);
3191 }
Thomas Gleixnerdade7712009-07-25 18:39:36 +02003192 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02003193 for (i = 0; i < nr_ioapic_registers[dev->id]; i++)
Andi Kleencf4c6a22006-09-26 10:52:30 +02003194 ioapic_write_entry(dev->id, i, entry[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195
3196 return 0;
3197}
3198
3199static struct sysdev_class ioapic_sysdev_class = {
Kay Sieversaf5ca3f2007-12-20 02:09:39 +01003200 .name = "ioapic",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 .suspend = ioapic_suspend,
3202 .resume = ioapic_resume,
3203};
3204
3205static int __init ioapic_init_sysfs(void)
3206{
Ingo Molnar54168ed2008-08-20 09:07:45 +02003207 struct sys_device * dev;
3208 int i, size, error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209
3210 error = sysdev_class_register(&ioapic_sysdev_class);
3211 if (error)
3212 return error;
3213
Ingo Molnar54168ed2008-08-20 09:07:45 +02003214 for (i = 0; i < nr_ioapics; i++ ) {
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02003215 size = sizeof(struct sys_device) + nr_ioapic_registers[i]
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216 * sizeof(struct IO_APIC_route_entry);
Christophe Jaillet25556c12008-06-22 22:13:48 +02003217 mp_ioapic_data[i] = kzalloc(size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 if (!mp_ioapic_data[i]) {
3219 printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i);
3220 continue;
3221 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 dev = &mp_ioapic_data[i]->dev;
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02003223 dev->id = i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 dev->cls = &ioapic_sysdev_class;
3225 error = sysdev_register(dev);
3226 if (error) {
3227 kfree(mp_ioapic_data[i]);
3228 mp_ioapic_data[i] = NULL;
3229 printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i);
3230 continue;
3231 }
3232 }
3233
3234 return 0;
3235}
3236
3237device_initcall(ioapic_init_sysfs);
3238
Eric W. Biederman3fc471e2006-10-04 02:16:39 -07003239/*
Eric W. Biederman95d77882006-10-04 02:17:01 -07003240 * Dynamic irq allocate and deallocation
Eric W. Biederman3fc471e2006-10-04 02:16:39 -07003241 */
Yinghai Lud047f53a2009-04-27 18:02:23 -07003242unsigned int create_irq_nr(unsigned int irq_want, int node)
Eric W. Biederman3fc471e2006-10-04 02:16:39 -07003243{
Eric W. Biedermanace80ab2006-10-04 02:16:47 -07003244 /* Allocate an unused irq */
Ingo Molnar54168ed2008-08-20 09:07:45 +02003245 unsigned int irq;
3246 unsigned int new;
Eric W. Biederman3fc471e2006-10-04 02:16:39 -07003247 unsigned long flags;
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08003248 struct irq_cfg *cfg_new = NULL;
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08003249 struct irq_desc *desc_new = NULL;
Yinghai Lu199751d2008-08-19 20:50:27 -07003250
3251 irq = 0;
Yinghai Luabcaa2b2009-02-08 16:18:03 -08003252 if (irq_want < nr_irqs_gsi)
3253 irq_want = nr_irqs_gsi;
3254
Thomas Gleixnerdade7712009-07-25 18:39:36 +02003255 raw_spin_lock_irqsave(&vector_lock, flags);
Mike Travis95949492009-01-10 22:24:06 -08003256 for (new = irq_want; new < nr_irqs; new++) {
Yinghai Lu85ac16d2009-04-27 18:00:38 -07003257 desc_new = irq_to_desc_alloc_node(new, node);
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08003258 if (!desc_new) {
3259 printk(KERN_INFO "can not get irq_desc for %d\n", new);
Eric W. Biedermanace80ab2006-10-04 02:16:47 -07003260 continue;
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08003261 }
3262 cfg_new = desc_new->chip_data;
3263
3264 if (cfg_new->vector != 0)
3265 continue;
Yinghai Lud047f53a2009-04-27 18:02:23 -07003266
Yinghai Lu15e957d2009-04-30 01:17:50 -07003267 desc_new = move_irq_desc(desc_new, node);
Yinghai Lu37ef2a32009-11-21 00:23:37 -08003268 cfg_new = desc_new->chip_data;
Yinghai Lud047f53a2009-04-27 18:02:23 -07003269
Ingo Molnarfe402e12009-01-28 04:32:51 +01003270 if (__assign_irq_vector(new, cfg_new, apic->target_cpus()) == 0)
Eric W. Biedermanace80ab2006-10-04 02:16:47 -07003271 irq = new;
3272 break;
3273 }
Thomas Gleixnerdade7712009-07-25 18:39:36 +02003274 raw_spin_unlock_irqrestore(&vector_lock, flags);
Eric W. Biederman3fc471e2006-10-04 02:16:39 -07003275
Brandon Phiilpsced5b692010-02-10 01:20:06 -08003276 if (irq > 0)
3277 dynamic_irq_init_keep_chip_data(irq);
3278
Eric W. Biederman3fc471e2006-10-04 02:16:39 -07003279 return irq;
3280}
3281
Yinghai Lu199751d2008-08-19 20:50:27 -07003282int create_irq(void)
3283{
Yinghai Lud047f53a2009-04-27 18:02:23 -07003284 int node = cpu_to_node(boot_cpu_id);
Yinghai Lube5d5352008-12-05 18:58:33 -08003285 unsigned int irq_want;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003286 int irq;
3287
Yinghai Lube5d5352008-12-05 18:58:33 -08003288 irq_want = nr_irqs_gsi;
Yinghai Lud047f53a2009-04-27 18:02:23 -07003289 irq = create_irq_nr(irq_want, node);
Ingo Molnar54168ed2008-08-20 09:07:45 +02003290
3291 if (irq == 0)
3292 irq = -1;
3293
3294 return irq;
Yinghai Lu199751d2008-08-19 20:50:27 -07003295}
3296
Eric W. Biederman3fc471e2006-10-04 02:16:39 -07003297void destroy_irq(unsigned int irq)
3298{
3299 unsigned long flags;
Eric W. Biederman3fc471e2006-10-04 02:16:39 -07003300
Brandon Phiilpsced5b692010-02-10 01:20:06 -08003301 dynamic_irq_cleanup_keep_chip_data(irq);
Eric W. Biederman3fc471e2006-10-04 02:16:39 -07003302
Ingo Molnar54168ed2008-08-20 09:07:45 +02003303 free_irte(irq);
Thomas Gleixnerdade7712009-07-25 18:39:36 +02003304 raw_spin_lock_irqsave(&vector_lock, flags);
Brandon Philipseb5b3792010-02-07 13:02:50 -08003305 __clear_irq_vector(irq, get_irq_chip_data(irq));
Thomas Gleixnerdade7712009-07-25 18:39:36 +02003306 raw_spin_unlock_irqrestore(&vector_lock, flags);
Eric W. Biederman3fc471e2006-10-04 02:16:39 -07003307}
Eric W. Biederman3fc471e2006-10-04 02:16:39 -07003308
Eric W. Biederman2d3fcc12006-10-04 02:16:43 -07003309/*
Simon Arlott27b46d72007-10-20 01:13:56 +02003310 * MSI message composition
Eric W. Biederman2d3fcc12006-10-04 02:16:43 -07003311 */
3312#ifdef CONFIG_PCI_MSI
Suresh Siddhac8bc6f32009-08-04 12:07:09 -07003313static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
3314 struct msi_msg *msg, u8 hpet_id)
Eric W. Biederman2d3fcc12006-10-04 02:16:43 -07003315{
Yinghai Lu497c9a12008-08-19 20:50:28 -07003316 struct irq_cfg *cfg;
3317 int err;
Eric W. Biederman2d3fcc12006-10-04 02:16:43 -07003318 unsigned dest;
3319
Jan Beulichf1182632009-01-14 12:27:35 +00003320 if (disable_apic)
3321 return -ENXIO;
3322
Yinghai Lu3145e942008-12-05 18:58:34 -08003323 cfg = irq_cfg(irq);
Ingo Molnarfe402e12009-01-28 04:32:51 +01003324 err = assign_irq_vector(irq, cfg, apic->target_cpus());
Yinghai Lu497c9a12008-08-19 20:50:28 -07003325 if (err)
3326 return err;
Eric W. Biederman2d3fcc12006-10-04 02:16:43 -07003327
Ingo Molnardebccb32009-01-28 15:20:18 +01003328 dest = apic->cpu_mask_to_apicid_and(cfg->domain, apic->target_cpus());
Eric W. Biederman2d3fcc12006-10-04 02:16:43 -07003329
Ingo Molnar54168ed2008-08-20 09:07:45 +02003330 if (irq_remapped(irq)) {
3331 struct irte irte;
3332 int ir_index;
3333 u16 sub_handle;
Yinghai Lu497c9a12008-08-19 20:50:28 -07003334
Ingo Molnar54168ed2008-08-20 09:07:45 +02003335 ir_index = map_irq_to_irte_handle(irq, &sub_handle);
3336 BUG_ON(ir_index == -1);
Yinghai Lu497c9a12008-08-19 20:50:28 -07003337
Ingo Molnar54168ed2008-08-20 09:07:45 +02003338 memset (&irte, 0, sizeof(irte));
3339
3340 irte.present = 1;
Ingo Molnar9b5bc8d2009-01-28 04:09:58 +01003341 irte.dst_mode = apic->irq_dest_mode;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003342 irte.trigger_mode = 0; /* edge */
Ingo Molnar9b5bc8d2009-01-28 04:09:58 +01003343 irte.dlvry_mode = apic->irq_delivery_mode;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003344 irte.vector = cfg->vector;
3345 irte.dest_id = IRTE_DEST(dest);
3346
Weidong Hanf007e992009-05-23 00:41:15 +08003347 /* Set source-id of interrupt request */
Suresh Siddhac8bc6f32009-08-04 12:07:09 -07003348 if (pdev)
3349 set_msi_sid(&irte, pdev);
3350 else
3351 set_hpet_sid(&irte, hpet_id);
Weidong Hanf007e992009-05-23 00:41:15 +08003352
Ingo Molnar54168ed2008-08-20 09:07:45 +02003353 modify_irte(irq, &irte);
3354
3355 msg->address_hi = MSI_ADDR_BASE_HI;
3356 msg->data = sub_handle;
3357 msg->address_lo = MSI_ADDR_BASE_LO | MSI_ADDR_IR_EXT_INT |
3358 MSI_ADDR_IR_SHV |
3359 MSI_ADDR_IR_INDEX1(ir_index) |
3360 MSI_ADDR_IR_INDEX2(ir_index);
Suresh Siddha29b61be2009-03-16 17:05:02 -07003361 } else {
Suresh Siddha9d783ba2009-03-16 17:04:55 -07003362 if (x2apic_enabled())
3363 msg->address_hi = MSI_ADDR_BASE_HI |
3364 MSI_ADDR_EXT_DEST_ID(dest);
3365 else
3366 msg->address_hi = MSI_ADDR_BASE_HI;
3367
Ingo Molnar54168ed2008-08-20 09:07:45 +02003368 msg->address_lo =
3369 MSI_ADDR_BASE_LO |
Ingo Molnar9b5bc8d2009-01-28 04:09:58 +01003370 ((apic->irq_dest_mode == 0) ?
Ingo Molnar54168ed2008-08-20 09:07:45 +02003371 MSI_ADDR_DEST_MODE_PHYSICAL:
3372 MSI_ADDR_DEST_MODE_LOGICAL) |
Ingo Molnar9b5bc8d2009-01-28 04:09:58 +01003373 ((apic->irq_delivery_mode != dest_LowestPrio) ?
Ingo Molnar54168ed2008-08-20 09:07:45 +02003374 MSI_ADDR_REDIRECTION_CPU:
3375 MSI_ADDR_REDIRECTION_LOWPRI) |
3376 MSI_ADDR_DEST_ID(dest);
3377
3378 msg->data =
3379 MSI_DATA_TRIGGER_EDGE |
3380 MSI_DATA_LEVEL_ASSERT |
Ingo Molnar9b5bc8d2009-01-28 04:09:58 +01003381 ((apic->irq_delivery_mode != dest_LowestPrio) ?
Ingo Molnar54168ed2008-08-20 09:07:45 +02003382 MSI_DATA_DELIVERY_FIXED:
3383 MSI_DATA_DELIVERY_LOWPRI) |
3384 MSI_DATA_VECTOR(cfg->vector);
3385 }
Yinghai Lu497c9a12008-08-19 20:50:28 -07003386 return err;
Eric W. Biederman2d3fcc12006-10-04 02:16:43 -07003387}
3388
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07003389#ifdef CONFIG_SMP
Yinghai Lud5dedd42009-04-27 17:59:21 -07003390static int set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07003391{
Yinghai Lu3145e942008-12-05 18:58:34 -08003392 struct irq_desc *desc = irq_to_desc(irq);
Yinghai Lu497c9a12008-08-19 20:50:28 -07003393 struct irq_cfg *cfg;
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07003394 struct msi_msg msg;
3395 unsigned int dest;
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07003396
Suresh Siddha18374d82009-12-17 18:29:46 -08003397 if (set_desc_affinity(desc, mask, &dest))
Yinghai Lud5dedd42009-04-27 17:59:21 -07003398 return -1;
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07003399
Yinghai Lu3145e942008-12-05 18:58:34 -08003400 cfg = desc->chip_data;
Yinghai Lu497c9a12008-08-19 20:50:28 -07003401
Ben Hutchings30da5522010-07-23 14:56:28 +01003402 get_cached_msi_msg_desc(desc, &msg);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07003403
3404 msg.data &= ~MSI_DATA_VECTOR_MASK;
Yinghai Lu497c9a12008-08-19 20:50:28 -07003405 msg.data |= MSI_DATA_VECTOR(cfg->vector);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07003406 msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
3407 msg.address_lo |= MSI_ADDR_DEST_ID(dest);
3408
Yinghai Lu3145e942008-12-05 18:58:34 -08003409 write_msi_msg_desc(desc, &msg);
Yinghai Lud5dedd42009-04-27 17:59:21 -07003410
3411 return 0;
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07003412}
Ingo Molnar54168ed2008-08-20 09:07:45 +02003413#ifdef CONFIG_INTR_REMAP
3414/*
3415 * Migrate the MSI irq to another cpumask. This migration is
3416 * done in the process context using interrupt-remapping hardware.
3417 */
Yinghai Lud5dedd42009-04-27 17:59:21 -07003418static int
Mike Travise7986732008-12-16 17:33:52 -08003419ir_set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
Ingo Molnar54168ed2008-08-20 09:07:45 +02003420{
Yinghai Lu3145e942008-12-05 18:58:34 -08003421 struct irq_desc *desc = irq_to_desc(irq);
Ingo Molnara7883de2008-12-19 00:59:09 +01003422 struct irq_cfg *cfg = desc->chip_data;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003423 unsigned int dest;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003424 struct irte irte;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003425
3426 if (get_irte(irq, &irte))
Yinghai Lud5dedd42009-04-27 17:59:21 -07003427 return -1;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003428
Suresh Siddha18374d82009-12-17 18:29:46 -08003429 if (set_desc_affinity(desc, mask, &dest))
Yinghai Lud5dedd42009-04-27 17:59:21 -07003430 return -1;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003431
Ingo Molnar54168ed2008-08-20 09:07:45 +02003432 irte.vector = cfg->vector;
3433 irte.dest_id = IRTE_DEST(dest);
3434
3435 /*
3436 * atomically update the IRTE with the new destination and vector.
3437 */
3438 modify_irte(irq, &irte);
3439
3440 /*
3441 * After this point, all the interrupts will start arriving
3442 * at the new destination. So, time to cleanup the previous
3443 * vector allocation.
3444 */
Mike Travis22f65d32008-12-16 17:33:56 -08003445 if (cfg->move_in_progress)
3446 send_cleanup_vector(cfg);
Yinghai Lud5dedd42009-04-27 17:59:21 -07003447
3448 return 0;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003449}
Yinghai Lu3145e942008-12-05 18:58:34 -08003450
Ingo Molnar54168ed2008-08-20 09:07:45 +02003451#endif
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07003452#endif /* CONFIG_SMP */
3453
3454/*
3455 * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
3456 * which implement the MSI or MSI-X Capability Structure.
3457 */
3458static struct irq_chip msi_chip = {
3459 .name = "PCI-MSI",
3460 .unmask = unmask_msi_irq,
3461 .mask = mask_msi_irq,
Yinghai Lu1d025192008-08-19 20:50:34 -07003462 .ack = ack_apic_edge,
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07003463#ifdef CONFIG_SMP
3464 .set_affinity = set_msi_irq_affinity,
3465#endif
3466 .retrigger = ioapic_retrigger_irq,
3467};
3468
Ingo Molnar54168ed2008-08-20 09:07:45 +02003469static struct irq_chip msi_ir_chip = {
3470 .name = "IR-PCI-MSI",
3471 .unmask = unmask_msi_irq,
3472 .mask = mask_msi_irq,
Jaswinder Singh Rajputa1e38ca2009-03-23 02:11:25 +05303473#ifdef CONFIG_INTR_REMAP
Han, Weidongd0b03bd2009-04-03 17:15:50 +08003474 .ack = ir_ack_apic_edge,
Ingo Molnar54168ed2008-08-20 09:07:45 +02003475#ifdef CONFIG_SMP
3476 .set_affinity = ir_set_msi_irq_affinity,
3477#endif
Jaswinder Singh Rajputa1e38ca2009-03-23 02:11:25 +05303478#endif
Ingo Molnar54168ed2008-08-20 09:07:45 +02003479 .retrigger = ioapic_retrigger_irq,
3480};
3481
3482/*
3483 * Map the PCI dev to the corresponding remapping hardware unit
3484 * and allocate 'nvec' consecutive interrupt-remapping table entries
3485 * in it.
3486 */
3487static int msi_alloc_irte(struct pci_dev *dev, int irq, int nvec)
3488{
3489 struct intel_iommu *iommu;
3490 int index;
3491
3492 iommu = map_dev_to_ir(dev);
3493 if (!iommu) {
3494 printk(KERN_ERR
3495 "Unable to map PCI %s to iommu\n", pci_name(dev));
3496 return -ENOENT;
3497 }
3498
3499 index = alloc_irte(iommu, irq, nvec);
3500 if (index < 0) {
3501 printk(KERN_ERR
3502 "Unable to allocate %d IRTE for PCI %s\n", nvec,
Thomas Gleixnerd6c88a52008-10-15 15:27:23 +02003503 pci_name(dev));
Ingo Molnar54168ed2008-08-20 09:07:45 +02003504 return -ENOSPC;
3505 }
3506 return index;
3507}
Yinghai Lu1d025192008-08-19 20:50:34 -07003508
Yinghai Lu3145e942008-12-05 18:58:34 -08003509static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
Yinghai Lu1d025192008-08-19 20:50:34 -07003510{
3511 int ret;
3512 struct msi_msg msg;
3513
Suresh Siddhac8bc6f32009-08-04 12:07:09 -07003514 ret = msi_compose_msg(dev, irq, &msg, -1);
Yinghai Lu1d025192008-08-19 20:50:34 -07003515 if (ret < 0)
3516 return ret;
3517
Yinghai Lu3145e942008-12-05 18:58:34 -08003518 set_irq_msi(irq, msidesc);
Yinghai Lu1d025192008-08-19 20:50:34 -07003519 write_msi_msg(irq, &msg);
3520
Ingo Molnar54168ed2008-08-20 09:07:45 +02003521 if (irq_remapped(irq)) {
3522 struct irq_desc *desc = irq_to_desc(irq);
3523 /*
3524 * irq migration in process context
3525 */
3526 desc->status |= IRQ_MOVE_PCNTXT;
3527 set_irq_chip_and_handler_name(irq, &msi_ir_chip, handle_edge_irq, "edge");
3528 } else
Ingo Molnar54168ed2008-08-20 09:07:45 +02003529 set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
Yinghai Lu1d025192008-08-19 20:50:34 -07003530
Yinghai Luc81bba42008-09-25 11:53:11 -07003531 dev_printk(KERN_DEBUG, &dev->dev, "irq %d for MSI/MSI-X\n", irq);
3532
Yinghai Lu1d025192008-08-19 20:50:34 -07003533 return 0;
3534}
3535
Yinghai Lu047c8fd2008-08-19 20:50:41 -07003536int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
3537{
Ingo Molnar54168ed2008-08-20 09:07:45 +02003538 unsigned int irq;
3539 int ret, sub_handle;
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08003540 struct msi_desc *msidesc;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003541 unsigned int irq_want;
Dmitri Vorobiev1cc18522009-03-22 19:11:09 +02003542 struct intel_iommu *iommu = NULL;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003543 int index = 0;
Yinghai Lud047f53a2009-04-27 18:02:23 -07003544 int node;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003545
Matthew Wilcox1c8d7b02009-03-17 08:54:10 -04003546 /* x86 doesn't support multiple MSI yet */
3547 if (type == PCI_CAP_ID_MSI && nvec > 1)
3548 return 1;
3549
Yinghai Lud047f53a2009-04-27 18:02:23 -07003550 node = dev_to_node(&dev->dev);
Yinghai Lube5d5352008-12-05 18:58:33 -08003551 irq_want = nr_irqs_gsi;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003552 sub_handle = 0;
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08003553 list_for_each_entry(msidesc, &dev->msi_list, list) {
Yinghai Lud047f53a2009-04-27 18:02:23 -07003554 irq = create_irq_nr(irq_want, node);
Ingo Molnar54168ed2008-08-20 09:07:45 +02003555 if (irq == 0)
3556 return -1;
Yinghai Luf1ee5542009-02-08 16:18:03 -08003557 irq_want = irq + 1;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003558 if (!intr_remapping_enabled)
3559 goto no_ir;
3560
3561 if (!sub_handle) {
3562 /*
3563 * allocate the consecutive block of IRTE's
3564 * for 'nvec'
3565 */
3566 index = msi_alloc_irte(dev, irq, nvec);
3567 if (index < 0) {
3568 ret = index;
3569 goto error;
3570 }
3571 } else {
3572 iommu = map_dev_to_ir(dev);
3573 if (!iommu) {
3574 ret = -ENOENT;
3575 goto error;
3576 }
3577 /*
3578 * setup the mapping between the irq and the IRTE
3579 * base index, the sub_handle pointing to the
3580 * appropriate interrupt remap table entry.
3581 */
3582 set_irte_irq(irq, iommu, index, sub_handle);
3583 }
3584no_ir:
Yinghai Lu0b8f1ef2008-12-05 18:58:31 -08003585 ret = setup_msi_irq(dev, msidesc, irq);
Ingo Molnar54168ed2008-08-20 09:07:45 +02003586 if (ret < 0)
3587 goto error;
3588 sub_handle++;
3589 }
3590 return 0;
Yinghai Lu047c8fd2008-08-19 20:50:41 -07003591
3592error:
Ingo Molnar54168ed2008-08-20 09:07:45 +02003593 destroy_irq(irq);
3594 return ret;
Yinghai Lu047c8fd2008-08-19 20:50:41 -07003595}
3596
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07003597void arch_teardown_msi_irq(unsigned int irq)
Eric W. Biederman2d3fcc12006-10-04 02:16:43 -07003598{
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -07003599 destroy_irq(irq);
Eric W. Biederman2d3fcc12006-10-04 02:16:43 -07003600}
3601
Suresh Siddha9d783ba2009-03-16 17:04:55 -07003602#if defined (CONFIG_DMAR) || defined (CONFIG_INTR_REMAP)
Ingo Molnar54168ed2008-08-20 09:07:45 +02003603#ifdef CONFIG_SMP
Yinghai Lud5dedd42009-04-27 17:59:21 -07003604static int dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
Ingo Molnar54168ed2008-08-20 09:07:45 +02003605{
Yinghai Lu3145e942008-12-05 18:58:34 -08003606 struct irq_desc *desc = irq_to_desc(irq);
Ingo Molnar54168ed2008-08-20 09:07:45 +02003607 struct irq_cfg *cfg;
3608 struct msi_msg msg;
3609 unsigned int dest;
Eric W. Biederman2d3fcc12006-10-04 02:16:43 -07003610
Suresh Siddha18374d82009-12-17 18:29:46 -08003611 if (set_desc_affinity(desc, mask, &dest))
Yinghai Lud5dedd42009-04-27 17:59:21 -07003612 return -1;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003613
Yinghai Lu3145e942008-12-05 18:58:34 -08003614 cfg = desc->chip_data;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003615
3616 dmar_msi_read(irq, &msg);
3617
3618 msg.data &= ~MSI_DATA_VECTOR_MASK;
3619 msg.data |= MSI_DATA_VECTOR(cfg->vector);
3620 msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
3621 msg.address_lo |= MSI_ADDR_DEST_ID(dest);
3622
3623 dmar_msi_write(irq, &msg);
Yinghai Lud5dedd42009-04-27 17:59:21 -07003624
3625 return 0;
Ingo Molnar54168ed2008-08-20 09:07:45 +02003626}
Yinghai Lu3145e942008-12-05 18:58:34 -08003627
Ingo Molnar54168ed2008-08-20 09:07:45 +02003628#endif /* CONFIG_SMP */
3629
Jaswinder Singh Rajput8f7007a2009-06-10 12:41:01 -07003630static struct irq_chip dmar_msi_type = {
Ingo Molnar54168ed2008-08-20 09:07:45 +02003631 .name = "DMAR_MSI",
3632 .unmask = dmar_msi_unmask,
3633 .mask = dmar_msi_mask,
3634 .ack = ack_apic_edge,
3635#ifdef CONFIG_SMP
3636 .set_affinity = dmar_msi_set_affinity,
3637#endif
3638 .retrigger = ioapic_retrigger_irq,
3639};
3640
3641int arch_setup_dmar_msi(unsigned int irq)
3642{
3643 int ret;
3644 struct msi_msg msg;
3645
Suresh Siddhac8bc6f32009-08-04 12:07:09 -07003646 ret = msi_compose_msg(NULL, irq, &msg, -1);
Ingo Molnar54168ed2008-08-20 09:07:45 +02003647 if (ret < 0)
3648 return ret;
3649 dmar_msi_write(irq, &msg);
3650 set_irq_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
3651 "edge");
3652 return 0;
3653}
3654#endif
3655
venkatesh.pallipadi@intel.com58ac1e72008-09-05 18:02:17 -07003656#ifdef CONFIG_HPET_TIMER
3657
3658#ifdef CONFIG_SMP
Yinghai Lud5dedd42009-04-27 17:59:21 -07003659static int hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
venkatesh.pallipadi@intel.com58ac1e72008-09-05 18:02:17 -07003660{
Yinghai Lu3145e942008-12-05 18:58:34 -08003661 struct irq_desc *desc = irq_to_desc(irq);
venkatesh.pallipadi@intel.com58ac1e72008-09-05 18:02:17 -07003662 struct irq_cfg *cfg;
venkatesh.pallipadi@intel.com58ac1e72008-09-05 18:02:17 -07003663 struct msi_msg msg;
3664 unsigned int dest;
venkatesh.pallipadi@intel.com58ac1e72008-09-05 18:02:17 -07003665
Suresh Siddha18374d82009-12-17 18:29:46 -08003666 if (set_desc_affinity(desc, mask, &dest))
Yinghai Lud5dedd42009-04-27 17:59:21 -07003667 return -1;
venkatesh.pallipadi@intel.com58ac1e72008-09-05 18:02:17 -07003668
Yinghai Lu3145e942008-12-05 18:58:34 -08003669 cfg = desc->chip_data;
venkatesh.pallipadi@intel.com58ac1e72008-09-05 18:02:17 -07003670
3671 hpet_msi_read(irq, &msg);
3672
3673 msg.data &= ~MSI_DATA_VECTOR_MASK;
3674 msg.data |= MSI_DATA_VECTOR(cfg->vector);
3675 msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
3676 msg.address_lo |= MSI_ADDR_DEST_ID(dest);
3677
3678 hpet_msi_write(irq, &msg);
Yinghai Lud5dedd42009-04-27 17:59:21 -07003679
3680 return 0;
venkatesh.pallipadi@intel.com58ac1e72008-09-05 18:02:17 -07003681}
Yinghai Lu3145e942008-12-05 18:58:34 -08003682
venkatesh.pallipadi@intel.com58ac1e72008-09-05 18:02:17 -07003683#endif /* CONFIG_SMP */
3684
Suresh Siddhac8bc6f32009-08-04 12:07:09 -07003685static struct irq_chip ir_hpet_msi_type = {
3686 .name = "IR-HPET_MSI",
3687 .unmask = hpet_msi_unmask,
3688 .mask = hpet_msi_mask,
3689#ifdef CONFIG_INTR_REMAP
3690 .ack = ir_ack_apic_edge,
3691#ifdef CONFIG_SMP
3692 .set_affinity = ir_set_msi_irq_affinity,
3693#endif
3694#endif
3695 .retrigger = ioapic_retrigger_irq,
3696};
3697
Dmitri Vorobiev1cc18522009-03-22 19:11:09 +02003698static struct irq_chip hpet_msi_type = {
venkatesh.pallipadi@intel.com58ac1e72008-09-05 18:02:17 -07003699 .name = "HPET_MSI",
3700 .unmask = hpet_msi_unmask,
3701 .mask = hpet_msi_mask,
3702 .ack = ack_apic_edge,
3703#ifdef CONFIG_SMP
3704 .set_affinity = hpet_msi_set_affinity,
3705#endif
3706 .retrigger = ioapic_retrigger_irq,
3707};
3708
Suresh Siddhac8bc6f32009-08-04 12:07:09 -07003709int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
venkatesh.pallipadi@intel.com58ac1e72008-09-05 18:02:17 -07003710{
3711 int ret;
3712 struct msi_msg msg;
Pallipadi, Venkatesh6ec3cfe2009-04-13 15:20:58 -07003713 struct irq_desc *desc = irq_to_desc(irq);
venkatesh.pallipadi@intel.com58ac1e72008-09-05 18:02:17 -07003714
Suresh Siddhac8bc6f32009-08-04 12:07:09 -07003715 if (intr_remapping_enabled) {
3716 struct intel_iommu *iommu = map_hpet_to_ir(id);
3717 int index;
3718
3719 if (!iommu)
3720 return -1;
3721
3722 index = alloc_irte(iommu, irq, 1);
3723 if (index < 0)
3724 return -1;
3725 }
3726
3727 ret = msi_compose_msg(NULL, irq, &msg, id);
venkatesh.pallipadi@intel.com58ac1e72008-09-05 18:02:17 -07003728 if (ret < 0)
3729 return ret;
3730
3731 hpet_msi_write(irq, &msg);
Pallipadi, Venkatesh6ec3cfe2009-04-13 15:20:58 -07003732 desc->status |= IRQ_MOVE_PCNTXT;
Suresh Siddhac8bc6f32009-08-04 12:07:09 -07003733 if (irq_remapped(irq))
3734 set_irq_chip_and_handler_name(irq, &ir_hpet_msi_type,
3735 handle_edge_irq, "edge");
3736 else
3737 set_irq_chip_and_handler_name(irq, &hpet_msi_type,
3738 handle_edge_irq, "edge");
Yinghai Luc81bba42008-09-25 11:53:11 -07003739
venkatesh.pallipadi@intel.com58ac1e72008-09-05 18:02:17 -07003740 return 0;
3741}
3742#endif
3743
Ingo Molnar54168ed2008-08-20 09:07:45 +02003744#endif /* CONFIG_PCI_MSI */
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003745/*
3746 * Hypertransport interrupt support
3747 */
3748#ifdef CONFIG_HT_IRQ
3749
3750#ifdef CONFIG_SMP
3751
Yinghai Lu497c9a12008-08-19 20:50:28 -07003752static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003753{
Eric W. Biedermanec683072006-11-08 17:44:57 -08003754 struct ht_irq_msg msg;
3755 fetch_ht_irq_msg(irq, &msg);
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003756
Yinghai Lu497c9a12008-08-19 20:50:28 -07003757 msg.address_lo &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK);
Eric W. Biedermanec683072006-11-08 17:44:57 -08003758 msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003759
Yinghai Lu497c9a12008-08-19 20:50:28 -07003760 msg.address_lo |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest);
Eric W. Biedermanec683072006-11-08 17:44:57 -08003761 msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest);
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003762
Eric W. Biedermanec683072006-11-08 17:44:57 -08003763 write_ht_irq_msg(irq, &msg);
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003764}
3765
Yinghai Lud5dedd42009-04-27 17:59:21 -07003766static int set_ht_irq_affinity(unsigned int irq, const struct cpumask *mask)
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003767{
Yinghai Lu3145e942008-12-05 18:58:34 -08003768 struct irq_desc *desc = irq_to_desc(irq);
Yinghai Lu497c9a12008-08-19 20:50:28 -07003769 struct irq_cfg *cfg;
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003770 unsigned int dest;
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003771
Suresh Siddha18374d82009-12-17 18:29:46 -08003772 if (set_desc_affinity(desc, mask, &dest))
Yinghai Lud5dedd42009-04-27 17:59:21 -07003773 return -1;
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003774
Yinghai Lu3145e942008-12-05 18:58:34 -08003775 cfg = desc->chip_data;
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003776
Yinghai Lu497c9a12008-08-19 20:50:28 -07003777 target_ht_irq(irq, dest, cfg->vector);
Yinghai Lud5dedd42009-04-27 17:59:21 -07003778
3779 return 0;
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003780}
Yinghai Lu3145e942008-12-05 18:58:34 -08003781
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003782#endif
3783
Aneesh Kumar K.Vc37e1082006-10-11 01:20:43 -07003784static struct irq_chip ht_irq_chip = {
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003785 .name = "PCI-HT",
3786 .mask = mask_ht_irq,
3787 .unmask = unmask_ht_irq,
Yinghai Lu1d025192008-08-19 20:50:34 -07003788 .ack = ack_apic_edge,
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003789#ifdef CONFIG_SMP
3790 .set_affinity = set_ht_irq_affinity,
3791#endif
3792 .retrigger = ioapic_retrigger_irq,
3793};
3794
3795int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
3796{
Yinghai Lu497c9a12008-08-19 20:50:28 -07003797 struct irq_cfg *cfg;
3798 int err;
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003799
Jan Beulichf1182632009-01-14 12:27:35 +00003800 if (disable_apic)
3801 return -ENXIO;
3802
Yinghai Lu3145e942008-12-05 18:58:34 -08003803 cfg = irq_cfg(irq);
Ingo Molnarfe402e12009-01-28 04:32:51 +01003804 err = assign_irq_vector(irq, cfg, apic->target_cpus());
Ingo Molnar54168ed2008-08-20 09:07:45 +02003805 if (!err) {
Eric W. Biedermanec683072006-11-08 17:44:57 -08003806 struct ht_irq_msg msg;
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003807 unsigned dest;
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003808
Ingo Molnardebccb32009-01-28 15:20:18 +01003809 dest = apic->cpu_mask_to_apicid_and(cfg->domain,
3810 apic->target_cpus());
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003811
Eric W. Biedermanec683072006-11-08 17:44:57 -08003812 msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest);
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003813
Eric W. Biedermanec683072006-11-08 17:44:57 -08003814 msg.address_lo =
3815 HT_IRQ_LOW_BASE |
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003816 HT_IRQ_LOW_DEST_ID(dest) |
Yinghai Lu497c9a12008-08-19 20:50:28 -07003817 HT_IRQ_LOW_VECTOR(cfg->vector) |
Ingo Molnar9b5bc8d2009-01-28 04:09:58 +01003818 ((apic->irq_dest_mode == 0) ?
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003819 HT_IRQ_LOW_DM_PHYSICAL :
3820 HT_IRQ_LOW_DM_LOGICAL) |
3821 HT_IRQ_LOW_RQEOI_EDGE |
Ingo Molnar9b5bc8d2009-01-28 04:09:58 +01003822 ((apic->irq_delivery_mode != dest_LowestPrio) ?
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003823 HT_IRQ_LOW_MT_FIXED :
3824 HT_IRQ_LOW_MT_ARBITRATED) |
3825 HT_IRQ_LOW_IRQ_MASKED;
3826
Eric W. Biedermanec683072006-11-08 17:44:57 -08003827 write_ht_irq_msg(irq, &msg);
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003828
Ingo Molnara460e742006-10-17 00:10:03 -07003829 set_irq_chip_and_handler_name(irq, &ht_irq_chip,
3830 handle_edge_irq, "edge");
Yinghai Luc81bba42008-09-25 11:53:11 -07003831
3832 dev_printk(KERN_DEBUG, &dev->dev, "irq %d for HT\n", irq);
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003833 }
Yinghai Lu497c9a12008-08-19 20:50:28 -07003834 return err;
Eric W. Biederman8b955b02006-10-04 02:16:55 -07003835}
3836#endif /* CONFIG_HT_IRQ */
3837
Yinghai Lu9d6a4d02008-08-19 20:50:52 -07003838int __init io_apic_get_redir_entries (int ioapic)
3839{
3840 union IO_APIC_reg_01 reg_01;
3841 unsigned long flags;
3842
Thomas Gleixnerdade7712009-07-25 18:39:36 +02003843 raw_spin_lock_irqsave(&ioapic_lock, flags);
Yinghai Lu9d6a4d02008-08-19 20:50:52 -07003844 reg_01.raw = io_apic_read(ioapic, 1);
Thomas Gleixnerdade7712009-07-25 18:39:36 +02003845 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Yinghai Lu9d6a4d02008-08-19 20:50:52 -07003846
Eric W. Biederman4b6b19a2010-03-30 01:07:08 -07003847 /* The register returns the maximum index redir index
3848 * supported, which is one less than the total number of redir
3849 * entries.
3850 */
3851 return reg_01.bits.entries + 1;
Yinghai Lu9d6a4d02008-08-19 20:50:52 -07003852}
3853
Yinghai Lube5d5352008-12-05 18:58:33 -08003854void __init probe_nr_irqs_gsi(void)
Yinghai Lu9d6a4d02008-08-19 20:50:52 -07003855{
Eric W. Biederman4afc51a2010-03-30 01:07:14 -07003856 int nr;
Yinghai Lube5d5352008-12-05 18:58:33 -08003857
Eric W. Biedermana4384df2010-06-08 11:44:32 -07003858 nr = gsi_top + NR_IRQS_LEGACY;
Eric W. Biederman4afc51a2010-03-30 01:07:14 -07003859 if (nr > nr_irqs_gsi)
Yinghai Lube5d5352008-12-05 18:58:33 -08003860 nr_irqs_gsi = nr;
Yinghai Lucc6c5002009-02-08 16:18:03 -08003861
3862 printk(KERN_DEBUG "nr_irqs_gsi: %d\n", nr_irqs_gsi);
Yinghai Lu9d6a4d02008-08-19 20:50:52 -07003863}
3864
Yinghai Lu4a046d12009-01-12 17:39:24 -08003865#ifdef CONFIG_SPARSE_IRQ
3866int __init arch_probe_nr_irqs(void)
3867{
3868 int nr;
3869
Yinghai Luf1ee5542009-02-08 16:18:03 -08003870 if (nr_irqs > (NR_VECTORS * nr_cpu_ids))
3871 nr_irqs = NR_VECTORS * nr_cpu_ids;
Yinghai Lu4a046d12009-01-12 17:39:24 -08003872
Yinghai Luf1ee5542009-02-08 16:18:03 -08003873 nr = nr_irqs_gsi + 8 * nr_cpu_ids;
3874#if defined(CONFIG_PCI_MSI) || defined(CONFIG_HT_IRQ)
3875 /*
3876 * for MSI and HT dyn irq
3877 */
3878 nr += nr_irqs_gsi * 16;
3879#endif
3880 if (nr < nr_irqs)
Yinghai Lu4a046d12009-01-12 17:39:24 -08003881 nr_irqs = nr;
3882
Thomas Gleixnerb683de22010-09-27 20:55:03 +02003883 return NR_IRQS_LEGACY;
Yinghai Lu4a046d12009-01-12 17:39:24 -08003884}
3885#endif
3886
Yinghai Lue5198072009-05-15 13:05:16 -07003887static int __io_apic_set_pci_routing(struct device *dev, int irq,
3888 struct io_apic_irq_attr *irq_attr)
Yinghai Lu5ef21832009-05-06 10:08:50 -07003889{
3890 struct irq_desc *desc;
3891 struct irq_cfg *cfg;
3892 int node;
Yinghai Lue5198072009-05-15 13:05:16 -07003893 int ioapic, pin;
3894 int trigger, polarity;
Yinghai Lu5ef21832009-05-06 10:08:50 -07003895
Yinghai Lue5198072009-05-15 13:05:16 -07003896 ioapic = irq_attr->ioapic;
Yinghai Lu5ef21832009-05-06 10:08:50 -07003897 if (!IO_APIC_IRQ(irq)) {
3898 apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
3899 ioapic);
3900 return -EINVAL;
3901 }
3902
3903 if (dev)
3904 node = dev_to_node(dev);
3905 else
3906 node = cpu_to_node(boot_cpu_id);
3907
3908 desc = irq_to_desc_alloc_node(irq, node);
3909 if (!desc) {
3910 printk(KERN_INFO "can not get irq_desc %d\n", irq);
3911 return 0;
3912 }
3913
Yinghai Lue5198072009-05-15 13:05:16 -07003914 pin = irq_attr->ioapic_pin;
3915 trigger = irq_attr->trigger;
3916 polarity = irq_attr->polarity;
3917
Yinghai Lu5ef21832009-05-06 10:08:50 -07003918 /*
3919 * IRQs < 16 are already in the irq_2_pin[] map
3920 */
Jacob Panb81bb372009-11-09 11:27:04 -08003921 if (irq >= legacy_pic->nr_legacy_irqs) {
Yinghai Lu5ef21832009-05-06 10:08:50 -07003922 cfg = desc->chip_data;
Cyrill Gorcunovf3d19152009-08-06 00:09:31 +04003923 if (add_pin_to_irq_node_nopanic(cfg, node, ioapic, pin)) {
3924 printk(KERN_INFO "can not add pin %d for irq %d\n",
3925 pin, irq);
3926 return 0;
3927 }
Yinghai Lu5ef21832009-05-06 10:08:50 -07003928 }
3929
Yinghai Lue5198072009-05-15 13:05:16 -07003930 setup_IO_APIC_irq(ioapic, pin, irq, desc, trigger, polarity);
Yinghai Lu5ef21832009-05-06 10:08:50 -07003931
3932 return 0;
3933}
3934
Yinghai Lue5198072009-05-15 13:05:16 -07003935int io_apic_set_pci_routing(struct device *dev, int irq,
3936 struct io_apic_irq_attr *irq_attr)
Yinghai Lu5ef21832009-05-06 10:08:50 -07003937{
Yinghai Lue5198072009-05-15 13:05:16 -07003938 int ioapic, pin;
Yinghai Lu5ef21832009-05-06 10:08:50 -07003939 /*
3940 * Avoid pin reprogramming. PRTs typically include entries
3941 * with redundant pin->gsi mappings (but unique PCI devices);
3942 * we only program the IOAPIC on the first.
3943 */
Yinghai Lue5198072009-05-15 13:05:16 -07003944 ioapic = irq_attr->ioapic;
3945 pin = irq_attr->ioapic_pin;
Yinghai Lu5ef21832009-05-06 10:08:50 -07003946 if (test_bit(pin, mp_ioapic_routing[ioapic].pin_programmed)) {
3947 pr_debug("Pin %d-%d already programmed\n",
3948 mp_ioapics[ioapic].apicid, pin);
3949 return 0;
3950 }
3951 set_bit(pin, mp_ioapic_routing[ioapic].pin_programmed);
3952
Yinghai Lue5198072009-05-15 13:05:16 -07003953 return __io_apic_set_pci_routing(dev, irq, irq_attr);
Yinghai Lu5ef21832009-05-06 10:08:50 -07003954}
3955
Feng Tang2a4ab642009-07-07 23:01:15 -04003956u8 __init io_apic_unique_id(u8 id)
3957{
3958#ifdef CONFIG_X86_32
3959 if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
3960 !APIC_XAPIC(apic_version[boot_cpu_physical_apicid]))
3961 return io_apic_get_unique_id(nr_ioapics, id);
3962 else
3963 return id;
3964#else
3965 int i;
3966 DECLARE_BITMAP(used, 256);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967
Feng Tang2a4ab642009-07-07 23:01:15 -04003968 bitmap_zero(used, 256);
3969 for (i = 0; i < nr_ioapics; i++) {
3970 struct mpc_ioapic *ia = &mp_ioapics[i];
3971 __set_bit(ia->apicid, used);
3972 }
3973 if (!test_bit(id, used))
3974 return id;
3975 return find_first_zero_bit(used, 256);
3976#endif
3977}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978
Ingo Molnar54168ed2008-08-20 09:07:45 +02003979#ifdef CONFIG_X86_32
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02003980int __init io_apic_get_unique_id(int ioapic, int apic_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981{
3982 union IO_APIC_reg_00 reg_00;
3983 static physid_mask_t apic_id_map = PHYSID_MASK_NONE;
3984 physid_mask_t tmp;
3985 unsigned long flags;
3986 int i = 0;
3987
3988 /*
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02003989 * The P4 platform supports up to 256 APIC IDs on two separate APIC
3990 * buses (one for LAPICs, one for IOAPICs), where predecessors only
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 * supports up to 16 on one shared APIC bus.
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02003992 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 * TBD: Expand LAPIC/IOAPIC support on P4-class systems to take full
3994 * advantage of new APIC bus architecture.
3995 */
3996
3997 if (physids_empty(apic_id_map))
Cyrill Gorcunov7abc0752009-11-10 01:06:59 +03003998 apic->ioapic_phys_id_map(&phys_cpu_present_map, &apic_id_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999
Thomas Gleixnerdade7712009-07-25 18:39:36 +02004000 raw_spin_lock_irqsave(&ioapic_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 reg_00.raw = io_apic_read(ioapic, 0);
Thomas Gleixnerdade7712009-07-25 18:39:36 +02004002 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003
4004 if (apic_id >= get_physical_broadcast()) {
4005 printk(KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying "
4006 "%d\n", ioapic, apic_id, reg_00.bits.ID);
4007 apic_id = reg_00.bits.ID;
4008 }
4009
4010 /*
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02004011 * Every APIC in a system must have a unique ID or we get lots of nice
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 * 'stuck on smp_invalidate_needed IPI wait' messages.
4013 */
Cyrill Gorcunov7abc0752009-11-10 01:06:59 +03004014 if (apic->check_apicid_used(&apic_id_map, apic_id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015
4016 for (i = 0; i < get_physical_broadcast(); i++) {
Cyrill Gorcunov7abc0752009-11-10 01:06:59 +03004017 if (!apic->check_apicid_used(&apic_id_map, i))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 break;
4019 }
4020
4021 if (i == get_physical_broadcast())
4022 panic("Max apic_id exceeded!\n");
4023
4024 printk(KERN_WARNING "IOAPIC[%d]: apic_id %d already used, "
4025 "trying %d\n", ioapic, apic_id, i);
4026
4027 apic_id = i;
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02004028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029
Cyrill Gorcunov7abc0752009-11-10 01:06:59 +03004030 apic->apicid_to_cpu_present(apic_id, &tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 physids_or(apic_id_map, apic_id_map, tmp);
4032
4033 if (reg_00.bits.ID != apic_id) {
4034 reg_00.bits.ID = apic_id;
4035
Thomas Gleixnerdade7712009-07-25 18:39:36 +02004036 raw_spin_lock_irqsave(&ioapic_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 io_apic_write(ioapic, 0, reg_00.raw);
4038 reg_00.raw = io_apic_read(ioapic, 0);
Thomas Gleixnerdade7712009-07-25 18:39:36 +02004039 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040
4041 /* Sanity check */
Andreas Deresch6070f9e2006-02-26 04:18:34 +01004042 if (reg_00.bits.ID != apic_id) {
4043 printk("IOAPIC[%d]: Unable to change apic_id!\n", ioapic);
4044 return -1;
4045 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 }
4047
4048 apic_printk(APIC_VERBOSE, KERN_INFO
4049 "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id);
4050
4051 return apic_id;
4052}
Naga Chumbalkar58f892e2009-05-26 21:48:07 +00004053#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054
Paolo Ciarrocchi36062442008-06-08 13:07:18 +02004055int __init io_apic_get_version(int ioapic)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056{
4057 union IO_APIC_reg_01 reg_01;
4058 unsigned long flags;
4059
Thomas Gleixnerdade7712009-07-25 18:39:36 +02004060 raw_spin_lock_irqsave(&ioapic_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 reg_01.raw = io_apic_read(ioapic, 1);
Thomas Gleixnerdade7712009-07-25 18:39:36 +02004062 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063
4064 return reg_01.bits.version;
4065}
4066
Eric W. Biederman9a0a91b2010-03-30 01:07:03 -07004067int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity)
Shaohua Li61fd47e2007-11-17 01:05:28 -05004068{
Eric W. Biederman9a0a91b2010-03-30 01:07:03 -07004069 int ioapic, pin, idx;
Shaohua Li61fd47e2007-11-17 01:05:28 -05004070
4071 if (skip_ioapic_setup)
4072 return -1;
4073
Eric W. Biederman9a0a91b2010-03-30 01:07:03 -07004074 ioapic = mp_find_ioapic(gsi);
4075 if (ioapic < 0)
Shaohua Li61fd47e2007-11-17 01:05:28 -05004076 return -1;
4077
Eric W. Biederman9a0a91b2010-03-30 01:07:03 -07004078 pin = mp_find_ioapic_pin(ioapic, gsi);
4079 if (pin < 0)
4080 return -1;
4081
4082 idx = find_irq_entry(ioapic, pin, mp_INT);
4083 if (idx < 0)
4084 return -1;
4085
4086 *trigger = irq_trigger(idx);
4087 *polarity = irq_polarity(idx);
Shaohua Li61fd47e2007-11-17 01:05:28 -05004088 return 0;
4089}
4090
Yinghai Lu497c9a12008-08-19 20:50:28 -07004091/*
4092 * This function currently is only a helper for the i386 smp boot process where
4093 * we need to reprogram the ioredtbls to cater for the cpus which have come online
Ingo Molnarfe402e12009-01-28 04:32:51 +01004094 * so mask in all cases should simply be apic->target_cpus()
Yinghai Lu497c9a12008-08-19 20:50:28 -07004095 */
4096#ifdef CONFIG_SMP
4097void __init setup_ioapic_dest(void)
4098{
Eric W. Biedermanfad53992010-02-28 01:06:34 -08004099 int pin, ioapic, irq, irq_entry;
Thomas Gleixner6c2e9402008-11-07 12:33:49 +01004100 struct irq_desc *desc;
Mike Travis22f65d32008-12-16 17:33:56 -08004101 const struct cpumask *mask;
Yinghai Lu497c9a12008-08-19 20:50:28 -07004102
4103 if (skip_ioapic_setup == 1)
4104 return;
4105
Eric W. Biedermanfad53992010-02-28 01:06:34 -08004106 for (ioapic = 0; ioapic < nr_ioapics; ioapic++)
Yinghai Lub9c61b702009-05-06 10:10:06 -07004107 for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) {
4108 irq_entry = find_irq_entry(ioapic, pin, mp_INT);
4109 if (irq_entry == -1)
4110 continue;
4111 irq = pin_2_irq(irq_entry, ioapic, pin);
4112
Eric W. Biedermanfad53992010-02-28 01:06:34 -08004113 if ((ioapic > 0) && (irq > 16))
4114 continue;
4115
Yinghai Lub9c61b702009-05-06 10:10:06 -07004116 desc = irq_to_desc(irq);
4117
4118 /*
4119 * Honour affinities which have been set in early boot
4120 */
4121 if (desc->status &
4122 (IRQ_NO_BALANCING | IRQ_AFFINITY_SET))
4123 mask = desc->affinity;
4124 else
4125 mask = apic->target_cpus();
4126
4127 if (intr_remapping_enabled)
4128 set_ir_ioapic_affinity_irq_desc(desc, mask);
4129 else
4130 set_ioapic_affinity_irq_desc(desc, mask);
4131 }
4132
Yinghai Lu497c9a12008-08-19 20:50:28 -07004133}
4134#endif
4135
Ingo Molnar54168ed2008-08-20 09:07:45 +02004136#define IOAPIC_RESOURCE_NAME_SIZE 11
4137
4138static struct resource *ioapic_resources;
4139
Cyrill Gorcunovffc43832009-08-24 21:53:39 +04004140static struct resource * __init ioapic_setup_resources(int nr_ioapics)
Ingo Molnar54168ed2008-08-20 09:07:45 +02004141{
4142 unsigned long n;
4143 struct resource *res;
4144 char *mem;
4145 int i;
4146
4147 if (nr_ioapics <= 0)
4148 return NULL;
4149
4150 n = IOAPIC_RESOURCE_NAME_SIZE + sizeof(struct resource);
4151 n *= nr_ioapics;
4152
4153 mem = alloc_bootmem(n);
4154 res = (void *)mem;
4155
Cyrill Gorcunovffc43832009-08-24 21:53:39 +04004156 mem += sizeof(struct resource) * nr_ioapics;
Ingo Molnar54168ed2008-08-20 09:07:45 +02004157
Cyrill Gorcunovffc43832009-08-24 21:53:39 +04004158 for (i = 0; i < nr_ioapics; i++) {
4159 res[i].name = mem;
4160 res[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY;
Cyrill Gorcunov4343fe12009-11-08 18:54:31 +03004161 snprintf(mem, IOAPIC_RESOURCE_NAME_SIZE, "IOAPIC %u", i);
Cyrill Gorcunovffc43832009-08-24 21:53:39 +04004162 mem += IOAPIC_RESOURCE_NAME_SIZE;
Ingo Molnar54168ed2008-08-20 09:07:45 +02004163 }
4164
4165 ioapic_resources = res;
4166
4167 return res;
4168}
Ingo Molnar54168ed2008-08-20 09:07:45 +02004169
Yinghai Luf3294a32008-06-27 01:41:56 -07004170void __init ioapic_init_mappings(void)
4171{
4172 unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
Ingo Molnar54168ed2008-08-20 09:07:45 +02004173 struct resource *ioapic_res;
Thomas Gleixnerd6c88a52008-10-15 15:27:23 +02004174 int i;
Yinghai Luf3294a32008-06-27 01:41:56 -07004175
Cyrill Gorcunovffc43832009-08-24 21:53:39 +04004176 ioapic_res = ioapic_setup_resources(nr_ioapics);
Yinghai Luf3294a32008-06-27 01:41:56 -07004177 for (i = 0; i < nr_ioapics; i++) {
4178 if (smp_found_config) {
Jaswinder Singh Rajputb5ba7e62009-01-12 17:46:17 +05304179 ioapic_phys = mp_ioapics[i].apicaddr;
Ingo Molnar54168ed2008-08-20 09:07:45 +02004180#ifdef CONFIG_X86_32
Thomas Gleixnerd6c88a52008-10-15 15:27:23 +02004181 if (!ioapic_phys) {
4182 printk(KERN_ERR
4183 "WARNING: bogus zero IO-APIC "
4184 "address found in MPTABLE, "
4185 "disabling IO/APIC support!\n");
4186 smp_found_config = 0;
4187 skip_ioapic_setup = 1;
4188 goto fake_ioapic_page;
4189 }
Ingo Molnar54168ed2008-08-20 09:07:45 +02004190#endif
Yinghai Luf3294a32008-06-27 01:41:56 -07004191 } else {
Ingo Molnar54168ed2008-08-20 09:07:45 +02004192#ifdef CONFIG_X86_32
Yinghai Luf3294a32008-06-27 01:41:56 -07004193fake_ioapic_page:
Ingo Molnar54168ed2008-08-20 09:07:45 +02004194#endif
Cyrill Gorcunove79c65a2009-11-16 18:14:26 +03004195 ioapic_phys = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
Yinghai Luf3294a32008-06-27 01:41:56 -07004196 ioapic_phys = __pa(ioapic_phys);
4197 }
4198 set_fixmap_nocache(idx, ioapic_phys);
Cyrill Gorcunove79c65a2009-11-16 18:14:26 +03004199 apic_printk(APIC_VERBOSE, "mapped IOAPIC to %08lx (%08lx)\n",
4200 __fix_to_virt(idx) + (ioapic_phys & ~PAGE_MASK),
4201 ioapic_phys);
Yinghai Luf3294a32008-06-27 01:41:56 -07004202 idx++;
Ingo Molnar54168ed2008-08-20 09:07:45 +02004203
Cyrill Gorcunovffc43832009-08-24 21:53:39 +04004204 ioapic_res->start = ioapic_phys;
Cyrill Gorcunove79c65a2009-11-16 18:14:26 +03004205 ioapic_res->end = ioapic_phys + IO_APIC_SLOT_SIZE - 1;
Cyrill Gorcunovffc43832009-08-24 21:53:39 +04004206 ioapic_res++;
Yinghai Luf3294a32008-06-27 01:41:56 -07004207 }
4208}
4209
Yinghai Lu857fdc52009-07-10 09:36:20 -07004210void __init ioapic_insert_resources(void)
Ingo Molnar54168ed2008-08-20 09:07:45 +02004211{
4212 int i;
4213 struct resource *r = ioapic_resources;
4214
4215 if (!r) {
Yinghai Lu857fdc52009-07-10 09:36:20 -07004216 if (nr_ioapics > 0)
Bartlomiej Zolnierkiewicz04c93ce2009-03-20 21:02:55 +01004217 printk(KERN_ERR
4218 "IO APIC resources couldn't be allocated.\n");
Yinghai Lu857fdc52009-07-10 09:36:20 -07004219 return;
Ingo Molnar54168ed2008-08-20 09:07:45 +02004220 }
4221
4222 for (i = 0; i < nr_ioapics; i++) {
4223 insert_resource(&iomem_resource, r);
4224 r++;
4225 }
Ingo Molnar54168ed2008-08-20 09:07:45 +02004226}
Ingo Molnar54168ed2008-08-20 09:07:45 +02004227
Eric W. Biedermaneddb0c52010-03-30 01:07:09 -07004228int mp_find_ioapic(u32 gsi)
Feng Tang2a4ab642009-07-07 23:01:15 -04004229{
4230 int i = 0;
4231
4232 /* Find the IOAPIC that manages this GSI. */
4233 for (i = 0; i < nr_ioapics; i++) {
4234 if ((gsi >= mp_gsi_routing[i].gsi_base)
4235 && (gsi <= mp_gsi_routing[i].gsi_end))
4236 return i;
4237 }
4238
4239 printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
4240 return -1;
4241}
4242
Eric W. Biedermaneddb0c52010-03-30 01:07:09 -07004243int mp_find_ioapic_pin(int ioapic, u32 gsi)
Feng Tang2a4ab642009-07-07 23:01:15 -04004244{
4245 if (WARN_ON(ioapic == -1))
4246 return -1;
4247 if (WARN_ON(gsi > mp_gsi_routing[ioapic].gsi_end))
4248 return -1;
4249
4250 return gsi - mp_gsi_routing[ioapic].gsi_base;
4251}
4252
4253static int bad_ioapic(unsigned long address)
4254{
4255 if (nr_ioapics >= MAX_IO_APICS) {
4256 printk(KERN_WARNING "WARING: Max # of I/O APICs (%d) exceeded "
4257 "(found %d), skipping\n", MAX_IO_APICS, nr_ioapics);
4258 return 1;
4259 }
4260 if (!address) {
4261 printk(KERN_WARNING "WARNING: Bogus (zero) I/O APIC address"
4262 " found in table, skipping!\n");
4263 return 1;
4264 }
Ingo Molnar54168ed2008-08-20 09:07:45 +02004265 return 0;
4266}
4267
Feng Tang2a4ab642009-07-07 23:01:15 -04004268void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
4269{
4270 int idx = 0;
Eric W. Biederman7716a5c2010-03-30 01:07:12 -07004271 int entries;
Feng Tang2a4ab642009-07-07 23:01:15 -04004272
4273 if (bad_ioapic(address))
4274 return;
4275
4276 idx = nr_ioapics;
4277
4278 mp_ioapics[idx].type = MP_IOAPIC;
4279 mp_ioapics[idx].flags = MPC_APIC_USABLE;
4280 mp_ioapics[idx].apicaddr = address;
4281
4282 set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
4283 mp_ioapics[idx].apicid = io_apic_unique_id(id);
4284 mp_ioapics[idx].apicver = io_apic_get_version(idx);
4285
4286 /*
4287 * Build basic GSI lookup table to facilitate gsi->io_apic lookups
4288 * and to prevent reprogramming of IOAPIC pins (PCI GSIs).
4289 */
Eric W. Biederman7716a5c2010-03-30 01:07:12 -07004290 entries = io_apic_get_redir_entries(idx);
Feng Tang2a4ab642009-07-07 23:01:15 -04004291 mp_gsi_routing[idx].gsi_base = gsi_base;
Eric W. Biederman7716a5c2010-03-30 01:07:12 -07004292 mp_gsi_routing[idx].gsi_end = gsi_base + entries - 1;
4293
4294 /*
4295 * The number of IO-APIC IRQ registers (== #pins):
4296 */
4297 nr_ioapic_registers[idx] = entries;
Feng Tang2a4ab642009-07-07 23:01:15 -04004298
Eric W. Biedermana4384df2010-06-08 11:44:32 -07004299 if (mp_gsi_routing[idx].gsi_end >= gsi_top)
4300 gsi_top = mp_gsi_routing[idx].gsi_end + 1;
Feng Tang2a4ab642009-07-07 23:01:15 -04004301
4302 printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%x, "
4303 "GSI %d-%d\n", idx, mp_ioapics[idx].apicid,
4304 mp_ioapics[idx].apicver, mp_ioapics[idx].apicaddr,
4305 mp_gsi_routing[idx].gsi_base, mp_gsi_routing[idx].gsi_end);
4306
4307 nr_ioapics++;
4308}
Jacob Pan05ddafb2009-09-23 07:20:23 -07004309
4310/* Enable IOAPIC early just for system timer */
4311void __init pre_init_apic_IRQ0(void)
4312{
4313 struct irq_cfg *cfg;
4314 struct irq_desc *desc;
4315
4316 printk(KERN_INFO "Early APIC setup for system timer0\n");
4317#ifndef CONFIG_SMP
4318 phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid);
4319#endif
4320 desc = irq_to_desc_alloc_node(0, 0);
4321
4322 setup_local_APIC();
4323
4324 cfg = irq_cfg(0);
4325 add_pin_to_irq_node(cfg, 0, 0, 0);
4326 set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge");
4327
4328 setup_IO_APIC_irq(0, 0, 0, desc, 0, 0);
4329}