aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux/linux-yocto-5.15/0073-perf-x86-amd-core-Add-PerfMonV2-counter-control.patch
diff options
context:
space:
mode:
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.patch138
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
+