patch-2_6_7-vs1_9_1_12
[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 extern cpumask_t        __cacheline_aligned pending_irq_cpumask[NR_IRQS];
104
105 /* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */
106
107 static struct iosapic_intr_info {
108         char            *addr;          /* base address of IOSAPIC */
109         u32             low32;          /* current value of low word of Redirection table entry */
110         unsigned int    gsi_base;       /* first GSI assigned to this IOSAPIC */
111         char            rte_index;      /* IOSAPIC RTE index (-1 => not an IOSAPIC interrupt) */
112         unsigned char   dmode   : 3;    /* delivery mode (see iosapic.h) */
113         unsigned char   polarity: 1;    /* interrupt polarity (see iosapic.h) */
114         unsigned char   trigger : 1;    /* trigger mode (see iosapic.h) */
115 } iosapic_intr_info[IA64_NUM_VECTORS];
116
117 static struct iosapic {
118         char            *addr;          /* base address of IOSAPIC */
119         unsigned int    gsi_base;       /* first GSI assigned to this IOSAPIC */
120         unsigned short  num_rte;        /* number of RTE in this IOSAPIC */
121 } iosapic_lists[NR_IOSAPICS];
122
123 static int num_iosapic;
124
125 static unsigned char pcat_compat __initdata;    /* 8259 compatibility flag */
126
127
128 /*
129  * Find an IOSAPIC associated with a GSI
130  */
131 static inline int
132 find_iosapic (unsigned int gsi)
133 {
134         int i;
135
136         for (i = 0; i < num_iosapic; i++) {
137                 if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte)
138                         return i;
139         }
140
141         return -1;
142 }
143
144 static inline int
145 _gsi_to_vector (unsigned int gsi)
146 {
147         struct iosapic_intr_info *info;
148
149         for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info)
150                 if (info->gsi_base + info->rte_index == gsi)
151                         return info - iosapic_intr_info;
152         return -1;
153 }
154
155 /*
156  * Translate GSI number to the corresponding IA-64 interrupt vector.  If no
157  * entry exists, return -1.
158  */
159 inline int
160 gsi_to_vector (unsigned int gsi)
161 {
162         return _gsi_to_vector(gsi);
163 }
164
165 int
166 gsi_to_irq (unsigned int gsi)
167 {
168         /*
169          * XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq
170          * numbers...
171          */
172         return _gsi_to_vector(gsi);
173 }
174
175 static void
176 set_rte (unsigned int vector, unsigned int dest, int mask)
177 {
178         unsigned long pol, trigger, dmode, flags;
179         u32 low32, high32;
180         char *addr;
181         int rte_index;
182         char redir;
183
184         DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest);
185
186         rte_index = iosapic_intr_info[vector].rte_index;
187         if (rte_index < 0)
188                 return;         /* not an IOSAPIC interrupt */
189
190         addr    = iosapic_intr_info[vector].addr;
191         pol     = iosapic_intr_info[vector].polarity;
192         trigger = iosapic_intr_info[vector].trigger;
193         dmode   = iosapic_intr_info[vector].dmode;
194         vector &= (~IA64_IRQ_REDIRECTED);
195
196         redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0;
197
198 #ifdef CONFIG_SMP
199         {
200                 unsigned int irq;
201
202                 for (irq = 0; irq < NR_IRQS; ++irq)
203                         if (irq_to_vector(irq) == vector) {
204                                 set_irq_affinity_info(irq, (int)(dest & 0xffff), redir);
205                                 break;
206                         }
207         }
208 #endif
209
210         low32 = ((pol << IOSAPIC_POLARITY_SHIFT) |
211                  (trigger << IOSAPIC_TRIGGER_SHIFT) |
212                  (dmode << IOSAPIC_DELIVERY_SHIFT) |
213                  ((mask ? 1 : 0) << IOSAPIC_MASK_SHIFT) |
214                  vector);
215
216         /* dest contains both id and eid */
217         high32 = (dest << IOSAPIC_DEST_SHIFT);
218
219         spin_lock_irqsave(&iosapic_lock, flags);
220         {
221                 writel(IOSAPIC_RTE_HIGH(rte_index), addr + IOSAPIC_REG_SELECT);
222                 writel(high32, addr + IOSAPIC_WINDOW);
223                 writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
224                 writel(low32, addr + IOSAPIC_WINDOW);
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 *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                 writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
254
255                 /* set only the mask bit */
256                 low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
257
258                 writel(low32, addr + IOSAPIC_WINDOW);
259         }
260         spin_unlock_irqrestore(&iosapic_lock, flags);
261 }
262
263 static void
264 unmask_irq (unsigned int irq)
265 {
266         unsigned long flags;
267         char *addr;
268         u32 low32;
269         int rte_index;
270         ia64_vector vec = irq_to_vector(irq);
271
272         addr = iosapic_intr_info[vec].addr;
273         rte_index = iosapic_intr_info[vec].rte_index;
274         if (rte_index < 0)
275                 return;                 /* not an IOSAPIC interrupt! */
276
277         spin_lock_irqsave(&iosapic_lock, flags);
278         {
279                 writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
280                 low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
281                 writel(low32, addr + IOSAPIC_WINDOW);
282         }
283         spin_unlock_irqrestore(&iosapic_lock, flags);
284 }
285
286
287 static void
288 iosapic_set_affinity (unsigned int irq, cpumask_t mask)
289 {
290 #ifdef CONFIG_SMP
291         unsigned long flags;
292         u32 high32, low32;
293         int dest, rte_index;
294         char *addr;
295         int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0;
296         ia64_vector vec;
297
298         irq &= (~IA64_IRQ_REDIRECTED);
299         vec = irq_to_vector(irq);
300
301         if (cpus_empty(mask))
302                 return;
303
304         dest = cpu_physical_id(first_cpu(mask));
305
306         rte_index = iosapic_intr_info[vec].rte_index;
307         addr = iosapic_intr_info[vec].addr;
308
309         if (rte_index < 0)
310                 return;                 /* not an IOSAPIC interrupt */
311
312         set_irq_affinity_info(irq, dest, redir);
313
314         /* dest contains both id and eid */
315         high32 = dest << IOSAPIC_DEST_SHIFT;
316
317         spin_lock_irqsave(&iosapic_lock, flags);
318         {
319                 low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT);
320
321                 if (redir)
322                         /* change delivery mode to lowest priority */
323                         low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT);
324                 else
325                         /* change delivery mode to fixed */
326                         low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
327
328                 iosapic_intr_info[vec].low32 = low32;
329                 writel(IOSAPIC_RTE_HIGH(rte_index), addr + IOSAPIC_REG_SELECT);
330                 writel(high32, addr + IOSAPIC_WINDOW);
331                 writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
332                 writel(low32, addr + IOSAPIC_WINDOW);
333         }
334         spin_unlock_irqrestore(&iosapic_lock, flags);
335 #endif
336 }
337
338 static inline void move_irq(int irq)
339 {
340         /* note - we hold desc->lock */
341         cpumask_t tmp;
342         irq_desc_t *desc = irq_descp(irq);
343
344         if (!cpus_empty(pending_irq_cpumask[irq])) {
345                 cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map);
346                 if (unlikely(!cpus_empty(tmp))) {
347                         desc->handler->set_affinity(irq, pending_irq_cpumask[irq]);
348                 }
349                 cpus_clear(pending_irq_cpumask[irq]);
350         }
351 }
352
353 /*
354  * Handlers for level-triggered interrupts.
355  */
356
357 static unsigned int
358 iosapic_startup_level_irq (unsigned int irq)
359 {
360         unmask_irq(irq);
361         return 0;
362 }
363
364 static void
365 iosapic_end_level_irq (unsigned int irq)
366 {
367         ia64_vector vec = irq_to_vector(irq);
368
369         move_irq(irq);
370         writel(vec, iosapic_intr_info[vec].addr + IOSAPIC_EOI);
371 }
372
373 #define iosapic_shutdown_level_irq      mask_irq
374 #define iosapic_enable_level_irq        unmask_irq
375 #define iosapic_disable_level_irq       mask_irq
376 #define iosapic_ack_level_irq           nop
377
378 struct hw_interrupt_type irq_type_iosapic_level = {
379         .typename =     "IO-SAPIC-level",
380         .startup =      iosapic_startup_level_irq,
381         .shutdown =     iosapic_shutdown_level_irq,
382         .enable =       iosapic_enable_level_irq,
383         .disable =      iosapic_disable_level_irq,
384         .ack =          iosapic_ack_level_irq,
385         .end =          iosapic_end_level_irq,
386         .set_affinity = iosapic_set_affinity
387 };
388
389 /*
390  * Handlers for edge-triggered interrupts.
391  */
392
393 static unsigned int
394 iosapic_startup_edge_irq (unsigned int irq)
395 {
396         unmask_irq(irq);
397         /*
398          * IOSAPIC simply drops interrupts pended while the
399          * corresponding pin was masked, so we can't know if an
400          * interrupt is pending already.  Let's hope not...
401          */
402         return 0;
403 }
404
405 static void
406 iosapic_ack_edge_irq (unsigned int irq)
407 {
408         irq_desc_t *idesc = irq_descp(irq);
409
410         move_irq(irq);
411         /*
412          * Once we have recorded IRQ_PENDING already, we can mask the
413          * interrupt for real. This prevents IRQ storms from unhandled
414          * devices.
415          */
416         if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED))
417                 mask_irq(irq);
418 }
419
420 #define iosapic_enable_edge_irq         unmask_irq
421 #define iosapic_disable_edge_irq        nop
422 #define iosapic_end_edge_irq            nop
423
424 struct hw_interrupt_type irq_type_iosapic_edge = {
425         .typename =     "IO-SAPIC-edge",
426         .startup =      iosapic_startup_edge_irq,
427         .shutdown =     iosapic_disable_edge_irq,
428         .enable =       iosapic_enable_edge_irq,
429         .disable =      iosapic_disable_edge_irq,
430         .ack =          iosapic_ack_edge_irq,
431         .end =          iosapic_end_edge_irq,
432         .set_affinity = iosapic_set_affinity
433 };
434
435 unsigned int
436 iosapic_version (char *addr)
437 {
438         /*
439          * IOSAPIC Version Register return 32 bit structure like:
440          * {
441          *      unsigned int version   : 8;
442          *      unsigned int reserved1 : 8;
443          *      unsigned int max_redir : 8;
444          *      unsigned int reserved2 : 8;
445          * }
446          */
447         writel(IOSAPIC_VERSION, addr + IOSAPIC_REG_SELECT);
448         return readl(IOSAPIC_WINDOW + addr);
449 }
450
451 /*
452  * if the given vector is already owned by other,
453  *  assign a new vector for the other and make the vector available
454  */
455 static void __init
456 iosapic_reassign_vector (int vector)
457 {
458         int new_vector;
459
460         if (iosapic_intr_info[vector].rte_index >= 0 || iosapic_intr_info[vector].addr
461             || iosapic_intr_info[vector].gsi_base || iosapic_intr_info[vector].dmode
462             || iosapic_intr_info[vector].polarity || iosapic_intr_info[vector].trigger)
463         {
464                 new_vector = assign_irq_vector(AUTO_ASSIGN);
465                 printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector);
466                 memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
467                        sizeof(struct iosapic_intr_info));
468                 memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
469                 iosapic_intr_info[vector].rte_index = -1;
470         }
471 }
472
473 static void
474 register_intr (unsigned int gsi, int vector, unsigned char delivery,
475                unsigned long polarity, unsigned long trigger)
476 {
477         irq_desc_t *idesc;
478         struct hw_interrupt_type *irq_type;
479         int rte_index;
480         int index;
481         unsigned long gsi_base;
482         char *iosapic_address;
483
484         index = find_iosapic(gsi);
485         if (index < 0) {
486                 printk(KERN_WARNING "%s: No IOSAPIC for GSI 0x%x\n", __FUNCTION__, gsi);
487                 return;
488         }
489
490         iosapic_address = iosapic_lists[index].addr;
491         gsi_base = iosapic_lists[index].gsi_base;
492
493         rte_index = gsi - gsi_base;
494         iosapic_intr_info[vector].rte_index = rte_index;
495         iosapic_intr_info[vector].polarity = polarity;
496         iosapic_intr_info[vector].dmode    = delivery;
497         iosapic_intr_info[vector].addr     = iosapic_address;
498         iosapic_intr_info[vector].gsi_base = gsi_base;
499         iosapic_intr_info[vector].trigger  = trigger;
500
501         if (trigger == IOSAPIC_EDGE)
502                 irq_type = &irq_type_iosapic_edge;
503         else
504                 irq_type = &irq_type_iosapic_level;
505
506         idesc = irq_descp(vector);
507         if (idesc->handler != irq_type) {
508                 if (idesc->handler != &no_irq_type)
509                         printk(KERN_WARNING "%s: changing vector %d from %s to %s\n",
510                                __FUNCTION__, vector, idesc->handler->typename, irq_type->typename);
511                 idesc->handler = irq_type;
512         }
513 }
514
515 /*
516  * ACPI can describe IOSAPIC interrupts via static tables and namespace
517  * methods.  This provides an interface to register those interrupts and
518  * program the IOSAPIC RTE.
519  */
520 int
521 iosapic_register_intr (unsigned int gsi,
522                        unsigned long polarity, unsigned long trigger)
523 {
524         int vector;
525         unsigned int dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
526
527         vector = gsi_to_vector(gsi);
528         if (vector < 0)
529                 vector = assign_irq_vector(AUTO_ASSIGN);
530
531         register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
532                       polarity, trigger);
533
534         printk(KERN_INFO "GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
535                gsi, (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
536                (trigger == IOSAPIC_EDGE ? "edge" : "level"), dest, vector);
537
538         /* program the IOSAPIC routing table */
539         set_rte(vector, dest, 0);
540         return vector;
541 }
542
543 /*
544  * ACPI calls this when it finds an entry for a platform interrupt.
545  * Note that the irq_base and IOSAPIC address must be set in iosapic_init().
546  */
547 int __init
548 iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
549                                 int iosapic_vector, u16 eid, u16 id,
550                                 unsigned long polarity, unsigned long trigger)
551 {
552         unsigned char delivery;
553         int vector;
554         unsigned int dest = ((id << 8) | eid) & 0xffff;
555
556         switch (int_type) {
557               case ACPI_INTERRUPT_PMI:
558                 vector = iosapic_vector;
559                 /*
560                  * since PMI vector is alloc'd by FW(ACPI) not by kernel,
561                  * we need to make sure the vector is available
562                  */
563                 iosapic_reassign_vector(vector);
564                 delivery = IOSAPIC_PMI;
565                 break;
566               case ACPI_INTERRUPT_INIT:
567                 vector = assign_irq_vector(AUTO_ASSIGN);
568                 delivery = IOSAPIC_INIT;
569                 break;
570               case ACPI_INTERRUPT_CPEI:
571                 vector = IA64_CPE_VECTOR;
572                 delivery = IOSAPIC_LOWEST_PRIORITY;
573                 break;
574               default:
575                 printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type\n");
576                 return -1;
577         }
578
579         register_intr(gsi, vector, delivery, polarity,
580                       trigger);
581
582         printk(KERN_INFO "PLATFORM int 0x%x: GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
583                int_type, gsi, (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
584                (trigger == IOSAPIC_EDGE ? "edge" : "level"), dest, vector);
585
586         /* program the IOSAPIC routing table */
587         set_rte(vector, dest, 0);
588         return vector;
589 }
590
591
592 /*
593  * ACPI calls this when it finds an entry for a legacy ISA IRQ override.
594  * Note that the gsi_base and IOSAPIC address must be set in iosapic_init().
595  */
596 void __init
597 iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
598                           unsigned long polarity,
599                           unsigned long trigger)
600 {
601         int vector;
602         unsigned int dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
603
604         vector = isa_irq_to_vector(isa_irq);
605
606         register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
607
608         DBG("ISA: IRQ %u -> GSI 0x%x (%s,%s) -> CPU 0x%04x vector %d\n",
609             isa_irq, gsi, polarity == IOSAPIC_POL_HIGH ? "high" : "low",
610             trigger == IOSAPIC_EDGE ? "edge" : "level", dest, vector);
611
612         /* program the IOSAPIC routing table */
613         set_rte(vector, dest, 0);
614 }
615
616 void __init
617 iosapic_system_init (int system_pcat_compat)
618 {
619         int vector;
620
621         for (vector = 0; vector < IA64_NUM_VECTORS; ++vector)
622                 iosapic_intr_info[vector].rte_index = -1;       /* mark as unused */
623
624         pcat_compat = system_pcat_compat;
625         if (pcat_compat) {
626                 /*
627                  * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support
628                  * enabled.
629                  */
630                 printk(KERN_INFO "%s: Disabling PC-AT compatible 8259 interrupts\n", __FUNCTION__);
631                 outb(0xff, 0xA1);
632                 outb(0xff, 0x21);
633         }
634 }
635
636 void __init
637 iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
638 {
639         int num_rte;
640         unsigned int isa_irq, ver;
641         char *addr;
642
643         addr = ioremap(phys_addr, 0);
644         ver = iosapic_version(addr);
645
646         /*
647          * The MAX_REDIR register holds the highest input pin
648          * number (starting from 0).
649          * We add 1 so that we can use it for number of pins (= RTEs)
650          */
651         num_rte = ((ver >> 16) & 0xff) + 1;
652
653         iosapic_lists[num_iosapic].addr = addr;
654         iosapic_lists[num_iosapic].gsi_base = gsi_base;
655         iosapic_lists[num_iosapic].num_rte = num_rte;
656         num_iosapic++;
657
658         if ((gsi_base == 0) && pcat_compat) {
659                 /*
660                  * Map the legacy ISA devices into the IOSAPIC data.  Some of these may
661                  * get reprogrammed later on with data from the ACPI Interrupt Source
662                  * Override table.
663                  */
664                 for (isa_irq = 0; isa_irq < 16; ++isa_irq)
665                         iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
666         }
667 }
668
669 void
670 iosapic_enable_intr (unsigned int vector)
671 {
672         unsigned int dest;
673         irq_desc_t *desc;
674
675         /*
676          * In the case of a shared interrupt, do not re-route the vector, and
677          * especially do not mask a running interrupt (startup will not get
678          * called for a shared interrupt).
679          */
680         desc = irq_descp(vector);
681         if (desc->action)
682                 return;
683
684 #ifdef CONFIG_SMP
685         /*
686          * For platforms that do not support interrupt redirect via the XTP interface, we
687          * can round-robin the PCI device interrupts to the processors
688          */
689         if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) {
690                 static int cpu_index = -1;
691
692                 do
693                         if (++cpu_index >= NR_CPUS)
694                                 cpu_index = 0;
695                 while (!cpu_online(cpu_index));
696
697                 dest = cpu_physical_id(cpu_index) & 0xffff;
698         } else {
699                 /*
700                  * Direct the interrupt vector to the current cpu, platform redirection
701                  * will distribute them.
702                  */
703                 dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
704         }
705 #else
706         /* direct the interrupt vector to the running cpu id */
707         dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
708 #endif
709         set_rte(vector, dest, 1);
710
711         printk(KERN_INFO "IOSAPIC: vector %d -> CPU 0x%04x, enabled\n",
712                vector, dest);
713 }
714
715 #ifdef CONFIG_ACPI_PCI
716
717 void __init
718 iosapic_parse_prt (void)
719 {
720         struct acpi_prt_entry *entry;
721         struct list_head *node;
722         unsigned int gsi;
723         int vector;
724         char pci_id[16];
725         struct hw_interrupt_type *irq_type = &irq_type_iosapic_level;
726         irq_desc_t *idesc;
727
728         list_for_each(node, &acpi_prt.entries) {
729                 entry = list_entry(node, struct acpi_prt_entry, node);
730
731                 /* We're only interested in static (non-link) entries.  */
732                 if (entry->link.handle)
733                         continue;
734
735                 gsi = entry->link.index;
736
737                 vector = gsi_to_vector(gsi);
738                 if (vector < 0) {
739                         if (find_iosapic(gsi) < 0)
740                                 continue;
741
742                         /* allocate a vector for this interrupt line */
743                         if (pcat_compat && (gsi < 16))
744                                 vector = isa_irq_to_vector(gsi);
745                         else
746                                 /* new GSI; allocate a vector for it */
747                                 vector = assign_irq_vector(AUTO_ASSIGN);
748
749                         register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW,
750                                       IOSAPIC_LEVEL);
751                 }
752                 entry->irq = vector;
753                 snprintf(pci_id, sizeof(pci_id), "%02x:%02x:%02x[%c]",
754                          entry->id.segment, entry->id.bus, entry->id.device, 'A' + entry->pin);
755
756                 /*
757                  * If vector was previously initialized to a different
758                  * handler, re-initialize.
759                  */
760                 idesc = irq_descp(vector);
761                 if (idesc->handler != irq_type)
762                         register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW,
763                                       IOSAPIC_LEVEL);
764
765         }
766 }
767
768 #endif /* CONFIG_ACPI */