Commit e6878835 authored by sukadev@linux.vnet.ibm.com's avatar sukadev@linux.vnet.ibm.com Committed by Benjamin Herrenschmidt

powerpc/perf: Sample only if SIAR-Valid bit is set in P7+

powerpc/perf: Sample only if SIAR-Valid bit is set in P7+

On POWER7+ two new bits (mmcra[35] and mmcra[36]) indicate whether the
contents of SIAR and SDAR are valid.

For marked instructions on P7+, we must save the contents of SIAR and
SDAR registers only if these new bits are set.

This code/check for the SIAR-Valid bit is specific to P7+, so rather than
waste a CPU-feature bit use the PVR flag.

Note that Carl Love proposed a similar change for oprofile:

        https://lkml.org/lkml/2012/6/22/309Signed-off-by: default avatarSukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent e8294de5
...@@ -49,6 +49,7 @@ struct power_pmu { ...@@ -49,6 +49,7 @@ struct power_pmu {
#define PPMU_ALT_SIPR 2 /* uses alternate posn for SIPR/HV */ #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_SIPR 4 /* no SIPR/HV in MMCRA at all */
#define PPMU_NO_CONT_SAMPLING 8 /* no continuous sampling */ #define PPMU_NO_CONT_SAMPLING 8 /* no continuous sampling */
#define PPMU_SIAR_VALID 16 /* Processor has SIAR Valid bit */
/* /*
* Values for flags to get_alternatives() * Values for flags to get_alternatives()
......
...@@ -606,6 +606,10 @@ ...@@ -606,6 +606,10 @@
#define POWER6_MMCRA_SIPR 0x0000020000000000ULL #define POWER6_MMCRA_SIPR 0x0000020000000000ULL
#define POWER6_MMCRA_THRM 0x00000020UL #define POWER6_MMCRA_THRM 0x00000020UL
#define POWER6_MMCRA_OTHER 0x0000000EUL #define POWER6_MMCRA_OTHER 0x0000000EUL
#define POWER7P_MMCRA_SIAR_VALID 0x10000000 /* P7+ SIAR contents valid */
#define POWER7P_MMCRA_SDAR_VALID 0x08000000 /* P7+ SDAR contents valid */
#define SPRN_PMC1 787 #define SPRN_PMC1 787
#define SPRN_PMC2 788 #define SPRN_PMC2 788
#define SPRN_PMC3 789 #define SPRN_PMC3 789
......
...@@ -82,6 +82,11 @@ static inline int perf_intr_is_nmi(struct pt_regs *regs) ...@@ -82,6 +82,11 @@ static inline int perf_intr_is_nmi(struct pt_regs *regs)
return 0; return 0;
} }
static inline int siar_valid(struct pt_regs *regs)
{
return 1;
}
#endif /* CONFIG_PPC32 */ #endif /* CONFIG_PPC32 */
/* /*
...@@ -106,14 +111,20 @@ static inline unsigned long perf_ip_adjust(struct pt_regs *regs) ...@@ -106,14 +111,20 @@ static inline unsigned long perf_ip_adjust(struct pt_regs *regs)
* If we're not doing instruction sampling, give them the SDAR * If we're not doing instruction sampling, give them the SDAR
* (sampled data address). If we are doing instruction sampling, then * (sampled data address). If we are doing instruction sampling, then
* only give them the SDAR if it corresponds to the instruction * only give them the SDAR if it corresponds to the instruction
* pointed to by SIAR; this is indicated by the [POWER6_]MMCRA_SDSYNC * pointed to by SIAR; this is indicated by the [POWER6_]MMCRA_SDSYNC or
* bit in MMCRA. * the [POWER7P_]MMCRA_SDAR_VALID bit in MMCRA.
*/ */
static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp) static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp)
{ {
unsigned long mmcra = regs->dsisr; unsigned long mmcra = regs->dsisr;
unsigned long sdsync = (ppmu->flags & PPMU_ALT_SIPR) ? unsigned long sdsync;
POWER6_MMCRA_SDSYNC : MMCRA_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;
if (!(mmcra & MMCRA_SAMPLE_ENABLE) || (mmcra & sdsync)) if (!(mmcra & MMCRA_SAMPLE_ENABLE) || (mmcra & sdsync))
*addrp = mfspr(SPRN_SDAR); *addrp = mfspr(SPRN_SDAR);
...@@ -230,6 +241,24 @@ static inline int perf_intr_is_nmi(struct pt_regs *regs) ...@@ -230,6 +241,24 @@ static inline int perf_intr_is_nmi(struct pt_regs *regs)
return !regs->softe; return !regs->softe;
} }
/*
* On processors like P7+ that have the SIAR-Valid bit, marked instructions
* must be sampled only if the SIAR-valid bit is set.
*
* For unmarked instructions and for processors that don't have the SIAR-Valid
* bit, assume that SIAR is valid.
*/
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;
return 1;
}
#endif /* CONFIG_PPC64 */ #endif /* CONFIG_PPC64 */
static void perf_event_interrupt(struct pt_regs *regs); static void perf_event_interrupt(struct pt_regs *regs);
...@@ -1291,6 +1320,7 @@ struct pmu power_pmu = { ...@@ -1291,6 +1320,7 @@ struct pmu power_pmu = {
.event_idx = power_pmu_event_idx, .event_idx = power_pmu_event_idx,
}; };
/* /*
* A counter has overflowed; update its count and record * A counter has overflowed; update its count and record
* things if requested. Note that interrupts are hard-disabled * things if requested. Note that interrupts are hard-disabled
...@@ -1324,7 +1354,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val, ...@@ -1324,7 +1354,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
left += period; left += period;
if (left <= 0) if (left <= 0)
left = period; left = period;
record = 1; record = siar_valid(regs);
event->hw.last_period = event->hw.sample_period; event->hw.last_period = event->hw.sample_period;
} }
if (left < 0x80000000LL) if (left < 0x80000000LL)
...@@ -1374,8 +1404,10 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs) ...@@ -1374,8 +1404,10 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs)
{ {
unsigned long use_siar = regs->result; unsigned long use_siar = regs->result;
if (use_siar) if (use_siar && siar_valid(regs))
return mfspr(SPRN_SIAR) + perf_ip_adjust(regs); return mfspr(SPRN_SIAR) + perf_ip_adjust(regs);
else if (use_siar)
return 0; // no valid instruction pointer
else else
return regs->nip; return regs->nip;
} }
......
...@@ -373,6 +373,9 @@ static int __init init_power7_pmu(void) ...@@ -373,6 +373,9 @@ static int __init init_power7_pmu(void)
strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power7")) strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power7"))
return -ENODEV; return -ENODEV;
if (pvr_version_is(PVR_POWER7p))
power7_pmu.flags |= PPMU_SIAR_VALID;
return register_power_pmu(&power7_pmu); return register_power_pmu(&power7_pmu);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment