ps3: cleanup interrupt bmp routines
Subsystems (2)
PATCH 8/16 ps3: cleanup interrupt bmp routines
From: Benjamin Herrenschmidt <[email protected]>
Change the PS3 interrupt bitmask routines to be lockless.
Signed-off-by Benjamin Herrenschmidt <[email protected]>
Signed-off-by Geoff Levand <[email protected]>
Acked-by Arnd Bergmann <[email protected]>
--- arch/powerpc/platforms/ps3/interrupt.c | 85 ++++++++++++++------------------- 1 files changed, 38 insertions(+), 47 deletions(-)
arch/powerpc/platforms/ps3/interrupt.c +38 -47
@@ -380,34 +380,50 @@ static void dump_bmp(struct ps3_private*static void ps3_chip_mask (unsigned int virq) { -unsigned long flags;struct ps3_private *pd =get_irq_chip_data (virq); +unsigned long bit =0x8000000000000000UL >> virq; +unsigned long *p = &pd->bmp.mask; +unsigned long old; +unsigned long flags;pr_debug ("%s:%d: cpu %u, virq %d\n" , __func__, __LINE__, pd->cpu, virq); -BUG_ON (virq <NUM_ISA_INTERRUPTS ); -BUG_ON (virq >PS3_PLUG_MAX ); +local_irq_save (flags); + asmvolatile ( +"1: ldarx %0,0,%3\n" +"andc %0,%0,%2\n" +"stdcx. %0,0,%3\n" +"bne- 1b" + :"=&r" (old),"+m" (*p) + :"r" (bit),"r" (p) + :"cc" ); -spin_lock_irqsave (&pd->bmp.lock, flags); - pd->bmp.mask &= ~(0x8000000000000000UL >> virq);lv1_did_update_interrupt_mask (pd->node, pd->cpu); -spin_unlock_irqrestore (&pd->bmp.lock, flags); +local_irq_restore (flags); }static void ps3_chip_unmask (unsigned int virq) { -unsigned long flags;struct ps3_private *pd =get_irq_chip_data (virq); +unsigned long bit =0x8000000000000000UL >> virq; +unsigned long *p = &pd->bmp.mask; +unsigned long old; +unsigned long flags;pr_debug ("%s:%d: cpu %u, virq %d\n" , __func__, __LINE__, pd->cpu, virq); -BUG_ON (virq <NUM_ISA_INTERRUPTS ); -BUG_ON (virq >PS3_PLUG_MAX ); +local_irq_save (flags); + asmvolatile ( +"1: ldarx %0,0,%3\n" +"or %0,%0,%2\n" +"stdcx. %0,0,%3\n" +"bne- 1b" + :"=&r" (old),"+m" (*p) + :"r" (bit),"r" (p) + :"cc" ); -spin_lock_irqsave (&pd->bmp.lock, flags); - pd->bmp.mask |= (0x8000000000000000UL >> virq);lv1_did_update_interrupt_mask (pd->node, pd->cpu); -spin_unlock_irqrestore (&pd->bmp.lock, flags); +local_irq_restore (flags); }static void ps3_chip_eoi (unsigned int virq)
@@ -481,46 +497,21 @@ void __init ps3_register_ipi_debug_brk(u cpu, virq, pd->bmp.ipi_debug_brk_mask); } -static int bmp_get_and_clear_status_bit (struct ps3_bmp *m) +unsigned int ps3_get_irq (void ) { -unsigned long flags; -unsigned int bit; -unsigned long x; - -spin_lock_irqsave (&m->lock, flags); +struct ps3_private *pd = &__get_cpu_var (ps3_private); +unsigned long x = (pd->bmp.status & pd->bmp.mask); +unsigned int plug;/* check for ipi break first to stop this cpu ASAP */ -if (m->status & m->ipi_debug_brk_mask) { - m->status &= ~m->ipi_debug_brk_mask; -spin_unlock_irqrestore (&m->lock, flags); -return __ilog2 (m->ipi_debug_brk_mask); - } - - x = (m->status & m->mask); - -for (bit =NUM_ISA_INTERRUPTS , x <<= bit; x; bit++, x <<=1 ) -if (x &0x8000000000000000UL ) { - m->status &= ~(0x8000000000000000UL >> bit); -spin_unlock_irqrestore (&m->lock, flags); -return bit; - } - -spin_unlock_irqrestore (&m->lock, flags); - -pr_debug ("%s:%d: not found\n" , __func__, __LINE__); -return -1 ; -} - -unsigned int ps3_get_irq (void ) -{ -int plug; - -struct ps3_private *pd = &__get_cpu_var (ps3_private); +if (x & pd->bmp.ipi_debug_brk_mask) + x &= pd->bmp.ipi_debug_brk_mask; - plug =bmp_get_and_clear_status_bit (&pd->bmp); + asmvolatile ("cntlzd %0,%1" :"=r" (plug) :"r" (x)); + plug &=0x3f ; -if (plug <1 ) { +if (unlikely (plug) ==NO_IRQ ) {pr_debug ("%s:%d: no plug found: cpu %u\n" , __func__, __LINE__, pd->cpu);dump_bmp (&per_cpu (ps3_private,0 ));
@@ -529,7 +520,7 @@ unsigned int ps3_get_irq(void) }#if defined(DEBUG ) -if (plug <NUM_ISA_INTERRUPTS || plug >PS3_PLUG_MAX ) { +if (unlikely (plug <NUM_ISA_INTERRUPTS || plug >PS3_PLUG_MAX )) {dump_bmp (&per_cpu (ps3_private,0 ));dump_bmp (&per_cpu (ps3_private,1 ));BUG ();