powerpc/perf: Fix instruction address sampling on 970 and Power4
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 26 Mar 2012 20:47:34 +0000 (20:47 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Wed, 28 Mar 2012 00:33:24 +0000 (11:33 +1100)
970 and Power4 don't support "continuous sampling" which means that
when we aren't in marked instruction sampling mode (marked events),
SIAR isn't updated with the last instruction sampled before the
perf interrupt. On those processors, we must thus use the exception
SRR0 value as the sampled instruction pointer.

Those processors also don't support the SIPR and SIHV bits in MMCRA
which means we need some kind of heuristic to decide if SIAR values
represent kernel or user addresses.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/include/asm/perf_event_server.h
arch/powerpc/perf/core-book3s.c
arch/powerpc/perf/power4-pmu.c
arch/powerpc/perf/ppc970-pmu.c

index 1a8093fa8f711a80c6d599507dfe8e0d0a0006bb..078019b5b353c916f49dd0d71087260302569c60 100644 (file)
@@ -47,6 +47,8 @@ struct power_pmu {
  */
 #define PPMU_LIMITED_PMC5_6    1       /* PMC5/6 have limited function */
 #define PPMU_ALT_SIPR          2       /* uses alternate posn for SIPR/HV */
+#define PPMU_NO_SIPR           4       /* no SIPR/HV in MMCRA at all */
+#define PPMU_NO_CONT_SAMPLING  8       /* no continuous sampling */
 
 /*
  * Values for flags to get_alternatives()
index c2e27ede07ec8afb138fbaac31b736ea96b6ddc1..02aee03e713c6f287721faa7079ac760c865f7c9 100644 (file)
@@ -116,14 +116,45 @@ static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp)
                *addrp = mfspr(SPRN_SDAR);
 }
 
+static inline u32 perf_flags_from_msr(struct pt_regs *regs)
+{
+       if (regs->msr & MSR_PR)
+               return PERF_RECORD_MISC_USER;
+       if ((regs->msr & MSR_HV) && freeze_events_kernel != MMCR0_FCHV)
+               return PERF_RECORD_MISC_HYPERVISOR;
+       return PERF_RECORD_MISC_KERNEL;
+}
+
 static inline u32 perf_get_misc_flags(struct pt_regs *regs)
 {
        unsigned long mmcra = regs->dsisr;
        unsigned long sihv = MMCRA_SIHV;
        unsigned long sipr = MMCRA_SIPR;
 
+       /* Not a PMU interrupt: Make up flags from regs->msr */
        if (TRAP(regs) != 0xf00)
-               return 0;       /* not a PMU interrupt */
+               return perf_flags_from_msr(regs);
+
+       /*
+        * If we don't support continuous sampling and this
+        * is not a marked event, same deal
+        */
+       if ((ppmu->flags & PPMU_NO_CONT_SAMPLING) &&
+           !(mmcra & MMCRA_SAMPLE_ENABLE))
+               return perf_flags_from_msr(regs);
+
+       /*
+        * If we don't have flags in MMCRA, rather than using
+        * the MSR, we intuit the flags from the address in
+        * SIAR which should give slightly more reliable
+        * results
+        */
+       if (ppmu->flags & PPMU_NO_SIPR) {
+               unsigned long siar = mfspr(SPRN_SIAR);
+               if (siar >= PAGE_OFFSET)
+                       return PERF_RECORD_MISC_KERNEL;
+               return PERF_RECORD_MISC_USER;
+       }
 
        if (ppmu->flags & PPMU_ALT_SIPR) {
                sihv = POWER6_MMCRA_SIHV;
@@ -1299,13 +1330,18 @@ unsigned long perf_misc_flags(struct pt_regs *regs)
  */
 unsigned long perf_instruction_pointer(struct pt_regs *regs)
 {
-       unsigned long ip;
+       unsigned long mmcra = regs->dsisr;
 
+       /* Not a PMU interrupt */
        if (TRAP(regs) != 0xf00)
-               return regs->nip;       /* not a PMU interrupt */
+               return regs->nip;
+
+       /* Processor doesn't support sampling non marked events */
+       if ((ppmu->flags & PPMU_NO_CONT_SAMPLING) &&
+           !(mmcra & MMCRA_SAMPLE_ENABLE))
+               return regs->nip;
 
-       ip = mfspr(SPRN_SIAR) + perf_ip_adjust(regs);
-       return ip;
+       return mfspr(SPRN_SIAR) + perf_ip_adjust(regs);
 }
 
 static bool pmc_overflow(unsigned long val)
index b4f1dda4d0896359e35d23ac497fcc4d37a5e64d..9103a1de864da338149e75a4b4e3ddc23f3f816f 100644 (file)
@@ -607,6 +607,7 @@ static struct power_pmu power4_pmu = {
        .n_generic              = ARRAY_SIZE(p4_generic_events),
        .generic_events         = p4_generic_events,
        .cache_events           = &power4_cache_events,
+       .flags                  = PPMU_NO_SIPR | PPMU_NO_CONT_SAMPLING,
 };
 
 static int __init init_power4_pmu(void)
index 111eb25bb0b6bb22d32b89222a2a3f64c2c93339..20139ceeacf68b03009a8854adb6eb82d8dfebb9 100644 (file)
@@ -487,6 +487,7 @@ static struct power_pmu ppc970_pmu = {
        .n_generic              = ARRAY_SIZE(ppc970_generic_events),
        .generic_events         = ppc970_generic_events,
        .cache_events           = &ppc970_cache_events,
+       .flags                  = PPMU_NO_SIPR | PPMU_NO_CONT_SAMPLING,
 };
 
 static int __init init_ppc970_pmu(void)