linux/arch/arm64/include/asm/irqflags.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-only */
   2/*
   3 * Copyright (C) 2012 ARM Ltd.
   4 */
   5#ifndef __ASM_IRQFLAGS_H
   6#define __ASM_IRQFLAGS_H
   7
   8#include <asm/alternative.h>
   9#include <asm/ptrace.h>
  10#include <asm/sysreg.h>
  11
  12/*
  13 * Aarch64 has flags for masking: Debug, Asynchronous (serror), Interrupts and
  14 * FIQ exceptions, in the 'daif' register. We mask and unmask them in 'dai'
  15 * order:
  16 * Masking debug exceptions causes all other exceptions to be masked too/
  17 * Masking SError masks irq, but not debug exceptions. Masking irqs has no
  18 * side effects for other flags. Keeping to this order makes it easier for
  19 * entry.S to know which exceptions should be unmasked.
  20 *
  21 * FIQ is never expected, but we mask it when we disable debug exceptions, and
  22 * unmask it at all other times.
  23 */
  24
  25/*
  26 * CPU interrupt mask handling.
  27 */
  28static inline void arch_local_irq_enable(void)
  29{
  30        if (system_has_prio_mask_debugging()) {
  31                u32 pmr = read_sysreg_s(SYS_ICC_PMR_EL1);
  32
  33                WARN_ON_ONCE(pmr != GIC_PRIO_IRQON && pmr != GIC_PRIO_IRQOFF);
  34        }
  35
  36        asm volatile(ALTERNATIVE(
  37                "msr    daifclr, #2             // arch_local_irq_enable\n"
  38                "nop",
  39                __msr_s(SYS_ICC_PMR_EL1, "%0")
  40                "dsb    sy",
  41                ARM64_HAS_IRQ_PRIO_MASKING)
  42                :
  43                : "r" ((unsigned long) GIC_PRIO_IRQON)
  44                : "memory");
  45}
  46
  47static inline void arch_local_irq_disable(void)
  48{
  49        if (system_has_prio_mask_debugging()) {
  50                u32 pmr = read_sysreg_s(SYS_ICC_PMR_EL1);
  51
  52                WARN_ON_ONCE(pmr != GIC_PRIO_IRQON && pmr != GIC_PRIO_IRQOFF);
  53        }
  54
  55        asm volatile(ALTERNATIVE(
  56                "msr    daifset, #2             // arch_local_irq_disable",
  57                __msr_s(SYS_ICC_PMR_EL1, "%0"),
  58                ARM64_HAS_IRQ_PRIO_MASKING)
  59                :
  60                : "r" ((unsigned long) GIC_PRIO_IRQOFF)
  61                : "memory");
  62}
  63
  64/*
  65 * Save the current interrupt enable state.
  66 */
  67static inline unsigned long arch_local_save_flags(void)
  68{
  69        unsigned long flags;
  70
  71        asm volatile(ALTERNATIVE(
  72                "mrs    %0, daif",
  73                __mrs_s("%0", SYS_ICC_PMR_EL1),
  74                ARM64_HAS_IRQ_PRIO_MASKING)
  75                : "=&r" (flags)
  76                :
  77                : "memory");
  78
  79        return flags;
  80}
  81
  82static inline int arch_irqs_disabled_flags(unsigned long flags)
  83{
  84        int res;
  85
  86        asm volatile(ALTERNATIVE(
  87                "and    %w0, %w1, #" __stringify(PSR_I_BIT),
  88                "eor    %w0, %w1, #" __stringify(GIC_PRIO_IRQON),
  89                ARM64_HAS_IRQ_PRIO_MASKING)
  90                : "=&r" (res)
  91                : "r" ((int) flags)
  92                : "memory");
  93
  94        return res;
  95}
  96
  97static inline unsigned long arch_local_irq_save(void)
  98{
  99        unsigned long flags;
 100
 101        flags = arch_local_save_flags();
 102
 103        /*
 104         * There are too many states with IRQs disabled, just keep the current
 105         * state if interrupts are already disabled/masked.
 106         */
 107        if (!arch_irqs_disabled_flags(flags))
 108                arch_local_irq_disable();
 109
 110        return flags;
 111}
 112
 113/*
 114 * restore saved IRQ state
 115 */
 116static inline void arch_local_irq_restore(unsigned long flags)
 117{
 118        asm volatile(ALTERNATIVE(
 119                        "msr    daif, %0\n"
 120                        "nop",
 121                        __msr_s(SYS_ICC_PMR_EL1, "%0")
 122                        "dsb    sy",
 123                        ARM64_HAS_IRQ_PRIO_MASKING)
 124                :
 125                : "r" (flags)
 126                : "memory");
 127}
 128
 129#endif /* __ASM_IRQFLAGS_H */
 130