[PATCH v13 04/25] x86/resctrl: Centralize monitoring feature enumeration

From: Tony Luck

Date: Mon Sep 28 2026 - 18:15:42 EST


The original implementation of Intel Cache QoS Monitoring (CQM) planned
to integrate with the "perf" and "cgroup" subsystems. With that plan it
made sense for parameters from CPUID to be stored in fields of the
cpuinfo_x86 structure. But that plan was abandoned and the resctrl file
system user interface replaced it.

Centralize all L3 monitoring enumeration within resctrl in preparation for
removal of resctrl fields from struct cpuinfo_x86.

Signed-off-by: Tony Luck <tony.luck@xxxxxxxxx>
---
v13:
Update commit subject and comment as suggested.
---
arch/x86/include/asm/resctrl.h | 9 ++++----
arch/x86/kernel/cpu/resctrl/monitor.c | 32 ++++++++++++++++++++++++---
2 files changed, 33 insertions(+), 8 deletions(-)

diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h
index 8f6edcdcfd87..c9f9db96f792 100644
--- a/arch/x86/include/asm/resctrl.h
+++ b/arch/x86/include/asm/resctrl.h
@@ -44,6 +44,7 @@ DECLARE_PER_CPU(struct resctrl_pqr_state, pqr_state);

extern bool rdt_alloc_capable;
extern bool rdt_mon_capable;
+extern unsigned int rdt_l3_mon_scale;

DECLARE_STATIC_KEY_FALSE(rdt_enable_key);
DECLARE_STATIC_KEY_FALSE(rdt_alloc_enable_key);
@@ -132,11 +133,9 @@ static inline void __resctrl_sched_in(struct task_struct *tsk)

static inline unsigned int resctrl_arch_round_mon_val(unsigned int val)
{
- unsigned int scale = boot_cpu_data.x86_cache_occ_scale;
-
- /* h/w works in units of "boot_cpu_data.x86_cache_occ_scale" */
- val /= scale;
- return val * scale;
+ /* Round down to nearest h/w monitoring unit */
+ val /= rdt_l3_mon_scale;
+ return val * rdt_l3_mon_scale;
}

static inline void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid,
diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c
index 3838e0a13d36..89b83cc7e800 100644
--- a/arch/x86/kernel/cpu/resctrl/monitor.c
+++ b/arch/x86/kernel/cpu/resctrl/monitor.c
@@ -32,6 +32,11 @@
*/
bool rdt_mon_capable;

+/*
+ * Scale factor to convert L3 monitor events to bytes.
+ */
+unsigned int __ro_after_init rdt_l3_mon_scale;
+
#define CF(cf) ((unsigned long)(1048576 * (cf) + 0.5))

static int snc_nodes_per_l3_cache = 1;
@@ -418,16 +423,37 @@ static __init int snc_get_config(void)

int __init rdt_get_l3_mon_config(struct rdt_resource *r)
{
- unsigned int mbm_offset = boot_cpu_data.x86_cache_mbm_width_offset;
struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
+ unsigned int mbm_offset;
unsigned int threshold;
u32 eax, ebx, ecx, edx;
+ u32 num_rmid;
+
+ /* Resource monitoring leaf is 0xf. L3 monitoring details in subleaf 1 */
+ cpuid_count(0xf, 1, &eax, &ebx, &ecx, &edx);
+ mbm_offset = eax & GENMASK(7, 0);
+ rdt_l3_mon_scale = ebx;
+ num_rmid = ecx + 1;
+
+ if (!mbm_offset) {
+ switch (boot_cpu_data.x86_vendor) {
+ case X86_VENDOR_AMD:
+ mbm_offset = MBM_CNTR_WIDTH_OFFSET_AMD;
+ break;
+ case X86_VENDOR_HYGON:
+ mbm_offset = MBM_CNTR_WIDTH_OFFSET_HYGON;
+ break;
+ default:
+ /* Leave mbm_offset as 0 */
+ break;
+ }
+ }

snc_nodes_per_l3_cache = snc_get_config();

resctrl_rmid_realloc_limit = boot_cpu_data.x86_cache_size * 1024;
- hw_res->mon_scale = boot_cpu_data.x86_cache_occ_scale / snc_nodes_per_l3_cache;
- r->mon.num_rmid = (boot_cpu_data.x86_cache_max_rmid + 1) / snc_nodes_per_l3_cache;
+ hw_res->mon_scale = rdt_l3_mon_scale / snc_nodes_per_l3_cache;
+ r->mon.num_rmid = num_rmid / snc_nodes_per_l3_cache;
hw_res->mbm_width = MBM_CNTR_WIDTH_BASE;

if (mbm_offset > 0 && mbm_offset <= MBM_CNTR_WIDTH_OFFSET_MAX)
--
2.55.0