ia64: Wide IOSAPIC base_irq field to 32 bits. Patch by KOCHI Takayoshi.
[opensuse:kernel.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 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  */
30 /*
31  * Here is what the interrupt logic between a PCI device and the CPU looks like:
32  *
33  * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, INTD).  The
34  *     device is uniquely identified by its bus--, and slot-number (the function
35  *     number does not matter here because all functions share the same interrupt
36  *     lines).
37  *
38  * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC controller.
39  *     Multiple interrupt lines may have to share the same IOSAPIC pin (if they're level
40  *     triggered and use the same polarity).  Each interrupt line has a unique IOSAPIC
41  *     irq number which can be calculated as the sum of the controller's base irq number
42  *     and the IOSAPIC pin number to which the line connects.
43  *
44  * (3) The IOSAPIC uses an internal table to map the IOSAPIC pin into the IA-64 interrupt
45  *     vector.  This interrupt vector is then sent to the CPU.
46  *
47  * In other words, there are two levels of indirections involved:
48  *
49  *      pci pin -> iosapic irq -> IA-64 vector
50  *
51  * Note: outside this module, IA-64 vectors are called "irqs".  This is because that's
52  * the traditional name Linux uses for interrupt vectors.
53  */
54 #include <linux/config.h>
55
56 #include <linux/kernel.h>
57 #include <linux/init.h>
58 #include <linux/pci.h>
59 #include <linux/smp.h>
60 #include <linux/smp_lock.h>
61 #include <linux/string.h>
62 #include <linux/irq.h>
63 #include <linux/acpi.h>
64
65 #include <asm/delay.h>
66 #include <asm/hw_irq.h>
67 #include <asm/io.h>
68 #include <asm/iosapic.h>
69 #include <asm/machvec.h>
70 #include <asm/processor.h>
71 #include <asm/ptrace.h>
72 #include <asm/system.h>
73
74
75 #undef DEBUG_IRQ_ROUTING
76 #undef OVERRIDE_DEBUG
77
78 static spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED;
79
80 /* PCI pin to IOSAPIC irq routing information.  This info typically comes from ACPI. */
81
82 static struct {
83         int num_routes;
84         struct pci_vector_struct *route;
85 } pci_irq;
86
87 /* This tables maps IA-64 vectors to the IOSAPIC pin that generates this vector. */
88
89 static struct iosapic_irq {
90         char *addr;                     /* base address of IOSAPIC */
91         unsigned int base_irq;          /* first irq assigned to this IOSAPIC */
92         char pin;                       /* IOSAPIC pin (-1 => not an IOSAPIC irq) */
93         unsigned char dmode     : 3;    /* delivery mode (see iosapic.h) */
94         unsigned char polarity  : 1;    /* interrupt polarity (see iosapic.h) */
95         unsigned char trigger   : 1;    /* trigger mode (see iosapic.h) */
96 } iosapic_irq[IA64_NUM_VECTORS];
97
98 static struct iosapic {
99         char *addr;                     /* base address of IOSAPIC */
100         unsigned int    base_irq;       /* first irq assigned to this IOSAPIC */
101         unsigned short  max_pin;        /* max input pin supported in this IOSAPIC */
102         unsigned char   pcat_compat;    /* 8259 compatibility flag */
103 } iosapic_lists[256] __initdata;
104
105 static int num_iosapic = 0;
106
107
108 /*
109  * Find an IOSAPIC associated with an IRQ
110  */
111 static inline int __init
112 find_iosapic (unsigned int irq)
113 {
114         int i;
115
116         for (i = 0; i < num_iosapic; i++) {
117                 if ((unsigned) (irq - iosapic_lists[i].base_irq) <= iosapic_lists[i].max_pin)
118                         return i;
119         }
120
121         return -1;
122 }
123
124 /*
125  * Translate IOSAPIC irq number to the corresponding IA-64 interrupt vector.  If no
126  * entry exists, return -1.
127  */
128 static int
129 iosapic_irq_to_vector (int irq)
130 {
131         int vector;
132
133         for (vector = 0; vector < IA64_NUM_VECTORS; ++vector)
134                 if (iosapic_irq[vector].base_irq + iosapic_irq[vector].pin == irq)
135                         return vector;
136         return -1;
137 }
138
139 /*
140  * Map PCI pin to the corresponding IA-64 interrupt vector.  If no such mapping exists,
141  * return -1.
142  */
143 int
144 pci_pin_to_vector (int bus, int slot, int pci_pin)
145 {
146         struct pci_vector_struct *r;
147
148         for (r = pci_irq.route; r < pci_irq.route + pci_irq.num_routes; ++r)
149                 if (r->bus == bus && (r->pci_id >> 16) == slot && r->pin == pci_pin)
150                         return iosapic_irq_to_vector(r->irq);
151         return -1;
152 }
153
154 static void
155 set_rte (unsigned int vector, unsigned long dest)
156 {
157         unsigned long pol, trigger, dmode;
158         u32 low32, high32;
159         char *addr;
160         int pin;
161         char redir;
162
163         pin = iosapic_irq[vector].pin;
164         if (pin < 0)
165                 return;         /* not an IOSAPIC interrupt */
166
167         addr    = iosapic_irq[vector].addr;
168         pol     = iosapic_irq[vector].polarity;
169         trigger = iosapic_irq[vector].trigger;
170         dmode   = iosapic_irq[vector].dmode;
171
172         redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0;
173 #ifdef CONFIG_SMP
174         set_irq_affinity_info(vector, (int)(dest & 0xffff), redir);
175 #endif
176
177         low32 = ((pol << IOSAPIC_POLARITY_SHIFT) |
178                  (trigger << IOSAPIC_TRIGGER_SHIFT) |
179                  (dmode << IOSAPIC_DELIVERY_SHIFT) |
180                  vector);
181
182         /* dest contains both id and eid */
183         high32 = (dest << IOSAPIC_DEST_SHIFT);
184
185         writel(IOSAPIC_RTE_HIGH(pin), addr + IOSAPIC_REG_SELECT);
186         writel(high32, addr + IOSAPIC_WINDOW);
187         writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT);
188         writel(low32, addr + IOSAPIC_WINDOW);
189 }
190
191 static void
192 nop (unsigned int vector)
193 {
194         /* do nothing... */
195 }
196
197 static void
198 mask_irq (unsigned int irq)
199 {
200         unsigned long flags;
201         char *addr;
202         u32 low32;
203         int pin;
204         ia64_vector vec = irq_to_vector(irq);
205
206         addr = iosapic_irq[vec].addr;
207         pin = iosapic_irq[vec].pin;
208
209         if (pin < 0)
210                 return;                 /* not an IOSAPIC interrupt! */
211
212         spin_lock_irqsave(&iosapic_lock, flags);
213         {
214                 writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT);
215                 low32 = readl(addr + IOSAPIC_WINDOW);
216
217                 low32 |= (1 << IOSAPIC_MASK_SHIFT);    /* set only the mask bit */
218                 writel(low32, addr + IOSAPIC_WINDOW);
219         }
220         spin_unlock_irqrestore(&iosapic_lock, flags);
221 }
222
223 static void
224 unmask_irq (unsigned int irq)
225 {
226         unsigned long flags;
227         char *addr;
228         u32 low32;
229         int pin;
230         ia64_vector vec = irq_to_vector(irq);
231
232         addr = iosapic_irq[vec].addr;
233         pin = iosapic_irq[vec].pin;
234         if (pin < 0)
235                 return;                 /* not an IOSAPIC interrupt! */
236
237         spin_lock_irqsave(&iosapic_lock, flags);
238         {
239                 writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT);
240                 low32 = readl(addr + IOSAPIC_WINDOW);
241
242                 low32 &= ~(1 << IOSAPIC_MASK_SHIFT);    /* clear only the mask bit */
243                 writel(low32, addr + IOSAPIC_WINDOW);
244         }
245         spin_unlock_irqrestore(&iosapic_lock, flags);
246 }
247
248
249 static void
250 iosapic_set_affinity (unsigned int irq, unsigned long mask)
251 {
252 #ifdef CONFIG_SMP
253         unsigned long flags;
254         u32 high32, low32;
255         int dest, pin;
256         char *addr;
257         int redir = (irq & (1<<31)) ? 1 : 0;
258
259         mask &= (1UL << smp_num_cpus) - 1;
260
261         if (!mask || irq >= IA64_NUM_VECTORS)
262                 return;
263
264         dest = cpu_physical_id(ffz(~mask));
265
266         pin = iosapic_irq[irq].pin;
267         addr = iosapic_irq[irq].addr;
268
269         if (pin < 0)
270                 return;                 /* not an IOSAPIC interrupt */
271
272         set_irq_affinity_info(irq,dest,redir);
273
274         /* dest contains both id and eid */
275         high32 = dest << IOSAPIC_DEST_SHIFT;
276
277         spin_lock_irqsave(&iosapic_lock, flags);
278         {
279                 /* get current delivery mode by reading the low32 */
280                 writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT);
281                 low32 = readl(addr + IOSAPIC_WINDOW);
282
283                 low32 &= ~(7 << IOSAPIC_DELIVERY_SHIFT);
284                 if (redir)
285                         /* change delivery mode to lowest priority */
286                         low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT);
287                 else
288                         /* change delivery mode to fixed */
289                         low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
290
291                 writel(IOSAPIC_RTE_HIGH(pin), addr + IOSAPIC_REG_SELECT);
292                 writel(high32, addr + IOSAPIC_WINDOW);
293                 writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT);
294                 writel(low32, addr + IOSAPIC_WINDOW);
295         }
296         spin_unlock_irqrestore(&iosapic_lock, flags);
297 #endif
298 }
299
300 /*
301  * Handlers for level-triggered interrupts.
302  */
303
304 static unsigned int
305 iosapic_startup_level_irq (unsigned int irq)
306 {
307         unmask_irq(irq);
308         return 0;
309 }
310
311 static void
312 iosapic_end_level_irq (unsigned int irq)
313 {
314         ia64_vector vec = irq_to_vector(irq);
315
316         writel(vec, iosapic_irq[vec].addr + IOSAPIC_EOI);
317 }
318
319 #define iosapic_shutdown_level_irq      mask_irq
320 #define iosapic_enable_level_irq        unmask_irq
321 #define iosapic_disable_level_irq       mask_irq
322 #define iosapic_ack_level_irq           nop
323
324 struct hw_interrupt_type irq_type_iosapic_level = {
325         typename:       "IO-SAPIC-level",
326         startup:        iosapic_startup_level_irq,
327         shutdown:       iosapic_shutdown_level_irq,
328         enable:         iosapic_enable_level_irq,
329         disable:        iosapic_disable_level_irq,
330         ack:            iosapic_ack_level_irq,
331         end:            iosapic_end_level_irq,
332         set_affinity:   iosapic_set_affinity
333 };
334
335 /*
336  * Handlers for edge-triggered interrupts.
337  */
338
339 static unsigned int
340 iosapic_startup_edge_irq (unsigned int irq)
341 {
342         unmask_irq(irq);
343         /*
344          * IOSAPIC simply drops interrupts pended while the
345          * corresponding pin was masked, so we can't know if an
346          * interrupt is pending already.  Let's hope not...
347          */
348         return 0;
349 }
350
351 static void
352 iosapic_ack_edge_irq (unsigned int irq)
353 {
354         irq_desc_t *idesc = irq_desc(irq);
355         /*
356          * Once we have recorded IRQ_PENDING already, we can mask the
357          * interrupt for real. This prevents IRQ storms from unhandled
358          * devices.
359          */
360         if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED))
361                 mask_irq(irq);
362 }
363
364 #define iosapic_enable_edge_irq         unmask_irq
365 #define iosapic_disable_edge_irq        nop
366 #define iosapic_end_edge_irq            nop
367
368 struct hw_interrupt_type irq_type_iosapic_edge = {
369         typename:       "IO-SAPIC-edge",
370         startup:        iosapic_startup_edge_irq,
371         shutdown:       iosapic_disable_edge_irq,
372         enable:         iosapic_enable_edge_irq,
373         disable:        iosapic_disable_edge_irq,
374         ack:            iosapic_ack_edge_irq,
375         end:            iosapic_end_edge_irq,
376         set_affinity:   iosapic_set_affinity
377 };
378
379 unsigned int
380 iosapic_version (char *addr)
381 {
382         /*
383          * IOSAPIC Version Register return 32 bit structure like:
384          * {
385          *      unsigned int version   : 8;
386          *      unsigned int reserved1 : 8;
387          *      unsigned int pins      : 8;
388          *      unsigned int reserved2 : 8;
389          * }
390          */
391         writel(IOSAPIC_VERSION, addr + IOSAPIC_REG_SELECT);
392         return readl(IOSAPIC_WINDOW + addr);
393 }
394
395 /*
396  * if the given vector is already owned by other,
397  *  assign a new vector for the other and make the vector available
398  */
399 static void
400 iosapic_reassign_vector (int vector)
401 {
402         int new_vector;
403
404         if (iosapic_irq[vector].pin >= 0 || iosapic_irq[vector].addr
405             || iosapic_irq[vector].base_irq || iosapic_irq[vector].dmode
406             || iosapic_irq[vector].polarity || iosapic_irq[vector].trigger)
407         {
408                 new_vector = ia64_alloc_irq();
409                 printk("Reassigning Vector 0x%x to 0x%x\n", vector, new_vector);
410                 memcpy (&iosapic_irq[new_vector], &iosapic_irq[vector],
411                         sizeof(struct iosapic_irq));
412                 memset (&iosapic_irq[vector], 0, sizeof(struct iosapic_irq));
413                 iosapic_irq[vector].pin = -1;
414         }
415 }
416
417 static void
418 register_irq (u32 global_vector, int vector, int pin, unsigned char delivery,
419               unsigned long polarity, unsigned long edge_triggered,
420               u32 base_irq, char *iosapic_address)
421 {
422         irq_desc_t *idesc;
423         struct hw_interrupt_type *irq_type;
424
425         iosapic_irq[vector].pin = pin;
426         iosapic_irq[vector].polarity = polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW;
427         iosapic_irq[vector].dmode    = delivery;
428
429         /*
430          * In override, it does not provide addr/base_irq.  global_vector is enough to
431          * locate iosapic addr, base_irq and pin by examining base_irq and max_pin of
432          * registered iosapics (tbd)
433          */
434 #ifndef OVERRIDE_DEBUG
435         if (iosapic_address) {
436                 iosapic_irq[vector].addr = iosapic_address;
437                 iosapic_irq[vector].base_irq = base_irq;
438         }
439 #else
440         if (iosapic_address) {
441                 if (iosapic_irq[vector].addr && (iosapic_irq[vector].addr != iosapic_address))
442                         printk("WARN: register_irq: diff IOSAPIC ADDRESS for gv %x, v %x\n",
443                                global_vector, vector);
444                 iosapic_irq[vector].addr = iosapic_address;
445                 if (iosapic_irq[vector].base_irq && (iosapic_irq[vector].base_irq != base_irq)) {
446                         printk("WARN: register_irq: diff BASE IRQ %x for gv %x, v %x\n",
447                                base_irq, global_vector, vector);
448                 }
449                 iosapic_irq[vector].base_irq = base_irq;
450         } else if (!iosapic_irq[vector].addr)
451                 printk("WARN: register_irq: invalid override for gv %x, v %x\n",
452                        global_vector, vector);
453 #endif
454         if (edge_triggered) {
455                 iosapic_irq[vector].trigger = IOSAPIC_EDGE;
456                 irq_type = &irq_type_iosapic_edge;
457         } else {
458                 iosapic_irq[vector].trigger = IOSAPIC_LEVEL;
459                 irq_type = &irq_type_iosapic_level;
460         }
461
462         idesc = irq_desc(vector);
463         if (idesc->handler != irq_type) {
464                 if (idesc->handler != &no_irq_type)
465                         printk("register_irq(): changing vector 0x%02x from "
466                                "%s to %s\n", vector, idesc->handler->typename, irq_type->typename);
467                 idesc->handler = irq_type;
468         }
469 }
470
471 /*
472  * ACPI can describe IOSAPIC interrupts via static tables and namespace
473  * methods.  This provides an interface to register those interrupts and
474  * program the IOSAPIC RTE.
475  */
476 int
477 iosapic_register_irq (u32 global_vector, unsigned long polarity, unsigned long
478                       edge_triggered, u32 base_irq, char *iosapic_address)
479 {
480         int vector;
481
482         vector = iosapic_irq_to_vector(global_vector);
483         if (vector < 0)
484                 vector = ia64_alloc_irq();
485
486         register_irq (global_vector, vector, global_vector - base_irq,
487                         IOSAPIC_LOWEST_PRIORITY, polarity, edge_triggered,
488                         base_irq, iosapic_address);
489
490         printk("IOSAPIC 0x%x(%s,%s) -> Vector 0x%x\n", global_vector,
491                (polarity ? "high" : "low"), (edge_triggered ? "edge" : "level"), vector);
492
493         /* program the IOSAPIC routing table */
494         set_rte(vector, (ia64_get_lid() >> 16) & 0xffff);
495         return vector;
496 }
497
498 /*
499  * ACPI calls this when it finds an entry for a platform interrupt.
500  * Note that the irq_base and IOSAPIC address must be set in iosapic_init().
501  */
502 int
503 iosapic_register_platform_irq (u32 int_type, u32 global_vector,
504                                u32 iosapic_vector, u16 eid, u16 id, unsigned long polarity,
505                                unsigned long edge_triggered, u32 base_irq, char *iosapic_address)
506 {
507         unsigned char delivery;
508         int vector;
509
510         switch (int_type) {
511               case ACPI_INTERRUPT_PMI:
512                 vector = iosapic_vector;
513                 /*
514                  * since PMI vector is alloc'd by FW(ACPI) not by kernel,
515                  * we need to make sure the vector is available
516                  */
517                 iosapic_reassign_vector(vector);
518                 delivery = IOSAPIC_PMI;
519                 break;
520               case ACPI_INTERRUPT_INIT:
521                 vector = ia64_alloc_irq();
522                 delivery = IOSAPIC_INIT;
523                 break;
524               case ACPI_INTERRUPT_CPEI:
525                 vector = IA64_PCE_VECTOR;
526                 delivery = IOSAPIC_LOWEST_PRIORITY;
527                 break;
528               default:
529                 printk("iosapic_register_platform_irq(): invalid int type\n");
530                 return -1;
531         }
532
533         register_irq(global_vector, vector, global_vector - base_irq, delivery, polarity,
534                      edge_triggered, base_irq, iosapic_address);
535
536         printk("PLATFORM int 0x%x: IOSAPIC 0x%x(%s,%s) -> Vector 0x%x CPU %.02u:%.02u\n",
537                int_type, global_vector, (polarity ? "high" : "low"),
538                (edge_triggered ? "edge" : "level"), vector, eid, id);
539
540         /* program the IOSAPIC routing table */
541         set_rte(vector, ((id << 8) | eid) & 0xffff);
542         return vector;
543 }
544
545
546 /*
547  * ACPI calls this when it finds an entry for a legacy ISA interrupt.
548  * Note that the irq_base and IOSAPIC address must be set in iosapic_init().
549  */
550 void
551 iosapic_register_legacy_irq (unsigned long irq,
552                              unsigned long pin, unsigned long polarity,
553                              unsigned long edge_triggered)
554 {
555         int vector = isa_irq_to_vector(irq);
556
557         register_irq(irq, vector, (int)pin, IOSAPIC_LOWEST_PRIORITY, polarity, edge_triggered,
558                      0, NULL);          /* ignored for override */
559
560 #ifdef DEBUG_IRQ_ROUTING
561         printk("ISA: IRQ %u -> IOSAPIC irq 0x%02x (%s, %s) -> vector %02x\n",
562                (unsigned) irq, (unsigned) pin,
563                polarity ? "high" : "low", edge_triggered ? "edge" : "level",
564                vector);
565 #endif
566
567         /* program the IOSAPIC routing table */
568         set_rte(vector, (ia64_get_lid() >> 16) & 0xffff);
569 }
570
571 void __init
572 iosapic_init (unsigned long phys_addr, unsigned int base_irq, int pcat_compat)
573 {
574         int irq, max_pin, vector, pin;
575         unsigned int ver;
576         char *addr;
577         static int first_time = 1;
578
579         if (first_time) {
580                 first_time = 0;
581                 for (vector = 0; vector < IA64_NUM_VECTORS; ++vector)
582                         iosapic_irq[vector].pin = -1;   /* mark as unused */
583         }
584
585         if (pcat_compat) {
586                 /*
587                  * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support
588                  * enabled.
589                  */
590                 printk("%s: Disabling PC-AT compatible 8259 interrupts\n", __FUNCTION__);
591                 outb(0xff, 0xA1);
592                 outb(0xff, 0x21);
593         }
594
595         addr = ioremap(phys_addr, 0);
596         ver = iosapic_version(addr);
597         max_pin = (ver >> 16) & 0xff;
598
599         iosapic_lists[num_iosapic].addr = addr;
600         iosapic_lists[num_iosapic].pcat_compat = pcat_compat;
601         iosapic_lists[num_iosapic].base_irq = base_irq;
602         iosapic_lists[num_iosapic].max_pin = max_pin;
603         num_iosapic++;
604
605         printk("IOSAPIC: version %x.%x, address 0x%lx, IRQs 0x%02x-0x%02x\n",
606                (ver & 0xf0) >> 4, (ver & 0x0f), phys_addr, base_irq, base_irq + max_pin);
607
608         if ((base_irq == 0) && pcat_compat) {
609                 /*
610                  * Map the legacy ISA devices into the IOSAPIC data.  Some of these may
611                  * get reprogrammed later on with data from the ACPI Interrupt Source
612                  * Override table.
613                  */
614                 for (irq = 0; irq < 16; ++irq) {
615                         vector = isa_irq_to_vector(irq);
616                         if ((pin = iosapic_irq[vector].pin) == -1)
617                                 pin = irq;
618
619                         register_irq(irq, vector, pin,
620                                      /* IOSAPIC_POL_HIGH, IOSAPIC_EDGE */
621                                      IOSAPIC_LOWEST_PRIORITY, 1, 1, base_irq, addr);
622
623 #ifdef DEBUG_IRQ_ROUTING
624                         printk("ISA: IRQ %u -> IOSAPIC irq 0x%02x (high, edge) -> vector 0x%02x\n",
625                                irq, iosapic_irq[vector].base_irq + iosapic_irq[vector].pin,
626                                vector);
627 #endif
628
629                         /* program the IOSAPIC routing table: */
630                         set_rte(vector, (ia64_get_lid() >> 16) & 0xffff);
631                 }
632         }
633 }
634
635 static void __init
636 iosapic_init_pci_irq (void)
637 {
638         int i, index, vector, pin;
639         int base_irq, max_pin, pcat_compat;
640         unsigned int irq;
641         char *addr;
642
643         if (0 != acpi_get_prt(&pci_irq.route, &pci_irq.num_routes))
644                 return;
645
646         for (i = 0; i < pci_irq.num_routes; i++) {
647
648                 irq = pci_irq.route[i].irq;
649
650                 index = find_iosapic(irq);
651                 if (index < 0) {
652                         printk("PCI: IRQ %u has no IOSAPIC mapping\n", irq);
653                         continue;
654                 }
655
656                 addr = iosapic_lists[index].addr;
657                 base_irq = iosapic_lists[index].base_irq;
658                 max_pin = iosapic_lists[index].max_pin;
659                 pcat_compat = iosapic_lists[index].pcat_compat;
660                 pin = irq - base_irq;
661
662                 if ((unsigned) pin > max_pin)
663                         /* the interrupt route is for another controller... */
664                         continue;
665
666                 if (pcat_compat && (irq < 16))
667                         vector = isa_irq_to_vector(irq);
668                 else {
669                         vector = iosapic_irq_to_vector(irq);
670                         if (vector < 0)
671                                 /* new iosapic irq: allocate a vector for it */
672                                 vector = ia64_alloc_irq();
673                 }
674
675                 register_irq(irq, vector, pin, IOSAPIC_LOWEST_PRIORITY, 0, 0, base_irq, addr);
676
677 #ifdef DEBUG_IRQ_ROUTING
678                 printk("PCI: (B%d,I%d,P%d) -> IOSAPIC irq 0x%02x -> vector 0x%02x\n",
679                        pci_irq.route[i].bus, pci_irq.route[i].pci_id>>16, pci_irq.route[i].pin,
680                        iosapic_irq[vector].base_irq + iosapic_irq[vector].pin, vector);
681 #endif
682
683                 /*
684                  * Forget not to program the IOSAPIC RTE per ACPI _PRT
685                  */
686                 set_rte(vector, (ia64_get_lid() >> 16) & 0xffff);
687         }
688 }
689
690 void
691 iosapic_pci_fixup (int phase)
692 {
693         struct  pci_dev *dev;
694         unsigned char pin;
695         int vector;
696         struct hw_interrupt_type *irq_type;
697         irq_desc_t *idesc;
698
699         if (phase == 0) {
700                 iosapic_init_pci_irq();
701                 return;
702         }
703
704         if (phase != 1)
705                 return;
706
707         pci_for_each_dev(dev) {
708                 pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
709                 if (pin) {
710                         pin--;          /* interrupt pins are numbered starting from 1 */
711                         vector = pci_pin_to_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
712                         if (vector < 0 && dev->bus->parent) {
713                                 /* go back to the bridge */
714                                 struct pci_dev *bridge = dev->bus->self;
715
716                                 if (bridge) {
717                                         /* allow for multiple bridges on an adapter */
718                                         do {
719                                                 /* do the bridge swizzle... */
720                                                 pin = (pin + PCI_SLOT(dev->devfn)) % 4;
721                                                 vector = pci_pin_to_vector(bridge->bus->number,
722                                                                            PCI_SLOT(bridge->devfn),
723                                                                            pin);
724                                         } while (vector < 0 && (bridge = bridge->bus->self));
725                                 }
726                                 if (vector >= 0)
727                                         printk(KERN_WARNING
728                                                "PCI: using PPB(B%d,I%d,P%d) to get vector %02x\n",
729                                                dev->bus->number, PCI_SLOT(dev->devfn),
730                                                pin, vector);
731                                 else
732                                         printk(KERN_WARNING
733                                                "PCI: Couldn't map irq for (B%d,I%d,P%d)\n",
734                                                dev->bus->number, PCI_SLOT(dev->devfn), pin);
735                         }
736                         if (vector >= 0) {
737                                 printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> 0x%02x\n",
738                                        dev->bus->number, PCI_SLOT(dev->devfn), pin, vector);
739                                 dev->irq = vector;
740
741                                 irq_type = &irq_type_iosapic_level;
742                                 idesc = irq_desc(vector);
743                                 if (idesc->handler != irq_type) {
744                                         if (idesc->handler != &no_irq_type)
745                                                 printk("iosapic_pci_fixup: changing vector 0x%02x "
746                                                        "from %s to %s\n", vector,
747                                                        idesc->handler->typename,
748                                                        irq_type->typename);
749                                         idesc->handler = irq_type;
750                                 }
751 #ifdef CONFIG_SMP
752                                 /*
753                                  * For platforms that do not support interrupt redirect
754                                  * via the XTP interface, we can round-robin the PCI
755                                  * device interrupts to the processors
756                                  */
757                                 if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) {
758                                         static int cpu_index = 0;
759
760                                         set_rte(vector, cpu_physical_id(cpu_index) & 0xffff);
761
762                                         cpu_index++;
763                                         if (cpu_index >= smp_num_cpus)
764                                                 cpu_index = 0;
765                                 } else {
766                                         /*
767                                          * Direct the interrupt vector to the current cpu,
768                                          * platform redirection will distribute them.
769                                          */
770                                         set_rte(vector, (ia64_get_lid() >> 16) & 0xffff);
771                                 }
772 #else
773                                 /* direct the interrupt vector to the running cpu id */
774                                 set_rte(vector, (ia64_get_lid() >> 16) & 0xffff);
775 #endif
776                         }
777                 }
778                 /*
779                  * Nothing to fixup
780                  * Fix out-of-range IRQ numbers
781                  */
782                 if (dev->irq >= IA64_NUM_VECTORS)
783                         dev->irq = 15;  /* Spurious interrupts */
784         }
785 }