* [PATCH v12 00/25] Allow AET to use PMT as loadable module
@ 2026-09-16 23:12 Tony Luck
2026-09-16 23:12 ` [PATCH v12 01/25] x86/cpufeatures: Add missing CQM feature dependency Tony Luck
` (25 more replies)
0 siblings, 26 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:12 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
Requiring INTEL_PMT_TELEMETRY=y to enable AET is a functional workaround
to enable enumeration of Application Energy Telemetry (AET) events, but
unacceptable to many users. It results in increased configuration complexity,
increased kernel memory footprint and inability to patch problems by unloading
a module and loading an updated version.
Add a registration function to the AET code that can be used by
INTEL_PMT_TELEMETRY to provide the enumeration functions.
INTEL_PMT_TELEMETRY can be loaded/unloaded independently of
resctrl file system mount/unmount. Perform enumeration on
every mount and cleanup on every unmount.
Patch series based on v7.3-rc3
Signed-off-by: Tony Luck <tony.luck@intel.com>
Changes since v11:
Link: https://lore.kernel.org/all/20260831174421.13921-1-tony.luck@intel.com/
Patch 12 "Handle change in number of RMIDs on each mount"
split into three parts (12, 13, 14 in this series)
Patch 14 "Enforce system RMID limit on AET event groups"
massively simplified, and moved later (now patch 20).
See individual patches for changes to each part.
Tony Luck (25):
x86/cpufeatures: Add missing CQM feature dependency
x86/resctrl: Check if monitoring features are supported
x86/resctrl: Enumerate monitor features in rdt_get_l3_mon_config()
x86/resctrl: Apply Intel MBM quirk from rdt_get_l3_mon_config()
x86/resctrl: Delete resctrl_cpu_detect()
arm,x86,fs/resctrl: Replace architecture
resctrl_arch_{alloc,mon}_capable()
x86/resctrl: Update special case for Intel Haswell enumeration
x86/resctrl: Delete rdt_alloc_capable and rdt_mon_capable
fs/resctrl: Remove redundant calls to resctrl_{alloc,mon}_capable()
x86/resctrl: Honor rdt=perf option to force enable AET perf events
fs/resctrl: Add interface to disable a monitor event
arm,x86,fs/resctrl: Allocate maximum needed rmid_ptrs[]
arm,x86,fs/resctrl: Allocate right size for L3 monitor arrays
fs/resctrl: Rebuild free RMID list on each mount
x86,fs/resctrl: Handle systems where AET is the only resource
x86/resctrl: Add PMT registration API for AET enumeration callbacks
platform/x86/intel/pmt: Register enumeration functions with resctrl
x86/resctrl: Use registered function pointers for AET enumeration
arm,x86,fs/resctrl: Enumerate AET on every resctrl mount
x86/resctrl: Enforce system RMID limit on AET
x86/resctrl: Export interface to report telemetry unbind/remove
platform/x86/intel/pmt: Inform resctrl when MMIO maps are being
removed
x86/resctrl: Require 64-bit x86 for resctrl support
x86/resctrl: Simplify Kconfig options for resctrl
x86,fs/resctrl: Document telemetry mount timing caveat
Documentation/filesystems/resctrl.rst | 18 ++-
include/linux/arm_mpam.h | 3 -
include/linux/intel_vsec.h | 14 ++
include/linux/resctrl.h | 82 ++++++++++-
arch/x86/include/asm/processor.h | 4 -
arch/x86/include/asm/resctrl.h | 24 +---
arch/x86/kernel/cpu/resctrl/internal.h | 23 +---
arch/x86/kernel/cpu/amd.c | 3 -
arch/x86/kernel/cpu/cpuid-deps.c | 1 +
arch/x86/kernel/cpu/hygon.c | 3 -
arch/x86/kernel/cpu/intel.c | 7 -
arch/x86/kernel/cpu/resctrl/core.c | 150 ++++++++++++---------
arch/x86/kernel/cpu/resctrl/intel_aet.c | 114 ++++++++++++++--
arch/x86/kernel/cpu/resctrl/monitor.c | 71 ++++++----
drivers/platform/x86/intel/pmt/telemetry.c | 47 ++++++-
drivers/resctrl/mpam_resctrl.c | 44 +++---
fs/resctrl/monitor.c | 119 +++++++++++-----
fs/resctrl/pseudo_lock.c | 6 +-
fs/resctrl/rdtgroup.c | 79 +++++++----
arch/x86/Kconfig | 15 +--
arch/x86/kernel/cpu/resctrl/Makefile | 3 +-
21 files changed, 562 insertions(+), 268 deletions(-)
base-commit: fd73f4a6659897191fa0d40695fe370925dd3780
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 01/25] x86/cpufeatures: Add missing CQM feature dependency
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
@ 2026-09-16 23:12 ` Tony Luck
2026-09-16 23:12 ` [PATCH v12 02/25] x86/resctrl: Check if monitoring features are supported Tony Luck
` (24 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:12 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
The Intel Software Developer's Manual says that software must check that
CPUID(0x7,0x0).EBX[12] (Linux X86_FEATURE_CQM) is set before checking
for monitoring features in CPUID leaf 0xF.
Add the missing dependency of X86_FEATURE_CQM_LLC on X86_FEATURE_CQM.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
Drop the X86_FEATURE renames. Just add the missing dependency.
---
arch/x86/kernel/cpu/cpuid-deps.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c
index 99801e844b30..93d45b688f6c 100644
--- a/arch/x86/kernel/cpu/cpuid-deps.c
+++ b/arch/x86/kernel/cpu/cpuid-deps.c
@@ -67,6 +67,7 @@ static const struct cpuid_dep cpuid_deps[] = {
{ X86_FEATURE_AVX512_4FMAPS, X86_FEATURE_AVX512F },
{ X86_FEATURE_AVX512_VPOPCNTDQ, X86_FEATURE_AVX512F },
{ X86_FEATURE_AVX512_VP2INTERSECT, X86_FEATURE_AVX512VL },
+ { X86_FEATURE_CQM_LLC, X86_FEATURE_CQM },
{ X86_FEATURE_CQM_OCCUP_LLC, X86_FEATURE_CQM_LLC },
{ X86_FEATURE_CQM_MBM_TOTAL, X86_FEATURE_CQM_LLC },
{ X86_FEATURE_CQM_MBM_LOCAL, X86_FEATURE_CQM_LLC },
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 02/25] x86/resctrl: Check if monitoring features are supported
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
2026-09-16 23:12 ` [PATCH v12 01/25] x86/cpufeatures: Add missing CQM feature dependency Tony Luck
@ 2026-09-16 23:12 ` Tony Luck
2026-09-16 23:12 ` [PATCH v12 03/25] x86/resctrl: Enumerate monitor features in rdt_get_l3_mon_config() Tony Luck
` (23 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:12 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
Both Intel and AMD manuals say that software must first check
CPUID(0x7,0x0).EBX[12] (Linux: X86_FEATURE_CQM) to see if any monitoring
features are supported before checking for specific features supported
in subleaves.
Each of the L3-based monitoring features is further gated by
CPUID(0xF,0x0).EDX[1] (Linux: X86_FEATURE_CQM_LLC).
Add checks for these feature bits.
Fixes: cbc82b172638 ("x86: Add support for Intel Cache QoS Monitoring (CQM) detection")
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
Revert X86_FEATURE name changes.
Invert the test for X86_FEATURE_CQM_LLC to avoid adding extra
indentation churn and keep call to rdt_get_l3_mon_config in
the X86_FEATURE_CQM_LLC code path.
---
arch/x86/kernel/cpu/resctrl/core.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index 55214d6fdc49..34ca3c7cc046 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -968,6 +968,14 @@ static __init bool get_rdt_mon_resources(void)
struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
bool ret = false;
+ /* Any monitoring at all? */
+ if (!cpu_feature_enabled(X86_FEATURE_CQM))
+ return false;
+
+ /* Any of the L3 monitoring features? */
+ if (!cpu_feature_enabled(X86_FEATURE_CQM_LLC))
+ return false;
+
if (rdt_cpu_has(X86_FEATURE_CQM_OCCUP_LLC)) {
resctrl_enable_mon_event(QOS_L3_OCCUP_EVENT_ID, false, 0, NULL);
ret = true;
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 03/25] x86/resctrl: Enumerate monitor features in rdt_get_l3_mon_config()
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
2026-09-16 23:12 ` [PATCH v12 01/25] x86/cpufeatures: Add missing CQM feature dependency Tony Luck
2026-09-16 23:12 ` [PATCH v12 02/25] x86/resctrl: Check if monitoring features are supported Tony Luck
@ 2026-09-16 23:12 ` Tony Luck
2026-09-16 23:12 ` [PATCH v12 04/25] x86/resctrl: Apply Intel MBM quirk from rdt_get_l3_mon_config() Tony Luck
` (22 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:12 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
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.
Change rdt_get_l3_mon_config() to make an explicit cpuid_count() call to
enumerate L3 monitoring features in preparation for the removal of
resctrl fields from cpuinfo_x86.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
Better comment for the cpuid_count() call.
s/0xff/GENMASK(7, 0)/
Update commit comment to say that this is in preparation
to remove the resctrl elements from boot_cpu_data.
---
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..9bfa9b14002b 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 __ro_after_init 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
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 04/25] x86/resctrl: Apply Intel MBM quirk from rdt_get_l3_mon_config()
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (2 preceding siblings ...)
2026-09-16 23:12 ` [PATCH v12 03/25] x86/resctrl: Enumerate monitor features in rdt_get_l3_mon_config() Tony Luck
@ 2026-09-16 23:12 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 05/25] x86/resctrl: Delete resctrl_cpu_detect() Tony Luck
` (21 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:12 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
The Intel quirk to adjust Memory Bandwidth Monitoring (MBM) values on
certain CPUs is applied early, before discovering if MBM is supported.
Move the call into rdt_get_l3_mon_config(), but keep the decision on
whether it is needed in __check_quirks_intel() with all the other
model specific tests.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
Change type of cf_index to unsigned in intel_rdt_mbm_apply_quirk()
---
arch/x86/kernel/cpu/resctrl/internal.h | 4 +--
arch/x86/kernel/cpu/resctrl/core.c | 2 +-
arch/x86/kernel/cpu/resctrl/monitor.c | 35 +++++++++++++++-----------
3 files changed, 23 insertions(+), 18 deletions(-)
diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h
index e3cfa0c10e92..e46eb9a4c725 100644
--- a/arch/x86/kernel/cpu/resctrl/internal.h
+++ b/arch/x86/kernel/cpu/resctrl/internal.h
@@ -151,6 +151,8 @@ static inline struct rdt_hw_resource *resctrl_to_arch_res(struct rdt_resource *r
extern struct rdt_hw_resource rdt_resources_all[];
+extern bool __initdata intel_rdt_mbm_need_quirk;
+
void arch_mon_domain_online(struct rdt_resource *r, struct rdt_l3_mon_domain *d);
/* CPUID.(EAX=10H, ECX=ResID=1).EAX */
@@ -228,8 +230,6 @@ int rdt_get_l3_mon_config(struct rdt_resource *r);
bool rdt_cpu_has(int flag);
-void __init intel_rdt_mbm_apply_quirk(void);
-
void rdt_domain_reconfigure_cdp(struct rdt_resource *r);
void resctrl_arch_mbm_cntr_assign_set_one(struct rdt_resource *r);
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index 34ca3c7cc046..82b27a0157ae 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -1011,7 +1011,7 @@ static __init void __check_quirks_intel(void)
set_rdt_options("!l3cat");
fallthrough;
case INTEL_BROADWELL_X:
- intel_rdt_mbm_apply_quirk();
+ intel_rdt_mbm_need_quirk = true;
break;
}
}
diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c
index 89b83cc7e800..ab9cb34145c5 100644
--- a/arch/x86/kernel/cpu/resctrl/monitor.c
+++ b/arch/x86/kernel/cpu/resctrl/monitor.c
@@ -37,6 +37,8 @@ bool rdt_mon_capable;
*/
unsigned int __ro_after_init rdt_l3_mon_scale;
+bool __initdata intel_rdt_mbm_need_quirk;
+
#define CF(cf) ((unsigned long)(1048576 * (cf) + 0.5))
static int snc_nodes_per_l3_cache = 1;
@@ -51,7 +53,7 @@ static int snc_nodes_per_l3_cache = 1;
* 1. The threshold 0 is changed to rmid count - 1 so don't do correction
* for the case.
* 2. MBM total and local correction table indexed by core counter which is
- * equal to (x86_cache_max_rmid + 1) / 8 - 1 and is from 0 up to 27.
+ * equal to r->mon.num_rmid / 8 - 1 and is from 0 up to 27.
* 3. The correction factor is normalized to 2^20 (1048576) so it's faster
* to calculate corrected value by shifting:
* corrected_value = (original_value * correction_factor) >> 20
@@ -421,6 +423,20 @@ static __init int snc_get_config(void)
return ret;
}
+static void __init intel_rdt_mbm_apply_quirk(u32 num_rmid)
+{
+ unsigned int cf_index;
+
+ cf_index = num_rmid / 8 - 1;
+ if (cf_index >= ARRAY_SIZE(mbm_cf_table)) {
+ pr_info("No MBM correction factor available\n");
+ return;
+ }
+
+ mbm_cf_rmidthreshold = mbm_cf_table[cf_index].rmidthreshold;
+ mbm_cf = mbm_cf_table[cf_index].cf;
+}
+
int __init rdt_get_l3_mon_config(struct rdt_resource *r)
{
struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
@@ -500,25 +516,14 @@ int __init rdt_get_l3_mon_config(struct rdt_resource *r)
hw_res->mbm_cntr_assign_enabled = true;
}
+ if (intel_rdt_mbm_need_quirk)
+ intel_rdt_mbm_apply_quirk(r->mon.num_rmid);
+
r->mon_capable = true;
return 0;
}
-void __init intel_rdt_mbm_apply_quirk(void)
-{
- int cf_index;
-
- cf_index = (boot_cpu_data.x86_cache_max_rmid + 1) / 8 - 1;
- if (cf_index >= ARRAY_SIZE(mbm_cf_table)) {
- pr_info("No MBM correction factor available\n");
- return;
- }
-
- mbm_cf_rmidthreshold = mbm_cf_table[cf_index].rmidthreshold;
- mbm_cf = mbm_cf_table[cf_index].cf;
-}
-
static void resctrl_abmc_set_one_amd(void *arg)
{
bool *enable = arg;
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 05/25] x86/resctrl: Delete resctrl_cpu_detect()
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (3 preceding siblings ...)
2026-09-16 23:12 ` [PATCH v12 04/25] x86/resctrl: Apply Intel MBM quirk from rdt_get_l3_mon_config() Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 06/25] arm,x86,fs/resctrl: Replace architecture resctrl_arch_{alloc,mon}_capable() Tony Luck
` (20 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck,
Borislav Petkov (AMD)
cpuinfo_x86::x86_cache_{max_rmid,occ_scale,mbm_width_offset} are no
longer used.
Delete resctrl_cpu_detect() and the fields from struct cpuinfo_x86.
Signed-off-by: Tony Luck <tony.luck@intel.com>
Acked-by: Borislav Petkov (AMD) <bp@alien8.de>
---
v12:
No change
---
arch/x86/include/asm/processor.h | 4 ---
arch/x86/include/asm/resctrl.h | 3 ---
arch/x86/kernel/cpu/amd.c | 3 ---
arch/x86/kernel/cpu/hygon.c | 3 ---
arch/x86/kernel/cpu/intel.c | 7 -----
arch/x86/kernel/cpu/resctrl/core.c | 42 ------------------------------
6 files changed, 62 deletions(-)
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index ec9db0dfa0df..4deb88c61c94 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -185,10 +185,6 @@ struct cpuinfo_x86 {
/* in KB - valid for CPUS which support this call: */
unsigned int x86_cache_size;
int x86_cache_alignment; /* In bytes */
- /* Cache QoS architectural values, valid only on the BSP: */
- int x86_cache_max_rmid; /* max index */
- int x86_cache_occ_scale; /* scale to bytes */
- int x86_cache_mbm_width_offset;
int x86_power;
unsigned long loops_per_jiffy;
/* protected processor identification number */
diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h
index 9bfa9b14002b..ab7f6ccd149e 100644
--- a/arch/x86/include/asm/resctrl.h
+++ b/arch/x86/include/asm/resctrl.h
@@ -193,12 +193,9 @@ static inline void resctrl_arch_mon_ctx_free(struct rdt_resource *r,
enum resctrl_event_id evtid,
void *ctx) { }
-void resctrl_cpu_detect(struct cpuinfo_x86 *c);
-
#else
static inline void resctrl_arch_sched_in(struct task_struct *tsk) {}
-static inline void resctrl_cpu_detect(struct cpuinfo_x86 *c) {}
#endif /* CONFIG_X86_CPU_RESCTRL */
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 54e14ed276b5..dd82a11084f4 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -23,7 +23,6 @@
#include <asm/pci-direct.h>
#include <asm/delay.h>
#include <asm/debugreg.h>
-#include <asm/resctrl.h>
#include <asm/msr.h>
#include <asm/sev.h>
@@ -475,8 +474,6 @@ static void bsp_init_amd(struct cpuinfo_x86 *c)
}
}
- resctrl_cpu_detect(c);
-
/* Figure out Zen generations: */
switch (c->x86) {
case 0x17:
diff --git a/arch/x86/kernel/cpu/hygon.c b/arch/x86/kernel/cpu/hygon.c
index ec51c2b9a257..0f226335dd9a 100644
--- a/arch/x86/kernel/cpu/hygon.c
+++ b/arch/x86/kernel/cpu/hygon.c
@@ -17,7 +17,6 @@
#include <asm/spec-ctrl.h>
#include <asm/delay.h>
#include <asm/msr.h>
-#include <asm/resctrl.h>
#include "cpu.h"
@@ -119,8 +118,6 @@ static void bsp_init_hygon(struct cpuinfo_x86 *c)
x86_amd_ls_cfg_ssbd_mask = 1ULL << 10;
}
}
-
- resctrl_cpu_detect(c);
}
static void early_init_hygon(struct cpuinfo_x86 *c)
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 4297ceb2cb24..2f09710e863c 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -22,7 +22,6 @@
#include <asm/microcode.h>
#include <asm/msr.h>
#include <asm/numa.h>
-#include <asm/resctrl.h>
#include <asm/thermal.h>
#include <asm/uaccess.h>
@@ -371,11 +370,6 @@ static void early_init_intel(struct cpuinfo_x86 *c)
detect_tme_early(c);
}
-static void bsp_init_intel(struct cpuinfo_x86 *c)
-{
- resctrl_cpu_detect(c);
-}
-
#ifdef CONFIG_X86_32
/*
* Early probe support logic for ppro memory erratum #50
@@ -804,7 +798,6 @@ static const struct cpu_dev intel_cpu_dev = {
#endif
.c_detect_tlb = intel_detect_tlb,
.c_early_init = early_init_intel,
- .c_bsp_init = bsp_init_intel,
.c_init = init_intel,
.c_x86_vendor = X86_VENDOR_INTEL,
};
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index 82b27a0157ae..f0cfb37482d3 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -1083,48 +1083,6 @@ static __init void rdt_init_res_defs(void)
static enum cpuhp_state rdt_online;
-/* Runs once on the BSP during boot. */
-void resctrl_cpu_detect(struct cpuinfo_x86 *c)
-{
- if (!cpu_has(c, X86_FEATURE_CQM_LLC) && !cpu_has(c, X86_FEATURE_ABMC)) {
- c->x86_cache_max_rmid = -1;
- c->x86_cache_occ_scale = -1;
- c->x86_cache_mbm_width_offset = -1;
- return;
- }
-
- /* will be overridden if occupancy monitoring exists */
- c->x86_cache_max_rmid = cpuid_ebx(0xf);
-
- if (cpu_has(c, X86_FEATURE_CQM_OCCUP_LLC) ||
- cpu_has(c, X86_FEATURE_CQM_MBM_TOTAL) ||
- cpu_has(c, X86_FEATURE_CQM_MBM_LOCAL) ||
- cpu_has(c, X86_FEATURE_ABMC)) {
- u32 eax, ebx, ecx, edx;
-
- /* QoS sub-leaf, EAX=0Fh, ECX=1 */
- cpuid_count(0xf, 1, &eax, &ebx, &ecx, &edx);
-
- c->x86_cache_max_rmid = ecx;
- c->x86_cache_occ_scale = ebx;
- c->x86_cache_mbm_width_offset = eax & 0xff;
-
- if (!c->x86_cache_mbm_width_offset) {
- switch (c->x86_vendor) {
- case X86_VENDOR_AMD:
- c->x86_cache_mbm_width_offset = MBM_CNTR_WIDTH_OFFSET_AMD;
- break;
- case X86_VENDOR_HYGON:
- c->x86_cache_mbm_width_offset = MBM_CNTR_WIDTH_OFFSET_HYGON;
- break;
- default:
- /* Leave c->x86_cache_mbm_width_offset as 0 */
- break;
- }
- }
- }
-}
-
static int __init resctrl_arch_late_init(void)
{
struct rdt_resource *r;
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 06/25] arm,x86,fs/resctrl: Replace architecture resctrl_arch_{alloc,mon}_capable()
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (4 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 05/25] x86/resctrl: Delete resctrl_cpu_detect() Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 07/25] x86/resctrl: Update special case for Intel Haswell enumeration Tony Luck
` (19 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
All the information to determine whether a system is alloc, or mon,
capable is available to the file system. Architecture helpers are not
needed.
Define generic resctrl_alloc_capable() and resctrl_mon_capable() and
replace all architecture versions.
Suggested-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
In each of resctrl_alloc_capable() and resctrl_mon_capable()
- Header comment is a question, end with "?" instead of period.
- Add { } around multi-line for-loop.
- s/(r)/r/
- Add blank line before final return.
---
include/linux/arm_mpam.h | 3 ---
include/linux/resctrl.h | 30 +++++++++++++++++++++++++++
arch/x86/include/asm/resctrl.h | 10 ---------
drivers/resctrl/mpam_resctrl.c | 26 ++---------------------
fs/resctrl/monitor.c | 10 ++++-----
fs/resctrl/pseudo_lock.c | 6 +++---
fs/resctrl/rdtgroup.c | 38 +++++++++++++++++-----------------
7 files changed, 59 insertions(+), 64 deletions(-)
diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
index f92a36187a52..ba4131048260 100644
--- a/include/linux/arm_mpam.h
+++ b/include/linux/arm_mpam.h
@@ -50,9 +50,6 @@ static inline int mpam_ris_create(struct mpam_msc *msc, u8 ris_idx,
}
#endif
-bool resctrl_arch_alloc_capable(void);
-bool resctrl_arch_mon_capable(void);
-
void resctrl_arch_set_cpu_default_closid(int cpu, u32 closid);
void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid);
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index dd09c2ce9a0f..6b07ac2c8675 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -346,6 +346,36 @@ struct rdt_resource {
*/
struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l);
+/*
+ * resctrl_alloc_capable - Are any allocation resources enabled?
+ */
+static inline bool resctrl_alloc_capable(void)
+{
+ struct rdt_resource *r;
+
+ for_each_rdt_resource(r) {
+ if (r->alloc_capable)
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * resctrl_mon_capable - Are any monitor resources enabled?
+ */
+static inline bool resctrl_mon_capable(void)
+{
+ struct rdt_resource *r;
+
+ for_each_rdt_resource(r) {
+ if (r->mon_capable)
+ return true;
+ }
+
+ return false;
+}
+
/**
* struct resctrl_schema - configuration abilities of a resource presented to
* user-space
diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h
index ab7f6ccd149e..fb6cfff82e2f 100644
--- a/arch/x86/include/asm/resctrl.h
+++ b/arch/x86/include/asm/resctrl.h
@@ -50,11 +50,6 @@ DECLARE_STATIC_KEY_FALSE(rdt_enable_key);
DECLARE_STATIC_KEY_FALSE(rdt_alloc_enable_key);
DECLARE_STATIC_KEY_FALSE(rdt_mon_enable_key);
-static inline bool resctrl_arch_alloc_capable(void)
-{
- return rdt_alloc_capable;
-}
-
static inline void resctrl_arch_enable_alloc(void)
{
static_branch_enable_cpuslocked(&rdt_alloc_enable_key);
@@ -67,11 +62,6 @@ static inline void resctrl_arch_disable_alloc(void)
static_branch_dec_cpuslocked(&rdt_enable_key);
}
-static inline bool resctrl_arch_mon_capable(void)
-{
- return rdt_mon_capable;
-}
-
static inline void resctrl_arch_enable_mon(void)
{
static_branch_enable_cpuslocked(&rdt_mon_enable_key);
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 9d223057953a..0db62dd2a71c 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -75,28 +75,6 @@ static DECLARE_WAIT_QUEUE_HEAD(wait_cacheinfo_ready);
*/
static bool resctrl_enabled;
-bool resctrl_arch_alloc_capable(void)
-{
- struct mpam_resctrl_res *res;
- enum resctrl_res_level rid;
-
- for_each_mpam_resctrl_control(res, rid) {
- if (res->resctrl_res.alloc_capable)
- return true;
- }
-
- return false;
-}
-
-bool resctrl_arch_mon_capable(void)
-{
- struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
- struct rdt_resource *l3 = &res->resctrl_res;
-
- /* All monitors are presented as being on the L3 cache */
- return l3->mon_capable;
-}
-
bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt)
{
return false;
@@ -1897,9 +1875,9 @@ int mpam_resctrl_setup(void)
cpus_read_unlock();
- if (!resctrl_arch_alloc_capable() && !resctrl_arch_mon_capable()) {
+ if (!resctrl_alloc_capable() && !resctrl_mon_capable()) {
pr_debug("No alloc(%u) or monitor(%u) found - resctrl not supported\n",
- resctrl_arch_alloc_capable(), resctrl_arch_mon_capable());
+ resctrl_alloc_capable(), resctrl_mon_capable());
return -EOPNOTSUPP;
}
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index 73413cb128ea..362737e13cd3 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -338,7 +338,7 @@ void free_rmid(u32 closid, u32 rmid)
* allows architectures that ignore the closid parameter to avoid an
* unnecessary check.
*/
- if (!resctrl_arch_mon_capable() ||
+ if (!resctrl_mon_capable() ||
idx == resctrl_arch_rmid_idx_encode(RESCTRL_RESERVED_CLOSID,
RESCTRL_RESERVED_RMID))
return;
@@ -888,7 +888,7 @@ void mbm_handle_overflow(struct work_struct *work)
* If the filesystem has been unmounted this work no longer needs to
* run.
*/
- if (!resctrl_mounted || !resctrl_arch_mon_capable())
+ if (!resctrl_mounted || !resctrl_mon_capable())
goto out_unlock;
/*
@@ -950,7 +950,7 @@ void mbm_setup_overflow_handler(struct rdt_l3_mon_domain *dom, unsigned long del
* When a domain comes online there is no guarantee the filesystem is
* mounted. If not, there is no need to catch counter overflow.
*/
- if (!resctrl_mounted || !resctrl_arch_mon_capable())
+ if (!resctrl_mounted || !resctrl_mon_capable())
return;
cpu = cpumask_any_housekeeping(&dom->hdr.cpu_mask, exclude_cpu);
dom->mbm_work_cpu = cpu;
@@ -966,7 +966,7 @@ int setup_rmid_lru_list(void)
u32 idx;
int i;
- if (!resctrl_arch_mon_capable())
+ if (!resctrl_mon_capable())
return 0;
/*
@@ -1006,7 +1006,7 @@ int setup_rmid_lru_list(void)
void free_rmid_lru_list(void)
{
- if (!resctrl_arch_mon_capable())
+ if (!resctrl_mon_capable())
return;
mutex_lock(&rdtgroup_mutex);
diff --git a/fs/resctrl/pseudo_lock.c b/fs/resctrl/pseudo_lock.c
index dea2b4bf966f..04b69c0e37f2 100644
--- a/fs/resctrl/pseudo_lock.c
+++ b/fs/resctrl/pseudo_lock.c
@@ -383,7 +383,7 @@ static int rdtgroup_locksetup_user_restrict(struct rdtgroup *rdtgrp)
if (ret)
goto err_cpus;
- if (resctrl_arch_mon_capable()) {
+ if (resctrl_mon_capable()) {
ret = rdtgroup_kn_mode_restrict(rdtgrp, "mon_groups");
if (ret)
goto err_cpus_list;
@@ -430,7 +430,7 @@ static int rdtgroup_locksetup_user_restore(struct rdtgroup *rdtgrp)
if (ret)
goto err_cpus;
- if (resctrl_arch_mon_capable()) {
+ if (resctrl_mon_capable()) {
ret = rdtgroup_kn_mode_restore(rdtgrp, "mon_groups", 0777);
if (ret)
goto err_cpus_list;
@@ -577,7 +577,7 @@ int rdtgroup_locksetup_exit(struct rdtgroup *rdtgrp)
{
int ret;
- if (resctrl_arch_mon_capable()) {
+ if (resctrl_mon_capable()) {
ret = alloc_rmid(rdtgrp->closid);
if (ret < 0) {
rdt_last_cmd_puts("Out of RMIDs\n");
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 5dcbb0a964e8..79977200b1a0 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -685,13 +685,13 @@ static int __rdtgroup_move_task(struct task_struct *tsk,
static bool is_closid_match(struct task_struct *t, struct rdtgroup *r)
{
- return (resctrl_arch_alloc_capable() && (r->type == RDTCTRL_GROUP) &&
+ return (resctrl_alloc_capable() && (r->type == RDTCTRL_GROUP) &&
resctrl_arch_match_closid(t, r->closid));
}
static bool is_rmid_match(struct task_struct *t, struct rdtgroup *r)
{
- return (resctrl_arch_mon_capable() && (r->type == RDTMON_GROUP) &&
+ return (resctrl_mon_capable() && (r->type == RDTMON_GROUP) &&
resctrl_arch_match_rmid(t, r->mon.parent->closid,
r->mon.rmid));
}
@@ -3159,9 +3159,9 @@ static void resctrl_unmount(void)
resctrl_arch_reset_all_ctrls(r);
resctrl_fs_teardown();
- if (resctrl_arch_alloc_capable())
+ if (resctrl_alloc_capable())
resctrl_arch_disable_alloc();
- if (resctrl_arch_mon_capable())
+ if (resctrl_mon_capable())
resctrl_arch_disable_mon();
resctrl_mounted = false;
mutex_unlock(&rdtgroup_mutex);
@@ -3215,7 +3215,7 @@ static int rdt_get_tree(struct fs_context *fc)
if (ret)
goto out_schemata_free;
- if (resctrl_arch_mon_capable())
+ if (resctrl_mon_capable())
flags |= RFTYPE_MON;
ret = rdtgroup_add_files(rdtgroup_default.kn, flags);
@@ -3228,7 +3228,7 @@ static int rdt_get_tree(struct fs_context *fc)
if (ret < 0)
goto out_closid_exit;
- if (resctrl_arch_mon_capable()) {
+ if (resctrl_mon_capable()) {
ret = mongroup_create_dir(rdtgroup_default.kn,
&rdtgroup_default, "mon_groups",
&kn_mongrp);
@@ -3248,12 +3248,12 @@ static int rdt_get_tree(struct fs_context *fc)
if (ret)
goto out_mondata;
- if (resctrl_arch_alloc_capable())
+ if (resctrl_alloc_capable())
resctrl_arch_enable_alloc();
- if (resctrl_arch_mon_capable())
+ if (resctrl_mon_capable())
resctrl_arch_enable_mon();
- if (resctrl_arch_alloc_capable() || resctrl_arch_mon_capable())
+ if (resctrl_alloc_capable() || resctrl_mon_capable())
resctrl_mounted = true;
if (resctrl_is_mbm_enabled()) {
@@ -3296,10 +3296,10 @@ static int rdt_get_tree(struct fs_context *fc)
return ret;
out_mondata:
- if (resctrl_arch_mon_capable())
+ if (resctrl_mon_capable())
kernfs_remove(kn_mondata);
out_mongrp:
- if (resctrl_arch_mon_capable()) {
+ if (resctrl_mon_capable()) {
mon_put_kn_priv();
rdtgroup_unassign_cntrs(&rdtgroup_default);
kernfs_remove(kn_mongrp);
@@ -3888,7 +3888,7 @@ static int mkdir_rdt_prepare_rmid_alloc(struct rdtgroup *rdtgrp)
{
int ret;
- if (!resctrl_arch_mon_capable())
+ if (!resctrl_mon_capable())
return 0;
ret = alloc_rmid(rdtgrp->closid);
@@ -3913,7 +3913,7 @@ static int mkdir_rdt_prepare_rmid_alloc(struct rdtgroup *rdtgrp)
static void mkdir_rdt_prepare_rmid_free(struct rdtgroup *rgrp)
{
- if (resctrl_arch_mon_capable()) {
+ if (resctrl_mon_capable()) {
rdtgroup_unassign_cntrs(rgrp);
free_rmid(rgrp->closid, rgrp->mon.rmid);
}
@@ -4004,7 +4004,7 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn,
if (rtype == RDTCTRL_GROUP) {
files = RFTYPE_BASE | RFTYPE_CTRL;
- if (resctrl_arch_mon_capable())
+ if (resctrl_mon_capable())
files |= RFTYPE_MON;
} else {
files = RFTYPE_BASE | RFTYPE_MON;
@@ -4113,7 +4113,7 @@ static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn,
list_add(&rdtgrp->rdtgroup_list, &rdt_all_groups);
- if (resctrl_arch_mon_capable()) {
+ if (resctrl_mon_capable()) {
/*
* Create an empty mon_groups directory to hold the subset
* of tasks and cpus to monitor.
@@ -4154,11 +4154,11 @@ static int rdtgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
* allocation is supported, add a control and monitoring
* subdirectory
*/
- if (resctrl_arch_alloc_capable() && parent_kn == rdtgroup_default.kn)
+ if (resctrl_alloc_capable() && parent_kn == rdtgroup_default.kn)
return rdtgroup_mkdir_ctrl_mon(parent_kn, name, mode);
/* Else, attempt to add a monitoring subdirectory. */
- if (resctrl_arch_mon_capable())
+ if (resctrl_mon_capable())
return rdtgroup_mkdir_mon(parent_kn, name, mode);
return -EPERM;
@@ -4573,7 +4573,7 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *h
* If resctrl is mounted, remove all the
* per domain monitor data directories.
*/
- if (resctrl_mounted && resctrl_arch_mon_capable())
+ if (resctrl_mounted && resctrl_mon_capable())
rmdir_mondata_subdir_allrdtgrp(r, hdr);
if (r->rid != RDT_RESOURCE_L3)
@@ -4710,7 +4710,7 @@ int resctrl_online_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *hdr
* by rdt_get_tree() calling mkdir_mondata_all().
* If resctrl is mounted, add per domain monitor data directories.
*/
- if (resctrl_mounted && resctrl_arch_mon_capable())
+ if (resctrl_mounted && resctrl_mon_capable())
mkdir_mondata_subdir_allrdtgrp(r, hdr);
out_unlock:
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 07/25] x86/resctrl: Update special case for Intel Haswell enumeration
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (5 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 06/25] arm,x86,fs/resctrl: Replace architecture resctrl_arch_{alloc,mon}_capable() Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 08/25] x86/resctrl: Delete rdt_alloc_capable and rdt_mon_capable Tony Luck
` (18 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
Certain Intel Haswell CPUs have support for resctrl L3 cache allocation
but do not enumerate the feature. There is a quirk to check for support
and provide hard-coded parameters. This quirk sets rdt_alloc_capable
to indicate to get_rdt_alloc_resources() that normal enumeration is
not needed.
Drop setting of rdt_alloc_capable in cache_alloc_hsw_probe() in
preparation for removal of this global variable.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
Remove the new hsw_alloc_capable variable.
---
arch/x86/kernel/cpu/resctrl/core.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index f0cfb37482d3..f2bf160d01c1 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -177,8 +177,6 @@ static inline void cache_alloc_hsw_probe(void)
r->cache.min_cbm_bits = 2;
r->cache.arch_has_sparse_bitmasks = false;
r->alloc_capable = true;
-
- rdt_alloc_capable = true;
}
/*
@@ -930,7 +928,11 @@ static __init bool get_rdt_alloc_resources(void)
struct rdt_resource *r;
bool ret = false;
- if (rdt_alloc_capable)
+ /*
+ * On Haswell systems cache_alloc_hsw_probe() already marked
+ * RDT_RESOURCE_L3 as alloc_capable. No further enumeration is needed.
+ */
+ if (resctrl_alloc_capable())
return true;
if (!boot_cpu_has(X86_FEATURE_RDT_A))
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 08/25] x86/resctrl: Delete rdt_alloc_capable and rdt_mon_capable
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (6 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 07/25] x86/resctrl: Update special case for Intel Haswell enumeration Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 09/25] fs/resctrl: Remove redundant calls to resctrl_{alloc,mon}_capable() Tony Luck
` (17 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
These globals are no longer needed, delete them.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
Changed names of local variables in get_rdt_resources()
---
arch/x86/include/asm/resctrl.h | 2 --
arch/x86/kernel/cpu/resctrl/core.c | 13 +++----------
arch/x86/kernel/cpu/resctrl/monitor.c | 6 ------
3 files changed, 3 insertions(+), 18 deletions(-)
diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h
index fb6cfff82e2f..49b5357e2e5c 100644
--- a/arch/x86/include/asm/resctrl.h
+++ b/arch/x86/include/asm/resctrl.h
@@ -42,8 +42,6 @@ struct resctrl_pqr_state {
DECLARE_PER_CPU(struct resctrl_pqr_state, pqr_state);
-extern bool rdt_alloc_capable;
-extern bool rdt_mon_capable;
extern unsigned int __ro_after_init rdt_l3_mon_scale;
DECLARE_STATIC_KEY_FALSE(rdt_enable_key);
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index f2bf160d01c1..2e3b9c16cbda 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -45,12 +45,6 @@ static DEFINE_MUTEX(domain_list_lock);
*/
DEFINE_PER_CPU(struct resctrl_pqr_state, pqr_state);
-/*
- * Global boolean for rdt_alloc which is true if any
- * resource allocation is enabled.
- */
-bool rdt_alloc_capable;
-
static void mba_wrmsr_intel(struct msr_param *m);
static void cat_wrmsr(struct msr_param *m);
static void mba_wrmsr_amd(struct msr_param *m);
@@ -781,7 +775,6 @@ void resctrl_arch_pre_mount(void)
cpus_read_lock();
mutex_lock(&domain_list_lock);
r->mon_capable = true;
- rdt_mon_capable = true;
for_each_online_cpu(cpu)
domain_add_cpu_mon(cpu, r);
mutex_unlock(&domain_list_lock);
@@ -1026,10 +1019,10 @@ static __init void check_quirks(void)
static __init bool get_rdt_resources(void)
{
- rdt_alloc_capable = get_rdt_alloc_resources();
- rdt_mon_capable = get_rdt_mon_resources();
+ bool alloc = get_rdt_alloc_resources();
+ bool mon = get_rdt_mon_resources();
- return (rdt_mon_capable || rdt_alloc_capable);
+ return alloc || mon;
}
static __init void rdt_init_res_defs_intel(void)
diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c
index ab9cb34145c5..2f3e5b89a7fc 100644
--- a/arch/x86/kernel/cpu/resctrl/monitor.c
+++ b/arch/x86/kernel/cpu/resctrl/monitor.c
@@ -26,12 +26,6 @@
#include "internal.h"
-/*
- * Global boolean for rdt_monitor which is true if any
- * resource monitoring is enabled.
- */
-bool rdt_mon_capable;
-
/*
* Scale factor to convert L3 monitor events to bytes.
*/
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 09/25] fs/resctrl: Remove redundant calls to resctrl_{alloc,mon}_capable()
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (7 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 08/25] x86/resctrl: Delete rdt_alloc_capable and rdt_mon_capable Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 10/25] x86/resctrl: Honor rdt=perf option to force enable AET perf events Tony Luck
` (16 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
resctrl_mon_capable() indicates whether any monitoring resources
are enabled on the system. It does this by scanning all resources.
Redundant calls to resctrl_mon_capable() in hot code paths should
be eliminated. There are two prime examples:
1) mbm_handle_overflow()
This function is called once per second from worker threads running on
each L3 domain. resctrl_mon_capable() is clearly redundant because worker
threads are only created if the MBM monitoring feature is enabled.
2) is_rmid_match()
This is called for every task on the system so making it less expensive is
appealing. resctrl_mon_capable() is redundant because the function also
checks "r->type == RDTMON_GROUP" and this type of group can only be created
on systems that support monitoring.
3) is_closid_match()
The call to resctrl_alloc_capable() is not just redundant, it is wrong.
On systems that only support monitoring it results in no tasks reported
in the "tasks" file of the resctrl root directory.
Remove the call to resctrl_{alloc,mon}_capable() from each of these functions.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
updated is_closid_match() per report by Sashiko
s/resctrl_arch_mon_capable/resctrl_mon_capable/
Removed unnecessary line break.
---
fs/resctrl/monitor.c | 2 +-
fs/resctrl/rdtgroup.c | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index 362737e13cd3..02e81fc82b14 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -888,7 +888,7 @@ void mbm_handle_overflow(struct work_struct *work)
* If the filesystem has been unmounted this work no longer needs to
* run.
*/
- if (!resctrl_mounted || !resctrl_mon_capable())
+ if (!resctrl_mounted)
goto out_unlock;
/*
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 79977200b1a0..c0b86ce05e50 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -685,13 +685,13 @@ static int __rdtgroup_move_task(struct task_struct *tsk,
static bool is_closid_match(struct task_struct *t, struct rdtgroup *r)
{
- return (resctrl_alloc_capable() && (r->type == RDTCTRL_GROUP) &&
+ return (r->type == RDTCTRL_GROUP &&
resctrl_arch_match_closid(t, r->closid));
}
static bool is_rmid_match(struct task_struct *t, struct rdtgroup *r)
{
- return (resctrl_mon_capable() && (r->type == RDTMON_GROUP) &&
+ return (r->type == RDTMON_GROUP &&
resctrl_arch_match_rmid(t, r->mon.parent->closid,
r->mon.rmid));
}
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 10/25] x86/resctrl: Honor rdt=perf option to force enable AET perf events
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (8 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 09/25] fs/resctrl: Remove redundant calls to resctrl_{alloc,mon}_capable() Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 11/25] fs/resctrl: Add interface to disable a monitor event Tony Luck
` (15 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
resctrl can disable ("force_off") a feature supported by the platform if,
for example, there is an erratum related to the feature or, in the case of AET
(Application Energy Telemetry), when the event group has insufficient RMIDs. The
"rdt=" kernel command line option lets the user override ("force_on") when
a feature is disabled in such case. Users may also disable ("force_off")
individual supported resctrl features they do not need.
Linux enumerates AET once on first mount and skips this enumeration if
the associated event group is supported but disabled. Since AET is only
enumerated once, this check is guaranteed to only consider disabling via
the rdt= kernel parameter.
However, when transitioning to enumerate AET on every mount, it is no longer
correct to skip enumeration simply because an event group is marked as
disabled. It is then possible for resctrl to have force-disabled the event
group during an earlier enumeration due to insufficient RMIDs, which would
improperly cause the kernel to ignore a user's explicit rdt= override on
subsequent mounts.
Ensure the user's command line choices take precedence over system-level limits.
Reviewed-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
No change
---
arch/x86/kernel/cpu/resctrl/intel_aet.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/kernel/cpu/resctrl/intel_aet.c b/arch/x86/kernel/cpu/resctrl/intel_aet.c
index c22c3cf5167d..4ad6ad78e93e 100644
--- a/arch/x86/kernel/cpu/resctrl/intel_aet.c
+++ b/arch/x86/kernel/cpu/resctrl/intel_aet.c
@@ -228,7 +228,7 @@ static bool enable_events(struct event_group *e, struct pmt_feature_group *p)
struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_PERF_PKG].r_resctrl;
int skipped_events = 0;
- if (e->force_off)
+ if (e->force_off && !e->force_on)
return false;
if (!group_has_usable_regions(e, p))
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 11/25] fs/resctrl: Add interface to disable a monitor event
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (9 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 10/25] x86/resctrl: Honor rdt=perf option to force enable AET perf events Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 12/25] arm,x86,fs/resctrl: Allocate maximum needed rmid_ptrs[] Tony Luck
` (14 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
resctrl currently assumes all monitor events are enabled before any domain
is created, because per-domain state is allocated by the architecture's CPU
hotplug callbacks. There is no way to disable an event once registered.
AET events are enumerated by the INTEL_PMT_TELEMETRY driver. To allow that
driver to be a loadable module, resctrl must tolerate AET events appearing
and disappearing, which requires the ability to disable an event when the
driver is unloaded.
Add resctrl_disable_mon_event(). The architecture owns domain lifetime
and knows mount state, so it is responsible for calling this only while
resctrl is unmounted and for cleaning up any per-domain state. Document
those requirements in the kerneldoc since they are not enforced in code.
Signed-off-by: Tony Luck <tony.luck@intel.com>
Reviewed-by: Reinette Chatre <reinette.chatre@intel.com>
---
v12:
Added Reinette RB tag (from v10 review).
Better header comment for resctrl_disable_mon_event().
---
include/linux/resctrl.h | 34 ++++++++++++++++++++++++++++++++++
fs/resctrl/monitor.c | 15 +++++++++++++++
2 files changed, 49 insertions(+)
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 6b07ac2c8675..fbf737e884db 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -449,9 +449,43 @@ u32 resctrl_arch_get_num_closid(struct rdt_resource *r);
u32 resctrl_arch_system_num_rmid_idx(void);
int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid);
+/**
+ * resctrl_enable_mon_event() - Enable monitoring event
+ * @eventid: ID of the event
+ * @any_cpu: True if event data can be read from any CPU.
+ * @binary_bits: Number of binary places of the fixed-point value expected to
+ * back a floating point event. Can only be set for floating point
+ * events.
+ * @arch_priv: Architecture private data associated with event. Passed back to
+ * architecture when reading the event via resctrl_arch_rmid_read().
+ *
+ * The file system must not be mounted when enabling an event.
+ *
+ * Events that require per-domain (architectural and/or filesystem) state must
+ * be enabled before the domain structures are allocated. For example before
+ * CPU hotplug callbacks that allocate domain structures are registered. If the
+ * architecture discovers a resource after initialization it should enable
+ * events needing per-domain state before any domain structure allocation which
+ * should be coordinated with the CPU hotplug callbacks.
+ *
+ * Return:
+ * true if event was successfully enabled, false otherwise.
+ */
bool resctrl_enable_mon_event(enum resctrl_event_id eventid, bool any_cpu,
unsigned int binary_bits, void *arch_priv);
+/**
+ * resctrl_disable_mon_event() - Disable monitoring event
+ * @eventid: ID of the event
+ *
+ * Never disable an event that may be accessed while the file system is unmounted.
+ *
+ * Events that require per-domain (architectural and/or filesystem) state
+ * will require additional cleanup which should be coordinated with the CPU
+ * hotplug callbacks.
+ */
+void resctrl_disable_mon_event(enum resctrl_event_id eventid);
+
bool resctrl_is_mon_event_enabled(enum resctrl_event_id eventid);
bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt);
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index 02e81fc82b14..2a28fe04284b 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -1066,6 +1066,21 @@ bool resctrl_enable_mon_event(enum resctrl_event_id eventid, bool any_cpu,
return true;
}
+void resctrl_disable_mon_event(enum resctrl_event_id eventid)
+{
+ if (WARN_ON_ONCE(eventid < QOS_FIRST_EVENT || eventid >= QOS_NUM_EVENTS))
+ return;
+ if (!mon_event_all[eventid].enabled) {
+ pr_warn("Event %d already disabled\n", eventid);
+ return;
+ }
+
+ mon_event_all[eventid].any_cpu = false;
+ mon_event_all[eventid].binary_bits = 0;
+ mon_event_all[eventid].arch_priv = NULL;
+ mon_event_all[eventid].enabled = false;
+}
+
bool resctrl_is_mon_event_enabled(enum resctrl_event_id eventid)
{
return eventid >= QOS_FIRST_EVENT && eventid < QOS_NUM_EVENTS &&
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 12/25] arm,x86,fs/resctrl: Allocate maximum needed rmid_ptrs[]
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (10 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 11/25] fs/resctrl: Add interface to disable a monitor event Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 13/25] arm,x86,fs/resctrl: Allocate right size for L3 monitor arrays Tony Luck
` (13 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
File system code allocates the rmid_ptrs[] array once during
initialization. The number of entries needed in this array is currently
constant. When changes are made to allow Application Energy Telemetry
(AET) to run with the pmt_telemetry driver as a module, then number of
entries needed may change from one mount to the next.
Allocate rmid_ptrs[] with enough entries for any future mount.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
New patch. Split out from old patch 12.
New global pqr_assoc_num_rmid to avoid repeat CPUID calls.
---
include/linux/resctrl.h | 1 +
arch/x86/kernel/cpu/resctrl/core.c | 27 +++++++++++++++++++++++++++
drivers/resctrl/mpam_resctrl.c | 9 +++++++++
fs/resctrl/monitor.c | 2 +-
4 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index fbf737e884db..5535bde7b925 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -447,6 +447,7 @@ static inline u32 resctrl_get_default_ctrl(struct rdt_resource *r)
/* The number of closid supported by this resource regardless of CDP */
u32 resctrl_arch_get_num_closid(struct rdt_resource *r);
u32 resctrl_arch_system_num_rmid_idx(void);
+u32 resctrl_arch_system_max_rmid_idx(void);
int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid);
/**
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index 2e3b9c16cbda..a9109f2bc43e 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -45,6 +45,9 @@ static DEFINE_MUTEX(domain_list_lock);
*/
DEFINE_PER_CPU(struct resctrl_pqr_state, pqr_state);
+/* Number of RMIDS values that can be written to IA32_PQR_ASSOC.RMID */
+static u32 pqr_assoc_num_rmid;
+
static void mba_wrmsr_intel(struct msr_param *m);
static void cat_wrmsr(struct msr_param *m);
static void mba_wrmsr_amd(struct msr_param *m);
@@ -124,6 +127,28 @@ u32 resctrl_arch_system_num_rmid_idx(void)
return num_rmids == U32_MAX ? 0 : num_rmids;
}
+/**
+ * resctrl_arch_system_max_rmid_idx - Largest possible number of RMIDs
+ *
+ * Return: Maximum possible number of RMIDs used for boot time allocations.
+ */
+u32 resctrl_arch_system_max_rmid_idx(void)
+{
+ struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
+ u32 num_rmid = pqr_assoc_num_rmid;
+
+ /*
+ * If the system is capable of L3 monitoring the maximum RMID value may
+ * be lower than the system maximum. Either because the L3 monitoring
+ * feature supports fewer RMIDs, or because SNC (Sub-NUMA Cluster)
+ * is enabled and divides RMIDs per cluster.
+ */
+ if (r->mon_capable)
+ num_rmid = r->mon.num_rmid;
+
+ return num_rmid;
+}
+
struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
{
if (l >= RDT_NUM_RESOURCES)
@@ -967,6 +992,8 @@ static __init bool get_rdt_mon_resources(void)
if (!cpu_feature_enabled(X86_FEATURE_CQM))
return false;
+ pqr_assoc_num_rmid = cpuid_ebx(0xf) + 1;
+
/* Any of the L3 monitoring features? */
if (!cpu_feature_enabled(X86_FEATURE_CQM_LLC))
return false;
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 0db62dd2a71c..0ffa25199f74 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -252,6 +252,15 @@ u32 resctrl_arch_system_num_rmid_idx(void)
return (mpam_pmg_max + 1) * (mpam_partid_max + 1);
}
+/*
+ * File system calls this for one-time allocation of structures
+ * during initialization. Return the largest possible value.
+ */
+u32 resctrl_arch_system_max_rmid_idx(void)
+{
+ return resctrl_arch_system_num_rmid_idx();
+}
+
u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid)
{
return closid * (mpam_pmg_max + 1) + rmid;
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index 2a28fe04284b..e8775e08aa18 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -978,7 +978,7 @@ int setup_rmid_lru_list(void)
if (rmid_ptrs)
return 0;
- idx_limit = resctrl_arch_system_num_rmid_idx();
+ idx_limit = resctrl_arch_system_max_rmid_idx();
rmid_ptrs = kzalloc_objs(struct rmid_entry, idx_limit);
if (!rmid_ptrs)
return -ENOMEM;
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 13/25] arm,x86,fs/resctrl: Allocate right size for L3 monitor arrays
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (11 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 12/25] arm,x86,fs/resctrl: Allocate maximum needed rmid_ptrs[] Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 14/25] fs/resctrl: Rebuild free RMID list on each mount Tony Luck
` (12 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
The number of RMIDs available may change from one mount to the next.
The sizes of the rdt_l3_mon_domain::rmid_busy_llc bitmap and the
rdt_l3_mon_domain::mbm_states array always depend on the number of
RMIDs supported by RDT_RESOURCE_L3.
Add resctrl_arch_get_num_rmid_idx(r) to report the maximum RMID index
for a resource. Use it to allocate the rdt_l3_mon_domain::rmid_busy_llc
bitmap and rdt_l3_mon_domain::mbm_states[] and when operating on these
structures.
The limbo code must deal with changes in the number of RMIDs from one
mount to the next because some RMIDs may still be "busy" when the file
system is unmounted, but be above resctrl_arch_system_num_rmid_idx()
for the remount. In this case RMIDs that can be released are not put
onto the rmid_free_lru list.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
New patch. Split from patch 12.
---
include/linux/resctrl.h | 7 +++++--
arch/x86/kernel/cpu/resctrl/core.c | 5 +++++
drivers/resctrl/mpam_resctrl.c | 5 +++++
fs/resctrl/monitor.c | 30 ++++++++++++++++++++++--------
fs/resctrl/rdtgroup.c | 6 +++---
5 files changed, 40 insertions(+), 13 deletions(-)
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 5535bde7b925..604ab7af7c2b 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -183,10 +183,12 @@ struct mbm_cntr_cfg {
* struct rdt_l3_mon_domain - group of CPUs sharing RDT_RESOURCE_L3 monitoring
* @hdr: common header for different domain types
* @ci_id: cache info id for this domain
- * @rmid_busy_llc: bitmap of which limbo RMIDs are above threshold
+ * @rmid_busy_llc: bitmap of which limbo RMIDs are above threshold. Sized for
+ * maximum supported RMIDs in L3 resource.
* @mbm_states: Per-event pointer to the MBM event's saved state.
* An MBM event's state is an array of struct mbm_state
* indexed by RMID on x86 or combined CLOSID, RMID on Arm.
+ * Sized same as @rmid_busy_llc.
* @mbm_over: worker to periodically read MBM h/w counters
* @cqm_limbo: worker to periodically read CQM h/w counters
* @mbm_work_cpu: worker CPU for MBM h/w counters
@@ -444,8 +446,9 @@ static inline u32 resctrl_get_default_ctrl(struct rdt_resource *r)
return WARN_ON_ONCE(1);
}
-/* The number of closid supported by this resource regardless of CDP */
+/* The number of closid/rmid supported by this resource regardless of CDP */
u32 resctrl_arch_get_num_closid(struct rdt_resource *r);
+u32 resctrl_arch_get_num_rmid_idx(struct rdt_resource *r);
u32 resctrl_arch_system_num_rmid_idx(void);
u32 resctrl_arch_system_max_rmid_idx(void);
int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid);
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index a9109f2bc43e..e633da548959 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -380,6 +380,11 @@ u32 resctrl_arch_get_num_closid(struct rdt_resource *r)
return resctrl_to_arch_res(r)->num_closid;
}
+u32 resctrl_arch_get_num_rmid_idx(struct rdt_resource *r)
+{
+ return r->mon.num_rmid;
+}
+
void rdt_ctrl_update(void *arg)
{
struct rdt_hw_resource *hw_res;
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 0ffa25199f74..69c9e02d2f40 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -247,6 +247,11 @@ u32 resctrl_arch_get_num_closid(struct rdt_resource *ignored)
return mpam_partid_max + 1;
}
+u32 resctrl_arch_get_num_rmid_idx(struct rdt_resource *ignored)
+{
+ return resctrl_arch_system_num_rmid_idx();
+}
+
u32 resctrl_arch_system_num_rmid_idx(void)
{
return (mpam_pmg_max + 1) * (mpam_partid_max + 1);
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index e8775e08aa18..b8bd59c52c62 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -115,10 +115,18 @@ static inline struct rmid_entry *__rmid_entry(u32 idx)
static void limbo_release_entry(struct rmid_entry *entry)
{
+ u32 cur_idx_limit = resctrl_arch_system_num_rmid_idx();
+
lockdep_assert_held(&rdtgroup_mutex);
rmid_limbo_count--;
- list_add_tail(&entry->list, &rmid_free_lru);
+
+ /*
+ * Limbo may be freeing an RMID from a previous mount where there
+ * were more RMIDs available.
+ */
+ if (resctrl_arch_rmid_idx_encode(entry->closid, entry->rmid) < cur_idx_limit)
+ list_add_tail(&entry->list, &rmid_free_lru);
if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID))
closid_num_dirty_rmid[entry->closid]--;
@@ -133,7 +141,7 @@ static void limbo_release_entry(struct rmid_entry *entry)
void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free)
{
struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
- u32 idx_limit = resctrl_arch_system_num_rmid_idx();
+ u32 l3_idx_limit = resctrl_arch_get_num_rmid_idx(r);
struct rmid_entry *entry;
bool rmid_dirty = true;
u32 idx, cur_idx = 1;
@@ -154,10 +162,15 @@ void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free)
* are marked as busy for occupancy < threshold. If the occupancy
* is less than the threshold decrement the busy counter of the
* RMID and move it to the free list when the counter reaches 0.
+ *
+ * RMIDs will keep counts of allocated LLC entries after the resctrl
+ * file system is unmounted. So check all possible RMIDs since a
+ * previous mount cycle may have used more than are available in
+ * this mount cycle.
*/
for (;;) {
- idx = find_next_bit(d->rmid_busy_llc, idx_limit, cur_idx);
- if (idx >= idx_limit)
+ idx = find_next_bit(d->rmid_busy_llc, l3_idx_limit, cur_idx);
+ if (idx >= l3_idx_limit)
break;
entry = __rmid_entry(idx);
@@ -197,9 +210,10 @@ void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free)
bool has_busy_rmid(struct rdt_l3_mon_domain *d)
{
- u32 idx_limit = resctrl_arch_system_num_rmid_idx();
+ struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
+ u32 l3_idx_limit = resctrl_arch_get_num_rmid_idx(r);
- return find_first_bit(d->rmid_busy_llc, idx_limit) != idx_limit;
+ return find_first_bit(d->rmid_busy_llc, l3_idx_limit) != l3_idx_limit;
}
static struct rmid_entry *resctrl_find_free_rmid(u32 closid)
@@ -1218,7 +1232,7 @@ static void mbm_cntr_free_all(struct rdt_resource *r, struct rdt_l3_mon_domain *
*/
static void resctrl_reset_rmid_all(struct rdt_resource *r, struct rdt_l3_mon_domain *d)
{
- u32 idx_limit = resctrl_arch_system_num_rmid_idx();
+ u32 l3_idx_limit = resctrl_arch_get_num_rmid_idx(r);
enum resctrl_event_id evt;
int idx;
@@ -1226,7 +1240,7 @@ static void resctrl_reset_rmid_all(struct rdt_resource *r, struct rdt_l3_mon_dom
if (!resctrl_is_mon_event_enabled(evt))
continue;
idx = MBM_STATE_IDX(evt);
- memset(d->mbm_states[idx], 0, sizeof(*d->mbm_states[0]) * idx_limit);
+ memset(d->mbm_states[idx], 0, sizeof(*d->mbm_states[0]) * l3_idx_limit);
}
}
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index c0b86ce05e50..0c9c29037667 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -4621,13 +4621,13 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *h
*/
static int domain_setup_l3_mon_state(struct rdt_resource *r, struct rdt_l3_mon_domain *d)
{
- u32 idx_limit = resctrl_arch_system_num_rmid_idx();
+ u32 l3_idx_limit = resctrl_arch_get_num_rmid_idx(r);
size_t tsize = sizeof(*d->mbm_states[0]);
enum resctrl_event_id eventid;
int idx;
if (resctrl_is_mon_event_enabled(QOS_L3_OCCUP_EVENT_ID)) {
- d->rmid_busy_llc = bitmap_zalloc(idx_limit, GFP_KERNEL);
+ d->rmid_busy_llc = bitmap_zalloc(l3_idx_limit, GFP_KERNEL);
if (!d->rmid_busy_llc)
return -ENOMEM;
}
@@ -4636,7 +4636,7 @@ static int domain_setup_l3_mon_state(struct rdt_resource *r, struct rdt_l3_mon_d
if (!resctrl_is_mon_event_enabled(eventid))
continue;
idx = MBM_STATE_IDX(eventid);
- d->mbm_states[idx] = kcalloc(idx_limit, tsize, GFP_KERNEL);
+ d->mbm_states[idx] = kcalloc(l3_idx_limit, tsize, GFP_KERNEL);
if (!d->mbm_states[idx])
goto cleanup;
}
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 14/25] fs/resctrl: Rebuild free RMID list on each mount
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (12 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 13/25] arm,x86,fs/resctrl: Allocate right size for L3 monitor arrays Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 15/25] x86,fs/resctrl: Handle systems where AET is the only resource Tony Luck
` (11 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
Application Energy Telemetry (AET) event enumeration takes place
asynchronously. Linux builds the pmt_telemetry module into the kernel to
kick off enumeration early enough that it completes before first mount of
the resctrl file system.
Allowing pmt_telemetry to be a loadable module means that it is possible
for different numbers of RMIDs to be supported on each mount, depending
on whether pmt_telemetry module is loaded.
Initialize rmid_free_lru based on the number of RMIDs available for the
current mount cycle.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
New patch. Split from patch 12.
---
fs/resctrl/monitor.c | 64 +++++++++++++++++++++++++++++---------------
1 file changed, 42 insertions(+), 22 deletions(-)
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index b8bd59c52c62..8dde2b81b72f 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -75,6 +75,11 @@ static unsigned int rmid_limbo_count;
*/
static struct rmid_entry *rmid_ptrs;
+/*
+ * @num_rmid_ptrs - The number of elements in rmid_ptrs[].
+ */
+static u32 num_rmid_ptrs;
+
/*
* This is the threshold cache occupancy in bytes at which we will consider an
* RMID available for re-allocation.
@@ -975,45 +980,60 @@ void mbm_setup_overflow_handler(struct rdt_l3_mon_domain *dom, unsigned long del
int setup_rmid_lru_list(void)
{
- struct rmid_entry *entry = NULL;
- u32 idx_limit;
- u32 idx;
+ struct rmid_entry *entry;
+ u32 cur_idx_limit;
+ u32 rsvd_idx;
int i;
if (!resctrl_mon_capable())
return 0;
/*
- * Called on every mount, but the number of RMIDs cannot change
- * after the first mount, so keep using the same set of rmid_ptrs[]
- * until resctrl_exit(). Note that the limbo handler continues to
- * access rmid_ptrs[] after resctrl is unmounted.
+ * Allocate the largest number of RMIDs that this system will ever
+ * need. These cannot be freed until resctrl_exit() because the limbo
+ * handler continues to access rmid_ptrs[] after resctrl is unmounted.
*/
- if (rmid_ptrs)
- return 0;
+ if (!rmid_ptrs) {
+ num_rmid_ptrs = resctrl_arch_system_max_rmid_idx();
+ rmid_ptrs = kzalloc_objs(struct rmid_entry, num_rmid_ptrs);
+ if (!rmid_ptrs) {
+ num_rmid_ptrs = 0;
+ return -ENOMEM;
+ }
- idx_limit = resctrl_arch_system_max_rmid_idx();
- rmid_ptrs = kzalloc_objs(struct rmid_entry, idx_limit);
- if (!rmid_ptrs)
- return -ENOMEM;
+ for (i = 0; i < num_rmid_ptrs; i++) {
+ entry = &rmid_ptrs[i];
+ INIT_LIST_HEAD(&entry->list);
- for (i = 0; i < idx_limit; i++) {
- entry = &rmid_ptrs[i];
- INIT_LIST_HEAD(&entry->list);
+ resctrl_arch_rmid_idx_decode(i, &entry->closid, &entry->rmid);
+ }
+ }
- resctrl_arch_rmid_idx_decode(i, &entry->closid, &entry->rmid);
- list_add_tail(&entry->list, &rmid_free_lru);
+ /* Find how many RMIDs are available for this mount */
+ cur_idx_limit = resctrl_arch_system_num_rmid_idx();
+ if (cur_idx_limit > num_rmid_ptrs) {
+ pr_warn_once("RMID count %u exceeds allocated %u; capping\n",
+ cur_idx_limit, num_rmid_ptrs);
+ cur_idx_limit = num_rmid_ptrs;
}
+ INIT_LIST_HEAD(&rmid_free_lru);
+
/*
* RESCTRL_RESERVED_CLOSID and RESCTRL_RESERVED_RMID are special and
* are always allocated. These are used for the rdtgroup_default
* control group, which was setup earlier in rdtgroup_setup_default().
*/
- idx = resctrl_arch_rmid_idx_encode(RESCTRL_RESERVED_CLOSID,
- RESCTRL_RESERVED_RMID);
- entry = __rmid_entry(idx);
- list_del(&entry->list);
+ rsvd_idx = resctrl_arch_rmid_idx_encode(RESCTRL_RESERVED_CLOSID,
+ RESCTRL_RESERVED_RMID);
+
+ for (i = 0; i < cur_idx_limit; i++) {
+ entry = &rmid_ptrs[i];
+ /* Don't add reserved or busy entries to free list */
+ if (i == rsvd_idx || entry->busy)
+ continue;
+ list_add_tail(&entry->list, &rmid_free_lru);
+ }
return 0;
}
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 15/25] x86,fs/resctrl: Handle systems where AET is the only resource
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (13 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 14/25] fs/resctrl: Rebuild free RMID list on each mount Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 16/25] x86/resctrl: Add PMT registration API for AET enumeration callbacks Tony Luck
` (10 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
On a system with no L3 monitor resources it should still be possible to
run with just AET.
Update get_rdt_mon_resources() to return true based on whether the
system supports monitoring rather than on the presence of any of the
L3 monitor features.
Refuse to mount the resctrl file system if there are no monitoring or
control features. Add invalfc() to rdt_get_tree() so the console log will
let the user know why the mount failed.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
Cleanups in get_rdt_mon_resources()
Add invalfc() to rdt_get_tree()
Change commit message with updated changes
---
arch/x86/kernel/cpu/resctrl/internal.h | 2 +-
arch/x86/kernel/cpu/resctrl/core.c | 20 +++++++++++---------
arch/x86/kernel/cpu/resctrl/monitor.c | 4 +---
fs/resctrl/rdtgroup.c | 8 ++++++--
4 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h
index e46eb9a4c725..d70c8cb1cb81 100644
--- a/arch/x86/kernel/cpu/resctrl/internal.h
+++ b/arch/x86/kernel/cpu/resctrl/internal.h
@@ -226,7 +226,7 @@ union l3_qos_abmc_cfg {
void rdt_ctrl_update(void *arg);
-int rdt_get_l3_mon_config(struct rdt_resource *r);
+void rdt_get_l3_mon_config(struct rdt_resource *r);
bool rdt_cpu_has(int flag);
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index e633da548959..addcb2a19c98 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -991,7 +991,7 @@ static __init bool get_rdt_alloc_resources(void)
static __init bool get_rdt_mon_resources(void)
{
struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
- bool ret = false;
+ bool l3_mon_found = false;
/* Any monitoring at all? */
if (!cpu_feature_enabled(X86_FEATURE_CQM))
@@ -1001,27 +1001,29 @@ static __init bool get_rdt_mon_resources(void)
/* Any of the L3 monitoring features? */
if (!cpu_feature_enabled(X86_FEATURE_CQM_LLC))
- return false;
+ goto skip_l3_feature_checks;
if (rdt_cpu_has(X86_FEATURE_CQM_OCCUP_LLC)) {
resctrl_enable_mon_event(QOS_L3_OCCUP_EVENT_ID, false, 0, NULL);
- ret = true;
+ l3_mon_found = true;
}
if (rdt_cpu_has(X86_FEATURE_CQM_MBM_TOTAL)) {
resctrl_enable_mon_event(QOS_L3_MBM_TOTAL_EVENT_ID, false, 0, NULL);
- ret = true;
+ l3_mon_found = true;
}
if (rdt_cpu_has(X86_FEATURE_CQM_MBM_LOCAL)) {
resctrl_enable_mon_event(QOS_L3_MBM_LOCAL_EVENT_ID, false, 0, NULL);
- ret = true;
+ l3_mon_found = true;
}
if (rdt_cpu_has(X86_FEATURE_ABMC))
- ret = true;
+ l3_mon_found = true;
- if (!ret)
- return false;
+ if (l3_mon_found)
+ rdt_get_l3_mon_config(r);
- return !rdt_get_l3_mon_config(r);
+skip_l3_feature_checks:
+ /* Even if there are no L3 monitor events, AET might be supported */
+ return true;
}
static __init void __check_quirks_intel(void)
diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c
index 2f3e5b89a7fc..e684353631de 100644
--- a/arch/x86/kernel/cpu/resctrl/monitor.c
+++ b/arch/x86/kernel/cpu/resctrl/monitor.c
@@ -431,7 +431,7 @@ static void __init intel_rdt_mbm_apply_quirk(u32 num_rmid)
mbm_cf = mbm_cf_table[cf_index].cf;
}
-int __init rdt_get_l3_mon_config(struct rdt_resource *r)
+void __init rdt_get_l3_mon_config(struct rdt_resource *r)
{
struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
unsigned int mbm_offset;
@@ -514,8 +514,6 @@ int __init rdt_get_l3_mon_config(struct rdt_resource *r)
intel_rdt_mbm_apply_quirk(r->mon.num_rmid);
r->mon_capable = true;
-
- return 0;
}
static void resctrl_abmc_set_one_amd(void *arg)
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 0c9c29037667..2e9f71901f68 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -3195,6 +3195,11 @@ static int rdt_get_tree(struct fs_context *fc)
goto out;
}
+ if (!resctrl_alloc_capable() && !resctrl_mon_capable()) {
+ ret = invalfc(fc, "No allocation or monitoring features are available or enabled");
+ goto out;
+ }
+
ret = setup_rmid_lru_list();
if (ret)
goto out;
@@ -3253,8 +3258,7 @@ static int rdt_get_tree(struct fs_context *fc)
if (resctrl_mon_capable())
resctrl_arch_enable_mon();
- if (resctrl_alloc_capable() || resctrl_mon_capable())
- resctrl_mounted = true;
+ resctrl_mounted = true;
if (resctrl_is_mbm_enabled()) {
r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 16/25] x86/resctrl: Add PMT registration API for AET enumeration callbacks
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (14 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 15/25] x86,fs/resctrl: Handle systems where AET is the only resource Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 17/25] platform/x86/intel/pmt: Register enumeration functions with resctrl Tony Luck
` (9 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
resctrl is always built-in; INTEL_PMT_TELEMETRY may be a module. Add, and
export, register/unregister functions so the PMT module can supply/clear
enumeration callback functions when loaded/unloaded.
Suggested-by: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
No change
---
include/linux/intel_vsec.h | 12 ++++++++++++
arch/x86/kernel/cpu/resctrl/intel_aet.c | 24 ++++++++++++++++++++++++
2 files changed, 36 insertions(+)
diff --git a/include/linux/intel_vsec.h b/include/linux/intel_vsec.h
index 843cda8f8644..c04b1d0f3143 100644
--- a/include/linux/intel_vsec.h
+++ b/include/linux/intel_vsec.h
@@ -257,4 +257,16 @@ static inline void
intel_pmt_put_feature_group(struct pmt_feature_group *feature_group) {}
#endif
+#ifdef CONFIG_X86_CPU_RESCTRL_INTEL_AET
+void intel_aet_register_enumeration(struct module *module,
+ struct pmt_feature_group *(*get)(enum pmt_feature_id id),
+ void (*put)(struct pmt_feature_group *p));
+void intel_aet_unregister_enumeration(void);
+#else
+static inline void intel_aet_register_enumeration(struct module *module,
+ struct pmt_feature_group *(*get)(enum pmt_feature_id id),
+ void (*put)(struct pmt_feature_group *p)) { }
+static inline void intel_aet_unregister_enumeration(void) { }
+#endif /* CONFIG_X86_CPU_RESCTRL_INTEL_AET */
+
#endif
diff --git a/arch/x86/kernel/cpu/resctrl/intel_aet.c b/arch/x86/kernel/cpu/resctrl/intel_aet.c
index 4ad6ad78e93e..6c4f0bf3b876 100644
--- a/arch/x86/kernel/cpu/resctrl/intel_aet.c
+++ b/arch/x86/kernel/cpu/resctrl/intel_aet.c
@@ -17,12 +17,14 @@
#include <linux/cpumask.h>
#include <linux/err.h>
#include <linux/errno.h>
+#include <linux/export.h>
#include <linux/gfp_types.h>
#include <linux/init.h>
#include <linux/intel_pmt_features.h>
#include <linux/intel_vsec.h>
#include <linux/io.h>
#include <linux/minmax.h>
+#include <linux/module.h>
#include <linux/printk.h>
#include <linux/rculist.h>
#include <linux/rcupdate.h>
@@ -291,6 +293,10 @@ static enum pmt_feature_id lookup_pfid(const char *pfname)
return FEATURE_INVALID;
}
+static struct module *pmt_module;
+static struct pmt_feature_group *(*get_feature)(enum pmt_feature_id id);
+static void (*put_feature)(struct pmt_feature_group *p);
+
/*
* Request a copy of struct pmt_feature_group for each event group. If there is
* one, the returned structure has an array of telemetry_region structures,
@@ -325,6 +331,24 @@ bool intel_aet_get_events(void)
return ret;
}
+void intel_aet_register_enumeration(struct module *module,
+ struct pmt_feature_group *(*get)(enum pmt_feature_id id),
+ void (*put)(struct pmt_feature_group *p))
+{
+ get_feature = get;
+ put_feature = put;
+ pmt_module = module;
+}
+EXPORT_SYMBOL_NS_GPL(intel_aet_register_enumeration, "INTEL_PMT");
+
+void intel_aet_unregister_enumeration(void)
+{
+ pmt_module = NULL;
+ get_feature = NULL;
+ put_feature = NULL;
+}
+EXPORT_SYMBOL_NS_GPL(intel_aet_unregister_enumeration, "INTEL_PMT");
+
void __exit intel_aet_exit(void)
{
struct event_group **peg;
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 17/25] platform/x86/intel/pmt: Register enumeration functions with resctrl
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (15 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 16/25] x86/resctrl: Add PMT registration API for AET enumeration callbacks Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 18/25] x86/resctrl: Use registered function pointers for AET enumeration Tony Luck
` (8 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
INTEL_PMT_TELEMETRY is a loadable module, but resctrl is built-in and cannot
call PMT functions directly.
Use ".probe_type = PROBE_FORCE_SYNCHRONOUS" to ensure sequential, synchronous
calls to per-device .probe() functions. Register the telemetry enumeration
function pointers at the end of pmt_telem_init() when all .probe() functions
have run and enumeration is complete.
Unregister at the start of pmt_telem_exit() before teardown of the
auxiliary drivers.
Suggested-by: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
No change
---
drivers/platform/x86/intel/pmt/telemetry.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/drivers/platform/x86/intel/pmt/telemetry.c b/drivers/platform/x86/intel/pmt/telemetry.c
index 953f35b6daec..bf0c9295feb3 100644
--- a/drivers/platform/x86/intel/pmt/telemetry.c
+++ b/drivers/platform/x86/intel/pmt/telemetry.c
@@ -427,16 +427,30 @@ static struct auxiliary_driver pmt_telem_aux_driver = {
.id_table = pmt_telem_id_table,
.remove = pmt_telem_remove,
.probe = pmt_telem_probe,
+ .driver = {
+ .probe_type = PROBE_FORCE_SYNCHRONOUS,
+ },
};
static int __init pmt_telem_init(void)
{
- return auxiliary_driver_register(&pmt_telem_aux_driver);
+ int ret;
+
+ ret = auxiliary_driver_register(&pmt_telem_aux_driver);
+
+ if (ret)
+ return ret;
+
+ intel_aet_register_enumeration(THIS_MODULE, intel_pmt_get_regions_by_feature,
+ intel_pmt_put_feature_group);
+
+ return 0;
}
module_init(pmt_telem_init);
static void __exit pmt_telem_exit(void)
{
+ intel_aet_unregister_enumeration();
auxiliary_driver_unregister(&pmt_telem_aux_driver);
xa_destroy(&telem_array);
}
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 18/25] x86/resctrl: Use registered function pointers for AET enumeration
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (16 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 17/25] platform/x86/intel/pmt: Register enumeration functions with resctrl Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 19/25] arm,x86,fs/resctrl: Enumerate AET on every resctrl mount Tony Luck
` (7 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
The INTEL_PMT_TELEMETRY driver registers enumeration functions with
resctrl Application Energy Telemetry (AET) code.
Use the function pointers instead of direct function calls in
preparation for the telemetry driver to be a loadable module.
In preparation for enumeration on each mount of the resctrl file system
place a hold on the pmt_telemetry module while enumerating AET events during
pre-mount processing. Release the hold if no events were enabled. This hold
will be released when the per-mount code is added.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
Split from part 17
---
arch/x86/kernel/cpu/resctrl/internal.h | 4 +--
arch/x86/kernel/cpu/resctrl/core.c | 2 +-
arch/x86/kernel/cpu/resctrl/intel_aet.c | 35 ++++++++++++++++++++++---
3 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h
index d70c8cb1cb81..fc60b0af250d 100644
--- a/arch/x86/kernel/cpu/resctrl/internal.h
+++ b/arch/x86/kernel/cpu/resctrl/internal.h
@@ -234,15 +234,15 @@ void rdt_domain_reconfigure_cdp(struct rdt_resource *r);
void resctrl_arch_mbm_cntr_assign_set_one(struct rdt_resource *r);
#ifdef CONFIG_X86_CPU_RESCTRL_INTEL_AET
-bool intel_aet_get_events(void);
void __exit intel_aet_exit(void);
+bool intel_aet_pre_mount(void);
int intel_aet_read_event(int domid, u32 rmid, void *arch_priv, u64 *val);
void intel_aet_mon_domain_setup(int cpu, int id, struct rdt_resource *r,
struct list_head *add_pos);
bool intel_handle_aet_option(bool force_off, char *tok);
#else
-static inline bool intel_aet_get_events(void) { return false; }
static inline void __exit intel_aet_exit(void) { }
+static inline bool intel_aet_pre_mount(void) { return false; }
static inline int intel_aet_read_event(int domid, u32 rmid, void *arch_priv, u64 *val)
{
return -EINVAL;
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index addcb2a19c98..2fa4ebf7159a 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -795,7 +795,7 @@ void resctrl_arch_pre_mount(void)
struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_PERF_PKG].r_resctrl;
int cpu;
- if (!intel_aet_get_events())
+ if (!intel_aet_pre_mount())
return;
/*
diff --git a/arch/x86/kernel/cpu/resctrl/intel_aet.c b/arch/x86/kernel/cpu/resctrl/intel_aet.c
index 6c4f0bf3b876..32f3f30894a4 100644
--- a/arch/x86/kernel/cpu/resctrl/intel_aet.c
+++ b/arch/x86/kernel/cpu/resctrl/intel_aet.c
@@ -12,6 +12,7 @@
#define pr_fmt(fmt) "resctrl: " fmt
#include <linux/bits.h>
+#include <linux/cleanup.h>
#include <linux/compiler_types.h>
#include <linux/container_of.h>
#include <linux/cpumask.h>
@@ -25,6 +26,7 @@
#include <linux/io.h>
#include <linux/minmax.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/printk.h>
#include <linux/rculist.h>
#include <linux/rcupdate.h>
@@ -293,6 +295,13 @@ static enum pmt_feature_id lookup_pfid(const char *pfname)
return FEATURE_INVALID;
}
+/*
+ * Protects pmt_module, get_feature, put_feature against races between module
+ * load/unload of the pmt_telemetry module and mount/unmount of the resctrl
+ * file system.
+ */
+static DEFINE_MUTEX(aet_register_lock);
+
static struct module *pmt_module;
static struct pmt_feature_group *(*get_feature)(enum pmt_feature_id id);
static void (*put_feature)(struct pmt_feature_group *p);
@@ -308,7 +317,7 @@ static void (*put_feature)(struct pmt_feature_group *p);
* struct pmt_feature_group to indicate that its events are successfully
* enabled.
*/
-bool intel_aet_get_events(void)
+static bool aet_get_events(void)
{
struct pmt_feature_group *p;
enum pmt_feature_id pfid;
@@ -317,14 +326,14 @@ bool intel_aet_get_events(void)
for_each_event_group(peg) {
pfid = lookup_pfid((*peg)->pfname);
- p = intel_pmt_get_regions_by_feature(pfid);
+ p = get_feature(pfid);
if (IS_ERR_OR_NULL(p))
continue;
if (enable_events(*peg, p)) {
(*peg)->pfg = p;
ret = true;
} else {
- intel_pmt_put_feature_group(p);
+ put_feature(p);
}
}
@@ -335,6 +344,7 @@ void intel_aet_register_enumeration(struct module *module,
struct pmt_feature_group *(*get)(enum pmt_feature_id id),
void (*put)(struct pmt_feature_group *p))
{
+ guard(mutex)(&aet_register_lock);
get_feature = get;
put_feature = put;
pmt_module = module;
@@ -343,12 +353,31 @@ EXPORT_SYMBOL_NS_GPL(intel_aet_register_enumeration, "INTEL_PMT");
void intel_aet_unregister_enumeration(void)
{
+ guard(mutex)(&aet_register_lock);
pmt_module = NULL;
get_feature = NULL;
put_feature = NULL;
}
EXPORT_SYMBOL_NS_GPL(intel_aet_unregister_enumeration, "INTEL_PMT");
+bool intel_aet_pre_mount(void)
+{
+ guard(mutex)(&aet_register_lock);
+
+ if (!get_feature || !put_feature)
+ return false;
+
+ if (!try_module_get(pmt_module))
+ return false;
+
+ if (!aet_get_events()) {
+ module_put(pmt_module);
+ return false;
+ }
+
+ return true;
+}
+
void __exit intel_aet_exit(void)
{
struct event_group **peg;
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 19/25] arm,x86,fs/resctrl: Enumerate AET on every resctrl mount
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (17 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 18/25] x86/resctrl: Use registered function pointers for AET enumeration Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 20/25] x86/resctrl: Enforce system RMID limit on AET Tony Luck
` (6 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
Call resctrl_arch_pre_mount() for every mount protected by
resctrl_mount_lock. Add matching resctrl_arch_unmount() path for
architecture code to clean up on mount failure or unmount.
Remove intel_aet_exit() after moving all the cleanup code into
intel_aet_unmount().
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
Rest of old patch 17 merged into patch 18 so the umount
code path is complete.
Fix rdt_get_tree() return value when kernfs_get_tree() fails.
Move resctrl_arch_unmount() after cpus_read_unlock() in out: error path
Update resctrl_arch_pre_mount() header comment to say it is now
called for each mount, not just the first.
Update comment for resctrl_mounted to say that both resctrl_mount_lock
and rdtgroup_mutex must be help to change state.
---
include/linux/resctrl.h | 10 ++++++--
arch/x86/kernel/cpu/resctrl/internal.h | 4 ++--
arch/x86/kernel/cpu/resctrl/core.c | 21 +++++++++++++++--
arch/x86/kernel/cpu/resctrl/intel_aet.c | 29 +++++++++++++++++++----
drivers/resctrl/mpam_resctrl.c | 4 ++++
fs/resctrl/rdtgroup.c | 31 ++++++++++++++++++++-----
6 files changed, 82 insertions(+), 17 deletions(-)
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 604ab7af7c2b..5a975856f670 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -590,11 +590,17 @@ void resctrl_online_cpu(unsigned int cpu);
void resctrl_offline_cpu(unsigned int cpu);
/*
- * Architecture hook called at beginning of first file system mount attempt.
- * No locks are held.
+ * Architecture hook called at beginning of each file system mount attempt.
+ * Called while holding resctrl_mount_lock.
*/
void resctrl_arch_pre_mount(void);
+/*
+ * Architecture hook called when mount fails, or on unmount.
+ * Called while holding resctrl_mount_lock.
+ */
+void resctrl_arch_unmount(void);
+
/**
* resctrl_arch_rmid_read() - Read the eventid counter corresponding to rmid
* for this resource and domain.
diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h
index fc60b0af250d..5e71dd758624 100644
--- a/arch/x86/kernel/cpu/resctrl/internal.h
+++ b/arch/x86/kernel/cpu/resctrl/internal.h
@@ -234,15 +234,15 @@ void rdt_domain_reconfigure_cdp(struct rdt_resource *r);
void resctrl_arch_mbm_cntr_assign_set_one(struct rdt_resource *r);
#ifdef CONFIG_X86_CPU_RESCTRL_INTEL_AET
-void __exit intel_aet_exit(void);
bool intel_aet_pre_mount(void);
+void intel_aet_unmount(void);
int intel_aet_read_event(int domid, u32 rmid, void *arch_priv, u64 *val);
void intel_aet_mon_domain_setup(int cpu, int id, struct rdt_resource *r,
struct list_head *add_pos);
bool intel_handle_aet_option(bool force_off, char *tok);
#else
-static inline void __exit intel_aet_exit(void) { }
static inline bool intel_aet_pre_mount(void) { return false; }
+static inline void intel_aet_unmount(void) { }
static inline int intel_aet_read_event(int domid, u32 rmid, void *arch_priv, u64 *val)
{
return -EINVAL;
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index 2fa4ebf7159a..3bf4d1a07593 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -811,6 +811,25 @@ void resctrl_arch_pre_mount(void)
cpus_read_unlock();
}
+void resctrl_arch_unmount(void)
+{
+ struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_PERF_PKG].r_resctrl;
+ int cpu;
+
+ if (!r->mon_capable)
+ return;
+
+ intel_aet_unmount();
+
+ cpus_read_lock();
+ mutex_lock(&domain_list_lock);
+ for_each_online_cpu(cpu)
+ domain_remove_cpu_mon(cpu, r);
+ r->mon_capable = false;
+ mutex_unlock(&domain_list_lock);
+ cpus_read_unlock();
+}
+
enum {
RDT_FLAG_CMT,
RDT_FLAG_MBM_TOTAL,
@@ -1159,8 +1178,6 @@ late_initcall(resctrl_arch_late_init);
static void __exit resctrl_arch_exit(void)
{
- intel_aet_exit();
-
cpuhp_remove_state(rdt_online);
resctrl_exit();
diff --git a/arch/x86/kernel/cpu/resctrl/intel_aet.c b/arch/x86/kernel/cpu/resctrl/intel_aet.c
index 32f3f30894a4..8aa2e18a6bbb 100644
--- a/arch/x86/kernel/cpu/resctrl/intel_aet.c
+++ b/arch/x86/kernel/cpu/resctrl/intel_aet.c
@@ -298,7 +298,7 @@ static enum pmt_feature_id lookup_pfid(const char *pfname)
/*
* Protects pmt_module, get_feature, put_feature against races between module
* load/unload of the pmt_telemetry module and mount/unmount of the resctrl
- * file system.
+ * file system. Also protects pmt_in_use.
*/
static DEFINE_MUTEX(aet_register_lock);
@@ -306,6 +306,11 @@ static struct module *pmt_module;
static struct pmt_feature_group *(*get_feature)(enum pmt_feature_id id);
static void (*put_feature)(struct pmt_feature_group *p);
+/*
+ * Track whether pmt_telemetry enumeration succeeded during mount for use during unmount.
+ */
+static bool pmt_in_use;
+
/*
* Request a copy of struct pmt_feature_group for each event group. If there is
* one, the returned structure has an array of telemetry_region structures,
@@ -375,19 +380,33 @@ bool intel_aet_pre_mount(void)
return false;
}
+ pmt_in_use = true;
+
return true;
}
-void __exit intel_aet_exit(void)
+void intel_aet_unmount(void)
{
+ struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_PERF_PKG].r_resctrl;
struct event_group **peg;
+ guard(mutex)(&aet_register_lock);
+ if (!pmt_in_use)
+ return;
+
for_each_event_group(peg) {
- if ((*peg)->pfg) {
- intel_pmt_put_feature_group((*peg)->pfg);
- (*peg)->pfg = NULL;
+ struct event_group *e = *peg;
+
+ if (e->pfg) {
+ for (int i = 0; i < e->num_events; i++)
+ resctrl_disable_mon_event(e->evts[i].id);
+ put_feature(e->pfg);
+ e->pfg = NULL;
}
}
+ module_put(pmt_module);
+ pmt_in_use = false;
+ r->mon.num_rmid = 0;
}
#define DATA_VALID BIT_ULL(63)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 69c9e02d2f40..f42f98f89c38 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -121,6 +121,10 @@ void resctrl_arch_pre_mount(void)
{
}
+void resctrl_arch_unmount(void)
+{
+}
+
bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level rid)
{
return mpam_resctrl_controls[rid].cdp_enabled;
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 2e9f71901f68..07fefa3c434e 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -30,6 +30,9 @@
#include "internal.h"
+/* Mutex protecting resctrl_mounted and mount/unmount operations */
+static DEFINE_MUTEX(resctrl_mount_lock);
+
/* Mutex to protect rdtgroup access. */
DEFINE_MUTEX(rdtgroup_mutex);
@@ -48,7 +51,10 @@ LIST_HEAD(resctrl_schema_all);
*/
static LIST_HEAD(mon_data_kn_priv_list);
-/* The filesystem can only be mounted once. */
+/*
+ * The filesystem can only be mounted once. Can only be updated
+ * while holding both resctrl_mount_lock and rdtgroup_mutex.
+ */
bool resctrl_mounted;
/* Kernel fs node for "info" directory under root */
@@ -3149,6 +3155,7 @@ static void resctrl_unmount(void)
{
struct rdt_resource *r;
+ mutex_lock(&resctrl_mount_lock);
cpus_read_lock();
mutex_lock(&rdtgroup_mutex);
@@ -3166,6 +3173,8 @@ static void resctrl_unmount(void)
resctrl_mounted = false;
mutex_unlock(&rdtgroup_mutex);
cpus_read_unlock();
+ resctrl_arch_unmount();
+ mutex_unlock(&resctrl_mount_lock);
}
static int rdt_get_tree(struct fs_context *fc)
@@ -3177,24 +3186,27 @@ static int rdt_get_tree(struct fs_context *fc)
struct rdt_resource *r;
int ret;
- DO_ONCE_SLEEPABLE(resctrl_arch_pre_mount);
+ mutex_lock(&resctrl_mount_lock);
- cpus_read_lock();
- mutex_lock(&rdtgroup_mutex);
/*
* resctrl file system can only be mounted once.
*/
if (resctrl_mounted) {
ret = -EBUSY;
- goto out;
+ goto out_mount_unlock;
}
/* Avoid races from pending operations from a previous mount */
if (atomic_read(&rdtgroup_default.waitcount) != 0) {
ret = -EBUSY;
- goto out;
+ goto out_mount_unlock;
}
+ resctrl_arch_pre_mount();
+
+ cpus_read_lock();
+ mutex_lock(&rdtgroup_mutex);
+
if (!resctrl_alloc_capable() && !resctrl_mon_capable()) {
ret = invalfc(fc, "No allocation or monitoring features are available or enabled");
goto out;
@@ -3289,6 +3301,8 @@ static int rdt_get_tree(struct fs_context *fc)
mutex_unlock(&rdtgroup_mutex);
cpus_read_unlock();
+ mutex_unlock(&resctrl_mount_lock);
+
ret = kernfs_get_tree(fc);
/*
* resctrl can only be mounted once, new superblock only expected
@@ -3297,6 +3311,7 @@ static int rdt_get_tree(struct fs_context *fc)
if (!ctx->kfc.new_sb_created)
resctrl_unmount();
kernfs_put(rdt_root_kn);
+
return ret;
out_mondata:
@@ -3320,6 +3335,10 @@ static int rdt_get_tree(struct fs_context *fc)
out:
mutex_unlock(&rdtgroup_mutex);
cpus_read_unlock();
+ resctrl_arch_unmount();
+out_mount_unlock:
+ mutex_unlock(&resctrl_mount_lock);
+
return ret;
}
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 20/25] x86/resctrl: Enforce system RMID limit on AET
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (18 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 19/25] arm,x86,fs/resctrl: Enumerate AET on every resctrl mount Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 21/25] x86/resctrl: Export interface to report telemetry unbind/remove Tony Luck
` (5 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
AET (Application Energy Telemetry) event groups each support a specific
number of RMIDs. But that number may be lower than the number supported
by the system. This is especially true on systems with SNC (Sub-NUMA Cluster)
enabled as that reduces the number of supported RMIDs.
Reduce r->mon.num_rmid if needed to ensure that info/PERF_PKG_MON/num_rmids
does not display an unachievable value to users.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
Replacement for v11 patch 14 "Enforce system RMID limit ..."
---
arch/x86/kernel/cpu/resctrl/core.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index 3bf4d1a07593..a20439a5099a 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -798,6 +798,12 @@ void resctrl_arch_pre_mount(void)
if (!intel_aet_pre_mount())
return;
+ /*
+ * AET may claim to support more RMIDs than are permitted to be
+ * assigned to IA32_PQR_ASSOC.RMID. Enforce this limit.
+ */
+ r->mon.num_rmid = min(r->mon.num_rmid, pqr_assoc_num_rmid);
+
/*
* Late discovery of telemetry events means the domains for the
* resource were not built. Do that now.
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 21/25] x86/resctrl: Export interface to report telemetry unbind/remove
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (19 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 20/25] x86/resctrl: Enforce system RMID limit on AET Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 22/25] platform/x86/intel/pmt: Inform resctrl when MMIO maps are being removed Tony Luck
` (4 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
Linux allows devices to be unbound from drivers, even if the modules
cannot be unloaded because of reference counts.
For telemetry this results in teardown of the virtual address mappings
of the MMIO regions which hold the event counters. Subsequent access
to these counters will page fault.
Export intel_aet_invalidate() for the pmt_telemetry module to inform
resctrl when invalidation is about to happen.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
Update comment on aet_register_lock
---
include/linux/intel_vsec.h | 2 ++
arch/x86/kernel/cpu/resctrl/intel_aet.c | 28 ++++++++++++++++++++++++-
2 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/include/linux/intel_vsec.h b/include/linux/intel_vsec.h
index c04b1d0f3143..bcbf4937c71c 100644
--- a/include/linux/intel_vsec.h
+++ b/include/linux/intel_vsec.h
@@ -262,11 +262,13 @@ void intel_aet_register_enumeration(struct module *module,
struct pmt_feature_group *(*get)(enum pmt_feature_id id),
void (*put)(struct pmt_feature_group *p));
void intel_aet_unregister_enumeration(void);
+void intel_aet_invalidate(u8 package_id);
#else
static inline void intel_aet_register_enumeration(struct module *module,
struct pmt_feature_group *(*get)(enum pmt_feature_id id),
void (*put)(struct pmt_feature_group *p)) { }
static inline void intel_aet_unregister_enumeration(void) { }
+static inline void intel_aet_invalidate(u8 package_id) { }
#endif /* CONFIG_X86_CPU_RESCTRL_INTEL_AET */
#endif
diff --git a/arch/x86/kernel/cpu/resctrl/intel_aet.c b/arch/x86/kernel/cpu/resctrl/intel_aet.c
index 8aa2e18a6bbb..1fd25fd9cd96 100644
--- a/arch/x86/kernel/cpu/resctrl/intel_aet.c
+++ b/arch/x86/kernel/cpu/resctrl/intel_aet.c
@@ -298,7 +298,7 @@ static enum pmt_feature_id lookup_pfid(const char *pfname)
/*
* Protects pmt_module, get_feature, put_feature against races between module
* load/unload of the pmt_telemetry module and mount/unmount of the resctrl
- * file system. Also protects pmt_in_use.
+ * file system. Also protects pmt_in_use telemetry_region::addr.
*/
static DEFINE_MUTEX(aet_register_lock);
@@ -365,6 +365,30 @@ void intel_aet_unregister_enumeration(void)
}
EXPORT_SYMBOL_NS_GPL(intel_aet_unregister_enumeration, "INTEL_PMT");
+/*
+ * pmt_telemetry driver calls this for unbind/remove operations that
+ * will invalidate the virtual addresses of MMIO registers provided
+ * by intel_pmt_get_regions_by_feature().
+ */
+void intel_aet_invalidate(u8 package_id)
+{
+ struct event_group **peg;
+
+ guard(mutex)(&aet_register_lock);
+
+ for_each_event_group(peg) {
+ struct event_group *e = *peg;
+
+ if (!e->pfg)
+ continue;
+ for (int i = 0; i < e->pfg->count; i++) {
+ if (e->pfg->regions[i].plat_info.package_id == package_id)
+ e->pfg->regions[i].addr = NULL;
+ }
+ }
+}
+EXPORT_SYMBOL_NS_GPL(intel_aet_invalidate, "INTEL_PMT");
+
bool intel_aet_pre_mount(void)
{
guard(mutex)(&aet_register_lock);
@@ -428,6 +452,8 @@ int intel_aet_read_event(int domid, u32 rmid, void *arch_priv, u64 *val)
void *pevt0;
u32 idx;
+ guard(mutex)(&aet_register_lock);
+
pevt0 = pevt - pevt->idx;
e = container_of(pevt0, struct event_group, evts);
idx = rmid * e->num_events;
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 22/25] platform/x86/intel/pmt: Inform resctrl when MMIO maps are being removed
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (20 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 21/25] x86/resctrl: Export interface to report telemetry unbind/remove Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 23/25] x86/resctrl: Require 64-bit x86 for resctrl support Tony Luck
` (3 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
Before destroying devices, tell resctrl that the virtual addresses
supplied by an earlier call to intel_pmt_get_regions_by_feature()
are about to be invalidated and should not be used again.
Avoid A-B deadlock between ep_lock and aet_register_lock.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
Ilpo: Downgrade "can't happen" dev_warn() to dev_debug()
Ilpo's suggestion to use guard(mutex) moot due to refactor.
Reinette: Refactor and eliminate "u32 ret" and s/packages/package/
Reinette: Explain ep_lock release/acquire.
---
drivers/platform/x86/intel/pmt/telemetry.c | 31 ++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/drivers/platform/x86/intel/pmt/telemetry.c b/drivers/platform/x86/intel/pmt/telemetry.c
index bf0c9295feb3..527563043777 100644
--- a/drivers/platform/x86/intel/pmt/telemetry.c
+++ b/drivers/platform/x86/intel/pmt/telemetry.c
@@ -366,12 +366,43 @@ pmt_telem_find_and_register_endpoint(struct device *dev, u32 guid, u16 pos)
}
EXPORT_SYMBOL_NS_GPL(pmt_telem_find_and_register_endpoint, "INTEL_PMT_TELEMETRY");
+static int pmt_telem_get_package_id(struct pmt_telem_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < priv->num_entries; i++) {
+ struct intel_pmt_entry *entry = &priv->entry[i];
+ struct pci_dev *pdev = to_pci_dev(entry->ep->dev);
+ struct oobmsm_plat_info *plat_info;
+
+ plat_info = intel_vsec_get_mapping(pdev);
+ if (!IS_ERR(plat_info))
+ return plat_info->package_id;
+ }
+
+ return -ENODEV;
+}
+
static void pmt_telem_remove(struct auxiliary_device *auxdev)
{
struct pmt_telem_priv *priv = auxiliary_get_drvdata(auxdev);
+ int package_id;
int i;
mutex_lock(&ep_lock);
+ package_id = pmt_telem_get_package_id(priv);
+ /*
+ * Tell resctrl/AET that virtual mappings for MMIO space in a CPU
+ * package are about to be torn down.
+ */
+ if (package_id < 0) {
+ dev_dbg(&auxdev->dev, "Unable to determine package ID for removed device\n");
+ } else {
+ mutex_unlock(&ep_lock);
+ intel_aet_invalidate(package_id);
+ mutex_lock(&ep_lock);
+ }
+
for (i = 0; i < priv->num_entries; i++) {
struct intel_pmt_entry *entry = &priv->entry[i];
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 23/25] x86/resctrl: Require 64-bit x86 for resctrl support
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (21 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 22/25] platform/x86/intel/pmt: Inform resctrl when MMIO maps are being removed Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 24/25] x86/resctrl: Simplify Kconfig options for resctrl Tony Luck
` (2 subsequent siblings)
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
Intel Application Energy Telemetry (AET) provides event counts in 64-bit
registers in MMIO space. For accurate results these should be read with a
single 64-bit load operation from the CPU.
In preparation for the removal of the separate CONFIG_X86_CPU_RESCTRL_INTEL_AET
configuration option, move the X86_64 dependency to X86_CPU_RESCTRL.
This in line with Dave Hansen's proposal[1] for an addition to Linux
documentation that details the state of 32-bit x86 support.
Link: https://lore.kernel.org/all/c6ab0c24-8931-4f0d-9be6-23498ab4c38b@intel.com/ # [1]
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
Added "#" to Link tag
---
arch/x86/Kconfig | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 15fd9ec5ecac..06b5d0c4633e 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -518,7 +518,7 @@ config X86_MPPARSE
config X86_CPU_RESCTRL
bool "x86 CPU resource control support"
- depends on X86 && (CPU_SUP_INTEL || CPU_SUP_AMD)
+ depends on X86_64 && (CPU_SUP_INTEL || CPU_SUP_AMD)
depends on MISC_FILESYSTEMS
select ARCH_HAS_CPU_RESCTRL
select RESCTRL_FS
@@ -541,7 +541,7 @@ config X86_CPU_RESCTRL
config X86_CPU_RESCTRL_INTEL_AET
bool "Intel Application Energy Telemetry"
- depends on X86_64 && X86_CPU_RESCTRL && CPU_SUP_INTEL && INTEL_PMT_TELEMETRY=y && INTEL_TPMI=y
+ depends on X86_CPU_RESCTRL && CPU_SUP_INTEL && INTEL_PMT_TELEMETRY=y && INTEL_TPMI=y
help
Enable per-RMID telemetry events in resctrl.
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 24/25] x86/resctrl: Simplify Kconfig options for resctrl
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (22 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 23/25] x86/resctrl: Require 64-bit x86 for resctrl support Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-16 23:13 ` [PATCH v12 25/25] x86,fs/resctrl: Document telemetry mount timing caveat Tony Luck
2026-09-17 16:32 ` [PATCH v12 00/25] Allow AET to use PMT as loadable module Luck, Tony
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
Linus Torvalds complained[1] about Kconfig complexity making it too
hard for "random people to build their own kernels".
CONFIG_X86_CPU_RESCTRL_INTEL_AET has been causing problems since it was first
added as it required other config options to be set to "built-in". There is
no longer a requirement that INTEL_PMT_TELEMETRY or INTEL_TPMI be built-in.
Drop CONFIG_X86_CPU_RESCTRL_INTEL_AET and unconditionally include
AET (Application Energy Telemetry) as part of X86_CPU_RESCTRL.
Link: https://lore.kernel.org/all/CAHk-=whigg3hvOy7c1j1MXFy6o6CHp0g4Tc3Y-MAk+XDssHU0A@mail.gmail.com # [1]
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
Added [] around "1" in Link tag.
In resctrl Makefile add intel_aet.o to ctrlmondata.o line.
Rewrite commit using imperative.
---
include/linux/intel_vsec.h | 4 ++--
arch/x86/kernel/cpu/resctrl/internal.h | 13 -------------
arch/x86/Kconfig | 13 -------------
arch/x86/kernel/cpu/resctrl/Makefile | 3 +--
4 files changed, 3 insertions(+), 30 deletions(-)
diff --git a/include/linux/intel_vsec.h b/include/linux/intel_vsec.h
index bcbf4937c71c..885f8e3ab057 100644
--- a/include/linux/intel_vsec.h
+++ b/include/linux/intel_vsec.h
@@ -257,7 +257,7 @@ static inline void
intel_pmt_put_feature_group(struct pmt_feature_group *feature_group) {}
#endif
-#ifdef CONFIG_X86_CPU_RESCTRL_INTEL_AET
+#ifdef CONFIG_X86_CPU_RESCTRL
void intel_aet_register_enumeration(struct module *module,
struct pmt_feature_group *(*get)(enum pmt_feature_id id),
void (*put)(struct pmt_feature_group *p));
@@ -269,6 +269,6 @@ static inline void intel_aet_register_enumeration(struct module *module,
void (*put)(struct pmt_feature_group *p)) { }
static inline void intel_aet_unregister_enumeration(void) { }
static inline void intel_aet_invalidate(u8 package_id) { }
-#endif /* CONFIG_X86_CPU_RESCTRL_INTEL_AET */
+#endif /* CONFIG_X86_CPU_RESCTRL */
#endif
diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h
index 5e71dd758624..93d36fa8c638 100644
--- a/arch/x86/kernel/cpu/resctrl/internal.h
+++ b/arch/x86/kernel/cpu/resctrl/internal.h
@@ -233,24 +233,11 @@ bool rdt_cpu_has(int flag);
void rdt_domain_reconfigure_cdp(struct rdt_resource *r);
void resctrl_arch_mbm_cntr_assign_set_one(struct rdt_resource *r);
-#ifdef CONFIG_X86_CPU_RESCTRL_INTEL_AET
bool intel_aet_pre_mount(void);
void intel_aet_unmount(void);
int intel_aet_read_event(int domid, u32 rmid, void *arch_priv, u64 *val);
void intel_aet_mon_domain_setup(int cpu, int id, struct rdt_resource *r,
struct list_head *add_pos);
bool intel_handle_aet_option(bool force_off, char *tok);
-#else
-static inline bool intel_aet_pre_mount(void) { return false; }
-static inline void intel_aet_unmount(void) { }
-static inline int intel_aet_read_event(int domid, u32 rmid, void *arch_priv, u64 *val)
-{
- return -EINVAL;
-}
-
-static inline void intel_aet_mon_domain_setup(int cpu, int id, struct rdt_resource *r,
- struct list_head *add_pos) { }
-static inline bool intel_handle_aet_option(bool force_off, char *tok) { return false; }
-#endif
#endif /* _ASM_X86_RESCTRL_INTERNAL_H */
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 06b5d0c4633e..47f92613434e 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -539,19 +539,6 @@ config X86_CPU_RESCTRL
Say N if unsure.
-config X86_CPU_RESCTRL_INTEL_AET
- bool "Intel Application Energy Telemetry"
- depends on X86_CPU_RESCTRL && CPU_SUP_INTEL && INTEL_PMT_TELEMETRY=y && INTEL_TPMI=y
- help
- Enable per-RMID telemetry events in resctrl.
-
- Intel feature that collects per-RMID execution data
- about energy consumption, measure of frequency independent
- activity and other performance metrics. Data is aggregated
- per package.
-
- Say N if unsure.
-
config X86_FRED
bool "Flexible Return and Event Delivery"
depends on X86_64
diff --git a/arch/x86/kernel/cpu/resctrl/Makefile b/arch/x86/kernel/cpu/resctrl/Makefile
index 273ddfa30836..9daf1c0abb80 100644
--- a/arch/x86/kernel/cpu/resctrl/Makefile
+++ b/arch/x86/kernel/cpu/resctrl/Makefile
@@ -1,7 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_X86_CPU_RESCTRL) += core.o rdtgroup.o monitor.o
-obj-$(CONFIG_X86_CPU_RESCTRL) += ctrlmondata.o
-obj-$(CONFIG_X86_CPU_RESCTRL_INTEL_AET) += intel_aet.o
+obj-$(CONFIG_X86_CPU_RESCTRL) += ctrlmondata.o intel_aet.o
obj-$(CONFIG_RESCTRL_FS_PSEUDO_LOCK) += pseudo_lock.o
# To allow define_trace.h's recursive include:
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v12 25/25] x86,fs/resctrl: Document telemetry mount timing caveat
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (23 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 24/25] x86/resctrl: Simplify Kconfig options for resctrl Tony Luck
@ 2026-09-16 23:13 ` Tony Luck
2026-09-17 16:32 ` [PATCH v12 00/25] Allow AET to use PMT as loadable module Luck, Tony
25 siblings, 0 replies; 27+ messages in thread
From: Tony Luck @ 2026-09-16 23:13 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches, Tony Luck
The PMT driver enumerates telemetry features asynchronously, so an
automatic mount of resctrl from /etc/fstab early in boot may occur before
those features are available, resulting in them not being enabled in the
mounted instance.
Add a footnote to the 'If telemetry monitoring is enabled' sentence
pointing readers to a new "Mounting resctrl with telemetry" section. That
section explains the race.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v12:
Drop problematic examples of systemd/udev rules.
---
Documentation/filesystems/resctrl.rst | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/Documentation/filesystems/resctrl.rst b/Documentation/filesystems/resctrl.rst
index e4b66af55ffb..91a2ab0fa027 100644
--- a/Documentation/filesystems/resctrl.rst
+++ b/Documentation/filesystems/resctrl.rst
@@ -630,7 +630,7 @@ When monitoring is enabled all MON groups will also contain:
each instance of an L3 cache. Each directory contains files for the enabled
L3 events (e.g. "llc_occupancy", "mbm_total_bytes", and "mbm_local_bytes").
- If telemetry monitoring is enabled, there will be a "mon_PERF_PKG_YY"
+ If telemetry monitoring is enabled [#]_, there will be a "mon_PERF_PKG_YY"
directory for each physical processor package. Each directory contains
files for the enabled telemetry events (e.g. "core_energy". "activity",
"uops_retired", etc.)
@@ -669,6 +669,10 @@ When monitoring is enabled all MON groups will also contain:
returned if the MBM event does not have an assigned counter in the
CTRL_MON group nor in any of its associated MON groups.
+.. [#] Telemetry features are enumerated asynchronously by the PMT driver, so
+ an automatic mount of resctrl from ``/etc/fstab`` at boot may not enable
+ them. See `Mounting resctrl with telemetry`_ below.
+
"mon_hw_id":
Available only with debug option. The identifier used by hardware
for the monitor group. On x86 this is the RMID.
@@ -1898,6 +1902,18 @@ m. Unmount the resctrl filesystem.
# umount /sys/fs/resctrl/
+Mounting resctrl with telemetry
+===============================
+
+Telemetry features (e.g. the ``mon_PERF_PKG_YY`` events) are enumerated
+asynchronously by the PMT driver. If resctrl is mounted before that
+enumeration completes (for example, when mounted automatically from
+``/etc/fstab`` early in boot) the telemetry features will not be available
+at mount time and will therefore not be enabled in the mounted instance.
+
+To avoid this race, defer the mount until after the ``pmt_telemetry`` module
+has loaded.
+
Intel RDT Errata
================
--
2.55.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v12 00/25] Allow AET to use PMT as loadable module
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
` (24 preceding siblings ...)
2026-09-16 23:13 ` [PATCH v12 25/25] x86,fs/resctrl: Document telemetry mount timing caveat Tony Luck
@ 2026-09-17 16:32 ` Luck, Tony
25 siblings, 0 replies; 27+ messages in thread
From: Luck, Tony @ 2026-09-17 16:32 UTC (permalink / raw)
To: Fenghua Yu, Reinette Chatre, Maciej Wieczor-Retman, Peter Newman,
James Morse, Babu Moger, Drew Fustini, Dave Martin, Chen Yu,
David E Box, x86
Cc: Christoph Hellwig, linux-kernel, patches
On Wed, Sep 16, 2026 at 04:12:55PM -0700, Tony Luck wrote:
> Requiring INTEL_PMT_TELEMETRY=y to enable AET is a functional workaround
> to enable enumeration of Application Energy Telemetry (AET) events, but
> unacceptable to many users. It results in increased configuration complexity,
> increased kernel memory footprint and inability to patch problems by unloading
> a module and loading an updated version.
>
> Add a registration function to the AET code that can be used by
> INTEL_PMT_TELEMETRY to provide the enumeration functions.
>
> INTEL_PMT_TELEMETRY can be loaded/unloaded independently of
> resctrl file system mount/unmount. Perform enumeration on
> every mount and cleanup on every unmount.
Sashiko report here:
https://sashiko.dev/#/patchset/20260916231320.14502-1-tony.luck%40intel.com
Only issues in parts 11, 20, 21
Patch 11: [PATCH v12 11/25] fs/resctrl: Add interface to disable a monitor event
This isn't a bug, but the kerneldoc for resctrl_disable_mon_event() appears
to contradict the core safety invariant described in the commit message.
The commit message states the architecture is responsible for calling this
interface "only while resctrl is unmounted", but this documentation says not
to disable an event that may be accessed while "unmounted".
Could this lead to confusion for callers reading the header file? Should this
say "while the file system is mounted" instead?
The kerneldoc comment is the better description here (supplied by
Reinette in the review of the v11 version of this series).
https://lore.kernel.org/all/f9f3cb40-bc98-449d-a801-6af836900e76@intel.com/
With the intent of reminding developers that resctrl code may not be
idle just because the file system is not mounted. The limbo timer code
will continue to run until LLC cache occupancy counters reduce to the
threshold value to stop tracking.
Commit message could be updated to match if we need a new series.
Patch 20: [PATCH v12 20/25] x86/resctrl: Enforce system RMID limit on AET
Does this code successfully enforce the system RMID limit on systems with SNC
enabled as stated in the commit message?
When SNC is enabled, the true maximum usable RMID limit is scaled down and
available via resctrl_arch_system_max_rmid_idx(). By capping AET's num_rmid
against pqr_assoc_num_rmid (the unscaled physical limit), the resulting limit
could remain incorrectly large, continuing to display an unachievable value to
users in info/PERF_PKG_MON/num_rmids.
This code is doing what I intend. Making sure that the value reported in
info/PERF_PKG_MON/num_rmids shows how many RMIDs can be supported by AET.
Perhaps the commit message could better explain this intent.
Patch 21: [PATCH v12 21/25] x86/resctrl: Export interface to report telemetry unbind/remove
Can this result in an invalid cast for non-PCI devices?
The PMT subsystem allows non-PCI devices (such as ACPI platform devices from
pwrm_telemetry.c) to register endpoints. Using to_pci_dev() blindly here
without verifying dev_is_pci() generates a bogus pointer for non-PCI devices.
...
When this bogus pointer is passed into intel_vsec_get_mapping() and
eventually to pci_match_id(), will it cause out-of-bounds memory reads or
KASAN panics when dereferencing pdev->vendor and pdev->device?
The AET endpoints are always PCIe (enumeration uses the VSEC feature).
Does dropping ep_lock here create a race condition?
While ep_lock is dropped, stale endpoints still remain in the global
telem_array list. A concurrent resctrl mount could invoke
intel_pmt_get_regions_by_feature(), acquire the lock, and cache pointers to
the MMIO resources of the devices currently being removed.
When pmt_telem_remove() resumes and re-acquires the lock, it unmaps those
regions. Won't the concurrent reader be left with validly cached but unmapped
memory pointers, leading to a kernel panic when dereferenced by AET?
This is an existing issue in the pmt_telemetry driver. Scenario is a
race between a resctrl mount and an unbind of a device. The unbind gets
to pmt_telem_remove() but loses the race to acquire ep_lock to the mount
code calling intel_pmt_get_regions_by_feature(). All devices report
valid MMIO addresses and ep_lock is released then pmt_telem_remove()
invalidates the MMIO mappings for the device being unbound/removed.
Perhaps the telemetry driver should prevent removal of devices for the
interval from intel_pmt_get_regions_by_feature() to intel_pmt_put_feature_group()?
Can it do that?
-Tony
^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2026-09-17 16:33 UTC | newest]
Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-16 23:12 [PATCH v12 00/25] Allow AET to use PMT as loadable module Tony Luck
2026-09-16 23:12 ` [PATCH v12 01/25] x86/cpufeatures: Add missing CQM feature dependency Tony Luck
2026-09-16 23:12 ` [PATCH v12 02/25] x86/resctrl: Check if monitoring features are supported Tony Luck
2026-09-16 23:12 ` [PATCH v12 03/25] x86/resctrl: Enumerate monitor features in rdt_get_l3_mon_config() Tony Luck
2026-09-16 23:12 ` [PATCH v12 04/25] x86/resctrl: Apply Intel MBM quirk from rdt_get_l3_mon_config() Tony Luck
2026-09-16 23:13 ` [PATCH v12 05/25] x86/resctrl: Delete resctrl_cpu_detect() Tony Luck
2026-09-16 23:13 ` [PATCH v12 06/25] arm,x86,fs/resctrl: Replace architecture resctrl_arch_{alloc,mon}_capable() Tony Luck
2026-09-16 23:13 ` [PATCH v12 07/25] x86/resctrl: Update special case for Intel Haswell enumeration Tony Luck
2026-09-16 23:13 ` [PATCH v12 08/25] x86/resctrl: Delete rdt_alloc_capable and rdt_mon_capable Tony Luck
2026-09-16 23:13 ` [PATCH v12 09/25] fs/resctrl: Remove redundant calls to resctrl_{alloc,mon}_capable() Tony Luck
2026-09-16 23:13 ` [PATCH v12 10/25] x86/resctrl: Honor rdt=perf option to force enable AET perf events Tony Luck
2026-09-16 23:13 ` [PATCH v12 11/25] fs/resctrl: Add interface to disable a monitor event Tony Luck
2026-09-16 23:13 ` [PATCH v12 12/25] arm,x86,fs/resctrl: Allocate maximum needed rmid_ptrs[] Tony Luck
2026-09-16 23:13 ` [PATCH v12 13/25] arm,x86,fs/resctrl: Allocate right size for L3 monitor arrays Tony Luck
2026-09-16 23:13 ` [PATCH v12 14/25] fs/resctrl: Rebuild free RMID list on each mount Tony Luck
2026-09-16 23:13 ` [PATCH v12 15/25] x86,fs/resctrl: Handle systems where AET is the only resource Tony Luck
2026-09-16 23:13 ` [PATCH v12 16/25] x86/resctrl: Add PMT registration API for AET enumeration callbacks Tony Luck
2026-09-16 23:13 ` [PATCH v12 17/25] platform/x86/intel/pmt: Register enumeration functions with resctrl Tony Luck
2026-09-16 23:13 ` [PATCH v12 18/25] x86/resctrl: Use registered function pointers for AET enumeration Tony Luck
2026-09-16 23:13 ` [PATCH v12 19/25] arm,x86,fs/resctrl: Enumerate AET on every resctrl mount Tony Luck
2026-09-16 23:13 ` [PATCH v12 20/25] x86/resctrl: Enforce system RMID limit on AET Tony Luck
2026-09-16 23:13 ` [PATCH v12 21/25] x86/resctrl: Export interface to report telemetry unbind/remove Tony Luck
2026-09-16 23:13 ` [PATCH v12 22/25] platform/x86/intel/pmt: Inform resctrl when MMIO maps are being removed Tony Luck
2026-09-16 23:13 ` [PATCH v12 23/25] x86/resctrl: Require 64-bit x86 for resctrl support Tony Luck
2026-09-16 23:13 ` [PATCH v12 24/25] x86/resctrl: Simplify Kconfig options for resctrl Tony Luck
2026-09-16 23:13 ` [PATCH v12 25/25] x86,fs/resctrl: Document telemetry mount timing caveat Tony Luck
2026-09-17 16:32 ` [PATCH v12 00/25] Allow AET to use PMT as loadable module Luck, Tony
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®