From d4796e458e69a0d52f8ea017cb424d0a09312130 Mon Sep 17 00:00:00 2001 From: Daniel Thompson Date: Tue, 17 Mar 2015 16:38:10 +0000 Subject: arm64: irqflags: Automatically identify I bit mis-management This is self-test code to identify circumstances where the I bit is set by hardware but no software exists to copy its state to the PMR. I don't really expect this patch to be retained much after the RFC stage. However I have included it in this RFC series to document the testing I have done and to allow further testing under different workloads. Signed-off-by: Daniel Thompson --- arch/arm64/include/asm/irqflags.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'arch/arm64/include/asm') diff --git a/arch/arm64/include/asm/irqflags.h b/arch/arm64/include/asm/irqflags.h index 7b6866022f82..89be5f830857 100644 --- a/arch/arm64/include/asm/irqflags.h +++ b/arch/arm64/include/asm/irqflags.h @@ -18,6 +18,7 @@ #ifdef __KERNEL__ +#include #include #ifndef CONFIG_USE_ICC_SYSREGS_FOR_IRQFLAGS @@ -90,6 +91,23 @@ static inline int arch_irqs_disabled_flags(unsigned long flags) #include +extern bool enable_i_bit_check; + +static inline void check_for_i_bit(void) +{ +#ifdef CONFIG_USE_ICC_SYSREGS_FOR_IRQFLAGS_SELF_TEST + unsigned long psr; + + if (enable_i_bit_check) { + asm volatile("mrs %0, daif" : "=r"(psr)); + if (psr & PSR_I_BIT) { + enable_i_bit_check = false; + WARN(true, "I bit is set: %08lx\n", psr); + } + } +#endif +} + /* * CPU interrupt mask handling. */ @@ -97,6 +115,8 @@ static inline unsigned long arch_local_irq_save(void) { unsigned long flags, masked = ICC_PMR_EL1_MASKED; + check_for_i_bit(); + asm volatile( "// arch_local_irq_save\n" "mrs_s %0, " __stringify(ICC_PMR_EL1) "\n" @@ -113,6 +133,8 @@ static inline void arch_local_irq_enable(void) { unsigned long unmasked = ICC_PMR_EL1_UNMASKED; + check_for_i_bit(); + asm volatile( "// arch_local_irq_enable\n" "msr_s " __stringify(ICC_PMR_EL1) ",%0\n" @@ -126,6 +148,8 @@ static inline void arch_local_irq_disable(void) { unsigned long masked = ICC_PMR_EL1_MASKED; + check_for_i_bit(); + asm volatile( "// arch_local_irq_disable\n" "msr_s " __stringify(ICC_PMR_EL1) ",%0\n" @@ -142,6 +166,8 @@ static inline unsigned long arch_local_save_flags(void) { unsigned long flags; + check_for_i_bit(); + asm volatile( "// arch_local_save_flags\n" "mrs_s %0, " __stringify(ICC_PMR_EL1) "\n" @@ -157,6 +183,8 @@ static inline unsigned long arch_local_save_flags(void) */ static inline void arch_local_irq_restore(unsigned long flags) { + check_for_i_bit(); + asm volatile( "// arch_local_irq_restore\n" "msr_s " __stringify(ICC_PMR_EL1) ",%0\n" @@ -168,6 +196,7 @@ static inline void arch_local_irq_restore(unsigned long flags) static inline int arch_irqs_disabled_flags(unsigned long flags) { + check_for_i_bit(); return !(flags & ICC_PMR_EL1_G_BIT); } -- cgit v1.2.3