Skip to content

Commit

Permalink
[PATCH] powerpc: Fix loss of interrupts with MPIC
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Benjamin Herrenschmidt authored and Linus Torvalds committed Jul 5, 2006
1 parent ca78f6b commit ba1826e
Showing 1 changed file with 29 additions and 10 deletions.
39 changes: 29 additions & 10 deletions arch/powerpc/sysdev/mpic.c
Original file line number Diff line number Diff line change
Expand Up @@ -405,30 +405,34 @@ static void mpic_unmask_irq(unsigned int irq)
unsigned int loops = 100000;
struct mpic *mpic = mpic_from_irq(irq);
unsigned int src = mpic_irq_to_hw(irq);
unsigned long flags;

DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src);

spin_lock_irqsave(&mpic_lock, flags);
mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) &
~MPIC_VECPRI_MASK);

/* make sure mask gets to controller before we return to user */
do {
if (!loops--) {
printk(KERN_ERR "mpic_enable_irq timeout\n");
break;
}
} while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);
} while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);
spin_unlock_irqrestore(&mpic_lock, flags);
}

static void mpic_mask_irq(unsigned int irq)
{
unsigned int loops = 100000;
struct mpic *mpic = mpic_from_irq(irq);
unsigned int src = mpic_irq_to_hw(irq);
unsigned long flags;

DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src);

spin_lock_irqsave(&mpic_lock, flags);
mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) |
MPIC_VECPRI_MASK);
Expand All @@ -440,6 +444,7 @@ static void mpic_mask_irq(unsigned int irq)
break;
}
} while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
spin_unlock_irqrestore(&mpic_lock, flags);
}

static void mpic_end_irq(unsigned int irq)
Expand Down Expand Up @@ -624,9 +629,10 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
struct irq_desc *desc = get_irq_desc(virq);
struct irq_chip *chip;
struct mpic *mpic = h->host_data;
unsigned int vecpri = MPIC_VECPRI_SENSE_LEVEL |
u32 v, vecpri = MPIC_VECPRI_SENSE_LEVEL |
MPIC_VECPRI_POLARITY_NEGATIVE;
int level;
unsigned long iflags;

pr_debug("mpic: map virq %d, hwirq 0x%lx, flags: 0x%x\n",
virq, hw, flags);
Expand Down Expand Up @@ -668,11 +674,21 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
}
#endif

/* Reconfigure irq */
vecpri |= MPIC_VECPRI_MASK | hw | (8 << MPIC_VECPRI_PRIORITY_SHIFT);
mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri);

pr_debug("mpic: mapping as IRQ\n");
/* Reconfigure irq. We must preserve the mask bit as we can be called
* while the interrupt is still active (This may change in the future
* but for now, it is the case).
*/
spin_lock_irqsave(&mpic_lock, iflags);
v = mpic_irq_read(hw, MPIC_IRQ_VECTOR_PRI);
vecpri = (v &
~(MPIC_VECPRI_POLARITY_MASK | MPIC_VECPRI_SENSE_MASK)) |
vecpri;
if (vecpri != v)
mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri);
spin_unlock_irqrestore(&mpic_lock, iflags);

pr_debug("mpic: mapping as IRQ, vecpri = 0x%08x (was 0x%08x)\n",
vecpri, v);

set_irq_chip_data(virq, mpic);
set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq);
Expand Down Expand Up @@ -904,8 +920,8 @@ void __init mpic_init(struct mpic *mpic)

/* do senses munging */
if (mpic->senses && i < mpic->senses_count)
vecpri = mpic_flags_to_vecpri(mpic->senses[i],
&level);
vecpri |= mpic_flags_to_vecpri(mpic->senses[i],
&level);
else
vecpri |= MPIC_VECPRI_SENSE_LEVEL;

Expand Down Expand Up @@ -955,14 +971,17 @@ void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio)

void __init mpic_set_serial_int(struct mpic *mpic, int enable)
{
unsigned long flags;
u32 v;

spin_lock_irqsave(&mpic_lock, flags);
v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1);
if (enable)
v |= MPIC_GREG_GLOBAL_CONF_1_SIE;
else
v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE;
mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v);
spin_unlock_irqrestore(&mpic_lock, flags);
}

void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
Expand Down

0 comments on commit ba1826e

Please sign in to comment.