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