OSDN Git Service

powerpc/64s: Add new set of irq_soft_mask_ functions for PMI masking
authorMadhavan Srinivasan <maddy@linux.vnet.ibm.com>
Wed, 20 Dec 2017 03:55:55 +0000 (09:25 +0530)
committerMichael Ellerman <mpe@ellerman.id.au>
Fri, 19 Jan 2018 11:37:03 +0000 (22:37 +1100)
To support soft-masking of the performance monitor interrupt, a set of
new powerpc_local_irq_pmu_save() and powerpc_local_irq_restore()
functions are added. And powerpc_local_irq_save() implemented, by
adding a new irq_soft_mask manipulation function
irq_soft_mask_or_return().

Local_irq_pmu_* macros are provided to access these
powerpc_local_irq_pmu* functions which includes
trace_hardirqs_on|off() to match what we have in
include/linux/irqflags.h.

Signed-off-by: Madhavan Srinivasan <maddy@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/hw_irq.h

index f40da3b..88e5e8f 100644 (file)
@@ -115,6 +115,24 @@ static inline notrace unsigned long irq_soft_mask_set_return(unsigned long mask)
        return flags;
 }
 
+static inline notrace unsigned long irq_soft_mask_or_return(unsigned long mask)
+{
+       unsigned long flags, tmp;
+
+       asm volatile(
+               "lbz %0,%2(13); or %1,%0,%3; stb %1,%2(13)"
+               : "=&r" (flags), "=r" (tmp)
+               : "i" (offsetof(struct paca_struct, irq_soft_mask)),
+                 "r" (mask)
+               : "memory");
+
+#ifdef CONFIG_PPC_IRQ_SOFT_MASK_DEBUG
+       WARN_ON((mask | flags) && !((mask | flags) & IRQS_DISABLED));
+#endif
+
+       return flags;
+}
+
 static inline unsigned long arch_local_save_flags(void)
 {
        return irq_soft_mask_return();
@@ -147,6 +165,55 @@ static inline bool arch_irqs_disabled(void)
        return arch_irqs_disabled_flags(arch_local_save_flags());
 }
 
+#ifdef CONFIG_PPC_BOOK3S
+/*
+ * To support disabling and enabling of irq with PMI, set of
+ * new powerpc_local_irq_pmu_save() and powerpc_local_irq_restore()
+ * functions are added. These macros are implemented using generic
+ * linux local_irq_* code from include/linux/irqflags.h.
+ */
+#define raw_local_irq_pmu_save(flags)                                  \
+       do {                                                            \
+               typecheck(unsigned long, flags);                        \
+               flags = irq_soft_mask_or_return(IRQS_DISABLED | \
+                               IRQS_PMI_DISABLED);                     \
+       } while(0)
+
+#define raw_local_irq_pmu_restore(flags)                               \
+       do {                                                            \
+               typecheck(unsigned long, flags);                        \
+               arch_local_irq_restore(flags);                          \
+       } while(0)
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+#define powerpc_local_irq_pmu_save(flags)                      \
+        do {                                                   \
+               raw_local_irq_pmu_save(flags);                  \
+               trace_hardirqs_off();                           \
+       } while(0)
+#define powerpc_local_irq_pmu_restore(flags)                   \
+       do {                                                    \
+               if (raw_irqs_disabled_flags(flags)) {           \
+                       raw_local_irq_pmu_restore(flags);       \
+                       trace_hardirqs_off();                   \
+               } else {                                        \
+                       trace_hardirqs_on();                    \
+                       raw_local_irq_pmu_restore(flags);       \
+               }                                               \
+       } while(0)
+#else
+#define powerpc_local_irq_pmu_save(flags)                      \
+       do {                                                    \
+               raw_local_irq_pmu_save(flags);                  \
+       } while(0)
+#define powerpc_local_irq_pmu_restore(flags)                   \
+       do {                                                    \
+               raw_local_irq_pmu_restore(flags);               \
+       } while (0)
+#endif  /* CONFIG_TRACE_IRQFLAGS */
+
+#endif /* CONFIG_PPC_BOOK3S */
+
 #ifdef CONFIG_PPC_BOOK3E
 #define __hard_irq_enable()    asm volatile("wrteei 1" : : : "memory")
 #define __hard_irq_disable()   asm volatile("wrteei 0" : : : "memory")