vserver 1.9.3
[linux-2.6.git] / arch / ia64 / kernel / iosapic.c
1 /*
2  * I/O SAPIC support.
3  *
4  * Copyright (C) 1999 Intel Corp.
5  * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
6  * Copyright (C) 2000-2002 J.I. Lee <jung-ik.lee@intel.com>
7  * Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co.
8  *      David Mosberger-Tang <davidm@hpl.hp.com>
9  * Copyright (C) 1999 VA Linux Systems
10  * Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
11  *
12  * 00/04/19     D. Mosberger    Rewritten to mirror more closely the x86 I/O APIC code.
13  *                              In particular, we now have separate handlers for edge
14  *                              and level triggered interrupts.
15  * 00/10/27     Asit Mallick, Goutham Rao <goutham.rao@intel.com> IRQ vector allocation
16  *                              PCI to vector mapping, shared PCI interrupts.
17  * 00/10/27     D. Mosberger    Document things a bit more to make them more understandable.
18  *                              Clean up much of the old IOSAPIC cruft.
19  * 01/07/27     J.I. Lee        PCI irq routing, Platform/Legacy interrupts and fixes for
20  *                              ACPI S5(SoftOff) support.
21  * 02/01/23     J.I. Lee        iosapic pgm fixes for PCI irq routing from _PRT
22  * 02/01/07     E. Focht        <efocht@ess.nec.de> Redirectable interrupt vectors in
23  *                              iosapic_set_affinity(), initializations for
24  *                              /proc/irq/#/smp_affinity
25  * 02/04/02     P. Diefenbaugh  Cleaned up ACPI PCI IRQ routing.
26  * 02/04/18     J.I. Lee        bug fix in iosapic_init_pci_irq
27  * 02/04/30     J.I. Lee        bug fix in find_iosapic to fix ACPI PCI IRQ to IOSAPIC mapping
28  *                              error
29  * 02/07/29     T. Kochi        Allocate interrupt vectors dynamically
30  * 02/08/04     T. Kochi        Cleaned up terminology (irq, global system interrupt, vector, etc.)
31  * 02/09/20     D. Mosberger    Simplified by taking advantage of ACPI's pci_irq code.
32  * 03/02/19     B. Helgaas      Make pcat_compat system-wide, not per-IOSAPIC.
33  *                              Remove iosapic_address & gsi_base from external interfaces.
34  *                              Rationalize __init/__devinit attributes.
35  * 04/12/04 Ashok Raj   <ashok.raj@intel.com> Intel Corporation 2004
36  *                              Updated to work with irq migration necessary for CPU Hotplug
37  */
38 /*
39  * Here is what the interrupt logic between a PCI device and the kernel looks like:
40  *
41  * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, INTD).  The
42  *     device is uniquely identified by its bus--, and slot-number (the function
43  *     number does not matter here because all functions share the same interrupt
44  *     lines).
45  *
46  * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC controller.
47  *     Multiple interrupt lines may have to share the same IOSAPIC pin (if they're level
48  *     triggered and use the same polarity).  Each interrupt line has a unique Global
49  *     System Interrupt (GSI) number which can be calculated as the sum of the controller's
50  *     base GSI number and the IOSAPIC pin number to which the line connects.
51  *
52  * (3) The IOSAPIC uses an internal routing table entries (RTEs) to map the IOSAPIC pin
53  *     into the IA-64 interrupt vector.  This interrupt vector is then sent to the CPU.
54  *
55  * (4) The kernel recognizes an interrupt as an IRQ.  The IRQ interface is used as
56  *     architecture-independent interrupt handling mechanism in Linux.  As an
57  *     IRQ is a number, we have to have IA-64 interrupt vector number <-> IRQ number
58  *     mapping.  On smaller systems, we use one-to-one mapping between IA-64 vector and
59  *     IRQ.  A platform can implement platform_irq_to_vector(irq) and
60  *     platform_local_vector_to_irq(vector) APIs to differentiate the mapping.
61  *     Please see also include/asm-ia64/hw_irq.h for those APIs.
62  *
63  * To sum up, there are three levels of mappings involved:
64  *
65  *      PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ
66  *
67  * Note: The term "IRQ" is loosely used everywhere in Linux kernel to describe interrupts.
68  * Now we use "IRQ" only for Linux IRQ's.  ISA IRQ (isa_irq) is the only exception in this
69  * source code.
70  */
71 #include <linux/config.h>
72
73 #include <linux/acpi.h>
74 #include <linux/init.h>
75 #include <linux/irq.h>
76 #include <linux/kernel.h>
77 #include <linux/list.h>
78 #include <linux/pci.h>
79 #include <linux/smp.h>
80 #include <linux/smp_lock.h>
81 #include <linux/string.h>
82
83 #include <asm/delay.h>
84 #include <asm/hw_irq.h>
85 #include <asm/io.h>
86 #include <asm/iosapic.h>
87 #include <asm/machvec.h>
88 #include <asm/processor.h>
89 #include <asm/ptrace.h>
90 #include <asm/system.h>
91
92
93 #undef DEBUG_INTERRUPT_ROUTING
94 #undef OVERRIDE_DEBUG
95
96 #ifdef DEBUG_INTERRUPT_ROUTING
97 #define DBG(fmt...)     printk(fmt)
98 #else
99 #define DBG(fmt...)
100 #endif
101
102 static spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED;
103
104 /* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */
105
106 static struct iosapic_intr_info {
107         char __iomem    *addr;          /* base address of IOSAPIC */
108         u32             low32;          /* current value of low word of Redirection table entry */
109         unsigned int    gsi_base;       /* first GSI assigned to this IOSAPIC */
110         char            rte_index;      /* IOSAPIC RTE index (-1 => not an IOSAPIC interrupt) */
111         unsigned char   dmode   : 3;    /* delivery mode (see iosapic.h) */
112         unsigned char   polarity: 1;    /* interrupt polarity (see iosapic.h) */
113         unsigned char   trigger : 1;    /* trigger mode (see iosapic.h) */
114 } iosapic_intr_info[IA64_NUM_VECTORS];
115
116 static struct iosapic {
117         char __iomem    *addr;          /* base address of IOSAPIC */
118         unsigned int    gsi_base;       /* first GSI assigned to this IOSAPIC */
119         unsigned short  num_rte;        /* number of RTE in this IOSAPIC */
120 #ifdef CONFIG_NUMA
121         unsigned short  node;           /* numa node association via pxm */
122 #endif
123 } iosapic_lists[NR_IOSAPICS];
124
125 static int num_iosapic;
126
127 static unsigned char pcat_compat __initdata;    /* 8259 compatibility flag */
128
129
130 /*
131  * Find an IOSAPIC associated with a GSI
132  */
133 static inline int
134 find_iosapic (unsigned int gsi)
135 {
136         int i;
137
138         for (i = 0; i < num_iosapic; i++) {
139                 if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte)
140                         return i;
141         }
142
143         return -1;
144 }
145
146 static inline int
147 _gsi_to_vector (unsigned int gsi)
148 {
149         struct iosapic_intr_info *info;
150
151         for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info)
152                 if (info->gsi_base + info->rte_index == gsi)
153                         return info - iosapic_intr_info;
154         return -1;
155 }
156
157 /*
158  * Translate GSI number to the corresponding IA-64 interrupt vector.  If no
159  * entry exists, return -1.
160  */
161 inline int
162 gsi_to_vector (unsigned int gsi)
163 {
164         return _gsi_to_vector(gsi);
165 }
166
167 int
168 gsi_to_irq (unsigned int gsi)
169 {
170         /*
171          * XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq
172          * numbers...
173          */
174         return _gsi_to_vector(gsi);
175 }
176
177 static void
178 set_rte (unsigned int vector, unsigned int dest, int mask)
179 {
180         unsigned long pol, trigger, dmode, flags;
181         u32 low32, high32;
182         char __iomem *addr;
183         int rte_index;
184         char redir;
185
186         DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest);
187
188         rte_index = iosapic_intr_info[vector].rte_index;
189         if (rte_index < 0)
190                 return;         /* not an IOSAPIC interrupt */
191
192         addr    = iosapic_intr_info[vector].addr;
193         pol     = iosapic_intr_info[vector].polarity;
194         trigger = iosapic_intr_info[vector].trigger;
195         dmode   = iosapic_intr_info[vector].dmode;
196         vector &= (~IA64_IRQ_REDIRECTED);
197
198         redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0;
199
200 #ifdef CONFIG_SMP
201         {
202                 unsigned int irq;
203
204                 for (irq = 0; irq < NR_IRQS; ++irq)
205                         if (irq_to_vector(irq) == vector) {
206                                 set_irq_affinity_info(irq, (int)(dest & 0xffff), redir);
207                                 break;
208                         }
209         }
210 #endif
211
212         low32 = ((pol << IOSAPIC_POLARITY_SHIFT) |
213                  (trigger << IOSAPIC_TRIGGER_SHIFT) |
214                  (dmode << IOSAPIC_DELIVERY_SHIFT) |
215                  ((mask ? 1 : 0) << IOSAPIC_MASK_SHIFT) |
216                  vector);
217
218         /* dest contains both id and eid */
219         high32 = (dest << IOSAPIC_DEST_SHIFT);
220
221         spin_lock_irqsave(&iosapic_lock, flags);
222         {
223                 iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
224                 iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
225                 iosapic_intr_info[vector].low32 = low32;
226         }
227         spin_unlock_irqrestore(&iosapic_lock, flags);
228 }
229
230 static void
231 nop (unsigned int vector)
232 {
233         /* do nothing... */
234 }
235
236 static void
237 mask_irq (unsigned int irq)
238 {
239         unsigned long flags;
240         char __iomem *addr;
241         u32 low32;
242         int rte_index;
243         ia64_vector vec = irq_to_vector(irq);
244
245         addr = iosapic_intr_info[vec].addr;
246         rte_index = iosapic_intr_info[vec].rte_index;
247
248         if (rte_index < 0)
249                 return;                 /* not an IOSAPIC interrupt! */
250
251         spin_lock_irqsave(&iosapic_lock, flags);
252         {
253                 /* set only the mask bit */
254                 low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
255                 iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
256         }
257         spin_unlock_irqrestore(&iosapic_lock, flags);
258 }
259
260 static void
261 unmask_irq (unsigned int irq)
262 {
263         unsigned long flags;
264         char __iomem *addr;
265         u32 low32;
266         int rte_index;
267         ia64_vector vec = irq_to_vector(irq);
268
269         addr = iosapic_intr_info[vec].addr;
270         rte_index = iosapic_intr_info[vec].rte_index;
271         if (rte_index < 0)
272                 return;                 /* not an IOSAPIC interrupt! */
273
274         spin_lock_irqsave(&iosapic_lock, flags);
275         {
276                 low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
277                 iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
278         }
279         spin_unlock_irqrestore(&iosapic_lock, flags);
280 }
281
282
283 static void
284 iosapic_set_affinity (unsigned int irq, cpumask_t mask)
285 {
286 #ifdef CONFIG_SMP
287         unsigned long flags;
288         u32 high32, low32;
289         int dest, rte_index;
290         char __iomem *addr;
291         int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0;
292         ia64_vector vec;
293
294         irq &= (~IA64_IRQ_REDIRECTED);
295         vec = irq_to_vector(irq);
296
297         if (cpus_empty(mask))
298                 return;
299
300         dest = cpu_physical_id(first_cpu(mask));
301
302         rte_index = iosapic_intr_info[vec].rte_index;
303         addr = iosapic_intr_info[vec].addr;
304
305         if (rte_index < 0)
306                 return;                 /* not an IOSAPIC interrupt */
307
308         set_irq_affinity_info(irq, dest, redir);
309
310         /* dest contains both id and eid */
311         high32 = dest << IOSAPIC_DEST_SHIFT;
312
313         spin_lock_irqsave(&iosapic_lock, flags);
314         {
315                 low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT);
316
317                 if (redir)
318                         /* change delivery mode to lowest priority */
319                         low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT);
320                 else
321                         /* change delivery mode to fixed */
322                         low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
323
324                 iosapic_intr_info[vec].low32 = low32;
325                 iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
326                 iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
327         }
328         spin_unlock_irqrestore(&iosapic_lock, flags);
329 #endif
330 }
331
332 /*
333  * Handlers for level-triggered interrupts.
334  */
335
336 static unsigned int
337 iosapic_startup_level_irq (unsigned int irq)
338 {
339         unmask_irq(irq);
340         return 0;
341 }
342
343 static void
344 iosapic_end_level_irq (unsigned int irq)
345 {
346         ia64_vector vec = irq_to_vector(irq);
347
348         move_irq(irq);
349         iosapic_eoi(iosapic_intr_info[vec].addr, vec);
350 }
351
352 #define iosapic_shutdown_level_irq      mask_irq
353 #define iosapic_enable_level_irq        unmask_irq
354 #define iosapic_disable_level_irq       mask_irq
355 #define iosapic_ack_level_irq           nop
356
357 struct hw_interrupt_type irq_type_iosapic_level = {
358         .typename =     "IO-SAPIC-level",
359         .startup =      iosapic_startup_level_irq,
360         .shutdown =     iosapic_shutdown_level_irq,
361         .enable =       iosapic_enable_level_irq,
362         .disable =      iosapic_disable_level_irq,
363         .ack =          iosapic_ack_level_irq,
364         .end =          iosapic_end_level_irq,
365         .set_affinity = iosapic_set_affinity
366 };
367
368 /*
369  * Handlers for edge-triggered interrupts.
370  */
371
372 static unsigned int
373 iosapic_startup_edge_irq (unsigned int irq)
374 {
375         unmask_irq(irq);
376         /*
377          * IOSAPIC simply drops interrupts pended while the
378          * corresponding pin was masked, so we can't know if an
379          * interrupt is pending already.  Let's hope not...
380          */
381         return 0;
382 }
383
384 static void
385 iosapic_ack_edge_irq (unsigned int irq)
386 {
387         irq_desc_t *idesc = irq_descp(irq);
388
389         move_irq(irq);
390         /*
391          * Once we have recorded IRQ_PENDING already, we can mask the
392          * interrupt for real. This prevents IRQ storms from unhandled
393          * devices.
394          */
395         if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED))
396                 mask_irq(irq);
397 }
398
399 #define iosapic_enable_edge_irq         unmask_irq
400 #define iosapic_disable_edge_irq        nop
401 #define iosapic_end_edge_irq            nop
402
403 struct hw_interrupt_type irq_type_iosapic_edge = {
404         .typename =     "IO-SAPIC-edge",
405         .startup =      iosapic_startup_edge_irq,
406         .shutdown =     iosapic_disable_edge_irq,
407         .enable =       iosapic_enable_edge_irq,
408         .disable =      iosapic_disable_edge_irq,
409         .ack =          iosapic_ack_edge_irq,
410         .end =          iosapic_end_edge_irq,
411         .set_affinity = iosapic_set_affinity
412 };
413
414 unsigned int
415 iosapic_version (char __iomem *addr)
416 {
417         /*
418          * IOSAPIC Version Register return 32 bit structure like:
419          * {
420          *      unsigned int version   : 8;
421          *      unsigned int reserved1 : 8;
422          *      unsigned int max_redir : 8;
423          *      unsigned int reserved2 : 8;
424          * }
425          */
426         return iosapic_read(addr, IOSAPIC_VERSION);
427 }
428
429 /*
430  * if the given vector is already owned by other,
431  *  assign a new vector for the other and make the vector available
432  */
433 static void __init
434 iosapic_reassign_vector (int vector)
435 {
436         int new_vector;
437
438         if (iosapic_intr_info[vector].rte_index >= 0 || iosapic_intr_info[vector].addr
439             || iosapic_intr_info[vector].gsi_base || iosapic_intr_info[vector].dmode
440             || iosapic_intr_info[vector].polarity || iosapic_intr_info[vector].trigger)
441         {
442                 new_vector = assign_irq_vector(AUTO_ASSIGN);
443                 printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector);
444                 memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
445                        sizeof(struct iosapic_intr_info));
446                 memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
447                 iosapic_intr_info[vector].rte_index = -1;
448         }
449 }
450
451 static void
452 register_intr (unsigned int gsi, int vector, unsigned char delivery,
453                unsigned long polarity, unsigned long trigger)
454 {
455         irq_desc_t *idesc;
456         struct hw_interrupt_type *irq_type;
457         int rte_index;
458         int index;
459         unsigned long gsi_base;
460         void __iomem *iosapic_address;
461
462         index = find_iosapic(gsi);
463         if (index < 0) {
464                 printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", __FUNCTION__, gsi);
465                 return;
466         }
467
468         iosapic_address = iosapic_lists[index].addr;
469         gsi_base = iosapic_lists[index].gsi_base;
470
471         rte_index = gsi - gsi_base;
472         iosapic_intr_info[vector].rte_index = rte_index;
473         iosapic_intr_info[vector].polarity = polarity;
474         iosapic_intr_info[vector].dmode    = delivery;
475         iosapic_intr_info[vector].addr     = iosapic_address;
476         iosapic_intr_info[vector].gsi_base = gsi_base;
477         iosapic_intr_info[vector].trigger  = trigger;
478
479         if (trigger == IOSAPIC_EDGE)
480                 irq_type = &irq_type_iosapic_edge;
481         else
482                 irq_type = &irq_type_iosapic_level;
483
484         idesc = irq_descp(vector);
485         if (idesc->handler != irq_type) {
486                 if (idesc->handler != &no_irq_type)
487                         printk(KERN_WARNING "%s: changing vector %d from %s to %s\n",
488                                __FUNCTION__, vector, idesc->handler->typename, irq_type->typename);
489                 idesc->handler = irq_type;
490         }
491 }
492
493 static unsigned int
494 get_target_cpu (unsigned int gsi, int vector)
495 {
496 #ifdef CONFIG_SMP
497         static int cpu = -1;
498
499         /*
500          * If the platform supports redirection via XTP, let it
501          * distribute interrupts.
502          */
503         if (smp_int_redirect & SMP_IRQ_REDIRECTION)
504                 return hard_smp_processor_id();
505
506         /*
507          * Some interrupts (ACPI SCI, for instance) are registered
508          * before the BSP is marked as online.
509          */
510         if (!cpu_online(smp_processor_id()))
511                 return hard_smp_processor_id();
512
513 #ifdef CONFIG_NUMA
514         {
515                 int num_cpus, cpu_index, iosapic_index, numa_cpu, i = 0;
516                 cpumask_t cpu_mask;
517
518                 iosapic_index = find_iosapic(gsi);
519                 if (iosapic_index < 0 ||
520                     iosapic_lists[iosapic_index].node == MAX_NUMNODES)
521                         goto skip_numa_setup;
522
523                 cpu_mask = node_to_cpumask(iosapic_lists[iosapic_index].node);
524                 
525                 num_cpus = cpus_weight(cpu_mask);
526
527                 if (!num_cpus)
528                         goto skip_numa_setup;
529
530                 /* Use vector assigment to distribute across cpus in node */
531                 cpu_index = vector % num_cpus;
532
533                 for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++)
534                         numa_cpu = next_cpu(numa_cpu, cpu_mask);
535
536                 if (numa_cpu != NR_CPUS)
537                         return cpu_physical_id(numa_cpu);
538         }
539 skip_numa_setup:
540 #endif
541         /*
542          * Otherwise, round-robin interrupt vectors across all the
543          * processors.  (It'd be nice if we could be smarter in the
544          * case of NUMA.)
545          */
546         do {
547                 if (++cpu >= NR_CPUS)
548                         cpu = 0;
549         } while (!cpu_online(cpu));
550
551         return cpu_physical_id(cpu);
552 #else
553         return hard_smp_processor_id();
554 #endif
555 }
556
557 /*
558  * ACPI can describe IOSAPIC interrupts via static tables and namespace
559  * methods.  This provides an interface to register those interrupts and
560  * program the IOSAPIC RTE.
561  */
562 int
563 iosapic_register_intr (unsigned int gsi,
564                        unsigned long polarity, unsigned long trigger)
565 {
566         int vector;
567         unsigned int dest;
568         unsigned long flags;
569
570         /*
571          * If this GSI has already been registered (i.e., it's a
572          * shared interrupt, or we lost a race to register it),
573          * don't touch the RTE.
574          */
575         spin_lock_irqsave(&iosapic_lock, flags);
576         {
577                 vector = gsi_to_vector(gsi);
578                 if (vector > 0) {
579                         spin_unlock_irqrestore(&iosapic_lock, flags);
580                         return vector;
581                 }
582
583                 vector = assign_irq_vector(AUTO_ASSIGN);
584                 dest = get_target_cpu(gsi, vector);
585                 register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
586                         polarity, trigger);
587         }
588         spin_unlock_irqrestore(&iosapic_lock, flags);
589
590         printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
591                gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
592                (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
593                cpu_logical_id(dest), dest, vector);
594
595         set_rte(vector, dest, 1);
596         return vector;
597 }
598
599 /*
600  * ACPI calls this when it finds an entry for a platform interrupt.
601  * Note that the irq_base and IOSAPIC address must be set in iosapic_init().
602  */
603 int __init
604 iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
605                                 int iosapic_vector, u16 eid, u16 id,
606                                 unsigned long polarity, unsigned long trigger)
607 {
608         static const char * const name[] = {"unknown", "PMI", "INIT", "CPEI"};
609         unsigned char delivery;
610         int vector, mask = 0;
611         unsigned int dest = ((id << 8) | eid) & 0xffff;
612
613         switch (int_type) {
614               case ACPI_INTERRUPT_PMI:
615                 vector = iosapic_vector;
616                 /*
617                  * since PMI vector is alloc'd by FW(ACPI) not by kernel,
618                  * we need to make sure the vector is available
619                  */
620                 iosapic_reassign_vector(vector);
621                 delivery = IOSAPIC_PMI;
622                 break;
623               case ACPI_INTERRUPT_INIT:
624                 vector = assign_irq_vector(AUTO_ASSIGN);
625                 delivery = IOSAPIC_INIT;
626                 break;
627               case ACPI_INTERRUPT_CPEI:
628                 vector = IA64_CPE_VECTOR;
629                 delivery = IOSAPIC_LOWEST_PRIORITY;
630                 mask = 1;
631                 break;
632               default:
633                 printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type 0x%x\n", int_type);
634                 return -1;
635         }
636
637         register_intr(gsi, vector, delivery, polarity, trigger);
638
639         printk(KERN_INFO "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
640                int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown",
641                int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
642                (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
643                cpu_logical_id(dest), dest, vector);
644
645         set_rte(vector, dest, mask);
646         return vector;
647 }
648
649
650 /*
651  * ACPI calls this when it finds an entry for a legacy ISA IRQ override.
652  * Note that the gsi_base and IOSAPIC address must be set in iosapic_init().
653  */
654 void __init
655 iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
656                           unsigned long polarity,
657                           unsigned long trigger)
658 {
659         int vector;
660         unsigned int dest = hard_smp_processor_id();
661
662         vector = isa_irq_to_vector(isa_irq);
663
664         register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
665
666         DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n",
667             isa_irq, gsi, trigger == IOSAPIC_EDGE ? "edge" : "level",
668             polarity == IOSAPIC_POL_HIGH ? "high" : "low",
669             cpu_logical_id(dest), dest, vector);
670
671         set_rte(vector, dest, 1);
672 }
673
674 void __init
675 iosapic_system_init (int system_pcat_compat)
676 {
677         int vector;
678
679         for (vector = 0; vector < IA64_NUM_VECTORS; ++vector)
680                 iosapic_intr_info[vector].rte_index = -1;       /* mark as unused */
681
682         pcat_compat = system_pcat_compat;
683         if (pcat_compat) {
684                 /*
685                  * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support
686                  * enabled.
687                  */
688                 printk(KERN_INFO "%s: Disabling PC-AT compatible 8259 interrupts\n", __FUNCTION__);
689                 outb(0xff, 0xA1);
690                 outb(0xff, 0x21);
691         }
692 }
693
694 void __init
695 iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
696 {
697         int num_rte;
698         unsigned int isa_irq, ver;
699         char __iomem *addr;
700
701         addr = ioremap(phys_addr, 0);
702         ver = iosapic_version(addr);
703
704         /*
705          * The MAX_REDIR register holds the highest input pin
706          * number (starting from 0).
707          * We add 1 so that we can use it for number of pins (= RTEs)
708          */
709         num_rte = ((ver >> 16) & 0xff) + 1;
710
711         iosapic_lists[num_iosapic].addr = addr;
712         iosapic_lists[num_iosapic].gsi_base = gsi_base;
713         iosapic_lists[num_iosapic].num_rte = num_rte;
714 #ifdef CONFIG_NUMA
715         iosapic_lists[num_iosapic].node = MAX_NUMNODES;
716 #endif
717         num_iosapic++;
718
719         if ((gsi_base == 0) && pcat_compat) {
720                 /*
721                  * Map the legacy ISA devices into the IOSAPIC data.  Some of these may
722                  * get reprogrammed later on with data from the ACPI Interrupt Source
723                  * Override table.
724                  */
725                 for (isa_irq = 0; isa_irq < 16; ++isa_irq)
726                         iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
727         }
728 }
729
730 #ifdef CONFIG_NUMA
731 void __init
732 map_iosapic_to_node(unsigned int gsi_base, int node)
733 {
734         int index;
735
736         index = find_iosapic(gsi_base);
737         if (index < 0) {
738                 printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n",
739                        __FUNCTION__, gsi_base);
740                 return;
741         }
742         iosapic_lists[index].node = node;
743         return;
744 }
745 #endif