Commit ba1826e5 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Linus Torvalds

[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: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent ca78f6ba
...@@ -405,20 +405,22 @@ static void mpic_unmask_irq(unsigned int irq) ...@@ -405,20 +405,22 @@ static void mpic_unmask_irq(unsigned int irq)
unsigned int loops = 100000; unsigned int loops = 100000;
struct mpic *mpic = mpic_from_irq(irq); struct mpic *mpic = mpic_from_irq(irq);
unsigned int src = mpic_irq_to_hw(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); 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_write(src, MPIC_IRQ_VECTOR_PRI,
mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) &
~MPIC_VECPRI_MASK); ~MPIC_VECPRI_MASK);
/* make sure mask gets to controller before we return to user */ /* make sure mask gets to controller before we return to user */
do { do {
if (!loops--) { if (!loops--) {
printk(KERN_ERR "mpic_enable_irq timeout\n"); printk(KERN_ERR "mpic_enable_irq timeout\n");
break; 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) static void mpic_mask_irq(unsigned int irq)
...@@ -426,9 +428,11 @@ static void mpic_mask_irq(unsigned int irq) ...@@ -426,9 +428,11 @@ static void mpic_mask_irq(unsigned int irq)
unsigned int loops = 100000; unsigned int loops = 100000;
struct mpic *mpic = mpic_from_irq(irq); struct mpic *mpic = mpic_from_irq(irq);
unsigned int src = mpic_irq_to_hw(irq); unsigned int src = mpic_irq_to_hw(irq);
unsigned long flags;
DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src); 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_write(src, MPIC_IRQ_VECTOR_PRI,
mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) | mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) |
MPIC_VECPRI_MASK); MPIC_VECPRI_MASK);
...@@ -440,6 +444,7 @@ static void mpic_mask_irq(unsigned int irq) ...@@ -440,6 +444,7 @@ static void mpic_mask_irq(unsigned int irq)
break; 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_end_irq(unsigned int irq) static void mpic_end_irq(unsigned int irq)
...@@ -624,9 +629,10 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, ...@@ -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_desc *desc = get_irq_desc(virq);
struct irq_chip *chip; struct irq_chip *chip;
struct mpic *mpic = h->host_data; struct mpic *mpic = h->host_data;
unsigned int vecpri = MPIC_VECPRI_SENSE_LEVEL | u32 v, vecpri = MPIC_VECPRI_SENSE_LEVEL |
MPIC_VECPRI_POLARITY_NEGATIVE; MPIC_VECPRI_POLARITY_NEGATIVE;
int level; int level;
unsigned long iflags;
pr_debug("mpic: map virq %d, hwirq 0x%lx, flags: 0x%x\n", pr_debug("mpic: map virq %d, hwirq 0x%lx, flags: 0x%x\n",
virq, hw, flags); virq, hw, flags);
...@@ -668,11 +674,21 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, ...@@ -668,11 +674,21 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
} }
#endif #endif
/* Reconfigure irq */ /* Reconfigure irq. We must preserve the mask bit as we can be called
vecpri |= MPIC_VECPRI_MASK | hw | (8 << MPIC_VECPRI_PRIORITY_SHIFT); * while the interrupt is still active (This may change in the future
mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri); * but for now, it is the case).
*/
pr_debug("mpic: mapping as IRQ\n"); 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_data(virq, mpic);
set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq); set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq);
...@@ -904,8 +920,8 @@ void __init mpic_init(struct mpic *mpic) ...@@ -904,8 +920,8 @@ void __init mpic_init(struct mpic *mpic)
/* do senses munging */ /* do senses munging */
if (mpic->senses && i < mpic->senses_count) if (mpic->senses && i < mpic->senses_count)
vecpri = mpic_flags_to_vecpri(mpic->senses[i], vecpri |= mpic_flags_to_vecpri(mpic->senses[i],
&level); &level);
else else
vecpri |= MPIC_VECPRI_SENSE_LEVEL; vecpri |= MPIC_VECPRI_SENSE_LEVEL;
...@@ -955,14 +971,17 @@ void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio) ...@@ -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) void __init mpic_set_serial_int(struct mpic *mpic, int enable)
{ {
unsigned long flags;
u32 v; u32 v;
spin_lock_irqsave(&mpic_lock, flags);
v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1); v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1);
if (enable) if (enable)
v |= MPIC_GREG_GLOBAL_CONF_1_SIE; v |= MPIC_GREG_GLOBAL_CONF_1_SIE;
else else
v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE; v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE;
mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v); 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) void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment