aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>2005-04-25 16:26:23 -0400
committerTony Luck <tony.luck@intel.com>2005-04-25 16:26:23 -0400
commit24eeb568aeeaee771b9f0a6fd6f5d01040a887da (patch)
tree4d3e731845cde292b5a40ff7db97cce639dc073c
parente927ecb05e1ce4bbb1e10f57008c94994e2160f5 (diff)
[IA64] vector sharing (Large I/O system support)
Current ia64 linux cannot handle greater than 184 interrupt sources because of the lack of vectors. The following patch enables ia64 linux to handle greater than 184 interrupt sources by allowing the same vector number to be shared by multiple IOSAPIC's RTEs. The design of this patch is besed on "Intel(R) Itanium(R) Processor Family Interrupt Architecture Guide". Even if you don't have a large I/O system, you can see the behavior of vector sharing by changing IOSAPIC_LAST_DEVICE_VECTOR to fewer value. Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
-rw-r--r--arch/ia64/kernel/iosapic.c358
-rw-r--r--arch/ia64/kernel/irq_ia64.c16
-rw-r--r--include/asm-ia64/hw_irq.h1
3 files changed, 286 insertions, 89 deletions
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index c15be5c38f56..11a221cc8dc3 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -79,6 +79,7 @@
79#include <linux/smp.h> 79#include <linux/smp.h>
80#include <linux/smp_lock.h> 80#include <linux/smp_lock.h>
81#include <linux/string.h> 81#include <linux/string.h>
82#include <linux/bootmem.h>
82 83
83#include <asm/delay.h> 84#include <asm/delay.h>
84#include <asm/hw_irq.h> 85#include <asm/hw_irq.h>
@@ -98,19 +99,30 @@
98#define DBG(fmt...) 99#define DBG(fmt...)
99#endif 100#endif
100 101
102#define NR_PREALLOCATE_RTE_ENTRIES (PAGE_SIZE / sizeof(struct iosapic_rte_info))
103#define RTE_PREALLOCATED (1)
104
101static DEFINE_SPINLOCK(iosapic_lock); 105static DEFINE_SPINLOCK(iosapic_lock);
102 106
103/* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */ 107/* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */
104 108
105static struct iosapic_intr_info { 109struct iosapic_rte_info {
110 struct list_head rte_list; /* node in list of RTEs sharing the same vector */
106 char __iomem *addr; /* base address of IOSAPIC */ 111 char __iomem *addr; /* base address of IOSAPIC */
107 u32 low32; /* current value of low word of Redirection table entry */
108 unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ 112 unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */
109 char rte_index; /* IOSAPIC RTE index (-1 => not an IOSAPIC interrupt) */ 113 char rte_index; /* IOSAPIC RTE index */
114 int refcnt; /* reference counter */
115 unsigned int flags; /* flags */
116} ____cacheline_aligned;
117
118static struct iosapic_intr_info {
119 struct list_head rtes; /* RTEs using this vector (empty => not an IOSAPIC interrupt) */
120 int count; /* # of RTEs that shares this vector */
121 u32 low32; /* current value of low word of Redirection table entry */
122 unsigned int dest; /* destination CPU physical ID */
110 unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ 123 unsigned char dmode : 3; /* delivery mode (see iosapic.h) */
111 unsigned char polarity: 1; /* interrupt polarity (see iosapic.h) */ 124 unsigned char polarity: 1; /* interrupt polarity (see iosapic.h) */
112 unsigned char trigger : 1; /* trigger mode (see iosapic.h) */ 125 unsigned char trigger : 1; /* trigger mode (see iosapic.h) */
113 int refcnt; /* reference counter */
114} iosapic_intr_info[IA64_NUM_VECTORS]; 126} iosapic_intr_info[IA64_NUM_VECTORS];
115 127
116static struct iosapic { 128static struct iosapic {
@@ -126,6 +138,8 @@ static int num_iosapic;
126 138
127static unsigned char pcat_compat __initdata; /* 8259 compatibility flag */ 139static unsigned char pcat_compat __initdata; /* 8259 compatibility flag */
128 140
141static int iosapic_kmalloc_ok;
142static LIST_HEAD(free_rte_list);
129 143
130/* 144/*
131 * Find an IOSAPIC associated with a GSI 145 * Find an IOSAPIC associated with a GSI
@@ -147,10 +161,12 @@ static inline int
147_gsi_to_vector (unsigned int gsi) 161_gsi_to_vector (unsigned int gsi)
148{ 162{
149 struct iosapic_intr_info *info; 163 struct iosapic_intr_info *info;
164 struct iosapic_rte_info *rte;
150 165
151 for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info) 166 for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info)
152 if (info->gsi_base + info->rte_index == gsi) 167 list_for_each_entry(rte, &info->rtes, rte_list)
153 return info - iosapic_intr_info; 168 if (rte->gsi_base + rte->rte_index == gsi)
169 return info - iosapic_intr_info;
154 return -1; 170 return -1;
155} 171}
156 172
@@ -167,33 +183,52 @@ gsi_to_vector (unsigned int gsi)
167int 183int
168gsi_to_irq (unsigned int gsi) 184gsi_to_irq (unsigned int gsi)
169{ 185{
186 unsigned long flags;
187 int irq;
170 /* 188 /*
171 * XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq 189 * XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq
172 * numbers... 190 * numbers...
173 */ 191 */
174 return _gsi_to_vector(gsi); 192 spin_lock_irqsave(&iosapic_lock, flags);
193 {
194 irq = _gsi_to_vector(gsi);
195 }
196 spin_unlock_irqrestore(&iosapic_lock, flags);
197
198 return irq;
199}
200
201static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi, unsigned int vec)
202{
203 struct iosapic_rte_info *rte;
204
205 list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
206 if (rte->gsi_base + rte->rte_index == gsi)
207 return rte;
208 return NULL;
175} 209}
176 210
177static void 211static void
178set_rte (unsigned int vector, unsigned int dest, int mask) 212set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
179{ 213{
180 unsigned long pol, trigger, dmode; 214 unsigned long pol, trigger, dmode;
181 u32 low32, high32; 215 u32 low32, high32;
182 char __iomem *addr; 216 char __iomem *addr;
183 int rte_index; 217 int rte_index;
184 char redir; 218 char redir;
219 struct iosapic_rte_info *rte;
185 220
186 DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest); 221 DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest);
187 222
188 rte_index = iosapic_intr_info[vector].rte_index; 223 rte = gsi_vector_to_rte(gsi, vector);
189 if (rte_index < 0) 224 if (!rte)
190 return; /* not an IOSAPIC interrupt */ 225 return; /* not an IOSAPIC interrupt */
191 226
192 addr = iosapic_intr_info[vector].addr; 227 rte_index = rte->rte_index;
228 addr = rte->addr;
193 pol = iosapic_intr_info[vector].polarity; 229 pol = iosapic_intr_info[vector].polarity;
194 trigger = iosapic_intr_info[vector].trigger; 230 trigger = iosapic_intr_info[vector].trigger;
195 dmode = iosapic_intr_info[vector].dmode; 231 dmode = iosapic_intr_info[vector].dmode;
196 vector &= (~IA64_IRQ_REDIRECTED);
197 232
198 redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0; 233 redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0;
199 234
@@ -221,6 +256,7 @@ set_rte (unsigned int vector, unsigned int dest, int mask)
221 iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); 256 iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
222 iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); 257 iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
223 iosapic_intr_info[vector].low32 = low32; 258 iosapic_intr_info[vector].low32 = low32;
259 iosapic_intr_info[vector].dest = dest;
224} 260}
225 261
226static void 262static void
@@ -237,18 +273,20 @@ mask_irq (unsigned int irq)
237 u32 low32; 273 u32 low32;
238 int rte_index; 274 int rte_index;
239 ia64_vector vec = irq_to_vector(irq); 275 ia64_vector vec = irq_to_vector(irq);
276 struct iosapic_rte_info *rte;
240 277
241 addr = iosapic_intr_info[vec].addr; 278 if (list_empty(&iosapic_intr_info[vec].rtes))
242 rte_index = iosapic_intr_info[vec].rte_index;
243
244 if (rte_index < 0)
245 return; /* not an IOSAPIC interrupt! */ 279 return; /* not an IOSAPIC interrupt! */
246 280
247 spin_lock_irqsave(&iosapic_lock, flags); 281 spin_lock_irqsave(&iosapic_lock, flags);
248 { 282 {
249 /* set only the mask bit */ 283 /* set only the mask bit */
250 low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK; 284 low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
251 iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); 285 list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
286 addr = rte->addr;
287 rte_index = rte->rte_index;
288 iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
289 }
252 } 290 }
253 spin_unlock_irqrestore(&iosapic_lock, flags); 291 spin_unlock_irqrestore(&iosapic_lock, flags);
254} 292}
@@ -261,16 +299,19 @@ unmask_irq (unsigned int irq)
261 u32 low32; 299 u32 low32;
262 int rte_index; 300 int rte_index;
263 ia64_vector vec = irq_to_vector(irq); 301 ia64_vector vec = irq_to_vector(irq);
302 struct iosapic_rte_info *rte;
264 303
265 addr = iosapic_intr_info[vec].addr; 304 if (list_empty(&iosapic_intr_info[vec].rtes))
266 rte_index = iosapic_intr_info[vec].rte_index;
267 if (rte_index < 0)
268 return; /* not an IOSAPIC interrupt! */ 305 return; /* not an IOSAPIC interrupt! */
269 306
270 spin_lock_irqsave(&iosapic_lock, flags); 307 spin_lock_irqsave(&iosapic_lock, flags);
271 { 308 {
272 low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK; 309 low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
273 iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); 310 list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
311 addr = rte->addr;
312 rte_index = rte->rte_index;
313 iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
314 }
274 } 315 }
275 spin_unlock_irqrestore(&iosapic_lock, flags); 316 spin_unlock_irqrestore(&iosapic_lock, flags);
276} 317}
@@ -286,6 +327,7 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask)
286 char __iomem *addr; 327 char __iomem *addr;
287 int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0; 328 int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0;
288 ia64_vector vec; 329 ia64_vector vec;
330 struct iosapic_rte_info *rte;
289 331
290 irq &= (~IA64_IRQ_REDIRECTED); 332 irq &= (~IA64_IRQ_REDIRECTED);
291 vec = irq_to_vector(irq); 333 vec = irq_to_vector(irq);
@@ -295,10 +337,7 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask)
295 337
296 dest = cpu_physical_id(first_cpu(mask)); 338 dest = cpu_physical_id(first_cpu(mask));
297 339
298 rte_index = iosapic_intr_info[vec].rte_index; 340 if (list_empty(&iosapic_intr_info[vec].rtes))
299 addr = iosapic_intr_info[vec].addr;
300
301 if (rte_index < 0)
302 return; /* not an IOSAPIC interrupt */ 341 return; /* not an IOSAPIC interrupt */
303 342
304 set_irq_affinity_info(irq, dest, redir); 343 set_irq_affinity_info(irq, dest, redir);
@@ -318,8 +357,13 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask)
318 low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT); 357 low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
319 358
320 iosapic_intr_info[vec].low32 = low32; 359 iosapic_intr_info[vec].low32 = low32;
321 iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); 360 iosapic_intr_info[vec].dest = dest;
322 iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); 361 list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
362 addr = rte->addr;
363 rte_index = rte->rte_index;
364 iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
365 iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
366 }
323 } 367 }
324 spin_unlock_irqrestore(&iosapic_lock, flags); 368 spin_unlock_irqrestore(&iosapic_lock, flags);
325#endif 369#endif
@@ -340,9 +384,11 @@ static void
340iosapic_end_level_irq (unsigned int irq) 384iosapic_end_level_irq (unsigned int irq)
341{ 385{
342 ia64_vector vec = irq_to_vector(irq); 386 ia64_vector vec = irq_to_vector(irq);
387 struct iosapic_rte_info *rte;
343 388
344 move_irq(irq); 389 move_irq(irq);
345 iosapic_eoi(iosapic_intr_info[vec].addr, vec); 390 list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
391 iosapic_eoi(rte->addr, vec);
346} 392}
347 393
348#define iosapic_shutdown_level_irq mask_irq 394#define iosapic_shutdown_level_irq mask_irq
@@ -422,6 +468,34 @@ iosapic_version (char __iomem *addr)
422 return iosapic_read(addr, IOSAPIC_VERSION); 468 return iosapic_read(addr, IOSAPIC_VERSION);
423} 469}
424 470
471static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long pol)
472{
473 int i, vector = -1, min_count = -1;
474 struct iosapic_intr_info *info;
475
476 /*
477 * shared vectors for edge-triggered interrupts are not
478 * supported yet
479 */
480 if (trigger == IOSAPIC_EDGE)
481 return -1;
482
483 for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) {
484 info = &iosapic_intr_info[i];
485 if (info->trigger == trigger && info->polarity == pol &&
486 (info->dmode == IOSAPIC_FIXED || info->dmode == IOSAPIC_LOWEST_PRIORITY)) {
487 if (min_count == -1 || info->count < min_count) {
488 vector = i;
489 min_count = info->count;
490 }
491 }
492 }
493 if (vector < 0)
494 panic("%s: out of interrupt vectors!\n", __FUNCTION__);
495
496 return vector;
497}
498
425/* 499/*
426 * if the given vector is already owned by other, 500 * if the given vector is already owned by other,
427 * assign a new vector for the other and make the vector available 501 * assign a new vector for the other and make the vector available
@@ -431,19 +505,63 @@ iosapic_reassign_vector (int vector)
431{ 505{
432 int new_vector; 506 int new_vector;
433 507
434 if (iosapic_intr_info[vector].rte_index >= 0 || iosapic_intr_info[vector].addr 508 if (!list_empty(&iosapic_intr_info[vector].rtes)) {
435 || iosapic_intr_info[vector].gsi_base || iosapic_intr_info[vector].dmode
436 || iosapic_intr_info[vector].polarity || iosapic_intr_info[vector].trigger)
437 {
438 new_vector = assign_irq_vector(AUTO_ASSIGN); 509 new_vector = assign_irq_vector(AUTO_ASSIGN);
439 printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector); 510 printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector);
440 memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector], 511 memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
441 sizeof(struct iosapic_intr_info)); 512 sizeof(struct iosapic_intr_info));
513 INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes);
514 list_move(iosapic_intr_info[vector].rtes.next, &iosapic_intr_info[new_vector].rtes);
442 memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); 515 memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
443 iosapic_intr_info[vector].rte_index = -1; 516 iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
517 INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
444 } 518 }
445} 519}
446 520
521static struct iosapic_rte_info *iosapic_alloc_rte (void)
522{
523 int i;
524 struct iosapic_rte_info *rte;
525 int preallocated = 0;
526
527 if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) {
528 rte = alloc_bootmem(sizeof(struct iosapic_rte_info) * NR_PREALLOCATE_RTE_ENTRIES);
529 if (!rte)
530 return NULL;
531 for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++)
532 list_add(&rte->rte_list, &free_rte_list);
533 }
534
535 if (!list_empty(&free_rte_list)) {
536 rte = list_entry(free_rte_list.next, struct iosapic_rte_info, rte_list);
537 list_del(&rte->rte_list);
538 preallocated++;
539 } else {
540 rte = kmalloc(sizeof(struct iosapic_rte_info), GFP_ATOMIC);
541 if (!rte)
542 return NULL;
543 }
544
545 memset(rte, 0, sizeof(struct iosapic_rte_info));
546 if (preallocated)
547 rte->flags |= RTE_PREALLOCATED;
548
549 return rte;
550}
551
552static void iosapic_free_rte (struct iosapic_rte_info *rte)
553{
554 if (rte->flags & RTE_PREALLOCATED)
555 list_add_tail(&rte->rte_list, &free_rte_list);
556 else
557 kfree(rte);
558}
559
560static inline int vector_is_shared (int vector)
561{
562 return (iosapic_intr_info[vector].count > 1);
563}
564
447static void 565static void
448register_intr (unsigned int gsi, int vector, unsigned char delivery, 566register_intr (unsigned int gsi, int vector, unsigned char delivery,
449 unsigned long polarity, unsigned long trigger) 567 unsigned long polarity, unsigned long trigger)
@@ -454,6 +572,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
454 int index; 572 int index;
455 unsigned long gsi_base; 573 unsigned long gsi_base;
456 void __iomem *iosapic_address; 574 void __iomem *iosapic_address;
575 struct iosapic_rte_info *rte;
457 576
458 index = find_iosapic(gsi); 577 index = find_iosapic(gsi);
459 if (index < 0) { 578 if (index < 0) {
@@ -464,14 +583,33 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
464 iosapic_address = iosapic_lists[index].addr; 583 iosapic_address = iosapic_lists[index].addr;
465 gsi_base = iosapic_lists[index].gsi_base; 584 gsi_base = iosapic_lists[index].gsi_base;
466 585
467 rte_index = gsi - gsi_base; 586 rte = gsi_vector_to_rte(gsi, vector);
468 iosapic_intr_info[vector].rte_index = rte_index; 587 if (!rte) {
588 rte = iosapic_alloc_rte();
589 if (!rte) {
590 printk(KERN_WARNING "%s: cannot allocate memory\n", __FUNCTION__);
591 return;
592 }
593
594 rte_index = gsi - gsi_base;
595 rte->rte_index = rte_index;
596 rte->addr = iosapic_address;
597 rte->gsi_base = gsi_base;
598 rte->refcnt++;
599 list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);
600 iosapic_intr_info[vector].count++;
601 }
602 else if (vector_is_shared(vector)) {
603 struct iosapic_intr_info *info = &iosapic_intr_info[vector];
604 if (info->trigger != trigger || info->polarity != polarity) {
605 printk (KERN_WARNING "%s: cannot override the interrupt\n", __FUNCTION__);
606 return;
607 }
608 }
609
469 iosapic_intr_info[vector].polarity = polarity; 610 iosapic_intr_info[vector].polarity = polarity;
470 iosapic_intr_info[vector].dmode = delivery; 611 iosapic_intr_info[vector].dmode = delivery;
471 iosapic_intr_info[vector].addr = iosapic_address;
472 iosapic_intr_info[vector].gsi_base = gsi_base;
473 iosapic_intr_info[vector].trigger = trigger; 612 iosapic_intr_info[vector].trigger = trigger;
474 iosapic_intr_info[vector].refcnt++;
475 613
476 if (trigger == IOSAPIC_EDGE) 614 if (trigger == IOSAPIC_EDGE)
477 irq_type = &irq_type_iosapic_edge; 615 irq_type = &irq_type_iosapic_edge;
@@ -494,6 +632,13 @@ get_target_cpu (unsigned int gsi, int vector)
494 static int cpu = -1; 632 static int cpu = -1;
495 633
496 /* 634 /*
635 * In case of vector shared by multiple RTEs, all RTEs that
636 * share the vector need to use the same destination CPU.
637 */
638 if (!list_empty(&iosapic_intr_info[vector].rtes))
639 return iosapic_intr_info[vector].dest;
640
641 /*
497 * If the platform supports redirection via XTP, let it 642 * If the platform supports redirection via XTP, let it
498 * distribute interrupts. 643 * distribute interrupts.
499 */ 644 */
@@ -565,10 +710,12 @@ int
565iosapic_register_intr (unsigned int gsi, 710iosapic_register_intr (unsigned int gsi,
566 unsigned long polarity, unsigned long trigger) 711 unsigned long polarity, unsigned long trigger)
567{ 712{
568 int vector; 713 int vector, mask = 1;
569 unsigned int dest; 714 unsigned int dest;
570 unsigned long flags; 715 unsigned long flags;
571 716 struct iosapic_rte_info *rte;
717 u32 low32;
718again:
572 /* 719 /*
573 * If this GSI has already been registered (i.e., it's a 720 * If this GSI has already been registered (i.e., it's a
574 * shared interrupt, or we lost a race to register it), 721 * shared interrupt, or we lost a race to register it),
@@ -578,19 +725,45 @@ iosapic_register_intr (unsigned int gsi,
578 { 725 {
579 vector = gsi_to_vector(gsi); 726 vector = gsi_to_vector(gsi);
580 if (vector > 0) { 727 if (vector > 0) {
581 iosapic_intr_info[vector].refcnt++; 728 rte = gsi_vector_to_rte(gsi, vector);
729 rte->refcnt++;
582 spin_unlock_irqrestore(&iosapic_lock, flags); 730 spin_unlock_irqrestore(&iosapic_lock, flags);
583 return vector; 731 return vector;
584 } 732 }
733 }
734 spin_unlock_irqrestore(&iosapic_lock, flags);
735
736 /* If vector is running out, we try to find a sharable vector */
737 vector = assign_irq_vector_nopanic(AUTO_ASSIGN);
738 if (vector < 0)
739 vector = iosapic_find_sharable_vector(trigger, polarity);
740
741 spin_lock_irqsave(&irq_descp(vector)->lock, flags);
742 spin_lock(&iosapic_lock);
743 {
744 if (gsi_to_vector(gsi) > 0) {
745 if (list_empty(&iosapic_intr_info[vector].rtes))
746 free_irq_vector(vector);
747 spin_unlock(&iosapic_lock);
748 spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
749 goto again;
750 }
585 751
586 vector = assign_irq_vector(AUTO_ASSIGN);
587 dest = get_target_cpu(gsi, vector); 752 dest = get_target_cpu(gsi, vector);
588 register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, 753 register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
589 polarity, trigger); 754 polarity, trigger);
590 755
591 set_rte(vector, dest, 1); 756 /*
757 * If the vector is shared and already unmasked for
758 * other interrupt sources, don't mask it.
759 */
760 low32 = iosapic_intr_info[vector].low32;
761 if (vector_is_shared(vector) && !(low32 & IOSAPIC_MASK))
762 mask = 0;
763 set_rte(gsi, vector, dest, mask);
592 } 764 }
593 spin_unlock_irqrestore(&iosapic_lock, flags); 765 spin_unlock_irq(&iosapic_lock);
766 spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
594 767
595 printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n", 768 printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
596 gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), 769 gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
@@ -607,8 +780,10 @@ iosapic_unregister_intr (unsigned int gsi)
607 unsigned long flags; 780 unsigned long flags;
608 int irq, vector; 781 int irq, vector;
609 irq_desc_t *idesc; 782 irq_desc_t *idesc;
610 int rte_index; 783 u32 low32;
611 unsigned long trigger, polarity; 784 unsigned long trigger, polarity;
785 unsigned int dest;
786 struct iosapic_rte_info *rte;
612 787
613 /* 788 /*
614 * If the irq associated with the gsi is not found, 789 * If the irq associated with the gsi is not found,
@@ -627,54 +802,56 @@ iosapic_unregister_intr (unsigned int gsi)
627 spin_lock_irqsave(&idesc->lock, flags); 802 spin_lock_irqsave(&idesc->lock, flags);
628 spin_lock(&iosapic_lock); 803 spin_lock(&iosapic_lock);
629 { 804 {
630 rte_index = iosapic_intr_info[vector].rte_index; 805 if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) {
631 if (rte_index < 0) {
632 spin_unlock(&iosapic_lock);
633 spin_unlock_irqrestore(&idesc->lock, flags);
634 printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi); 806 printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi);
635 WARN_ON(1); 807 WARN_ON(1);
636 return; 808 goto out;
637 } 809 }
638 810
639 if (--iosapic_intr_info[vector].refcnt > 0) { 811 if (--rte->refcnt > 0)
640 spin_unlock(&iosapic_lock); 812 goto out;
641 spin_unlock_irqrestore(&idesc->lock, flags);
642 return;
643 }
644 813
645 /* 814 /* Mask the interrupt */
646 * If interrupt handlers still exist on the irq 815 low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK;
647 * associated with the gsi, don't unregister the 816 iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index), low32);
648 * interrupt.
649 */
650 if (idesc->action) {
651 iosapic_intr_info[vector].refcnt++;
652 spin_unlock(&iosapic_lock);
653 spin_unlock_irqrestore(&idesc->lock, flags);
654 printk(KERN_WARNING "Cannot unregister GSI. IRQ %u is still in use.\n", irq);
655 return;
656 }
657 817
658 /* Clear the interrupt controller descriptor. */ 818 /* Remove the rte entry from the list */
659 idesc->handler = &no_irq_type; 819 list_del(&rte->rte_list);
820 iosapic_intr_info[vector].count--;
821 iosapic_free_rte(rte);
660 822
661 trigger = iosapic_intr_info[vector].trigger; 823 trigger = iosapic_intr_info[vector].trigger;
662 polarity = iosapic_intr_info[vector].polarity; 824 polarity = iosapic_intr_info[vector].polarity;
825 dest = iosapic_intr_info[vector].dest;
826 printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n",
827 gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
828 (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
829 cpu_logical_id(dest), dest, vector);
830
831 if (list_empty(&iosapic_intr_info[vector].rtes)) {
832 /* Sanity check */
833 BUG_ON(iosapic_intr_info[vector].count);
834
835 /* Clear the interrupt controller descriptor */
836 idesc->handler = &no_irq_type;
837
838 /* Clear the interrupt information */
839 memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
840 iosapic_intr_info[vector].low32 |= IOSAPIC_MASK;
841 INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
842
843 if (idesc->action) {
844 printk(KERN_ERR "interrupt handlers still exist on IRQ %u\n", irq);
845 WARN_ON(1);
846 }
663 847
664 /* Clear the interrupt information. */ 848 /* Free the interrupt vector */
665 memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); 849 free_irq_vector(vector);
666 iosapic_intr_info[vector].rte_index = -1; /* mark as unused */ 850 }
667 } 851 }
852 out:
668 spin_unlock(&iosapic_lock); 853 spin_unlock(&iosapic_lock);
669 spin_unlock_irqrestore(&idesc->lock, flags); 854 spin_unlock_irqrestore(&idesc->lock, flags);
670
671 /* Free the interrupt vector */
672 free_irq_vector(vector);
673
674 printk(KERN_INFO "GSI %u (%s, %s) -> vector %d unregisterd.\n",
675 gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
676 (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
677 vector);
678} 855}
679#endif /* CONFIG_ACPI_DEALLOCATE_IRQ */ 856#endif /* CONFIG_ACPI_DEALLOCATE_IRQ */
680 857
@@ -724,7 +901,7 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
724 (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), 901 (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
725 cpu_logical_id(dest), dest, vector); 902 cpu_logical_id(dest), dest, vector);
726 903
727 set_rte(vector, dest, mask); 904 set_rte(gsi, vector, dest, mask);
728 return vector; 905 return vector;
729} 906}
730 907
@@ -750,7 +927,7 @@ iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
750 polarity == IOSAPIC_POL_HIGH ? "high" : "low", 927 polarity == IOSAPIC_POL_HIGH ? "high" : "low",
751 cpu_logical_id(dest), dest, vector); 928 cpu_logical_id(dest), dest, vector);
752 929
753 set_rte(vector, dest, 1); 930 set_rte(gsi, vector, dest, 1);
754} 931}
755 932
756void __init 933void __init
@@ -758,8 +935,10 @@ iosapic_system_init (int system_pcat_compat)
758{ 935{
759 int vector; 936 int vector;
760 937
761 for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) 938 for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) {
762 iosapic_intr_info[vector].rte_index = -1; /* mark as unused */ 939 iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
940 INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); /* mark as unused */
941 }
763 942
764 pcat_compat = system_pcat_compat; 943 pcat_compat = system_pcat_compat;
765 if (pcat_compat) { 944 if (pcat_compat) {
@@ -825,3 +1004,10 @@ map_iosapic_to_node(unsigned int gsi_base, int node)
825 return; 1004 return;
826} 1005}
827#endif 1006#endif
1007
1008static int __init iosapic_enable_kmalloc (void)
1009{
1010 iosapic_kmalloc_ok = 1;
1011 return 0;
1012}
1013core_initcall (iosapic_enable_kmalloc);
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index 5ba06ebe355b..4fe60c7a2e90 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -63,20 +63,30 @@ EXPORT_SYMBOL(isa_irq_to_vector_map);
63static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)]; 63static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
64 64
65int 65int
66assign_irq_vector (int irq) 66assign_irq_vector_nopanic (int irq)
67{ 67{
68 int pos, vector; 68 int pos, vector;
69 again: 69 again:
70 pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS); 70 pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS);
71 vector = IA64_FIRST_DEVICE_VECTOR + pos; 71 vector = IA64_FIRST_DEVICE_VECTOR + pos;
72 if (vector > IA64_LAST_DEVICE_VECTOR) 72 if (vector > IA64_LAST_DEVICE_VECTOR)
73 /* XXX could look for sharable vectors instead of panic'ing... */ 73 return -1;
74 panic("assign_irq_vector: out of interrupt vectors!");
75 if (test_and_set_bit(pos, ia64_vector_mask)) 74 if (test_and_set_bit(pos, ia64_vector_mask))
76 goto again; 75 goto again;
77 return vector; 76 return vector;
78} 77}
79 78
79int
80assign_irq_vector (int irq)
81{
82 int vector = assign_irq_vector_nopanic(irq);
83
84 if (vector < 0)
85 panic("assign_irq_vector: out of interrupt vectors!");
86
87 return vector;
88}
89
80void 90void
81free_irq_vector (int vector) 91free_irq_vector (int vector)
82{ 92{
diff --git a/include/asm-ia64/hw_irq.h b/include/asm-ia64/hw_irq.h
index 041ab8c51a64..cd4e06b74ab6 100644
--- a/include/asm-ia64/hw_irq.h
+++ b/include/asm-ia64/hw_irq.h
@@ -81,6 +81,7 @@ extern __u8 isa_irq_to_vector_map[16];
81 81
82extern struct hw_interrupt_type irq_type_ia64_lsapic; /* CPU-internal interrupt controller */ 82extern struct hw_interrupt_type irq_type_ia64_lsapic; /* CPU-internal interrupt controller */
83 83
84extern int assign_irq_vector_nopanic (int irq); /* allocate a free vector without panic */
84extern int assign_irq_vector (int irq); /* allocate a free vector */ 85extern int assign_irq_vector (int irq); /* allocate a free vector */
85extern void free_irq_vector (int vector); 86extern void free_irq_vector (int vector);
86extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect); 87extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);