[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>

authored by Benjamin Herrenschmidt and committed by Linus Torvalds ba1826e5 ca78f6ba

+28 -9
+28 -9
arch/powerpc/sysdev/mpic.c
··· 405 unsigned int loops = 100000; 406 struct mpic *mpic = mpic_from_irq(irq); 407 unsigned int src = mpic_irq_to_hw(irq); 408 409 DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src); 410 411 mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, 412 mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & 413 ~MPIC_VECPRI_MASK); 414 - 415 /* make sure mask gets to controller before we return to user */ 416 do { 417 if (!loops--) { 418 printk(KERN_ERR "mpic_enable_irq timeout\n"); 419 break; 420 } 421 - } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK); 422 } 423 424 static void mpic_mask_irq(unsigned int irq) ··· 428 unsigned int loops = 100000; 429 struct mpic *mpic = mpic_from_irq(irq); 430 unsigned int src = mpic_irq_to_hw(irq); 431 432 DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src); 433 434 mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, 435 mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) | 436 MPIC_VECPRI_MASK); ··· 444 break; 445 } 446 } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK)); 447 } 448 449 static void mpic_end_irq(unsigned int irq) ··· 629 struct irq_desc *desc = get_irq_desc(virq); 630 struct irq_chip *chip; 631 struct mpic *mpic = h->host_data; 632 - unsigned int vecpri = MPIC_VECPRI_SENSE_LEVEL | 633 MPIC_VECPRI_POLARITY_NEGATIVE; 634 int level; 635 636 pr_debug("mpic: map virq %d, hwirq 0x%lx, flags: 0x%x\n", 637 virq, hw, flags); ··· 674 } 675 #endif 676 677 - /* Reconfigure irq */ 678 - vecpri |= MPIC_VECPRI_MASK | hw | (8 << MPIC_VECPRI_PRIORITY_SHIFT); 679 - mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri); 680 681 - pr_debug("mpic: mapping as IRQ\n"); 682 683 set_irq_chip_data(virq, mpic); 684 set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq); ··· 920 921 /* do senses munging */ 922 if (mpic->senses && i < mpic->senses_count) 923 - vecpri = mpic_flags_to_vecpri(mpic->senses[i], 924 - &level); 925 else 926 vecpri |= MPIC_VECPRI_SENSE_LEVEL; 927 ··· 971 972 void __init mpic_set_serial_int(struct mpic *mpic, int enable) 973 { 974 u32 v; 975 976 v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1); 977 if (enable) 978 v |= MPIC_GREG_GLOBAL_CONF_1_SIE; 979 else 980 v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE; 981 mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v); 982 } 983 984 void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
··· 405 unsigned int loops = 100000; 406 struct mpic *mpic = mpic_from_irq(irq); 407 unsigned int src = mpic_irq_to_hw(irq); 408 + unsigned long flags; 409 410 DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src); 411 412 + spin_lock_irqsave(&mpic_lock, flags); 413 mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, 414 mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & 415 ~MPIC_VECPRI_MASK); 416 /* make sure mask gets to controller before we return to user */ 417 do { 418 if (!loops--) { 419 printk(KERN_ERR "mpic_enable_irq timeout\n"); 420 break; 421 } 422 + } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK); 423 + spin_unlock_irqrestore(&mpic_lock, flags); 424 } 425 426 static void mpic_mask_irq(unsigned int irq) ··· 426 unsigned int loops = 100000; 427 struct mpic *mpic = mpic_from_irq(irq); 428 unsigned int src = mpic_irq_to_hw(irq); 429 + unsigned long flags; 430 431 DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src); 432 433 + spin_lock_irqsave(&mpic_lock, flags); 434 mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, 435 mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) | 436 MPIC_VECPRI_MASK); ··· 440 break; 441 } 442 } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK)); 443 + spin_unlock_irqrestore(&mpic_lock, flags); 444 } 445 446 static void mpic_end_irq(unsigned int irq) ··· 624 struct irq_desc *desc = get_irq_desc(virq); 625 struct irq_chip *chip; 626 struct mpic *mpic = h->host_data; 627 + u32 v, vecpri = MPIC_VECPRI_SENSE_LEVEL | 628 MPIC_VECPRI_POLARITY_NEGATIVE; 629 int level; 630 + unsigned long iflags; 631 632 pr_debug("mpic: map virq %d, hwirq 0x%lx, flags: 0x%x\n", 633 virq, hw, flags); ··· 668 } 669 #endif 670 671 + /* Reconfigure irq. We must preserve the mask bit as we can be called 672 + * while the interrupt is still active (This may change in the future 673 + * but for now, it is the case). 674 + */ 675 + spin_lock_irqsave(&mpic_lock, iflags); 676 + v = mpic_irq_read(hw, MPIC_IRQ_VECTOR_PRI); 677 + vecpri = (v & 678 + ~(MPIC_VECPRI_POLARITY_MASK | MPIC_VECPRI_SENSE_MASK)) | 679 + vecpri; 680 + if (vecpri != v) 681 + mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri); 682 + spin_unlock_irqrestore(&mpic_lock, iflags); 683 684 + pr_debug("mpic: mapping as IRQ, vecpri = 0x%08x (was 0x%08x)\n", 685 + vecpri, v); 686 687 set_irq_chip_data(virq, mpic); 688 set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq); ··· 904 905 /* do senses munging */ 906 if (mpic->senses && i < mpic->senses_count) 907 + vecpri |= mpic_flags_to_vecpri(mpic->senses[i], 908 + &level); 909 else 910 vecpri |= MPIC_VECPRI_SENSE_LEVEL; 911 ··· 955 956 void __init mpic_set_serial_int(struct mpic *mpic, int enable) 957 { 958 + unsigned long flags; 959 u32 v; 960 961 + spin_lock_irqsave(&mpic_lock, flags); 962 v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1); 963 if (enable) 964 v |= MPIC_GREG_GLOBAL_CONF_1_SIE; 965 else 966 v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE; 967 mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v); 968 + spin_unlock_irqrestore(&mpic_lock, flags); 969 } 970 971 void mpic_irq_set_priority(unsigned int irq, unsigned int pri)