Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3202e35e authored by Ravi Bangoria's avatar Ravi Bangoria Committed by Michael Ellerman
Browse files

powerpc/perf: Fix MMCRA corruption by bhrb_filter



Consider a scenario where user creates two events:

  1st event:
    attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
    attr.branch_sample_type = PERF_SAMPLE_BRANCH_ANY;
    fd = perf_event_open(attr, 0, 1, -1, 0);

  This sets cpuhw->bhrb_filter to 0 and returns valid fd.

  2nd event:
    attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
    attr.branch_sample_type = PERF_SAMPLE_BRANCH_CALL;
    fd = perf_event_open(attr, 0, 1, -1, 0);

  It overrides cpuhw->bhrb_filter to -1 and returns with error.

Now if power_pmu_enable() gets called by any path other than
power_pmu_add(), ppmu->config_bhrb(-1) will set MMCRA to -1.

Fixes: 3925f46b ("powerpc/perf: Enable branch stack sampling framework")
Cc: stable@vger.kernel.org # v3.10+
Signed-off-by: default avatarRavi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: default avatarMadhavan Srinivasan <maddy@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent b59bd352
Loading
Loading
Loading
Loading
+4 −2
Original line number Original line Diff line number Diff line
@@ -1850,6 +1850,7 @@ static int power_pmu_event_init(struct perf_event *event)
	int n;
	int n;
	int err;
	int err;
	struct cpu_hw_events *cpuhw;
	struct cpu_hw_events *cpuhw;
	u64 bhrb_filter;


	if (!ppmu)
	if (!ppmu)
		return -ENOENT;
		return -ENOENT;
@@ -1955,13 +1956,14 @@ static int power_pmu_event_init(struct perf_event *event)
	err = power_check_constraints(cpuhw, events, cflags, n + 1);
	err = power_check_constraints(cpuhw, events, cflags, n + 1);


	if (has_branch_stack(event)) {
	if (has_branch_stack(event)) {
		cpuhw->bhrb_filter = ppmu->bhrb_filter_map(
		bhrb_filter = ppmu->bhrb_filter_map(
					event->attr.branch_sample_type);
					event->attr.branch_sample_type);


		if (cpuhw->bhrb_filter == -1) {
		if (bhrb_filter == -1) {
			put_cpu_var(cpu_hw_events);
			put_cpu_var(cpu_hw_events);
			return -EOPNOTSUPP;
			return -EOPNOTSUPP;
		}
		}
		cpuhw->bhrb_filter = bhrb_filter;
	}
	}


	put_cpu_var(cpu_hw_events);
	put_cpu_var(cpu_hw_events);
+3 −0
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@ enum {
#define	POWER8_MMCRA_IFM1		0x0000000040000000UL
#define	POWER8_MMCRA_IFM1		0x0000000040000000UL
#define	POWER8_MMCRA_IFM2		0x0000000080000000UL
#define	POWER8_MMCRA_IFM2		0x0000000080000000UL
#define	POWER8_MMCRA_IFM3		0x00000000C0000000UL
#define	POWER8_MMCRA_IFM3		0x00000000C0000000UL
#define	POWER8_MMCRA_BHRB_MASK		0x00000000C0000000UL


/*
/*
 * Raw event encoding for PowerISA v2.07 (Power8):
 * Raw event encoding for PowerISA v2.07 (Power8):
@@ -243,6 +244,8 @@ static u64 power8_bhrb_filter_map(u64 branch_sample_type)


static void power8_config_bhrb(u64 pmu_bhrb_filter)
static void power8_config_bhrb(u64 pmu_bhrb_filter)
{
{
	pmu_bhrb_filter &= POWER8_MMCRA_BHRB_MASK;

	/* Enable BHRB filter in PMU */
	/* Enable BHRB filter in PMU */
	mtspr(SPRN_MMCRA, (mfspr(SPRN_MMCRA) | pmu_bhrb_filter));
	mtspr(SPRN_MMCRA, (mfspr(SPRN_MMCRA) | pmu_bhrb_filter));
}
}
+3 −0
Original line number Original line Diff line number Diff line
@@ -92,6 +92,7 @@ enum {
#define POWER9_MMCRA_IFM1		0x0000000040000000UL
#define POWER9_MMCRA_IFM1		0x0000000040000000UL
#define POWER9_MMCRA_IFM2		0x0000000080000000UL
#define POWER9_MMCRA_IFM2		0x0000000080000000UL
#define POWER9_MMCRA_IFM3		0x00000000C0000000UL
#define POWER9_MMCRA_IFM3		0x00000000C0000000UL
#define POWER9_MMCRA_BHRB_MASK		0x00000000C0000000UL


/* Nasty Power9 specific hack */
/* Nasty Power9 specific hack */
#define PVR_POWER9_CUMULUS		0x00002000
#define PVR_POWER9_CUMULUS		0x00002000
@@ -300,6 +301,8 @@ static u64 power9_bhrb_filter_map(u64 branch_sample_type)


static void power9_config_bhrb(u64 pmu_bhrb_filter)
static void power9_config_bhrb(u64 pmu_bhrb_filter)
{
{
	pmu_bhrb_filter &= POWER9_MMCRA_BHRB_MASK;

	/* Enable BHRB filter in PMU */
	/* Enable BHRB filter in PMU */
	mtspr(SPRN_MMCRA, (mfspr(SPRN_MMCRA) | pmu_bhrb_filter));
	mtspr(SPRN_MMCRA, (mfspr(SPRN_MMCRA) | pmu_bhrb_filter));
}
}