aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/kernel/iosapic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ia64/kernel/iosapic.c')
-rw-r--r--arch/ia64/kernel/iosapic.c358
1 files changed, 272 insertions, 86 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);