arm64: daifflags: Include PMR in daifflags restore operations
authorJulien Thierry <julien.thierry@arm.com>
Thu, 31 Jan 2019 14:58:51 +0000 (14:58 +0000)
committerCatalin Marinas <catalin.marinas@arm.com>
Wed, 6 Feb 2019 10:05:19 +0000 (10:05 +0000)
The addition of PMR should not bypass the semantics of daifflags.

When DA_F are set, I bit is also set as no interrupts (even of higher
priority) is allowed.

When DA_F are cleared, I bit is cleared and interrupt enabling/disabling
goes through ICC_PMR_EL1.

Signed-off-by: Julien Thierry <julien.thierry@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: James Morse <james.morse@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/include/asm/daifflags.h

index 546bc39..1dd3d7a 100644 (file)
@@ -18,6 +18,8 @@
 
 #include <linux/irqflags.h>
 
+#include <asm/cpufeature.h>
+
 #define DAIF_PROCCTX           0
 #define DAIF_PROCCTX_NOIRQ     PSR_I_BIT
 
@@ -36,7 +38,13 @@ static inline unsigned long local_daif_save(void)
 {
        unsigned long flags;
 
-       flags = arch_local_save_flags();
+       flags = read_sysreg(daif);
+
+       if (system_uses_irq_prio_masking()) {
+               /* If IRQs are masked with PMR, reflect it in the flags */
+               if (read_sysreg_s(SYS_ICC_PMR_EL1) <= GIC_PRIO_IRQOFF)
+                       flags |= PSR_I_BIT;
+       }
 
        local_daif_mask();
 
@@ -45,12 +53,46 @@ static inline unsigned long local_daif_save(void)
 
 static inline void local_daif_restore(unsigned long flags)
 {
-       if (!arch_irqs_disabled_flags(flags))
+       bool irq_disabled = flags & PSR_I_BIT;
+
+       if (!irq_disabled) {
                trace_hardirqs_on();
 
-       arch_local_irq_restore(flags);
+               if (system_uses_irq_prio_masking())
+                       arch_local_irq_enable();
+       } else if (!(flags & PSR_A_BIT)) {
+               /*
+                * If interrupts are disabled but we can take
+                * asynchronous errors, we can take NMIs
+                */
+               if (system_uses_irq_prio_masking()) {
+                       flags &= ~PSR_I_BIT;
+                       /*
+                        * There has been concern that the write to daif
+                        * might be reordered before this write to PMR.
+                        * From the ARM ARM DDI 0487D.a, section D1.7.1
+                        * "Accessing PSTATE fields":
+                        *   Writes to the PSTATE fields have side-effects on
+                        *   various aspects of the PE operation. All of these
+                        *   side-effects are guaranteed:
+                        *     - Not to be visible to earlier instructions in
+                        *       the execution stream.
+                        *     - To be visible to later instructions in the
+                        *       execution stream
+                        *
+                        * Also, writes to PMR are self-synchronizing, so no
+                        * interrupts with a lower priority than PMR is signaled
+                        * to the PE after the write.
+                        *
+                        * So we don't need additional synchronization here.
+                        */
+                       arch_local_irq_disable();
+               }
+       }
+
+       write_sysreg(flags, daif);
 
-       if (arch_irqs_disabled_flags(flags))
+       if (irq_disabled)
                trace_hardirqs_off();
 }