aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2006-07-05 01:36:15 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-07-05 12:29:43 -0400
commitba1826e5eced176cc9ec0033ad8ee0f1cd5ad2e4 (patch)
tree56a9e6aab061bde5402ced7b7a875a01888b4e2c /arch/powerpc/sysdev
parentca78f6baca863afe2e6a244a0fe94b3a70211d46 (diff)
[PATCH] powerpc: Fix loss of interrupts with MPIC
With the new interrupt rework, an interrupt "host" map() callback can be called after the interrupt is already active. It's called again for an already mapped interrupt to allow changing the trigger setup, and currently this is not guarded with a test of wether the interrupt is requested or not. I plan to change some of this logic to be a bit less lenient against random reconfiguring of live interrupts but just not yet. The ported MPIC driver has a bug where when that happens, it will mask the interrupt. This changes it to preserve the previous masking of the interrupt instead. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r--arch/powerpc/sysdev/mpic.c39
1 files changed, 29 insertions, 10 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 7d31d7cc392d..9cecebaa0360 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -405,20 +405,22 @@ static void mpic_unmask_irq(unsigned int irq)
405 unsigned int loops = 100000; 405 unsigned int loops = 100000;
406 struct mpic *mpic = mpic_from_irq(irq); 406 struct mpic *mpic = mpic_from_irq(irq);
407 unsigned int src = mpic_irq_to_hw(irq); 407 unsigned int src = mpic_irq_to_hw(irq);
408 unsigned long flags;
408 409
409 DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src); 410 DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src);
410 411
412 spin_lock_irqsave(&mpic_lock, flags);
411 mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, 413 mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
412 mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & 414 mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) &
413 ~MPIC_VECPRI_MASK); 415 ~MPIC_VECPRI_MASK);
414
415 /* make sure mask gets to controller before we return to user */ 416 /* make sure mask gets to controller before we return to user */
416 do { 417 do {
417 if (!loops--) { 418 if (!loops--) {
418 printk(KERN_ERR "mpic_enable_irq timeout\n"); 419 printk(KERN_ERR "mpic_enable_irq timeout\n");
419 break; 420 break;
420 } 421 }
421 } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK); 422 } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);
423 spin_unlock_irqrestore(&mpic_lock, flags);
422} 424}
423 425
424static void mpic_mask_irq(unsigned int irq) 426static void mpic_mask_irq(unsigned int irq)
@@ -426,9 +428,11 @@ static void mpic_mask_irq(unsigned int irq)
426 unsigned int loops = 100000; 428 unsigned int loops = 100000;
427 struct mpic *mpic = mpic_from_irq(irq); 429 struct mpic *mpic = mpic_from_irq(irq);
428 unsigned int src = mpic_irq_to_hw(irq); 430 unsigned int src = mpic_irq_to_hw(irq);
431 unsigned long flags;
429 432
430 DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src); 433 DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src);
431 434
435 spin_lock_irqsave(&mpic_lock, flags);
432 mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, 436 mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
433 mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) | 437 mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) |
434 MPIC_VECPRI_MASK); 438 MPIC_VECPRI_MASK);
@@ -440,6 +444,7 @@ static void mpic_mask_irq(unsigned int irq)
440 break; 444 break;
441 } 445 }
442 } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK)); 446 } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
447 spin_unlock_irqrestore(&mpic_lock, flags);
443} 448}
444 449
445static void mpic_end_irq(unsigned int irq) 450static void mpic_end_irq(unsigned int irq)
@@ -624,9 +629,10 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
624 struct irq_desc *desc = get_irq_desc(virq); 629 struct irq_desc *desc = get_irq_desc(virq);
625 struct irq_chip *chip; 630 struct irq_chip *chip;
626 struct mpic *mpic = h->host_data; 631 struct mpic *mpic = h->host_data;
627 unsigned int vecpri = MPIC_VECPRI_SENSE_LEVEL | 632 u32 v, vecpri = MPIC_VECPRI_SENSE_LEVEL |
628 MPIC_VECPRI_POLARITY_NEGATIVE; 633 MPIC_VECPRI_POLARITY_NEGATIVE;
629 int level; 634 int level;
635 unsigned long iflags;
630 636
631 pr_debug("mpic: map virq %d, hwirq 0x%lx, flags: 0x%x\n", 637 pr_debug("mpic: map virq %d, hwirq 0x%lx, flags: 0x%x\n",
632 virq, hw, flags); 638 virq, hw, flags);
@@ -668,11 +674,21 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
668 } 674 }
669#endif 675#endif
670 676
671 /* Reconfigure irq */ 677 /* Reconfigure irq. We must preserve the mask bit as we can be called
672 vecpri |= MPIC_VECPRI_MASK | hw | (8 << MPIC_VECPRI_PRIORITY_SHIFT); 678 * while the interrupt is still active (This may change in the future
673 mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri); 679 * but for now, it is the case).
674 680 */
675 pr_debug("mpic: mapping as IRQ\n"); 681 spin_lock_irqsave(&mpic_lock, iflags);
682 v = mpic_irq_read(hw, MPIC_IRQ_VECTOR_PRI);
683 vecpri = (v &
684 ~(MPIC_VECPRI_POLARITY_MASK | MPIC_VECPRI_SENSE_MASK)) |
685 vecpri;
686 if (vecpri != v)
687 mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri);
688 spin_unlock_irqrestore(&mpic_lock, iflags);
689
690 pr_debug("mpic: mapping as IRQ, vecpri = 0x%08x (was 0x%08x)\n",
691 vecpri, v);
676 692
677 set_irq_chip_data(virq, mpic); 693 set_irq_chip_data(virq, mpic);
678 set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq); 694 set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq);
@@ -904,8 +920,8 @@ void __init mpic_init(struct mpic *mpic)
904 920
905 /* do senses munging */ 921 /* do senses munging */
906 if (mpic->senses && i < mpic->senses_count) 922 if (mpic->senses && i < mpic->senses_count)
907 vecpri = mpic_flags_to_vecpri(mpic->senses[i], 923 vecpri |= mpic_flags_to_vecpri(mpic->senses[i],
908 &level); 924 &level);
909 else 925 else
910 vecpri |= MPIC_VECPRI_SENSE_LEVEL; 926 vecpri |= MPIC_VECPRI_SENSE_LEVEL;
911 927
@@ -955,14 +971,17 @@ void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio)
955 971
956void __init mpic_set_serial_int(struct mpic *mpic, int enable) 972void __init mpic_set_serial_int(struct mpic *mpic, int enable)
957{ 973{
974 unsigned long flags;
958 u32 v; 975 u32 v;
959 976
977 spin_lock_irqsave(&mpic_lock, flags);
960 v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1); 978 v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1);
961 if (enable) 979 if (enable)
962 v |= MPIC_GREG_GLOBAL_CONF_1_SIE; 980 v |= MPIC_GREG_GLOBAL_CONF_1_SIE;
963 else 981 else
964 v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE; 982 v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE;
965 mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v); 983 mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v);
984 spin_unlock_irqrestore(&mpic_lock, flags);
966} 985}
967 986
968void mpic_irq_set_priority(unsigned int irq, unsigned int pri) 987void mpic_irq_set_priority(unsigned int irq, unsigned int pri)