[PATCH 2/2] hwpmc_amd: fix DF counter MSR sharing in amd_pcpu_init()

Paulo Fragoso <[email protected]>
Newsgroups gmane.os.freebsd.devel.hackers
Message-ID <[email protected]>
AMD Data Fabric (DF) performance counter MSRs are shared across all
cores in a package. From AMD PPR 57930-A0 section 2.1.9 [Register
Sharing]:

   'The DF Performance Monitors are shared by all cores/threads in
    the socket. Software must coordinate writing to shared registers
    with other threads in the same sharing hierarchy level.'

Previously, amd_pcpu_init() marked DF counters as PMC_PHW_FLAG_IS_ENABLED
on all CPUs. This caused KASSERT failures in amd_start_pmc() and
amd_stop_pmc() when multiple CPUs attempted to start/stop the same
shared MSRs simultaneously, as AMD_PMC_IS_STOPPED() reads the physical
MSR state which is visible to all cores.

Fix by marking DF counters as enabled only on the package master CPU
(cpu_top->cg_first, the lowest CPU ID in the package). The MI layer
returns EPERM for allocation attempts on non-master CPUs, preventing
concurrent MSR access. DF counters remain functional via CPU 0 using
'pmcstat -c 0 -s <df_event>'.

Tested on: AMD Ryzen 5600X (Family 19h, Zen 3), FreeBSD 16.0-CURRENT
   - DF counters ENABLED on CPU 0 only
   - DF counters DISABLED on CPUs 1-11
   - dram_channel_data_controller_0 returns valid counts on CPU 0

Sponsored by: NLINK (https://nlink.com.br), Recife, Brazil
---
  sys/dev/hwpmc/hwpmc_amd.c | 19 +++++++++++++++++--
  1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/sys/dev/hwpmc/hwpmc_amd.c b/sys/dev/hwpmc/hwpmc_amd.c
index b7dbbca18da2..0013228da82d 100644
--- a/sys/dev/hwpmc/hwpmc_amd.c
+++ b/sys/dev/hwpmc/hwpmc_amd.c
@@ -705,8 +705,23 @@ amd_pcpu_init(struct pmc_mdep *md, int cpu)
  	KASSERT(pc != NULL, ("[amd,%d] NULL per-cpu pointer", __LINE__));

  	for (n = 0, phw = pac->pc_amdpmcs; n < amd_npmcs; n++, phw++) {
-		phw->phw_state = PMC_PHW_FLAG_IS_ENABLED |
-		    PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(n);
+		/*
+		 * DF MSRs are shared across all cores in the package.
+		 * See AMD PPR section 2.1.9 [Register Sharing].
+		 * Only mark DF counters as enabled on the package
+		 * master CPU (lowest CPU ID in the package, cg_first
+		 * of cpu_top) to prevent multiple CPUs from writing
+		 * the shared MSRs simultaneously.
+		 */
+		if (amd_pmcdesc[n].pm_subclass ==
+		    PMC_AMD_SUB_CLASS_DATA_FABRIC &&
+		    cpu != cpu_top->cg_first) {
+			phw->phw_state = 0;
+		} else {
+			phw->phw_state = PMC_PHW_FLAG_IS_ENABLED |
+			    PMC_PHW_CPU_TO_STATE(cpu) |
+			    PMC_PHW_INDEX_TO_STATE(n);
+		}
  		phw->phw_pmc = NULL;
  		pc->pc_hwpmcs[n + first_ri] = phw;
  	}
--
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.