Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 28 Apr 2026 18:49:26 +0000
Message-ID:  <69f10136.23a7a.4d667d23@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=39f48829a045e22c39e7099fa39c1a8b7d3fa7f4

commit 39f48829a045e22c39e7099fa39c1a8b7d3fa7f4
Author:     Andre Silva <andasilv@amd.com>
AuthorDate: 2026-04-23 19:45:26 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2026-04-28 18:49:22 +0000

    hwpmc: Add IBS capability control policy
    
    Reject unsupported AMD IBS and PMU control bits before programming the
    MSRs.
    
    Initialize IBS fetch/op allow masks from CPUID feature bits and validate
    user-provided IBS control values against those masks. Keep the
    load-latency filter dependency on L3MissOnly, but avoid decoding fields
    that are already constrained by the mask.
    
    Apply the same reserved-bit policy to the AMD PMU raw-config path by
    checking core, L3, and data fabric configs against subclass-specific
    masks.
    
    Fix the IBS CPUID feature bit definitions used by the policy.
    
    Reviewed by:    mhorne, Ali Mashtizadeh <ali@mashtizadeh.com>
    Sponsored by:   AMD
    Signed-off-by:  Andre Silva <andasilv@amd.com>
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/2140
---
 sys/dev/hwpmc/hwpmc_amd.c | 51 +++++++++++++++++++++++++++--
 sys/dev/hwpmc/hwpmc_amd.h | 22 +++++++++++++
 sys/dev/hwpmc/hwpmc_ibs.c | 81 +++++++++++++++++++++++++++++++++++++++++++++--
 sys/dev/hwpmc/hwpmc_ibs.h | 22 ++++++++++---
 4 files changed, 166 insertions(+), 10 deletions(-)

diff --git a/sys/dev/hwpmc/hwpmc_amd.c b/sys/dev/hwpmc/hwpmc_amd.c
index 51505bfcff37..8531db13dc6f 100644
--- a/sys/dev/hwpmc/hwpmc_amd.c
+++ b/sys/dev/hwpmc/hwpmc_amd.c
@@ -178,6 +178,45 @@ struct amd_cpu {
 };
 static struct amd_cpu **amd_pcpu;
 
+/* Populated by amd_init_policy(); PRECISERETIRE is OR-ed in per-allocation. */
+static uint64_t amd_core_allowed_mask;
+static uint64_t amd_l3_allowed_mask;
+static uint64_t amd_df_allowed_mask;
+
+static void
+amd_init_policy(void)
+{
+	int family;
+
+	family = CPUID_TO_FAMILY(cpu_id);
+
+	amd_core_allowed_mask = AMD_VALID_BITS;
+
+	amd_l3_allowed_mask = (family <= 0x17) ?
+	    AMD_PMC_L3_FAMILY17_MASK : AMD_PMC_L3_FAMILY19_MASK;
+
+	amd_df_allowed_mask = (family <= 0x19) ?
+	    AMD_PMC_DF_FAMILY17_MASK : AMD_PMC_DF_FAMILY1A_MASK;
+}
+
+static uint64_t
+amd_config_mask(enum sub_class subclass, uint64_t caps)
+{
+
+	switch (subclass) {
+	case PMC_AMD_SUB_CLASS_CORE:
+		return (amd_core_allowed_mask |
+		    (((caps & PMC_CAP_PRECISE) != 0) ?
+		    AMD_PMC_PRECISERETIRE : 0));
+	case PMC_AMD_SUB_CLASS_L3_CACHE:
+		return (amd_l3_allowed_mask);
+	case PMC_AMD_SUB_CLASS_DATA_FABRIC:
+		return (amd_df_allowed_mask);
+	default:
+		return (0);
+	}
+}
+
 /*
  * Read a PMC value from the MSR.
  */
@@ -358,9 +397,13 @@ amd_allocate_pmc(int cpu __unused, int ri, struct pmc *pm,
 		return (EINVAL);
 
 	if (strlen(pmc_cpuid) != 0) {
-		pm->pm_md.pm_amd.pm_amd_evsel = a->pm_md.pm_amd.pm_amd_config;
-		PMCDBG2(MDP, ALL, 2,"amd-allocate ri=%d -> config=0x%x", ri,
-		    a->pm_md.pm_amd.pm_amd_config);
+		config = a->pm_md.pm_amd.pm_amd_config;
+		if ((config & ~amd_config_mask(amd_pmcdesc[ri].pm_subclass,
+		    caps)) != 0)
+			return (EINVAL);
+		pm->pm_md.pm_amd.pm_amd_evsel = config;
+		PMCDBG2(MDP, ALL, 2, "amd-allocate ri=%d -> config=0x%jx",
+		    ri, (uintmax_t)config);
 		return (0);
 	}
 
@@ -981,6 +1024,8 @@ pmc_amd_initialize(void)
 
 	pmc_mdep->pmd_npmc	+= amd_npmcs;
 
+	amd_init_policy();
+
 	PMCDBG0(MDP, INI, 0, "amd-initialize");
 
 	if (nclasses >= 3) {
diff --git a/sys/dev/hwpmc/hwpmc_amd.h b/sys/dev/hwpmc/hwpmc_amd.h
index 6d8ab8203942..616d115ecc25 100644
--- a/sys/dev/hwpmc/hwpmc_amd.h
+++ b/sys/dev/hwpmc/hwpmc_amd.h
@@ -122,6 +122,18 @@
 #define	AMD_PMC_L3_TO_UNITMASK(x)	(((x) << 8) & AMD_PMC_UNITMASK)
 #define	AMD_PMC_L3_TO_EVENTMASK(x)	((x) & 0xFF)
 
+#define	AMD_PMC_L3_FAMILY17_MASK					\
+	(AMD_PMC_ENABLE | AMD_PMC_L3_TO_EVENTMASK(0xff) |		\
+	 AMD_PMC_L3_TO_UNITMASK(0xff) |					\
+	 AMD_PMC_L31_SLICEMASK | AMD_PMC_L31_COREMASK)
+
+#define	AMD_PMC_L3_FAMILY19_MASK					\
+	(AMD_PMC_ENABLE | AMD_PMC_L3_TO_EVENTMASK(0xff) |		\
+	 AMD_PMC_L3_TO_UNITMASK(0xff) |					\
+	 AMD_PMC_L32_THREADMASK | AMD_PMC_L32_SOURCEMASK |		\
+	 AMD_PMC_L32_ALLCORES | AMD_PMC_L32_ALLSOURCES |		\
+	 AMD_PMC_L32_COREMASK)
+
 #define AMD_PMC_L3_CAPS		(PMC_CAP_READ | PMC_CAP_WRITE | \
 	PMC_CAP_QUALIFIER | PMC_CAP_DOMWIDE)
 
@@ -148,6 +160,16 @@
 #define AMD_PMC_DF2_TO_UNITMASK(x)	((((x) & 0xFF) << 8) | \
 	(((uint64_t)(x) & 0x0F00) << 16))
 
+#define	AMD_PMC_DF_FAMILY17_MASK					\
+	(AMD_PMC_ENABLE |						\
+	 AMD_PMC_DF1_TO_EVENTMASK(0x3fff) |				\
+	 AMD_PMC_DF1_TO_UNITMASK(0xff))
+
+#define	AMD_PMC_DF_FAMILY1A_MASK					\
+	(AMD_PMC_ENABLE |						\
+	 AMD_PMC_DF2_TO_EVENTMASK(0x7fff) |				\
+	 AMD_PMC_DF2_TO_UNITMASK(0xfff))
+
 #define	AMD_NPMCS_K8		4
 #define AMD_NPMCS_MAX		(AMD_PMC_CORE_MAX + AMD_PMC_L3_MAX + \
 				 AMD_PMC_DF_MAX)
diff --git a/sys/dev/hwpmc/hwpmc_ibs.c b/sys/dev/hwpmc/hwpmc_ibs.c
index 280a84208847..93e43d657633 100644
--- a/sys/dev/hwpmc/hwpmc_ibs.c
+++ b/sys/dev/hwpmc/hwpmc_ibs.c
@@ -57,6 +57,8 @@ struct ibs_descr {
  * Globals
  */
 static uint64_t ibs_features;
+static uint64_t ibs_fetch_allowed_mask;
+static uint64_t ibs_op_allowed_mask;
 
 /*
  * Per-processor information
@@ -71,6 +73,73 @@ struct ibs_cpu {
 };
 static struct ibs_cpu **ibs_pcpu;
 
+static void
+ibs_init_policy(void)
+{
+
+	ibs_fetch_allowed_mask = IBS_FETCH_ALLOWED_MASK_BASE;
+
+	ibs_op_allowed_mask = IBS_OP_CTL_MAXCNTBASEMASK;
+
+	if ((ibs_features & CPUID_IBSID_ZEN4IBSEXTENSIONS) != 0)
+		ibs_fetch_allowed_mask |= IBS_FETCH_CTL_L3MISSONLY;
+
+	if ((ibs_features & CPUID_IBSID_OPCNT) != 0)
+		ibs_op_allowed_mask |= IBS_OP_CTL_COUNTERCONTROL;
+
+	if ((ibs_features & CPUID_IBSID_OPCNTEXT) != 0)
+		ibs_op_allowed_mask |= IBS_OP_CTL_MAXCNTEXTMASK;
+
+	if ((ibs_features & CPUID_IBSID_ZEN4IBSEXTENSIONS) != 0)
+		ibs_op_allowed_mask |= IBS_OP_CTL_L3MISSONLY;
+}
+
+static int
+ibs_validate_fetch_config(uint64_t config)
+{
+
+	if ((config & ~ibs_fetch_allowed_mask) != 0)
+		return (EINVAL);
+
+	return (0);
+}
+
+static int
+ibs_validate_op_config(uint64_t config)
+{
+	uint64_t allowed_mask;
+
+	allowed_mask = ibs_op_allowed_mask;
+
+	if ((config & IBS_OP_CTL_LATFLTEN) != 0) {
+		if ((ibs_features & CPUID_IBSID_IBSLOADLATENCYFILT) == 0)
+			return (EINVAL);
+		if ((config & IBS_OP_CTL_L3MISSONLY) == 0)
+			return (EINVAL);
+
+		allowed_mask |= IBS_OP_CTL_LDLATMASK | IBS_OP_CTL_L3MISSONLY;
+	}
+
+	if ((config & ~allowed_mask) != 0)
+		return (EINVAL);
+
+	return (0);
+}
+
+static int
+ibs_validate_pmc_config(int ri, uint64_t config)
+{
+
+	switch (ri) {
+	case IBS_PMC_FETCH:
+		return (ibs_validate_fetch_config(config));
+	case IBS_PMC_OP:
+		return (ibs_validate_op_config(config));
+	default:
+		return (EINVAL);
+	}
+}
+
 /*
  * Read a PMC value from the MSR.
  */
@@ -182,6 +251,7 @@ ibs_allocate_pmc(int cpu __unused, int ri, struct pmc *pm,
     const struct pmc_op_pmcallocate *a)
 {
 	uint64_t caps, config;
+	int error;
 
 	KASSERT(ri >= 0 && ri < IBS_NPMCS,
 	    ("[ibs,%d] illegal row index %d", __LINE__, ri));
@@ -205,9 +275,13 @@ ibs_allocate_pmc(int cpu __unused, int ri, struct pmc *pm,
 		return (EINVAL);
 
 	config = a->pm_md.pm_ibs.ibs_ctl;
+	error = ibs_validate_pmc_config(ri, config);
+	if (error != 0)
+		return (error);
 	pm->pm_md.pm_ibs.ibs_ctl = config;
 
-	PMCDBG2(MDP, ALL, 2, "ibs-allocate ri=%d -> config=0x%x", ri, config);
+	PMCDBG2(MDP, ALL, 2, "ibs-allocate ri=%d -> config=0x%jx", ri,
+	    config);
 
 	return (0);
 }
@@ -361,7 +435,6 @@ pmc_ibs_process_fetch(struct pmc *pm, struct trapframe *tf, uint64_t config)
 	if ((ibs_features & CPUID_IBSID_IBSFETCHCTLEXTD) != 0) {
 		mpd.pl_mpdata[PMC_MPIDX_FETCH_EXTCTL] = rdmsr(IBS_FETCH_EXTCTL);
 	}
-	mpd.pl_mpdata[PMC_MPIDX_FETCH_CTL] = config;
 	mpd.pl_mpdata[PMC_MPIDX_FETCH_LINADDR] = rdmsr(IBS_FETCH_LINADDR);
 	if ((config & IBS_FETCH_CTL_PHYSADDRVALID) != 0) {
 		mpd.pl_mpdata[PMC_MPIDX_FETCH_PHYSADDR] =
@@ -622,10 +695,14 @@ pmc_ibs_initialize(struct pmc_mdep *pmc_mdep, int ncpus)
 	if (cpu_exthigh >= CPUID_IBSID) {
 		do_cpuid(CPUID_IBSID, regs);
 		ibs_features = regs[0];
+		if ((ibs_features & CPUID_IBSID_IBSFFV) == 0)
+			ibs_features = 0;
 	} else {
 		ibs_features = 0;
 	}
 
+	ibs_init_policy();
+
 	PMCDBG0(MDP, INI, 0, "ibs-initialize");
 
 	return (0);
diff --git a/sys/dev/hwpmc/hwpmc_ibs.h b/sys/dev/hwpmc/hwpmc_ibs.h
index 2b4e111ba171..433397954d4f 100644
--- a/sys/dev/hwpmc/hwpmc_ibs.h
+++ b/sys/dev/hwpmc/hwpmc_ibs.h
@@ -100,6 +100,8 @@
 #define IBS_FETCH_CTL_TO_LAT(_c)	(((_c) >> 32) & 0x0000FFFF)
 #define IBS_FETCH_COUNT_TO_CTL(_c)	(((_c) << 12) & IBS_FETCH_CTL_CURCNTMASK)
 #define IBS_FETCH_CTL_TO_COUNT(_c)	(((_c) & IBS_FETCH_CTL_CURCNTMASK) >> 12)
+#define IBS_FETCH_ALLOWED_MASK_BASE	(IBS_FETCH_CTL_MAXCNTMASK | \
+    IBS_FETCH_CTL_RANDOMIZE)
 
 #define IBS_FETCH_LINADDR		0xC0011031 /* Fetch Linear Address */
 #define IBS_FETCH_PHYSADDR		0xC0011032 /* Fetch Physical Address */
@@ -118,12 +120,22 @@
 #define IBS_OP_CTL_VALID		(1ULL << 18) /* Valid */
 #define IBS_OP_CTL_ENABLE		(1ULL << 17) /* Enable */
 #define IBS_OP_CTL_L3MISSONLY		(1ULL << 16) /* L3 Miss Filtering */
-#define IBS_OP_CTL_MAXCNTMASK		0x07F0FFFFULL
+#define IBS_OP_CTL_MAXCNTMASK		0x07F0FFFFULL /* Max Count */
+#define IBS_OP_CTL_MAXCNTEXTMASK	0x07F00000ULL /* Max Count Extended */
+#define IBS_OP_CTL_MAXCNTBASEMASK	(IBS_OP_CTL_MAXCNTMASK & \
+    ~IBS_OP_CTL_MAXCNTEXTMASK) /* Max Count Base */
 #define IBS_OP_CTL_CURCNTMASK		0x07FFFFFF00000000ULL
-
-#define IBS_OP_CTL_LDLAT_TO_CTL(_c)	((((ldlat) >> 7) - 1) << 59)
-#define IBS_OP_INTERVAL_TO_CTL(_c)	((((_c) >> 4) & 0x0000FFFFULL) | ((_c) & 0x07F00000))
-#define IBS_OP_CTL_TO_INTERVAL(_c)	((((_c) & 0x0000FFFFULL) << 4) | ((_c) & 0x07F00000))
+#define IBS_OP_CTL_LDLATTRSHMASK	(0xFULL << 59) /* Load Lat Threshold */
+#define IBS_OP_CTL_LDLATMASK		(IBS_OP_CTL_LATFLTEN | \
+    IBS_OP_CTL_LDLATTRSHMASK) /* Load Lat Combined */
+
+#define IBS_OP_CTL_LDLAT_TO_CTL(_c)	(((((_c) >> 7) - 1) & 0xFULL) << 59)
+#define IBS_OP_INTERVAL_TO_CTL(_c)					\
+	((((_c) >> 4) & IBS_OP_CTL_MAXCNTBASEMASK) |			\
+	((_c) & IBS_OP_CTL_MAXCNTEXTMASK))
+#define IBS_OP_CTL_TO_INTERVAL(_c)					\
+	((((_c) & IBS_OP_CTL_MAXCNTBASEMASK) << 4) |			\
+	((_c) & IBS_OP_CTL_MAXCNTEXTMASK))
 #define IBS_OP_COUNT_TO_CTL(_c)		(((_c) << 32) & IBS_OP_CTL_CURCNTMASK)
 #define IBS_OP_CTL_TO_COUNT(_c)		(((_c) & IBS_OP_CTL_CURCNTMASK) >> 32)
 


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69f10136.23a7a.4d667d23>