Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
[platform/kernel/linux-rpi.git] / arch / powerpc / perf / core-book3s.c
index 426180b..29c6482 100644 (file)
@@ -110,7 +110,7 @@ static inline void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) {}
 
 static bool regs_use_siar(struct pt_regs *regs)
 {
-       return !!(regs->result & 1);
+       return !!regs->result;
 }
 
 /*
@@ -136,22 +136,30 @@ static inline unsigned long perf_ip_adjust(struct pt_regs *regs)
  * If we're not doing instruction sampling, give them the SDAR
  * (sampled data address).  If we are doing instruction sampling, then
  * only give them the SDAR if it corresponds to the instruction
- * pointed to by SIAR; this is indicated by the [POWER6_]MMCRA_SDSYNC or
- * the [POWER7P_]MMCRA_SDAR_VALID bit in MMCRA.
+ * pointed to by SIAR; this is indicated by the [POWER6_]MMCRA_SDSYNC, the
+ * [POWER7P_]MMCRA_SDAR_VALID bit in MMCRA, or the SDAR_VALID bit in SIER.
  */
 static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp)
 {
        unsigned long mmcra = regs->dsisr;
-       unsigned long sdsync;
+       bool sdar_valid;
 
-       if (ppmu->flags & PPMU_SIAR_VALID)
-               sdsync = POWER7P_MMCRA_SDAR_VALID;
-       else if (ppmu->flags & PPMU_ALT_SIPR)
-               sdsync = POWER6_MMCRA_SDSYNC;
-       else
-               sdsync = MMCRA_SDSYNC;
+       if (ppmu->flags & PPMU_HAS_SIER)
+               sdar_valid = regs->dar & SIER_SDAR_VALID;
+       else {
+               unsigned long sdsync;
+
+               if (ppmu->flags & PPMU_SIAR_VALID)
+                       sdsync = POWER7P_MMCRA_SDAR_VALID;
+               else if (ppmu->flags & PPMU_ALT_SIPR)
+                       sdsync = POWER6_MMCRA_SDSYNC;
+               else
+                       sdsync = MMCRA_SDSYNC;
+
+               sdar_valid = mmcra & sdsync;
+       }
 
-       if (!(mmcra & MMCRA_SAMPLE_ENABLE) || (mmcra & sdsync))
+       if (!(mmcra & MMCRA_SAMPLE_ENABLE) || sdar_valid)
                *addrp = mfspr(SPRN_SDAR);
 }
 
@@ -181,11 +189,6 @@ static bool regs_sipr(struct pt_regs *regs)
        return !!(regs->dsisr & sipr);
 }
 
-static bool regs_no_sipr(struct pt_regs *regs)
-{
-       return !!(regs->result & 2);
-}
-
 static inline u32 perf_flags_from_msr(struct pt_regs *regs)
 {
        if (regs->msr & MSR_PR)
@@ -208,7 +211,7 @@ static inline u32 perf_get_misc_flags(struct pt_regs *regs)
         * SIAR which should give slightly more reliable
         * results
         */
-       if (regs_no_sipr(regs)) {
+       if (ppmu->flags & PPMU_NO_SIPR) {
                unsigned long siar = mfspr(SPRN_SIAR);
                if (siar >= PAGE_OFFSET)
                        return PERF_RECORD_MISC_KERNEL;
@@ -239,22 +242,9 @@ static inline void perf_read_regs(struct pt_regs *regs)
        int use_siar;
 
        regs->dsisr = mmcra;
-       regs->result = 0;
-
-       if (ppmu->flags & PPMU_NO_SIPR)
-               regs->result |= 2;
-
-       /*
-        * On power8 if we're in random sampling mode, the SIER is updated.
-        * If we're in continuous sampling mode, we don't have SIPR.
-        */
-       if (ppmu->flags & PPMU_HAS_SIER) {
-               if (marked)
-                       regs->dar = mfspr(SPRN_SIER);
-               else
-                       regs->result |= 2;
-       }
 
+       if (ppmu->flags & PPMU_HAS_SIER)
+               regs->dar = mfspr(SPRN_SIER);
 
        /*
         * If this isn't a PMU exception (eg a software event) the SIAR is
@@ -279,12 +269,12 @@ static inline void perf_read_regs(struct pt_regs *regs)
                use_siar = 1;
        else if ((ppmu->flags & PPMU_NO_CONT_SAMPLING))
                use_siar = 0;
-       else if (!regs_no_sipr(regs) && regs_sipr(regs))
+       else if (!(ppmu->flags & PPMU_NO_SIPR) && regs_sipr(regs))
                use_siar = 0;
        else
                use_siar = 1;
 
-       regs->result |= use_siar;
+       regs->result = use_siar;
 }
 
 /*
@@ -308,8 +298,13 @@ static inline int siar_valid(struct pt_regs *regs)
        unsigned long mmcra = regs->dsisr;
        int marked = mmcra & MMCRA_SAMPLE_ENABLE;
 
-       if ((ppmu->flags & PPMU_SIAR_VALID) && marked)
-               return mmcra & POWER7P_MMCRA_SIAR_VALID;
+       if (marked) {
+               if (ppmu->flags & PPMU_HAS_SIER)
+                       return regs->dar & SIER_SIAR_VALID;
+
+               if (ppmu->flags & PPMU_SIAR_VALID)
+                       return mmcra & POWER7P_MMCRA_SIAR_VALID;
+       }
 
        return 1;
 }
@@ -1763,7 +1758,7 @@ static void perf_event_interrupt(struct pt_regs *regs)
                        }
                }
        }
-       if ((!found) && printk_ratelimit())
+       if (!found && !nmi && printk_ratelimit())
                printk(KERN_WARNING "Can't find PMC that caused IRQ\n");
 
        /*