diff options
-rw-r--r-- | arch/ia64/kernel/iosapic.c | 260 |
1 files changed, 161 insertions, 99 deletions
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 8832c553230a..22d845f85366 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c | |||
@@ -9,54 +9,65 @@ | |||
9 | * Copyright (C) 1999 VA Linux Systems | 9 | * Copyright (C) 1999 VA Linux Systems |
10 | * Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com> | 10 | * Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com> |
11 | * | 11 | * |
12 | * 00/04/19 D. Mosberger Rewritten to mirror more closely the x86 I/O APIC code. | 12 | * 00/04/19 D. Mosberger Rewritten to mirror more closely the x86 I/O |
13 | * In particular, we now have separate handlers for edge | 13 | * APIC code. In particular, we now have separate |
14 | * and level triggered interrupts. | 14 | * handlers for edge and level triggered |
15 | * 00/10/27 Asit Mallick, Goutham Rao <goutham.rao@intel.com> IRQ vector allocation | 15 | * interrupts. |
16 | * PCI to vector mapping, shared PCI interrupts. | 16 | * 00/10/27 Asit Mallick, Goutham Rao <goutham.rao@intel.com> IRQ vector |
17 | * 00/10/27 D. Mosberger Document things a bit more to make them more understandable. | 17 | * allocation PCI to vector mapping, shared PCI |
18 | * Clean up much of the old IOSAPIC cruft. | 18 | * interrupts. |
19 | * 01/07/27 J.I. Lee PCI irq routing, Platform/Legacy interrupts and fixes for | 19 | * 00/10/27 D. Mosberger Document things a bit more to make them more |
20 | * ACPI S5(SoftOff) support. | 20 | * understandable. Clean up much of the old |
21 | * IOSAPIC cruft. | ||
22 | * 01/07/27 J.I. Lee PCI irq routing, Platform/Legacy interrupts | ||
23 | * and fixes for ACPI S5(SoftOff) support. | ||
21 | * 02/01/23 J.I. Lee iosapic pgm fixes for PCI irq routing from _PRT | 24 | * 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 | 25 | * 02/01/07 E. Focht <efocht@ess.nec.de> Redirectable interrupt |
23 | * iosapic_set_affinity(), initializations for | 26 | * vectors in iosapic_set_affinity(), |
24 | * /proc/irq/#/smp_affinity | 27 | * initializations for /proc/irq/#/smp_affinity |
25 | * 02/04/02 P. Diefenbaugh Cleaned up ACPI PCI IRQ routing. | 28 | * 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 | 29 | * 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 | 30 | * 02/04/30 J.I. Lee bug fix in find_iosapic to fix ACPI PCI IRQ to |
28 | * error | 31 | * IOSAPIC mapping error |
29 | * 02/07/29 T. Kochi Allocate interrupt vectors dynamically | 32 | * 02/07/29 T. Kochi Allocate interrupt vectors dynamically |
30 | * 02/08/04 T. Kochi Cleaned up terminology (irq, global system interrupt, vector, etc.) | 33 | * 02/08/04 T. Kochi Cleaned up terminology (irq, global system |
31 | * 02/09/20 D. Mosberger Simplified by taking advantage of ACPI's pci_irq code. | 34 | * interrupt, vector, etc.) |
35 | * 02/09/20 D. Mosberger Simplified by taking advantage of ACPI's | ||
36 | * pci_irq code. | ||
32 | * 03/02/19 B. Helgaas Make pcat_compat system-wide, not per-IOSAPIC. | 37 | * 03/02/19 B. Helgaas Make pcat_compat system-wide, not per-IOSAPIC. |
33 | * Remove iosapic_address & gsi_base from external interfaces. | 38 | * Remove iosapic_address & gsi_base from |
34 | * Rationalize __init/__devinit attributes. | 39 | * external interfaces. Rationalize |
40 | * __init/__devinit attributes. | ||
35 | * 04/12/04 Ashok Raj <ashok.raj@intel.com> Intel Corporation 2004 | 41 | * 04/12/04 Ashok Raj <ashok.raj@intel.com> Intel Corporation 2004 |
36 | * Updated to work with irq migration necessary for CPU Hotplug | 42 | * Updated to work with irq migration necessary |
43 | * for CPU Hotplug | ||
37 | */ | 44 | */ |
38 | /* | 45 | /* |
39 | * Here is what the interrupt logic between a PCI device and the kernel looks like: | 46 | * Here is what the interrupt logic between a PCI device and the kernel looks |
47 | * like: | ||
40 | * | 48 | * |
41 | * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, INTD). The | 49 | * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, |
42 | * device is uniquely identified by its bus--, and slot-number (the function | 50 | * INTD). The device is uniquely identified by its bus-, and slot-number |
43 | * number does not matter here because all functions share the same interrupt | 51 | * (the function number does not matter here because all functions share |
44 | * lines). | 52 | * the same interrupt lines). |
45 | * | 53 | * |
46 | * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC controller. | 54 | * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC |
47 | * Multiple interrupt lines may have to share the same IOSAPIC pin (if they're level | 55 | * controller. Multiple interrupt lines may have to share the same |
48 | * triggered and use the same polarity). Each interrupt line has a unique Global | 56 | * IOSAPIC pin (if they're level triggered and use the same polarity). |
49 | * System Interrupt (GSI) number which can be calculated as the sum of the controller's | 57 | * Each interrupt line has a unique Global System Interrupt (GSI) number |
50 | * base GSI number and the IOSAPIC pin number to which the line connects. | 58 | * which can be calculated as the sum of the controller's base GSI number |
59 | * and the IOSAPIC pin number to which the line connects. | ||
51 | * | 60 | * |
52 | * (3) The IOSAPIC uses an internal routing table entries (RTEs) to map the IOSAPIC pin | 61 | * (3) The IOSAPIC uses an internal routing table entries (RTEs) to map the |
53 | * into the IA-64 interrupt vector. This interrupt vector is then sent to the CPU. | 62 | * IOSAPIC pin into the IA-64 interrupt vector. This interrupt vector is then |
63 | * sent to the CPU. | ||
54 | * | 64 | * |
55 | * (4) The kernel recognizes an interrupt as an IRQ. The IRQ interface is used as | 65 | * (4) The kernel recognizes an interrupt as an IRQ. The IRQ interface is |
56 | * architecture-independent interrupt handling mechanism in Linux. As an | 66 | * used as architecture-independent interrupt handling mechanism in Linux. |
57 | * IRQ is a number, we have to have IA-64 interrupt vector number <-> IRQ number | 67 | * As an IRQ is a number, we have to have |
58 | * mapping. On smaller systems, we use one-to-one mapping between IA-64 vector and | 68 | * IA-64 interrupt vector number <-> IRQ number mapping. On smaller |
59 | * IRQ. A platform can implement platform_irq_to_vector(irq) and | 69 | * systems, we use one-to-one mapping between IA-64 vector and IRQ. A |
70 | * platform can implement platform_irq_to_vector(irq) and | ||
60 | * platform_local_vector_to_irq(vector) APIs to differentiate the mapping. | 71 | * platform_local_vector_to_irq(vector) APIs to differentiate the mapping. |
61 | * Please see also include/asm-ia64/hw_irq.h for those APIs. | 72 | * Please see also include/asm-ia64/hw_irq.h for those APIs. |
62 | * | 73 | * |
@@ -64,9 +75,9 @@ | |||
64 | * | 75 | * |
65 | * PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ | 76 | * PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ |
66 | * | 77 | * |
67 | * Note: The term "IRQ" is loosely used everywhere in Linux kernel to describe interrupts. | 78 | * Note: The term "IRQ" is loosely used everywhere in Linux kernel to |
68 | * Now we use "IRQ" only for Linux IRQ's. ISA IRQ (isa_irq) is the only exception in this | 79 | * describeinterrupts. Now we use "IRQ" only for Linux IRQ's. ISA IRQ |
69 | * source code. | 80 | * (isa_irq) is the only exception in this source code. |
70 | */ | 81 | */ |
71 | #include <linux/config.h> | 82 | #include <linux/config.h> |
72 | 83 | ||
@@ -90,7 +101,6 @@ | |||
90 | #include <asm/ptrace.h> | 101 | #include <asm/ptrace.h> |
91 | #include <asm/system.h> | 102 | #include <asm/system.h> |
92 | 103 | ||
93 | |||
94 | #undef DEBUG_INTERRUPT_ROUTING | 104 | #undef DEBUG_INTERRUPT_ROUTING |
95 | 105 | ||
96 | #ifdef DEBUG_INTERRUPT_ROUTING | 106 | #ifdef DEBUG_INTERRUPT_ROUTING |
@@ -99,36 +109,46 @@ | |||
99 | #define DBG(fmt...) | 109 | #define DBG(fmt...) |
100 | #endif | 110 | #endif |
101 | 111 | ||
102 | #define NR_PREALLOCATE_RTE_ENTRIES (PAGE_SIZE / sizeof(struct iosapic_rte_info)) | 112 | #define NR_PREALLOCATE_RTE_ENTRIES \ |
113 | (PAGE_SIZE / sizeof(struct iosapic_rte_info)) | ||
103 | #define RTE_PREALLOCATED (1) | 114 | #define RTE_PREALLOCATED (1) |
104 | 115 | ||
105 | static DEFINE_SPINLOCK(iosapic_lock); | 116 | static DEFINE_SPINLOCK(iosapic_lock); |
106 | 117 | ||
107 | /* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */ | 118 | /* |
119 | * These tables map IA-64 vectors to the IOSAPIC pin that generates this | ||
120 | * vector. | ||
121 | */ | ||
108 | 122 | ||
109 | struct iosapic_rte_info { | 123 | struct iosapic_rte_info { |
110 | struct list_head rte_list; /* node in list of RTEs sharing the same vector */ | 124 | struct list_head rte_list; /* node in list of RTEs sharing the |
125 | * same vector */ | ||
111 | char __iomem *addr; /* base address of IOSAPIC */ | 126 | char __iomem *addr; /* base address of IOSAPIC */ |
112 | unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ | 127 | unsigned int gsi_base; /* first GSI assigned to this |
128 | * IOSAPIC */ | ||
113 | char rte_index; /* IOSAPIC RTE index */ | 129 | char rte_index; /* IOSAPIC RTE index */ |
114 | int refcnt; /* reference counter */ | 130 | int refcnt; /* reference counter */ |
115 | unsigned int flags; /* flags */ | 131 | unsigned int flags; /* flags */ |
116 | } ____cacheline_aligned; | 132 | } ____cacheline_aligned; |
117 | 133 | ||
118 | static struct iosapic_intr_info { | 134 | static struct iosapic_intr_info { |
119 | struct list_head rtes; /* RTEs using this vector (empty => not an IOSAPIC interrupt) */ | 135 | struct list_head rtes; /* RTEs using this vector (empty => |
136 | * not an IOSAPIC interrupt) */ | ||
120 | int count; /* # of RTEs that shares this vector */ | 137 | int count; /* # of RTEs that shares this vector */ |
121 | u32 low32; /* current value of low word of Redirection table entry */ | 138 | u32 low32; /* current value of low word of |
139 | * Redirection table entry */ | ||
122 | unsigned int dest; /* destination CPU physical ID */ | 140 | unsigned int dest; /* destination CPU physical ID */ |
123 | unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ | 141 | unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ |
124 | unsigned char polarity: 1; /* interrupt polarity (see iosapic.h) */ | 142 | unsigned char polarity: 1; /* interrupt polarity |
143 | * (see iosapic.h) */ | ||
125 | unsigned char trigger : 1; /* trigger mode (see iosapic.h) */ | 144 | unsigned char trigger : 1; /* trigger mode (see iosapic.h) */ |
126 | } iosapic_intr_info[IA64_NUM_VECTORS]; | 145 | } iosapic_intr_info[IA64_NUM_VECTORS]; |
127 | 146 | ||
128 | static struct iosapic { | 147 | static struct iosapic { |
129 | char __iomem *addr; /* base address of IOSAPIC */ | 148 | char __iomem *addr; /* base address of IOSAPIC */ |
130 | unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ | 149 | unsigned int gsi_base; /* first GSI assigned to this |
131 | unsigned short num_rte; /* number of RTE in this IOSAPIC */ | 150 | * IOSAPIC */ |
151 | unsigned short num_rte; /* # of RTEs on this IOSAPIC */ | ||
132 | int rtes_inuse; /* # of RTEs in use on this IOSAPIC */ | 152 | int rtes_inuse; /* # of RTEs in use on this IOSAPIC */ |
133 | #ifdef CONFIG_NUMA | 153 | #ifdef CONFIG_NUMA |
134 | unsigned short node; /* numa node association via pxm */ | 154 | unsigned short node; /* numa node association via pxm */ |
@@ -149,7 +169,8 @@ find_iosapic (unsigned int gsi) | |||
149 | int i; | 169 | int i; |
150 | 170 | ||
151 | for (i = 0; i < NR_IOSAPICS; i++) { | 171 | for (i = 0; i < NR_IOSAPICS; i++) { |
152 | if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte) | 172 | if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < |
173 | iosapic_lists[i].num_rte) | ||
153 | return i; | 174 | return i; |
154 | } | 175 | } |
155 | 176 | ||
@@ -162,7 +183,8 @@ _gsi_to_vector (unsigned int gsi) | |||
162 | struct iosapic_intr_info *info; | 183 | struct iosapic_intr_info *info; |
163 | struct iosapic_rte_info *rte; | 184 | struct iosapic_rte_info *rte; |
164 | 185 | ||
165 | for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info) | 186 | for (info = iosapic_intr_info; info < |
187 | iosapic_intr_info + IA64_NUM_VECTORS; ++info) | ||
166 | list_for_each_entry(rte, &info->rtes, rte_list) | 188 | list_for_each_entry(rte, &info->rtes, rte_list) |
167 | if (rte->gsi_base + rte->rte_index == gsi) | 189 | if (rte->gsi_base + rte->rte_index == gsi) |
168 | return info - iosapic_intr_info; | 190 | return info - iosapic_intr_info; |
@@ -185,8 +207,8 @@ gsi_to_irq (unsigned int gsi) | |||
185 | unsigned long flags; | 207 | unsigned long flags; |
186 | int irq; | 208 | int irq; |
187 | /* | 209 | /* |
188 | * XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq | 210 | * XXX fix me: this assumes an identity mapping between IA-64 vector |
189 | * numbers... | 211 | * and Linux irq numbers... |
190 | */ | 212 | */ |
191 | spin_lock_irqsave(&iosapic_lock, flags); | 213 | spin_lock_irqsave(&iosapic_lock, flags); |
192 | { | 214 | { |
@@ -197,7 +219,8 @@ gsi_to_irq (unsigned int gsi) | |||
197 | return irq; | 219 | return irq; |
198 | } | 220 | } |
199 | 221 | ||
200 | static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi, unsigned int vec) | 222 | static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi, |
223 | unsigned int vec) | ||
201 | { | 224 | { |
202 | struct iosapic_rte_info *rte; | 225 | struct iosapic_rte_info *rte; |
203 | 226 | ||
@@ -237,7 +260,9 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask) | |||
237 | 260 | ||
238 | for (irq = 0; irq < NR_IRQS; ++irq) | 261 | for (irq = 0; irq < NR_IRQS; ++irq) |
239 | if (irq_to_vector(irq) == vector) { | 262 | if (irq_to_vector(irq) == vector) { |
240 | set_irq_affinity_info(irq, (int)(dest & 0xffff), redir); | 263 | set_irq_affinity_info(irq, |
264 | (int)(dest & 0xffff), | ||
265 | redir); | ||
241 | break; | 266 | break; |
242 | } | 267 | } |
243 | } | 268 | } |
@@ -259,7 +284,7 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask) | |||
259 | } | 284 | } |
260 | 285 | ||
261 | static void | 286 | static void |
262 | nop (unsigned int vector) | 287 | nop (unsigned int irq) |
263 | { | 288 | { |
264 | /* do nothing... */ | 289 | /* do nothing... */ |
265 | } | 290 | } |
@@ -281,7 +306,8 @@ mask_irq (unsigned int irq) | |||
281 | { | 306 | { |
282 | /* set only the mask bit */ | 307 | /* set only the mask bit */ |
283 | low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK; | 308 | low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK; |
284 | list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { | 309 | list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, |
310 | rte_list) { | ||
285 | addr = rte->addr; | 311 | addr = rte->addr; |
286 | rte_index = rte->rte_index; | 312 | rte_index = rte->rte_index; |
287 | iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); | 313 | iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); |
@@ -306,7 +332,8 @@ unmask_irq (unsigned int irq) | |||
306 | spin_lock_irqsave(&iosapic_lock, flags); | 332 | spin_lock_irqsave(&iosapic_lock, flags); |
307 | { | 333 | { |
308 | low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK; | 334 | low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK; |
309 | list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { | 335 | list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, |
336 | rte_list) { | ||
310 | addr = rte->addr; | 337 | addr = rte->addr; |
311 | rte_index = rte->rte_index; | 338 | rte_index = rte->rte_index; |
312 | iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); | 339 | iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); |
@@ -346,21 +373,25 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask) | |||
346 | 373 | ||
347 | spin_lock_irqsave(&iosapic_lock, flags); | 374 | spin_lock_irqsave(&iosapic_lock, flags); |
348 | { | 375 | { |
349 | low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT); | 376 | low32 = iosapic_intr_info[vec].low32 & |
377 | ~(7 << IOSAPIC_DELIVERY_SHIFT); | ||
350 | 378 | ||
351 | if (redir) | 379 | if (redir) |
352 | /* change delivery mode to lowest priority */ | 380 | /* change delivery mode to lowest priority */ |
353 | low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT); | 381 | low32 |= (IOSAPIC_LOWEST_PRIORITY << |
382 | IOSAPIC_DELIVERY_SHIFT); | ||
354 | else | 383 | else |
355 | /* change delivery mode to fixed */ | 384 | /* change delivery mode to fixed */ |
356 | low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT); | 385 | low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT); |
357 | 386 | ||
358 | iosapic_intr_info[vec].low32 = low32; | 387 | iosapic_intr_info[vec].low32 = low32; |
359 | iosapic_intr_info[vec].dest = dest; | 388 | iosapic_intr_info[vec].dest = dest; |
360 | list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { | 389 | list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, |
390 | rte_list) { | ||
361 | addr = rte->addr; | 391 | addr = rte->addr; |
362 | rte_index = rte->rte_index; | 392 | rte_index = rte->rte_index; |
363 | iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); | 393 | iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), |
394 | high32); | ||
364 | iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); | 395 | iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); |
365 | } | 396 | } |
366 | } | 397 | } |
@@ -433,7 +464,8 @@ iosapic_ack_edge_irq (unsigned int irq) | |||
433 | * interrupt for real. This prevents IRQ storms from unhandled | 464 | * interrupt for real. This prevents IRQ storms from unhandled |
434 | * devices. | 465 | * devices. |
435 | */ | 466 | */ |
436 | if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED)) | 467 | if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == |
468 | (IRQ_PENDING|IRQ_DISABLED)) | ||
437 | mask_irq(irq); | 469 | mask_irq(irq); |
438 | } | 470 | } |
439 | 471 | ||
@@ -467,7 +499,8 @@ iosapic_version (char __iomem *addr) | |||
467 | return iosapic_read(addr, IOSAPIC_VERSION); | 499 | return iosapic_read(addr, IOSAPIC_VERSION); |
468 | } | 500 | } |
469 | 501 | ||
470 | static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long pol) | 502 | static int iosapic_find_sharable_vector (unsigned long trigger, |
503 | unsigned long pol) | ||
471 | { | 504 | { |
472 | int i, vector = -1, min_count = -1; | 505 | int i, vector = -1, min_count = -1; |
473 | struct iosapic_intr_info *info; | 506 | struct iosapic_intr_info *info; |
@@ -482,7 +515,8 @@ static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long po | |||
482 | for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) { | 515 | for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) { |
483 | info = &iosapic_intr_info[i]; | 516 | info = &iosapic_intr_info[i]; |
484 | if (info->trigger == trigger && info->polarity == pol && | 517 | if (info->trigger == trigger && info->polarity == pol && |
485 | (info->dmode == IOSAPIC_FIXED || info->dmode == IOSAPIC_LOWEST_PRIORITY)) { | 518 | (info->dmode == IOSAPIC_FIXED || info->dmode == |
519 | IOSAPIC_LOWEST_PRIORITY)) { | ||
486 | if (min_count == -1 || info->count < min_count) { | 520 | if (min_count == -1 || info->count < min_count) { |
487 | vector = i; | 521 | vector = i; |
488 | min_count = info->count; | 522 | min_count = info->count; |
@@ -506,12 +540,15 @@ iosapic_reassign_vector (int vector) | |||
506 | new_vector = assign_irq_vector(AUTO_ASSIGN); | 540 | new_vector = assign_irq_vector(AUTO_ASSIGN); |
507 | if (new_vector < 0) | 541 | if (new_vector < 0) |
508 | panic("%s: out of interrupt vectors!\n", __FUNCTION__); | 542 | panic("%s: out of interrupt vectors!\n", __FUNCTION__); |
509 | printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector); | 543 | printk(KERN_INFO "Reassigning vector %d to %d\n", |
544 | vector, new_vector); | ||
510 | memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector], | 545 | memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector], |
511 | sizeof(struct iosapic_intr_info)); | 546 | sizeof(struct iosapic_intr_info)); |
512 | INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes); | 547 | INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes); |
513 | list_move(iosapic_intr_info[vector].rtes.next, &iosapic_intr_info[new_vector].rtes); | 548 | list_move(iosapic_intr_info[vector].rtes.next, |
514 | memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); | 549 | &iosapic_intr_info[new_vector].rtes); |
550 | memset(&iosapic_intr_info[vector], 0, | ||
551 | sizeof(struct iosapic_intr_info)); | ||
515 | iosapic_intr_info[vector].low32 = IOSAPIC_MASK; | 552 | iosapic_intr_info[vector].low32 = IOSAPIC_MASK; |
516 | INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); | 553 | INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); |
517 | } | 554 | } |
@@ -524,7 +561,8 @@ static struct iosapic_rte_info *iosapic_alloc_rte (void) | |||
524 | int preallocated = 0; | 561 | int preallocated = 0; |
525 | 562 | ||
526 | if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) { | 563 | if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) { |
527 | rte = alloc_bootmem(sizeof(struct iosapic_rte_info) * NR_PREALLOCATE_RTE_ENTRIES); | 564 | rte = alloc_bootmem(sizeof(struct iosapic_rte_info) * |
565 | NR_PREALLOCATE_RTE_ENTRIES); | ||
528 | if (!rte) | 566 | if (!rte) |
529 | return NULL; | 567 | return NULL; |
530 | for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++) | 568 | for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++) |
@@ -532,7 +570,8 @@ static struct iosapic_rte_info *iosapic_alloc_rte (void) | |||
532 | } | 570 | } |
533 | 571 | ||
534 | if (!list_empty(&free_rte_list)) { | 572 | if (!list_empty(&free_rte_list)) { |
535 | rte = list_entry(free_rte_list.next, struct iosapic_rte_info, rte_list); | 573 | rte = list_entry(free_rte_list.next, struct iosapic_rte_info, |
574 | rte_list); | ||
536 | list_del(&rte->rte_list); | 575 | list_del(&rte->rte_list); |
537 | preallocated++; | 576 | preallocated++; |
538 | } else { | 577 | } else { |
@@ -575,7 +614,8 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, | |||
575 | 614 | ||
576 | index = find_iosapic(gsi); | 615 | index = find_iosapic(gsi); |
577 | if (index < 0) { | 616 | if (index < 0) { |
578 | printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", __FUNCTION__, gsi); | 617 | printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", |
618 | __FUNCTION__, gsi); | ||
579 | return -ENODEV; | 619 | return -ENODEV; |
580 | } | 620 | } |
581 | 621 | ||
@@ -586,7 +626,8 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, | |||
586 | if (!rte) { | 626 | if (!rte) { |
587 | rte = iosapic_alloc_rte(); | 627 | rte = iosapic_alloc_rte(); |
588 | if (!rte) { | 628 | if (!rte) { |
589 | printk(KERN_WARNING "%s: cannot allocate memory\n", __FUNCTION__); | 629 | printk(KERN_WARNING "%s: cannot allocate memory\n", |
630 | __FUNCTION__); | ||
590 | return -ENOMEM; | 631 | return -ENOMEM; |
591 | } | 632 | } |
592 | 633 | ||
@@ -602,7 +643,9 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, | |||
602 | else if (vector_is_shared(vector)) { | 643 | else if (vector_is_shared(vector)) { |
603 | struct iosapic_intr_info *info = &iosapic_intr_info[vector]; | 644 | struct iosapic_intr_info *info = &iosapic_intr_info[vector]; |
604 | if (info->trigger != trigger || info->polarity != polarity) { | 645 | if (info->trigger != trigger || info->polarity != polarity) { |
605 | printk (KERN_WARNING "%s: cannot override the interrupt\n", __FUNCTION__); | 646 | printk (KERN_WARNING |
647 | "%s: cannot override the interrupt\n", | ||
648 | __FUNCTION__); | ||
606 | return -EINVAL; | 649 | return -EINVAL; |
607 | } | 650 | } |
608 | } | 651 | } |
@@ -619,8 +662,10 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, | |||
619 | idesc = irq_descp(vector); | 662 | idesc = irq_descp(vector); |
620 | if (idesc->handler != irq_type) { | 663 | if (idesc->handler != irq_type) { |
621 | if (idesc->handler != &no_irq_type) | 664 | if (idesc->handler != &no_irq_type) |
622 | printk(KERN_WARNING "%s: changing vector %d from %s to %s\n", | 665 | printk(KERN_WARNING |
623 | __FUNCTION__, vector, idesc->handler->typename, irq_type->typename); | 666 | "%s: changing vector %d from %s to %s\n", |
667 | __FUNCTION__, vector, | ||
668 | idesc->handler->typename, irq_type->typename); | ||
624 | idesc->handler = irq_type; | 669 | idesc->handler = irq_type; |
625 | } | 670 | } |
626 | return 0; | 671 | return 0; |
@@ -681,7 +726,7 @@ get_target_cpu (unsigned int gsi, int vector) | |||
681 | if (!num_cpus) | 726 | if (!num_cpus) |
682 | goto skip_numa_setup; | 727 | goto skip_numa_setup; |
683 | 728 | ||
684 | /* Use vector assigment to distribute across cpus in node */ | 729 | /* Use vector assignment to distribute across cpus in node */ |
685 | cpu_index = vector % num_cpus; | 730 | cpu_index = vector % num_cpus; |
686 | 731 | ||
687 | for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++) | 732 | for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++) |
@@ -703,7 +748,7 @@ skip_numa_setup: | |||
703 | } while (!cpu_online(cpu)); | 748 | } while (!cpu_online(cpu)); |
704 | 749 | ||
705 | return cpu_physical_id(cpu); | 750 | return cpu_physical_id(cpu); |
706 | #else | 751 | #else /* CONFIG_SMP */ |
707 | return cpu_physical_id(smp_processor_id()); | 752 | return cpu_physical_id(smp_processor_id()); |
708 | #endif | 753 | #endif |
709 | } | 754 | } |
@@ -755,7 +800,8 @@ again: | |||
755 | if (list_empty(&iosapic_intr_info[vector].rtes)) | 800 | if (list_empty(&iosapic_intr_info[vector].rtes)) |
756 | free_irq_vector(vector); | 801 | free_irq_vector(vector); |
757 | spin_unlock(&iosapic_lock); | 802 | spin_unlock(&iosapic_lock); |
758 | spin_unlock_irqrestore(&irq_descp(vector)->lock, flags); | 803 | spin_unlock_irqrestore(&irq_descp(vector)->lock, |
804 | flags); | ||
759 | goto again; | 805 | goto again; |
760 | } | 806 | } |
761 | 807 | ||
@@ -764,7 +810,8 @@ again: | |||
764 | polarity, trigger); | 810 | polarity, trigger); |
765 | if (err < 0) { | 811 | if (err < 0) { |
766 | spin_unlock(&iosapic_lock); | 812 | spin_unlock(&iosapic_lock); |
767 | spin_unlock_irqrestore(&irq_descp(vector)->lock, flags); | 813 | spin_unlock_irqrestore(&irq_descp(vector)->lock, |
814 | flags); | ||
768 | return err; | 815 | return err; |
769 | } | 816 | } |
770 | 817 | ||
@@ -806,7 +853,8 @@ iosapic_unregister_intr (unsigned int gsi) | |||
806 | */ | 853 | */ |
807 | irq = gsi_to_irq(gsi); | 854 | irq = gsi_to_irq(gsi); |
808 | if (irq < 0) { | 855 | if (irq < 0) { |
809 | printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi); | 856 | printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", |
857 | gsi); | ||
810 | WARN_ON(1); | 858 | WARN_ON(1); |
811 | return; | 859 | return; |
812 | } | 860 | } |
@@ -817,7 +865,9 @@ iosapic_unregister_intr (unsigned int gsi) | |||
817 | spin_lock(&iosapic_lock); | 865 | spin_lock(&iosapic_lock); |
818 | { | 866 | { |
819 | if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) { | 867 | if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) { |
820 | printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi); | 868 | printk(KERN_ERR |
869 | "iosapic_unregister_intr(%u) unbalanced\n", | ||
870 | gsi); | ||
821 | WARN_ON(1); | 871 | WARN_ON(1); |
822 | goto out; | 872 | goto out; |
823 | } | 873 | } |
@@ -827,7 +877,8 @@ iosapic_unregister_intr (unsigned int gsi) | |||
827 | 877 | ||
828 | /* Mask the interrupt */ | 878 | /* Mask the interrupt */ |
829 | low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK; | 879 | low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK; |
830 | iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index), low32); | 880 | iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index), |
881 | low32); | ||
831 | 882 | ||
832 | /* Remove the rte entry from the list */ | 883 | /* Remove the rte entry from the list */ |
833 | list_del(&rte->rte_list); | 884 | list_del(&rte->rte_list); |
@@ -840,7 +891,9 @@ iosapic_unregister_intr (unsigned int gsi) | |||
840 | trigger = iosapic_intr_info[vector].trigger; | 891 | trigger = iosapic_intr_info[vector].trigger; |
841 | polarity = iosapic_intr_info[vector].polarity; | 892 | polarity = iosapic_intr_info[vector].polarity; |
842 | dest = iosapic_intr_info[vector].dest; | 893 | dest = iosapic_intr_info[vector].dest; |
843 | printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n", | 894 | printk(KERN_INFO |
895 | "GSI %u (%s, %s) -> CPU %d (0x%04x)" | ||
896 | " vector %d unregistered\n", | ||
844 | gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), | 897 | gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), |
845 | (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), | 898 | (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), |
846 | cpu_logical_id(dest), dest, vector); | 899 | cpu_logical_id(dest), dest, vector); |
@@ -853,12 +906,15 @@ iosapic_unregister_intr (unsigned int gsi) | |||
853 | idesc->handler = &no_irq_type; | 906 | idesc->handler = &no_irq_type; |
854 | 907 | ||
855 | /* Clear the interrupt information */ | 908 | /* Clear the interrupt information */ |
856 | memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); | 909 | memset(&iosapic_intr_info[vector], 0, |
910 | sizeof(struct iosapic_intr_info)); | ||
857 | iosapic_intr_info[vector].low32 |= IOSAPIC_MASK; | 911 | iosapic_intr_info[vector].low32 |= IOSAPIC_MASK; |
858 | INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); | 912 | INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); |
859 | 913 | ||
860 | if (idesc->action) { | 914 | if (idesc->action) { |
861 | printk(KERN_ERR "interrupt handlers still exist on IRQ %u\n", irq); | 915 | printk(KERN_ERR |
916 | "interrupt handlers still exist on" | ||
917 | "IRQ %u\n", irq); | ||
862 | WARN_ON(1); | 918 | WARN_ON(1); |
863 | } | 919 | } |
864 | 920 | ||
@@ -873,7 +929,6 @@ iosapic_unregister_intr (unsigned int gsi) | |||
873 | 929 | ||
874 | /* | 930 | /* |
875 | * ACPI calls this when it finds an entry for a platform interrupt. | 931 | * ACPI calls this when it finds an entry for a platform interrupt. |
876 | * Note that the irq_base and IOSAPIC address must be set in iosapic_init(). | ||
877 | */ | 932 | */ |
878 | int __init | 933 | int __init |
879 | iosapic_register_platform_intr (u32 int_type, unsigned int gsi, | 934 | iosapic_register_platform_intr (u32 int_type, unsigned int gsi, |
@@ -907,13 +962,16 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi, | |||
907 | mask = 1; | 962 | mask = 1; |
908 | break; | 963 | break; |
909 | default: | 964 | default: |
910 | printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type 0x%x\n", int_type); | 965 | printk(KERN_ERR "%s: invalid int type 0x%x\n", __FUNCTION__, |
966 | int_type); | ||
911 | return -1; | 967 | return -1; |
912 | } | 968 | } |
913 | 969 | ||
914 | register_intr(gsi, vector, delivery, polarity, trigger); | 970 | register_intr(gsi, vector, delivery, polarity, trigger); |
915 | 971 | ||
916 | printk(KERN_INFO "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n", | 972 | printk(KERN_INFO |
973 | "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x)" | ||
974 | " vector %d\n", | ||
917 | int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown", | 975 | int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown", |
918 | int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), | 976 | int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), |
919 | (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), | 977 | (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), |
@@ -923,10 +981,8 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi, | |||
923 | return vector; | 981 | return vector; |
924 | } | 982 | } |
925 | 983 | ||
926 | |||
927 | /* | 984 | /* |
928 | * ACPI calls this when it finds an entry for a legacy ISA IRQ override. | 985 | * ACPI calls this when it finds an entry for a legacy ISA IRQ override. |
929 | * Note that the gsi_base and IOSAPIC address must be set in iosapic_init(). | ||
930 | */ | 986 | */ |
931 | void __init | 987 | void __init |
932 | iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi, | 988 | iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi, |
@@ -955,16 +1011,19 @@ iosapic_system_init (int system_pcat_compat) | |||
955 | 1011 | ||
956 | for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) { | 1012 | for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) { |
957 | iosapic_intr_info[vector].low32 = IOSAPIC_MASK; | 1013 | iosapic_intr_info[vector].low32 = IOSAPIC_MASK; |
958 | INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); /* mark as unused */ | 1014 | /* mark as unused */ |
1015 | INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); | ||
959 | } | 1016 | } |
960 | 1017 | ||
961 | pcat_compat = system_pcat_compat; | 1018 | pcat_compat = system_pcat_compat; |
962 | if (pcat_compat) { | 1019 | if (pcat_compat) { |
963 | /* | 1020 | /* |
964 | * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support | 1021 | * Disable the compatibility mode interrupts (8259 style), |
965 | * enabled. | 1022 | * needs IN/OUT support enabled. |
966 | */ | 1023 | */ |
967 | printk(KERN_INFO "%s: Disabling PC-AT compatible 8259 interrupts\n", __FUNCTION__); | 1024 | printk(KERN_INFO |
1025 | "%s: Disabling PC-AT compatible 8259 interrupts\n", | ||
1026 | __FUNCTION__); | ||
968 | outb(0xff, 0xA1); | 1027 | outb(0xff, 0xA1); |
969 | outb(0xff, 0x21); | 1028 | outb(0xff, 0x21); |
970 | } | 1029 | } |
@@ -1053,12 +1112,14 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base) | |||
1053 | 1112 | ||
1054 | if ((gsi_base == 0) && pcat_compat) { | 1113 | if ((gsi_base == 0) && pcat_compat) { |
1055 | /* | 1114 | /* |
1056 | * Map the legacy ISA devices into the IOSAPIC data. Some of these may | 1115 | * Map the legacy ISA devices into the IOSAPIC data. Some of |
1057 | * get reprogrammed later on with data from the ACPI Interrupt Source | 1116 | * these may get reprogrammed later on with data from the ACPI |
1058 | * Override table. | 1117 | * Interrupt Source Override table. |
1059 | */ | 1118 | */ |
1060 | for (isa_irq = 0; isa_irq < 16; ++isa_irq) | 1119 | for (isa_irq = 0; isa_irq < 16; ++isa_irq) |
1061 | iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE); | 1120 | iosapic_override_isa_irq(isa_irq, isa_irq, |
1121 | IOSAPIC_POL_HIGH, | ||
1122 | IOSAPIC_EDGE); | ||
1062 | } | 1123 | } |
1063 | return 0; | 1124 | return 0; |
1064 | } | 1125 | } |
@@ -1081,7 +1142,8 @@ iosapic_remove (unsigned int gsi_base) | |||
1081 | 1142 | ||
1082 | if (iosapic_lists[index].rtes_inuse) { | 1143 | if (iosapic_lists[index].rtes_inuse) { |
1083 | err = -EBUSY; | 1144 | err = -EBUSY; |
1084 | printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n", | 1145 | printk(KERN_WARNING |
1146 | "%s: IOSAPIC for GSI base %u is busy\n", | ||
1085 | __FUNCTION__, gsi_base); | 1147 | __FUNCTION__, gsi_base); |
1086 | goto out; | 1148 | goto out; |
1087 | } | 1149 | } |