Commit 373a3499 authored by Catalin Marinas's avatar Catalin Marinas

DSB needed after disabling masking the IRQ

Starting with ARMv6, accesses to strongly ordered memory are not
guaranteed to complete before a subsequent instruction modifying the
interrupt mask in CPSR. This can cause potential problems with masking
or acknowledging an IRQ at the device or interrupt controller level
followed by a local_irq_enable or local_irq_restore (see B2.4.3 in ARM
ARM revI). This patch adds a DSB after masking the interrupts at the
interrupt controller level to ensure that the strongly ordered memory
access was completed.
Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent fc65a471
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/threads.h> #include <linux/threads.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <asm/system.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <asm/hardware/gic.h> #include <asm/hardware/gic.h>
...@@ -89,6 +90,7 @@ static void gic_ack_irq(unsigned int irq) ...@@ -89,6 +90,7 @@ static void gic_ack_irq(unsigned int irq)
spin_lock(&irq_controller_lock); spin_lock(&irq_controller_lock);
writel(mask, gic_dist_base(irq) + GIC_DIST_ENABLE_CLEAR + (gic_irq(irq) / 32) * 4); writel(mask, gic_dist_base(irq) + GIC_DIST_ENABLE_CLEAR + (gic_irq(irq) / 32) * 4);
writel(gic_irq(irq), gic_cpu_base(irq) + GIC_CPU_EOI); writel(gic_irq(irq), gic_cpu_base(irq) + GIC_CPU_EOI);
dsb();
spin_unlock(&irq_controller_lock); spin_unlock(&irq_controller_lock);
} }
...@@ -98,6 +100,7 @@ static void gic_mask_irq(unsigned int irq) ...@@ -98,6 +100,7 @@ static void gic_mask_irq(unsigned int irq)
spin_lock(&irq_controller_lock); spin_lock(&irq_controller_lock);
writel(mask, gic_dist_base(irq) + GIC_DIST_ENABLE_CLEAR + (gic_irq(irq) / 32) * 4); writel(mask, gic_dist_base(irq) + GIC_DIST_ENABLE_CLEAR + (gic_irq(irq) / 32) * 4);
dsb();
spin_unlock(&irq_controller_lock); spin_unlock(&irq_controller_lock);
} }
...@@ -231,6 +234,7 @@ void __init gic_dist_init(unsigned int gic_nr, void __iomem *base, ...@@ -231,6 +234,7 @@ void __init gic_dist_init(unsigned int gic_nr, void __iomem *base,
*/ */
for (i = 0; i < max_irq; i += 32) for (i = 0; i < max_irq; i += 32)
writel(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); writel(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
dsb();
/* /*
* Setup the Linux IRQ subsystem. * Setup the Linux IRQ subsystem.
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/list.h> #include <linux/list.h>
#include <asm/system.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <asm/hardware/vic.h> #include <asm/hardware/vic.h>
...@@ -30,6 +31,7 @@ static void vic_mask_irq(unsigned int irq) ...@@ -30,6 +31,7 @@ static void vic_mask_irq(unsigned int irq)
void __iomem *base = get_irq_chipdata(irq); void __iomem *base = get_irq_chipdata(irq);
irq &= 31; irq &= 31;
writel(1 << irq, base + VIC_INT_ENABLE_CLEAR); writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
dsb();
} }
static void vic_unmask_irq(unsigned int irq) static void vic_unmask_irq(unsigned int irq)
......
...@@ -154,6 +154,7 @@ static void __init ap_map_io(void) ...@@ -154,6 +154,7 @@ static void __init ap_map_io(void)
static void sc_mask_irq(unsigned int irq) static void sc_mask_irq(unsigned int irq)
{ {
writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_CLEAR); writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_CLEAR);
dsb();
} }
static void sc_unmask_irq(unsigned int irq) static void sc_unmask_irq(unsigned int irq)
......
...@@ -148,6 +148,7 @@ static void cic_mask_irq(unsigned int irq) ...@@ -148,6 +148,7 @@ static void cic_mask_irq(unsigned int irq)
{ {
irq -= IRQ_CIC_START; irq -= IRQ_CIC_START;
cic_writel(1 << irq, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR); cic_writel(1 << irq, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR);
dsb();
} }
static void cic_unmask_irq(unsigned int irq) static void cic_unmask_irq(unsigned int irq)
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <asm/system.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -61,6 +62,7 @@ static void omap_mask_irq(unsigned int irq) ...@@ -61,6 +62,7 @@ static void omap_mask_irq(unsigned int irq)
} }
omap_writel(1 << irq, irq_banks[0].base_reg + INTC_MIR_SET0 + offset); omap_writel(1 << irq, irq_banks[0].base_reg + INTC_MIR_SET0 + offset);
dsb();
} }
static void omap_unmask_irq(unsigned int irq) static void omap_unmask_irq(unsigned int irq)
......
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