arm64: daifflags: Include PMR in daifflags restore operations
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>
This commit is contained in:
parent
4a503217ce
commit
8cb7eff32c
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
if (arch_irqs_disabled_flags(flags))
|
||||
write_sysreg(flags, daif);
|
||||
|
||||
if (irq_disabled)
|
||||
trace_hardirqs_off();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue