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