diff --git a/arch/powerpc/include/asm/perf_event.h b/arch/powerpc/include/asm/perf_event.h index 5c16b891d501f8f3943a10311d1020da608843d1..0bb23725b1e721a0d5e89f23db233f15b8a9b3ac 100644 --- a/arch/powerpc/include/asm/perf_event.h +++ b/arch/powerpc/include/asm/perf_event.h @@ -26,8 +26,13 @@ #include #include +/* + * Overload regs->result to specify whether we should use the MSR (result + * is zero) or the SIAR (result is non zero). + */ #define perf_arch_fetch_caller_regs(regs, __ip) \ do { \ + (regs)->result = 0; \ (regs)->nip = __ip; \ (regs)->gpr[1] = *(unsigned long *)__get_SP(); \ asm volatile("mfmsr %0" : "=r" ((regs)->msr)); \ diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 1818f636b9aef1434f1e7481eda023da0572c146..dcb6a798f1110eee37b3d7e1164cf31c71f9bd0a 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -73,7 +73,10 @@ static inline u32 perf_get_misc_flags(struct pt_regs *regs) { return 0; } -static inline void perf_read_regs(struct pt_regs *regs) { } +static inline void perf_read_regs(struct pt_regs *regs) +{ + regs->result = 0; +} static inline int perf_intr_is_nmi(struct pt_regs *regs) { return 0; @@ -148,17 +151,9 @@ static inline u32 perf_flags_from_msr(struct pt_regs *regs) static inline u32 perf_get_misc_flags(struct pt_regs *regs) { unsigned long mmcra = regs->dsisr; + unsigned long use_siar = regs->result; - /* Not a PMU interrupt: Make up flags from regs->msr */ - if (TRAP(regs) != 0xf00) - 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)) + if (!use_siar) return perf_flags_from_msr(regs); /* @@ -185,10 +180,24 @@ static inline u32 perf_get_misc_flags(struct pt_regs *regs) /* * Overload regs->dsisr to store MMCRA so we only need to read it once * on each interrupt. + * Overload regs->result to specify whether we should use the MSR (result + * is zero) or the SIAR (result is non zero). */ static inline void perf_read_regs(struct pt_regs *regs) { - regs->dsisr = mfspr(SPRN_MMCRA); + unsigned long mmcra = mfspr(SPRN_MMCRA); + int marked = mmcra & MMCRA_SAMPLE_ENABLE; + int use_siar; + + if (TRAP(regs) != 0xf00) + use_siar = 0; + else if ((ppmu->flags & PPMU_NO_CONT_SAMPLING) && !marked) + use_siar = 0; + else + use_siar = 1; + + regs->dsisr = mmcra; + regs->result = use_siar; } /* @@ -1342,18 +1351,12 @@ unsigned long perf_misc_flags(struct pt_regs *regs) */ unsigned long perf_instruction_pointer(struct pt_regs *regs) { - unsigned long mmcra = regs->dsisr; + unsigned long use_siar = regs->result; - /* Not a PMU interrupt */ - if (TRAP(regs) != 0xf00) - return regs->nip; - - /* Processor doesn't support sampling non marked events */ - if ((ppmu->flags & PPMU_NO_CONT_SAMPLING) && - !(mmcra & MMCRA_SAMPLE_ENABLE)) + if (use_siar) + return mfspr(SPRN_SIAR) + perf_ip_adjust(regs); + else return regs->nip; - - return mfspr(SPRN_SIAR) + perf_ip_adjust(regs); } static bool pmc_overflow(unsigned long val)