Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9cf9e196 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Paul Mackerras
Browse files

[POWERPC] ps3: cleanup interrupt bmp routines



Change the PS3 interrupt bitmask routines to be lockless.

Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarGeoff Levand <geoffrey.levand@am.sony.com>
Acked-by: default avatarArnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 407e24a0
Loading
Loading
Loading
Loading
+38 −47
Original line number Diff line number Diff line
@@ -380,34 +380,50 @@ static void dump_bmp(struct ps3_private* pd) {};

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);
	asm volatile(
		     "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);
	asm volatile(
		     "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(unsigned int cpu, unsigned int virq)
		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);
	asm volatile("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();