Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64...
[linux-2.6-microblaze.git] / arch / arm64 / include / asm / irqflags.h
index 6299631..7872f26 100644 (file)
@@ -1,17 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (C) 2012 ARM Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 #ifndef __ASM_IRQFLAGS_H
 #define __ASM_IRQFLAGS_H
  */
 static inline void arch_local_irq_enable(void)
 {
+       if (system_has_prio_mask_debugging()) {
+               u32 pmr = read_sysreg_s(SYS_ICC_PMR_EL1);
+
+               WARN_ON_ONCE(pmr != GIC_PRIO_IRQON && pmr != GIC_PRIO_IRQOFF);
+       }
+
        asm volatile(ALTERNATIVE(
                "msr    daifclr, #2             // arch_local_irq_enable\n"
                "nop",
@@ -53,6 +48,12 @@ static inline void arch_local_irq_enable(void)
 
 static inline void arch_local_irq_disable(void)
 {
+       if (system_has_prio_mask_debugging()) {
+               u32 pmr = read_sysreg_s(SYS_ICC_PMR_EL1);
+
+               WARN_ON_ONCE(pmr != GIC_PRIO_IRQON && pmr != GIC_PRIO_IRQOFF);
+       }
+
        asm volatile(ALTERNATIVE(
                "msr    daifset, #2             // arch_local_irq_disable",
                __msr_s(SYS_ICC_PMR_EL1, "%0"),
@@ -67,43 +68,46 @@ static inline void arch_local_irq_disable(void)
  */
 static inline unsigned long arch_local_save_flags(void)
 {
-       unsigned long daif_bits;
        unsigned long flags;
 
-       daif_bits = read_sysreg(daif);
-
-       /*
-        * The asm is logically equivalent to:
-        *
-        * if (system_uses_irq_prio_masking())
-        *      flags = (daif_bits & PSR_I_BIT) ?
-        *                      GIC_PRIO_IRQOFF :
-        *                      read_sysreg_s(SYS_ICC_PMR_EL1);
-        * else
-        *      flags = daif_bits;
-        */
        asm volatile(ALTERNATIVE(
-                       "mov    %0, %1\n"
-                       "nop\n"
-                       "nop",
-                       __mrs_s("%0", SYS_ICC_PMR_EL1)
-                       "ands   %1, %1, " __stringify(PSR_I_BIT) "\n"
-                       "csel   %0, %0, %2, eq",
-                       ARM64_HAS_IRQ_PRIO_MASKING)
-               : "=&r" (flags), "+r" (daif_bits)
-               : "r" ((unsigned long) GIC_PRIO_IRQOFF)
+               "mrs    %0, daif",
+               __mrs_s("%0", SYS_ICC_PMR_EL1),
+               ARM64_HAS_IRQ_PRIO_MASKING)
+               : "=&r" (flags)
+               :
                : "memory");
 
        return flags;
 }
 
+static inline int arch_irqs_disabled_flags(unsigned long flags)
+{
+       int res;
+
+       asm volatile(ALTERNATIVE(
+               "and    %w0, %w1, #" __stringify(PSR_I_BIT),
+               "eor    %w0, %w1, #" __stringify(GIC_PRIO_IRQON),
+               ARM64_HAS_IRQ_PRIO_MASKING)
+               : "=&r" (res)
+               : "r" ((int) flags)
+               : "memory");
+
+       return res;
+}
+
 static inline unsigned long arch_local_irq_save(void)
 {
        unsigned long flags;
 
        flags = arch_local_save_flags();
 
-       arch_local_irq_disable();
+       /*
+        * There are too many states with IRQs disabled, just keep the current
+        * state if interrupts are already disabled/masked.
+        */
+       if (!arch_irqs_disabled_flags(flags))
+               arch_local_irq_disable();
 
        return flags;
 }
@@ -119,26 +123,10 @@ static inline void arch_local_irq_restore(unsigned long flags)
                        __msr_s(SYS_ICC_PMR_EL1, "%0")
                        "dsb    sy",
                        ARM64_HAS_IRQ_PRIO_MASKING)
-               : "+r" (flags)
                :
+               : "r" (flags)
                : "memory");
 }
 
-static inline int arch_irqs_disabled_flags(unsigned long flags)
-{
-       int res;
-
-       asm volatile(ALTERNATIVE(
-                       "and    %w0, %w1, #" __stringify(PSR_I_BIT) "\n"
-                       "nop",
-                       "cmp    %w1, #" __stringify(GIC_PRIO_IRQOFF) "\n"
-                       "cset   %w0, ls",
-                       ARM64_HAS_IRQ_PRIO_MASKING)
-               : "=&r" (res)
-               : "r" ((int) flags)
-               : "memory");
-
-       return res;
-}
 #endif
 #endif