aboutsummaryrefslogtreecommitdiff
path: root/drivers/irqchip/irq-gic-v3.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/irqchip/irq-gic-v3.c')
-rw-r--r--drivers/irqchip/irq-gic-v3.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 32533650494c..3923b2a2150c 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -110,8 +110,33 @@ static void gic_redist_wait_for_rwp(void)
static u64 __maybe_unused gic_read_iar(void)
{
u64 irqstat;
+ u64 __maybe_unused daif;
+ u64 __maybe_unused pmr;
+ u64 __maybe_unused default_pmr_value = DEFAULT_PMR_VALUE;
+#ifndef CONFIG_USE_ICC_SYSREGS_FOR_IRQFLAGS
asm volatile("mrs_s %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat));
+#else
+ /*
+ * The PMR may be configured to mask interrupts when this code is
+ * called, thus in order to acknowledge interrupts we must set the
+ * PMR to its default value before reading from the IAR.
+ *
+ * To do this without taking an interrupt we also ensure the I bit
+ * is set whilst we are interfering with the value of the PMR.
+ */
+ asm volatile(
+ "mrs %1, daif\n" /* save I bit */
+ "msr daifset, #2\n" /* set I bit */
+ "mrs_s %2, " __stringify(ICC_PMR_EL1) "\n" /* save PMR */
+ "msr_s " __stringify(ICC_PMR_EL1) ",%3\n" /* set PMR */
+ "mrs_s %0, " __stringify(ICC_IAR1_EL1) "\n" /* ack int */
+ "msr_s " __stringify(ICC_PMR_EL1) ",%2\n" /* restore PMR */
+ "isb\n"
+ "msr daif, %1" /* restore I */
+ : "=r" (irqstat), "=&r" (daif), "=&r" (pmr)
+ : "r" (default_pmr_value));
+#endif
return irqstat;
}
@@ -142,7 +167,7 @@ static void __maybe_unused gic_write_sgi1r(u64 val)
asm volatile("msr_s " __stringify(ICC_SGI1R_EL1) ", %0" : : "r" (val));
}
-static void gic_enable_sre(void)
+static void __maybe_unused gic_enable_sre(void)
{
u64 val;
@@ -382,11 +407,13 @@ static int gic_populate_rdist(void)
static void gic_cpu_sys_reg_init(void)
{
+#ifndef CONFIG_USE_ICC_SYSREGS_FOR_IRQFLAGS
/* Enable system registers */
gic_enable_sre();
/* Set priority mask register */
gic_write_pmr(DEFAULT_PMR_VALUE);
+#endif
/*
* On FVP, CPU 0 arrives in the kernel with its BPR changed from the