diff options
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-5.15/0073-perf-x86-amd-core-Add-PerfMonV2-counter-control.patch')
-rw-r--r-- | meta-amd-bsp/recipes-kernel/linux/linux-yocto-5.15/0073-perf-x86-amd-core-Add-PerfMonV2-counter-control.patch | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-5.15/0073-perf-x86-amd-core-Add-PerfMonV2-counter-control.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-5.15/0073-perf-x86-amd-core-Add-PerfMonV2-counter-control.patch new file mode 100644 index 00000000..afd91e4e --- /dev/null +++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-5.15/0073-perf-x86-amd-core-Add-PerfMonV2-counter-control.patch @@ -0,0 +1,138 @@ +From 21ca98c4c18bf0b0c13e77180a713a33401d539d Mon Sep 17 00:00:00 2001 +From: Sandipan Das <sandipan.das@amd.com> +Date: Thu, 21 Apr 2022 11:16:57 +0530 +Subject: [PATCH 73/86] perf/x86/amd/core: Add PerfMonV2 counter control + +commit 9622e67e3980c01872490de0925e5c6c23247c94 upstream + +If AMD Performance Monitoring Version 2 (PerfMonV2) is +supported, use a new scheme to manage the Core PMCs using +the new global control and status registers. This will be +bypassed on unsupported hardware (x86_pmu.version < 2). + +Currently, all PMCs have dedicated control (PERF_CTL) and +counter (PERF_CTR) registers. For a given PMC, the enable +(En) bit of its PERF_CTL register is used to start or stop +counting. + +The Performance Counter Global Control (PerfCntrGlobalCtl) +register has enable (PerfCntrEn) bits for each PMC. For a +PMC to start counting, both PERF_CTL and PerfCntrGlobalCtl +enable bits must be set. If either of those are cleared, +the PMC stops counting. + +In x86_pmu_{en,dis}able_all(), the PERF_CTL registers of +all active PMCs are written to in a loop. Ideally, PMCs +counting the same event that were started and stopped at +the same time should record the same counts. Due to delays +in between writes to the PERF_CTL registers across loop +iterations, the PMCs cannot be enabled or disabled at the +same instant and hence, record slightly different counts. +This is fixed by enabling or disabling all active PMCs at +the same time with a single write to the PerfCntrGlobalCtl +register. + +Signed-off-by: Sandipan Das <sandipan.das@amd.com> +Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> +Link: https://lkml.kernel.org/r/dfe8e934074aaabc6ba748dfaccd0a77c974bb82.1650515382.git.sandipan.das@amd.com +Signed-off-by: Zhaolong Zhang <zhaolong.zhang@windriver.com> +--- + arch/x86/events/amd/core.c | 50 ++++++++++++++++++++++++++++++++++---- + 1 file changed, 45 insertions(+), 5 deletions(-) + +diff --git a/arch/x86/events/amd/core.c b/arch/x86/events/amd/core.c +index 52fd7941a724..a339c3e0be33 100644 +--- a/arch/x86/events/amd/core.c ++++ b/arch/x86/events/amd/core.c +@@ -664,6 +664,11 @@ static void amd_pmu_cpu_dead(int cpu) + amd_pmu_cpu_reset(cpu); + } + ++static inline void amd_pmu_set_global_ctl(u64 ctl) ++{ ++ wrmsrl(MSR_AMD64_PERF_CNTR_GLOBAL_CTL, ctl); ++} ++ + /* + * When a PMC counter overflows, an NMI is used to process the event and + * reset the counter. NMI latency can result in the counter being updated +@@ -693,15 +698,11 @@ static void amd_pmu_wait_on_overflow(int idx) + } + } + +-static void amd_pmu_disable_all(void) ++static void amd_pmu_check_overflow(void) + { + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); + int idx; + +- amd_brs_disable_all(); +- +- x86_pmu_disable_all(); +- + /* + * This shouldn't be called from NMI context, but add a safeguard here + * to return, since if we're in NMI context we can't wait for an NMI +@@ -748,6 +749,26 @@ static void amd_pmu_enable_all(int added) + } + } + ++static void amd_pmu_v2_enable_event(struct perf_event *event) ++{ ++ struct hw_perf_event *hwc = &event->hw; ++ ++ /* ++ * Testing cpu_hw_events.enabled should be skipped in this case unlike ++ * in x86_pmu_enable_event(). ++ * ++ * Since cpu_hw_events.enabled is set only after returning from ++ * x86_pmu_start(), the PMCs must be programmed and kept ready. ++ * Counting starts only after x86_pmu_enable_all() is called. ++ */ ++ __x86_pmu_enable_event(hwc, ARCH_PERFMON_EVENTSEL_ENABLE); ++} ++ ++static void amd_pmu_v2_enable_all(int added) ++{ ++ amd_pmu_set_global_ctl(amd_pmu_global_cntr_mask); ++} ++ + static void amd_pmu_disable_event(struct perf_event *event) + { + x86_pmu_disable_event(event); +@@ -765,6 +786,20 @@ static void amd_pmu_disable_event(struct perf_event *event) + amd_pmu_wait_on_overflow(event->hw.idx); + } + ++static void amd_pmu_disable_all(void) ++{ ++ amd_brs_disable_all(); ++ x86_pmu_disable_all(); ++ amd_pmu_check_overflow(); ++} ++ ++static void amd_pmu_v2_disable_all(void) ++{ ++ /* Disable all PMCs */ ++ amd_pmu_set_global_ctl(0); ++ amd_pmu_check_overflow(); ++} ++ + static void amd_pmu_add_event(struct perf_event *event) + { + if (needs_branch_stack(event)) +@@ -1216,6 +1251,11 @@ static int __init amd_core_pmu_init(void) + x86_pmu.num_counters = ebx.split.num_core_pmc; + + amd_pmu_global_cntr_mask = (1ULL << x86_pmu.num_counters) - 1; ++ ++ /* Update PMC handling functions */ ++ x86_pmu.enable_all = amd_pmu_v2_enable_all; ++ x86_pmu.disable_all = amd_pmu_v2_disable_all; ++ x86_pmu.enable = amd_pmu_v2_enable_event; + } + + /* +-- +2.37.3 + |