summaryrefslogtreecommitdiff
path: root/arch/powerpc/include/asm/hw_irq.h
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/include/asm/hw_irq.h')
-rw-r--r--arch/powerpc/include/asm/hw_irq.h30
1 files changed, 23 insertions, 7 deletions
diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h
index 52afb1595cb0..f96280ee9540 100644
--- a/arch/powerpc/include/asm/hw_irq.h
+++ b/arch/powerpc/include/asm/hw_irq.h
@@ -31,8 +31,8 @@
/*
* flags for paca->soft_enabled
*/
-#define IRQS_ENABLED 1
-#define IRQS_DISABLED 0
+#define IRQS_ENABLED 0
+#define IRQS_DISABLED 1
#endif /* CONFIG_PPC64 */
@@ -68,6 +68,18 @@ static inline notrace unsigned long soft_enabled_return(void)
*/
static inline notrace void soft_enabled_set(unsigned long enable)
{
+#ifdef CONFIG_TRACE_IRQFLAGS
+ /*
+ * mask must always include LINUX bit if any are set, and
+ * interrupts don't get replayed until the Linux interrupt is
+ * unmasked. This could be changed to replay partial unmasks
+ * in future, which would allow Linux masks to nest inside
+ * other masks, among other things. For now, be very dumb and
+ * simple.
+ */
+ WARN_ON(mask && !(mask & IRQS_DISABLED));
+#endif
+
asm volatile(
"stb %0,%1(13)"
:
@@ -76,15 +88,19 @@ static inline notrace void soft_enabled_set(unsigned long enable)
: "memory");
}
-static inline notrace unsigned long soft_enabled_set_return(unsigned long enable)
+static inline notrace unsigned long soft_enabled_set_return(unsigned long mask)
{
unsigned long flags;
+#ifdef CONFIG_TRACE_IRQFLAGS
+ WARN_ON(mask && !(mask & IRQS_DISABLED));
+#endif
+
asm volatile(
"lbz %0,%1(13); stb %2,%1(13)"
: "=&r" (flags)
: "i" (offsetof(struct paca_struct, soft_enabled)),
- "r" (enable)
+ "r" (mask)
: "memory");
return flags;
@@ -114,7 +130,7 @@ static inline unsigned long arch_local_irq_save(void)
static inline bool arch_irqs_disabled_flags(unsigned long flags)
{
- return flags == IRQS_DISABLED;
+ return flags & IRQS_DISABLED;
}
static inline bool arch_irqs_disabled(void)
@@ -133,7 +149,7 @@ static inline bool arch_irqs_disabled(void)
#define hard_irq_disable() do { \
unsigned long flags; \
__hard_irq_disable(); \
- flags = soft_enabled_set_return(IRQS_DISABLED); \
+ flags = soft_enabled_set_return(IRQS_DISABLED);\
local_paca->irq_happened |= PACA_IRQ_HARD_DIS; \
if (!arch_irqs_disabled_flags(flags)) \
trace_hardirqs_off(); \
@@ -158,7 +174,7 @@ static inline void may_hard_irq_enable(void)
static inline bool arch_irq_disabled_regs(struct pt_regs *regs)
{
- return (regs->softe == IRQS_DISABLED);
+ return (regs->softe & IRQS_DISABLED);
}
extern bool prep_irq_for_idle(void);