[PATCH 1/2] hwpmc_amd: fix amd_get_msr() MSR offset for newer counter, bases

Paulo Fragoso <[email protected]>
Newsgroups gmane.os.freebsd.devel.hackers
Message-ID <[email protected]>
The previous code subtracted AMD_PMC_PERFCTR_0 (0xC0010004) from all
perfctr MSR addresses to compute a relative offset. This is incorrect
for counters using AMD_PMC_CORE_BASE (0xC0010200), AMD_PMC_L3_BASE
(0xC0010230), and AMD_PMC_DF_BASE (0xC0010240), producing wrong offsets.

For example, core counter 4 (pm_perfctr = 0xC0010209) would produce:
   0xC0010209 - 0xC0010004 = 517  (wrong)
instead of:
   (0xC0010209 - 0xC0010200) / 2 = 4  (correct)

Fix by computing the MSR offset relative to the correct base address
for each counter sub-class using a switch on pm_subclass field added
by the Netflix hwpmc commit (37bba2ad92d8).

The CORE case handles both legacy processors (using AMD_PMC_PERFCTR_0)
and newer processors with AMDID2_PCXC feature bit (using AMD_PMC_CORE_BASE)
as documented in AMD PPR 57930-A0 page 220:
   MSRC001_0200 [Performance Event Select 0] (Core::X86::Msr::PERF_CTL0)

Verified on: AMD Ryzen 5600X (Family 19h, Zen 3), FreeBSD 16.0-CURRENT
   - 6 core counters (K8-0..K8-5) ENABLED
   - 6 L3 counters  (K8-L3-0..K8-L3-5) ENABLED
   - 4 DF counters  (K8-DF-0..K8-DF-3) ENABLED
   Total: 16 K8 PMCs correctly registered

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

diff --git a/sys/dev/hwpmc/hwpmc_amd.c b/sys/dev/hwpmc/hwpmc_amd.c
index 801b75b39595..b7dbbca18da2 100644
--- a/sys/dev/hwpmc/hwpmc_amd.c
+++ b/sys/dev/hwpmc/hwpmc_amd.c
@@ -655,7 +655,24 @@ amd_get_msr(int ri, uint32_t *msr)
  	KASSERT(ri >= 0 && ri < amd_npmcs,
  	    ("[amd,%d] ri %d out of range", __LINE__, ri));

-	*msr = amd_pmcdesc[ri].pm_perfctr - AMD_PMC_PERFCTR_0;
+	switch (amd_pmcdesc[ri].pm_subclass) {
+	case PMC_AMD_SUB_CLASS_CORE:
+		if (amd_pmcdesc[ri].pm_perfctr >= AMD_PMC_CORE_BASE)
+			*msr = (amd_pmcdesc[ri].pm_perfctr -
+			    AMD_PMC_CORE_BASE) / 2;
+		else
+			*msr = amd_pmcdesc[ri].pm_perfctr -
+			    AMD_PMC_PERFCTR_0;
+		break;
+	case PMC_AMD_SUB_CLASS_L3_CACHE:
+		*msr = (amd_pmcdesc[ri].pm_perfctr - AMD_PMC_L3_BASE) / 2;
+		break;
+	case PMC_AMD_SUB_CLASS_DATA_FABRIC:
+		*msr = (amd_pmcdesc[ri].pm_perfctr - AMD_PMC_DF_BASE) / 2;
+		break;
+	default:
+		return (EINVAL);
+	}
  	return (0);
  }

--
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.