powerpc/perf: Fix MMCRA corruption by bhrb_filter [Linux 5.2]

powerpc/perf: Fix MMCRA corruption by bhrb_filter [Linux 5.2]

This Linux kernel change "powerpc/perf: Fix MMCRA corruption by bhrb_filter" is included in the Linux 5.2 release. This change is authored by Ravi Bangoria <ravi.bangoria [at] linux.ibm.com> on Sat May 11 08:12:17 2019 +0530. The commit for this change in Linux stable tree is 3202e35 (patch).

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: 3925f46bb590 ("powerpc/perf: Enable branch stack sampling framework")
Cc: [email protected] # v3.10+
Signed-off-by: Ravi Bangoria <[email protected]>
Reviewed-by: Madhavan Srinivasan <[email protected]>
Signed-off-by: Michael Ellerman <[email protected]>

There are 12 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 arch/powerpc/perf/core-book3s.c | 6 ++++--
 arch/powerpc/perf/power8-pmu.c  | 3 +++
 arch/powerpc/perf/power9-pmu.c  | 3 +++
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index a66fb9c..2c21ff8 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -1850,6 +1850,7 @@ static int power_pmu_event_init(struct perf_event *event)
    int n;
    int err;
    struct cpu_hw_events *cpuhw;
+   u64 bhrb_filter;

    if (!ppmu)
        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);

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

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

    put_cpu_var(cpu_hw_events);
diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c
index bcc3409..c0eb3e2 100644
--- a/arch/powerpc/perf/power8-pmu.c
+++ b/arch/powerpc/perf/power8-pmu.c
@@ -29,6 +29,7 @@ enum {
 #define    POWER8_MMCRA_IFM1       0x0000000040000000UL
 #define    POWER8_MMCRA_IFM2       0x0000000080000000UL
 #define    POWER8_MMCRA_IFM3       0x00000000C0000000UL
+#define    POWER8_MMCRA_BHRB_MASK      0x00000000C0000000UL

 /*
  * 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)
 {
+   pmu_bhrb_filter &= POWER8_MMCRA_BHRB_MASK;
+
    /* Enable BHRB filter in PMU */
    mtspr(SPRN_MMCRA, (mfspr(SPRN_MMCRA) | pmu_bhrb_filter));
 }
diff --git a/arch/powerpc/perf/power9-pmu.c b/arch/powerpc/perf/power9-pmu.c
index 3a31ac6..e19c492 100644
--- a/arch/powerpc/perf/power9-pmu.c
+++ b/arch/powerpc/perf/power9-pmu.c
@@ -92,6 +92,7 @@ enum {
 #define POWER9_MMCRA_IFM1      0x0000000040000000UL
 #define POWER9_MMCRA_IFM2      0x0000000080000000UL
 #define POWER9_MMCRA_IFM3      0x00000000C0000000UL
+#define POWER9_MMCRA_BHRB_MASK     0x00000000C0000000UL

 /* Nasty Power9 specific hack */
 #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)
 {
+   pmu_bhrb_filter &= POWER9_MMCRA_BHRB_MASK;
+
    /* Enable BHRB filter in PMU */
    mtspr(SPRN_MMCRA, (mfspr(SPRN_MMCRA) | pmu_bhrb_filter));
 }

Leave a Reply

Your email address will not be published. Required fields are marked *