* [PATCH v10 01/17] x86/resctrl: Fix enumeration of number of supported RMIDs
2026-07-29 17:27 [PATCH v10 00/17] Allow AET to use PMT as loadable module Tony Luck
@ 2026-07-29 17:27 ` Tony Luck
2026-07-29 17:27 ` [PATCH v10 02/17] x86/resctrl: Require 64-bit x86 for resctrl support Tony Luck
` (16 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Tony Luck @ 2026-07-29 17:27 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
There is a multi-step decision tree for enumeration on X86 of Intel Resource
Director Technology (RDT) also known as AMD Platform Quality of Service (PQOS)
First check CPUID(0x7,0x0).EBX{12} (Linux feature flag X86_FEATURE_CQM).
If this is "0" no monitoring features are supported. If it is "1" then
monitoring is supported, the IA32_PQR_ASSOC MSR exists, and the RMID field can
be written with values from zero to the value enumerated in CPUID(0xF,0x0).EBX.
Second check CPUID(0xF,0x0).EDX{1} (Linux feature flag X86_FEATURE_CQM_LLC).
If this is "1" then one or more L3 cache monitoring features exist and
further enumeration from CPUID(0xF,0x1) provides information about L3
monitoring features.
Linux skips the check for X86_FEATURE_CQM and begins with step two checking
X86_FEATURE_CQM_LLC.
This is a problem for systems that do not support any L3 monitoring features
(or have disabled them with the kernel boot parameter "clearcpuid=cqm_llc")
but do support other features such as Application Energy Telemetry. On
such a system cpuinfo_x86::x86_cache_max_rmid is incorrectly set to "-1".
Correct the checks to follow guidance from the Intel Software
Developer's manual and AMD Architecture Programmer's Manual.
Fixes: cbc82b172638 ("x86: Add support for Intel Cache QoS Monitoring (CQM) detection")
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v10:
New patch so that boot_cpu_data.x86_cache_max_rmid is useful
even on systems that don't have cache monitoring.
Perhaps only worthy of backport to older kernels if taking the
rest of this series.
arch/x86/kernel/cpu/resctrl/core.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index 9b9495174041..e3544c99cff1 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -1075,20 +1075,17 @@ 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)) {
+ if (!cpu_has(c, X86_FEATURE_CQM)) {
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 */
+ /* May be overridden if L3 monitoring exists and supports fewer RMIDs. */
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)) {
+ if (cpu_has(c, X86_FEATURE_CQM_LLC) || cpu_has(c, X86_FEATURE_ABMC)) {
u32 eax, ebx, ecx, edx;
/* QoS sub-leaf, EAX=0Fh, ECX=1 */
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH v10 02/17] x86/resctrl: Require 64-bit x86 for resctrl support
2026-07-29 17:27 [PATCH v10 00/17] Allow AET to use PMT as loadable module Tony Luck
2026-07-29 17:27 ` [PATCH v10 01/17] x86/resctrl: Fix enumeration of number of supported RMIDs Tony Luck
@ 2026-07-29 17:27 ` Tony Luck
2026-07-29 17:27 ` [PATCH v10 03/17] fs/resctrl: Remove redundant calls to resctrl_arch_mon_capable() Tony Luck
` (15 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Tony Luck @ 2026-07-29 17:27 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, Hongyu Ning, Tony Luck
From: Chen Yu <yu.c.chen@intel.com>
All known hardware that supports Intel RDT or AMD QoS is 64-bit. Future
enhancements like MMIO-based Enhanced RDT (ERDT) monitoring require
readq()/writeq() which are only available on 64-bit. There is also no
realistic use case for users to build a 32-bit kernel on a server and
enable resctrl.
Drop 32-bit support by changing the X86_CPU_RESCTRL dependency from X86
to X86_64.
Since X86_CPU_RESCTRL now implies X86_64, remove the redundant X86_64
dependency from X86_CPU_RESCTRL_INTEL_AET.
Tested-by: Hongyu Ning <hongyu.ning@linux.intel.com>
Signed-off-by: Chen Yu <yu.c.chen@intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v10:
New patch. Split out from the "Simplyfy Kconfig" patch in
v9. Chen Yu also needs this for his MMIO enabling patches,
so I've just copied his patch.
arch/x86/Kconfig | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index bdad90f210e4..6685e120cff3 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -514,7 +514,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
@@ -537,7 +537,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 related [flat|nested] 19+ messages in thread* [PATCH v10 03/17] fs/resctrl: Remove redundant calls to resctrl_arch_mon_capable()
2026-07-29 17:27 [PATCH v10 00/17] Allow AET to use PMT as loadable module Tony Luck
2026-07-29 17:27 ` [PATCH v10 01/17] x86/resctrl: Fix enumeration of number of supported RMIDs Tony Luck
2026-07-29 17:27 ` [PATCH v10 02/17] x86/resctrl: Require 64-bit x86 for resctrl support Tony Luck
@ 2026-07-29 17:27 ` Tony Luck
2026-07-29 17:27 ` [PATCH v10 04/17] x86/resctrl: Honor rdt=perf option to force enable AET perf events Tony Luck
` (14 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Tony Luck @ 2026-07-29 17:27 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
Architecture code provides resctrl_arch_mon_capable() so that file
system code knows whether any monitor features are supported. This
is used to decide whether to create "mon_data" directories etc.
Initially resctrl_arch_mon_capable() was an inline function providing
the value of the x86 architecture variable "rdt_mon_capable". I.e.
extremely low overhead and so it was used liberally as a sanity check.
The ARM implementation of resctrl_arch_mon_capable() is not inline and
chases a couple of pointers. Future changes to x86 implementation will
also make resctrl_arch_mon_capable() more expensive.
Redundant calls to resctrl_arch_mon_capable() in hot code paths should
be eliminated.
1) mbm_handle_overflow()
This function is called once per second from worker threads running on
each L3 domain. The call is clearly redundant because worker threads are
only created if the MBM monitoring feature is enabled.
2) is_rmid_match()
This function is called when a user reads a "tasks" file of a MON_GROUP.
The call 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.
Remove the call to resctrl_arch_mon_capable() from both of these
functions.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v10:
Unchanged since v9
fs/resctrl/monitor.c | 2 +-
fs/resctrl/rdtgroup.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index 73413cb128ea..6acf6106e6f1 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_arch_mon_capable())
+ if (!resctrl_mounted)
goto out_unlock;
/*
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 5dcbb0a964e8..8d6d65e6097e 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -691,7 +691,7 @@ static bool is_closid_match(struct task_struct *t, struct rdtgroup *r)
static bool is_rmid_match(struct task_struct *t, struct rdtgroup *r)
{
- return (resctrl_arch_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 related [flat|nested] 19+ messages in thread* [PATCH v10 04/17] x86/resctrl: Honor rdt=perf option to force enable AET perf events
2026-07-29 17:27 [PATCH v10 00/17] Allow AET to use PMT as loadable module Tony Luck
` (2 preceding siblings ...)
2026-07-29 17:27 ` [PATCH v10 03/17] fs/resctrl: Remove redundant calls to resctrl_arch_mon_capable() Tony Luck
@ 2026-07-29 17:27 ` Tony Luck
2026-07-29 17:27 ` [PATCH v10 05/17] fs/resctrl: Add interface to disable a monitor event Tony Luck
` (13 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Tony Luck @ 2026-07-29 17:27 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.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v10:
Rewrite commit comment based on Reinette suggestion
Dropped the change to event_group::force_off kerneldoc
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 related [flat|nested] 19+ messages in thread* [PATCH v10 05/17] fs/resctrl: Add interface to disable a monitor event
2026-07-29 17:27 [PATCH v10 00/17] Allow AET to use PMT as loadable module Tony Luck
` (3 preceding siblings ...)
2026-07-29 17:27 ` [PATCH v10 04/17] x86/resctrl: Honor rdt=perf option to force enable AET perf events Tony Luck
@ 2026-07-29 17:27 ` Tony Luck
2026-07-29 17:27 ` [PATCH v10 06/17] x86/resctrl: Drop global 'rdt_mon_capable' flag Tony Luck
` (12 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Tony Luck @ 2026-07-29 17:27 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>
---
v10:
Unchanged since v9
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 dd09c2ce9a0f..a184500745f8 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -419,9 +419,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
+ *
+ * The file system must not be mounted when disabling an event.
+ *
+ * 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 6acf6106e6f1..d7ad976ed503 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 related [flat|nested] 19+ messages in thread* [PATCH v10 06/17] x86/resctrl: Drop global 'rdt_mon_capable' flag
2026-07-29 17:27 [PATCH v10 00/17] Allow AET to use PMT as loadable module Tony Luck
` (4 preceding siblings ...)
2026-07-29 17:27 ` [PATCH v10 05/17] fs/resctrl: Add interface to disable a monitor event Tony Luck
@ 2026-07-29 17:27 ` Tony Luck
2026-07-29 17:27 ` [PATCH v10 07/17] arm,x86,fs/resctrl: Handle change in number of RMIDs on each mount Tony Luck
` (11 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Tony Luck @ 2026-07-29 17:27 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 calls resctrl_arch_mon_capable() to determine if the
system supports any monitoring features.
x86 architecture code sets a global flag to support implementation of
resctrl_arch_mon_capable() but the upcoming change to enumerate AET
(Application Energy Telemetry) features on each mount introduces a new
corner case.
Specifically when AET is the only monitoring feature, loading and
unloading the pmt_telemetry module between resctrl mounts may result
in monitoring support enabled on some mounts, but not on others.
Replace the global flag with a scan of resources to check if any are
marked mon_capable.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v10:
Move declaration of resctrl_arch_mon_capable() to <linux/resctrl.h>
and provide kerneldoc comment on usage.
include/linux/arm_mpam.h | 1 -
include/linux/resctrl.h | 17 +++++++++++++++++
arch/x86/include/asm/resctrl.h | 6 ------
arch/x86/kernel/cpu/resctrl/core.c | 19 ++++++++++++++++---
arch/x86/kernel/cpu/resctrl/monitor.c | 6 ------
5 files changed, 33 insertions(+), 16 deletions(-)
diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
index f92a36187a52..b6e8683657c0 100644
--- a/include/linux/arm_mpam.h
+++ b/include/linux/arm_mpam.h
@@ -51,7 +51,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);
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index a184500745f8..59ddedb27539 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -419,6 +419,23 @@ 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_arch_mon_capable() - Report whether monitor events are enabled
+ *
+ * Some monitor events may be enumerated or implemented in loadable modules.
+ * This means that available events may vary from one mount of the resctrl
+ * file system to another. If modules are not loaded at mount time there
+ * may be no monitor events at all.
+ *
+ * File system code may call it during mount after architecture enumeration is
+ * complete. Calls during domain add/remove operations must check resctrl_mounted
+ * before calling.
+ *
+ * Return:
+ * true if any monitor events are enabled in the current mount cycle.
+ */
+bool resctrl_arch_mon_capable(void);
+
/**
* resctrl_enable_mon_event() - Enable monitoring event
* @eventid: ID of the event
diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h
index 575f8408a9e7..923b188e11a7 100644
--- a/arch/x86/include/asm/resctrl.h
+++ b/arch/x86/include/asm/resctrl.h
@@ -43,7 +43,6 @@ struct resctrl_pqr_state {
DECLARE_PER_CPU(struct resctrl_pqr_state, pqr_state);
extern bool rdt_alloc_capable;
-extern bool rdt_mon_capable;
DECLARE_STATIC_KEY_FALSE(rdt_enable_key);
DECLARE_STATIC_KEY_FALSE(rdt_alloc_enable_key);
@@ -66,11 +65,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/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index e3544c99cff1..fb20a31d8c73 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -51,6 +51,21 @@ DEFINE_PER_CPU(struct resctrl_pqr_state, pqr_state);
*/
bool rdt_alloc_capable;
+/*
+ * Some monitor events depend on whether the module(s) that enumerate them
+ * are loaded. So resctrl must re-evaluate whether monitoring is supported
+ * for each mount.
+ */
+bool resctrl_arch_mon_capable(void)
+{
+ struct rdt_resource *r;
+
+ for_each_mon_capable_rdt_resource(r)
+ return true;
+
+ return false;
+}
+
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);
@@ -780,7 +795,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);
@@ -1014,9 +1028,8 @@ 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();
- return (rdt_mon_capable || rdt_alloc_capable);
+ return get_rdt_mon_resources() || rdt_alloc_capable;
}
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 430b8fae0b77..1fea893f2cc1 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;
-
#define CF(cf) ((unsigned long)(1048576 * (cf) + 0.5))
static int snc_nodes_per_l3_cache = 1;
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH v10 07/17] arm,x86,fs/resctrl: Handle change in number of RMIDs on each mount
2026-07-29 17:27 [PATCH v10 00/17] Allow AET to use PMT as loadable module Tony Luck
` (5 preceding siblings ...)
2026-07-29 17:27 ` [PATCH v10 06/17] x86/resctrl: Drop global 'rdt_mon_capable' flag Tony Luck
@ 2026-07-29 17:27 ` Tony Luck
2026-07-29 17:27 ` [PATCH v10 08/17] x86/resctrl: Enforce system RMID limit on AET event groups Tony Luck
` (10 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Tony Luck @ 2026-07-29 17:27 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.
For simplicity, calculate the maximum possible number of RMIDs and use
that value to allocate the rmid_ptrs[] array just once. Use this same
calculated value for all references to rmid_ptrs[] instead of calling
resctrl_arch_system_max_rmid_idx() in multiple places.
Also use this maximum RMID value when allocating
rdt_l3_mon_domain::rmid_busy_llc bitmap and rdt_l3_mon_domain::mbm_states.
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>
---
v10:
Better implementation of resctrl_arch_system_max_rmid_idx()
with better comments.
Make max_idx_limit static global in monitor.c and only
initialize it once.
Add sanity check that resctrl_arch_system_num_rmid_idx()
does not provide a value above max_idx_limit.
Rename min_idx_limit to cur_idx_limit.
include/linux/resctrl.h | 5 +-
arch/x86/kernel/cpu/resctrl/core.c | 25 +++++++++
drivers/resctrl/mpam_resctrl.c | 5 ++
fs/resctrl/monitor.c | 82 ++++++++++++++++++++----------
fs/resctrl/rdtgroup.c | 6 +--
5 files changed, 92 insertions(+), 31 deletions(-)
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 59ddedb27539..ec9bf1b09e3f 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
+ * resctrl_arch_system_max_rmid_idx() RMIDs
* @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.
+ * Also sized for resctrl_arch_system_max_rmid_idx() RMIDs.
* @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
@@ -417,6 +419,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 fb20a31d8c73..092764cf693f 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -145,6 +145,31 @@ 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 ret = 0;
+
+ if (boot_cpu_data.x86_cache_max_rmid > 0)
+ ret = boot_cpu_data.x86_cache_max_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)
+ ret = r->mon.num_rmid;
+
+ return ret;
+}
+
struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
{
if (l >= RDT_NUM_RESOURCES)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 226ff6f532fa..7079870ca894 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -272,6 +272,11 @@ u32 resctrl_arch_system_num_rmid_idx(void)
return (mpam_pmg_max + 1) * (mpam_partid_max + 1);
}
+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 d7ad976ed503..2a1d2ee2b91d 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;
+/*
+ * @max_idx_limit - The number of elements allocated in *rmid_ptrs.
+ */
+static u32 max_idx_limit;
+
/*
* This is the threshold cache occupancy in bytes at which we will consider an
* RMID available for re-allocation.
@@ -115,10 +120,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 +146,6 @@ 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();
struct rmid_entry *entry;
bool rmid_dirty = true;
u32 idx, cur_idx = 1;
@@ -156,8 +168,12 @@ void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free)
* RMID and move it to the free list when the counter reaches 0.
*/
for (;;) {
- idx = find_next_bit(d->rmid_busy_llc, idx_limit, cur_idx);
- if (idx >= idx_limit)
+ /*
+ * Need to check all possible RMIDs, not just the range
+ * available in this mount cycle.
+ */
+ idx = find_next_bit(d->rmid_busy_llc, max_idx_limit, cur_idx);
+ if (idx >= max_idx_limit)
break;
entry = __rmid_entry(idx);
@@ -197,9 +213,7 @@ 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();
-
- return find_first_bit(d->rmid_busy_llc, idx_limit) != idx_limit;
+ return find_first_bit(d->rmid_busy_llc, max_idx_limit) != max_idx_limit;
}
static struct rmid_entry *resctrl_find_free_rmid(u32 closid)
@@ -962,7 +976,7 @@ 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 cur_idx_limit;
u32 idx;
int i;
@@ -970,27 +984,36 @@ int setup_rmid_lru_list(void)
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) {
+ max_idx_limit = resctrl_arch_system_max_rmid_idx();
+ rmid_ptrs = kzalloc_objs(struct rmid_entry, max_idx_limit);
+ if (!rmid_ptrs) {
+ max_idx_limit = 0;
+ return -ENOMEM;
+ }
- idx_limit = resctrl_arch_system_num_rmid_idx();
- rmid_ptrs = kzalloc_objs(struct rmid_entry, idx_limit);
- if (!rmid_ptrs)
- return -ENOMEM;
+ for (i = 0; i < max_idx_limit; 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 needed for this mount */
+ cur_idx_limit = resctrl_arch_system_num_rmid_idx();
+ if (cur_idx_limit > max_idx_limit) {
+ pr_warn_once("RMID count %u exceeds allocated %u; capping\n",
+ cur_idx_limit, max_idx_limit);
+ cur_idx_limit = max_idx_limit;
}
+ 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
@@ -998,8 +1021,14 @@ int setup_rmid_lru_list(void)
*/
idx = resctrl_arch_rmid_idx_encode(RESCTRL_RESERVED_CLOSID,
RESCTRL_RESERVED_RMID);
- entry = __rmid_entry(idx);
- list_del(&entry->list);
+
+ for (i = 0; i < cur_idx_limit; i++) {
+ entry = &rmid_ptrs[i];
+ /* Don't add reserved or busy entries to free list */
+ if (i == idx || entry->busy)
+ continue;
+ list_add_tail(&entry->list, &rmid_free_lru);
+ }
return 0;
}
@@ -1218,7 +1247,6 @@ 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();
enum resctrl_event_id evt;
int idx;
@@ -1226,7 +1254,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]) * max_idx_limit);
}
}
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 8d6d65e6097e..0a9645c35f43 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 max_idx_limit = resctrl_arch_system_max_rmid_idx();
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(max_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(max_idx_limit, tsize, GFP_KERNEL);
if (!d->mbm_states[idx])
goto cleanup;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH v10 08/17] x86/resctrl: Enforce system RMID limit on AET event groups
2026-07-29 17:27 [PATCH v10 00/17] Allow AET to use PMT as loadable module Tony Luck
` (6 preceding siblings ...)
2026-07-29 17:27 ` [PATCH v10 07/17] arm,x86,fs/resctrl: Handle change in number of RMIDs on each mount Tony Luck
@ 2026-07-29 17:27 ` Tony Luck
2026-07-29 17:27 ` [PATCH v10 09/17] x86/resctrl: Add PMT registration API for AET enumeration callbacks Tony Luck
` (9 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Tony Luck @ 2026-07-29 17:27 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. Especially true on systems with SNC (Sub-NUMA Cluster)
enabled as that reduces the number of supported RMIDs.
Fix get_rdt_mon_resources() to return true when any monitor resource is
possibly enabled. Call intel_aet_init() to adjust the event_group::num_rmid
values to not exceed the system supported maximum.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v10:
New patch
arch/x86/kernel/cpu/resctrl/internal.h | 4 +++-
arch/x86/kernel/cpu/resctrl/core.c | 8 +++++---
arch/x86/kernel/cpu/resctrl/intel_aet.c | 17 +++++++++++++----
arch/x86/kernel/cpu/resctrl/monitor.c | 4 +---
4 files changed, 22 insertions(+), 11 deletions(-)
diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h
index e3cfa0c10e92..8e4f0bb91785 100644
--- a/arch/x86/kernel/cpu/resctrl/internal.h
+++ b/arch/x86/kernel/cpu/resctrl/internal.h
@@ -224,7 +224,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);
@@ -235,6 +235,7 @@ 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 __init intel_aet_init(void);
void __exit intel_aet_exit(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,
@@ -242,6 +243,7 @@ void intel_aet_mon_domain_setup(int cpu, int id, struct rdt_resource *r,
bool intel_handle_aet_option(bool force_off, char *tok);
#else
static inline bool intel_aet_get_events(void) { return false; }
+static inline void intel_aet_init(void) { }
static inline void __exit intel_aet_exit(void) { }
static inline int intel_aet_read_event(int domid, u32 rmid, void *arch_priv, u64 *val)
{
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index 092764cf693f..2c938b97b147 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -1019,10 +1019,10 @@ static __init bool get_rdt_mon_resources(void)
if (rdt_cpu_has(X86_FEATURE_ABMC))
ret = true;
- if (!ret)
- return false;
+ if (ret)
+ rdt_get_l3_mon_config(r);
- return !rdt_get_l3_mon_config(r);
+ return boot_cpu_data.x86_cache_max_rmid > 0;
}
static __init void __check_quirks_intel(void)
@@ -1169,6 +1169,8 @@ static int __init resctrl_arch_late_init(void)
if (!get_rdt_resources())
return -ENODEV;
+ intel_aet_init();
+
state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
"x86/resctrl/cat:online:",
resctrl_arch_online_cpu,
diff --git a/arch/x86/kernel/cpu/resctrl/intel_aet.c b/arch/x86/kernel/cpu/resctrl/intel_aet.c
index 4ad6ad78e93e..e6cc57206381 100644
--- a/arch/x86/kernel/cpu/resctrl/intel_aet.c
+++ b/arch/x86/kernel/cpu/resctrl/intel_aet.c
@@ -65,10 +65,10 @@ struct pmt_event {
* @force_on: True when "rdt" command line overrides disable of this
* event group.
* @guid: Unique number per XML description file.
- * @num_rmid: Number of RMIDs supported by this group. May be
- * adjusted downwards if enumeration from
- * intel_pmt_get_regions_by_feature() indicates fewer
- * RMIDs can be tracked simultaneously.
+ * @num_rmid: Number of RMIDs supported by this group. May be adjusted
+ * downwards if the system supports fewer RMIDs or
+ * enumeration from intel_pmt_get_regions_by_feature()
+ * indicates fewer RMIDs can be tracked simultaneously.
* @mmio_size: Number of bytes of MMIO registers for this group.
* @num_events: Number of events in this group.
* @evts: Array of event descriptors.
@@ -325,6 +325,15 @@ bool intel_aet_get_events(void)
return ret;
}
+void __init intel_aet_init(void)
+{
+ u32 max_rmid = resctrl_arch_system_max_rmid_idx();
+ struct event_group **peg;
+
+ for_each_event_group(peg)
+ (*peg)->num_rmid = min(max_rmid, (*peg)->num_rmid);
+}
+
void __exit intel_aet_exit(void)
{
struct event_group **peg;
diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c
index 1fea893f2cc1..f40f5dd1440c 100644
--- a/arch/x86/kernel/cpu/resctrl/monitor.c
+++ b/arch/x86/kernel/cpu/resctrl/monitor.c
@@ -407,7 +407,7 @@ static __init int snc_get_config(void)
return ret;
}
-int __init rdt_get_l3_mon_config(struct rdt_resource *r)
+void __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);
@@ -466,8 +466,6 @@ int __init rdt_get_l3_mon_config(struct rdt_resource *r)
}
r->mon_capable = true;
-
- return 0;
}
void __init intel_rdt_mbm_apply_quirk(void)
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH v10 09/17] x86/resctrl: Add PMT registration API for AET enumeration callbacks
2026-07-29 17:27 [PATCH v10 00/17] Allow AET to use PMT as loadable module Tony Luck
` (7 preceding siblings ...)
2026-07-29 17:27 ` [PATCH v10 08/17] x86/resctrl: Enforce system RMID limit on AET event groups Tony Luck
@ 2026-07-29 17:27 ` Tony Luck
2026-07-29 17:27 ` [PATCH v10 10/17] platform/x86/intel/pmt: Register enumeration functions with resctrl Tony Luck
` (8 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Tony Luck @ 2026-07-29 17:27 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>
---
v10:
Move declaration and stubs for registration functions out
of <asm/resctrl.h> and into <linux/intel_vsec.h>
Defer adding aet_register_lock mutex until mount/unmount
changes where it is needed.
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 e6cc57206381..407c9aba5eea 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,
@@ -334,6 +340,24 @@ void __init intel_aet_init(void)
(*peg)->num_rmid = min(max_rmid, (*peg)->num_rmid);
}
+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 related [flat|nested] 19+ messages in thread* [PATCH v10 10/17] platform/x86/intel/pmt: Register enumeration functions with resctrl
2026-07-29 17:27 [PATCH v10 00/17] Allow AET to use PMT as loadable module Tony Luck
` (8 preceding siblings ...)
2026-07-29 17:27 ` [PATCH v10 09/17] x86/resctrl: Add PMT registration API for AET enumeration callbacks Tony Luck
@ 2026-07-29 17:27 ` Tony Luck
2026-07-29 17:27 ` [PATCH v10 11/17] arm,x86/resctrl: Resolve INTEL_PMT_TELEMETRY symbols at runtime Tony Luck
` (7 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Tony Luck @ 2026-07-29 17:27 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>
---
v10:
No need for <asm/resctrl.h> now that declarations of
intel_aet*() moved to <linux/intel_vsec,h>
drivers/platform/x86/intel/pmt/telemetry.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/platform/x86/intel/pmt/telemetry.c b/drivers/platform/x86/intel/pmt/telemetry.c
index 953f35b6daec..cafa2288600d 100644
--- a/drivers/platform/x86/intel/pmt/telemetry.c
+++ b/drivers/platform/x86/intel/pmt/telemetry.c
@@ -427,16 +427,26 @@ 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 = auxiliary_driver_register(&pmt_telem_aux_driver);
+
+ if (!ret)
+ intel_aet_register_enumeration(THIS_MODULE, intel_pmt_get_regions_by_feature,
+ intel_pmt_put_feature_group);
+
+ return ret;
}
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 related [flat|nested] 19+ messages in thread* [PATCH v10 11/17] arm,x86/resctrl: Resolve INTEL_PMT_TELEMETRY symbols at runtime
2026-07-29 17:27 [PATCH v10 00/17] Allow AET to use PMT as loadable module Tony Luck
` (9 preceding siblings ...)
2026-07-29 17:27 ` [PATCH v10 10/17] platform/x86/intel/pmt: Register enumeration functions with resctrl Tony Luck
@ 2026-07-29 17:27 ` Tony Luck
2026-07-29 17:27 ` [PATCH v10 12/17] x86/resctrl: Prepare to handle nested mount requests Tony Luck
` (6 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Tony Luck @ 2026-07-29 17:27 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, but INTEL_PMT_TELEMETRY and INTEL_TPMI are
logically independent and should be loadable modules. Switch AET to use the
function-pointer registration API instead of direct link-time references to
PMT symbols.
Prepare for the file system to call resctrl_arch_pre_mount() on every mount
by moving AET enumeration into resctrl_arch_pre_mount() and cleanup into
resctrl_arch_unmount(). This allows the PMT module to be unloaded whenever
the filesystem is not mounted.
intel_aet_exit() was never called because resctrl is built into the kernel. All
cleanup is now handled in the unmount path. Remove intel_aet_exit().
Note that the Linux file system code does not serialize calls to
fs_context_operations::get_tree(), so there may be arbitrarily many parallel
calls if users invoke mount(2) multiple times.
Zero rdt_resource::resctrl_mon::num_rmid for RDT_RESOURCE_PERF_PKG so
that it will be re-computed next mount.
event_group::num_rmid may be reset (reduced) during enumeration. This is
not worth resetting on unmount because the same reduction would occur on
each subsequent mount.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v10:
Add to commit that intel_aet_exit() wasn't called before.
Introduce aet_register_lock mutex here where it is clear
that it is needed to resolve module load/unload and resctrl
mount/unmount races.
Drop intel_aet_try_module_get()/intel_aet_module_put(). The
generic versions handle NULL module arguments.
Zero rdt_resource::resctrl_mon::num_rmid in unmount path.
Pass status back from intel_aet_pre_mount() to resctrl_arch_pre_mount()
include/linux/resctrl.h | 6 +++
arch/x86/kernel/cpu/resctrl/internal.h | 8 ++--
arch/x86/kernel/cpu/resctrl/core.c | 25 ++++++++--
arch/x86/kernel/cpu/resctrl/intel_aet.c | 61 ++++++++++++++++++++++---
drivers/resctrl/mpam_resctrl.c | 4 ++
5 files changed, 90 insertions(+), 14 deletions(-)
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index ec9bf1b09e3f..568a650c0224 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -581,6 +581,12 @@ void resctrl_offline_cpu(unsigned int cpu);
*/
void resctrl_arch_pre_mount(void);
+/*
+ * Architecture hook called when mount fails, or on unmount.
+ * No locks are held.
+ */
+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 8e4f0bb91785..099356e4328a 100644
--- a/arch/x86/kernel/cpu/resctrl/internal.h
+++ b/arch/x86/kernel/cpu/resctrl/internal.h
@@ -234,17 +234,17 @@ 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 __init intel_aet_init(void);
-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 bool intel_aet_get_events(void) { return false; }
static inline void intel_aet_init(void) { }
-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 2c938b97b147..e335a143f3e5 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -16,10 +16,12 @@
#define pr_fmt(fmt) "resctrl: " fmt
+#include <linux/cleanup.h>
#include <linux/cpu.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/cpuhotplug.h>
+#include <linux/mutex.h>
#include <asm/cpu_device_id.h>
#include <asm/cpuid/api.h>
@@ -810,7 +812,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;
/*
@@ -826,6 +828,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,
@@ -1198,8 +1219,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 407c9aba5eea..65b70cc8d0a5 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>
@@ -308,7 +310,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 +319,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);
}
}
@@ -340,10 +342,22 @@ void __init intel_aet_init(void)
(*peg)->num_rmid = min(max_rmid, (*peg)->num_rmid);
}
+/*
+ * Defend 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);
+
+/*
+ * Track whether pmt_telemetry enumeration succeeded during mount for use during unmount.
+ */
+static bool pmt_in_use;
+
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;
@@ -352,22 +366,55 @@ 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");
-void __exit intel_aet_exit(void)
+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;
+ }
+
+ pmt_in_use = true;
+
+ return true;
+}
+
+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 7079870ca894..5859cc0f5e37 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -162,6 +162,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;
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH v10 12/17] x86/resctrl: Prepare to handle nested mount requests
2026-07-29 17:27 [PATCH v10 00/17] Allow AET to use PMT as loadable module Tony Luck
` (10 preceding siblings ...)
2026-07-29 17:27 ` [PATCH v10 11/17] arm,x86/resctrl: Resolve INTEL_PMT_TELEMETRY symbols at runtime Tony Luck
@ 2026-07-29 17:27 ` Tony Luck
2026-07-29 17:27 ` [PATCH v10 13/17] fs/resctrl: Call architecture hooks for every mount/unmount Tony Luck
` (5 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Tony Luck @ 2026-07-29 17:27 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
There is no upper level serialization of mount(2) system calls.
mount/unmount operations can happen in parallel with CPU hotplug events
that need to add/remove files and directories when domains are added or
removed.
Use cpus_read_lock() plus mutex_lock(&domain_list_lock) to protect
architecture code from races.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v10:
New patch
include/linux/resctrl.h | 2 +-
arch/x86/kernel/cpu/resctrl/core.c | 40 ++++++++++++++++++++++++------
drivers/resctrl/mpam_resctrl.c | 3 ++-
3 files changed, 35 insertions(+), 10 deletions(-)
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 568a650c0224..65245f2fdad0 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -579,7 +579,7 @@ void resctrl_offline_cpu(unsigned int cpu);
* Architecture hook called at beginning of first file system mount attempt.
* No locks are held.
*/
-void resctrl_arch_pre_mount(void);
+int resctrl_arch_pre_mount(void);
/*
* Architecture hook called when mount fails, or on unmount.
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index e335a143f3e5..906aa4dfc363 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -16,7 +16,6 @@
#define pr_fmt(fmt) "resctrl: " fmt
-#include <linux/cleanup.h>
#include <linux/cpu.h>
#include <linux/slab.h>
#include <linux/err.h>
@@ -807,25 +806,47 @@ static int resctrl_arch_offline_cpu(unsigned int cpu)
return 0;
}
-void resctrl_arch_pre_mount(void)
+/*
+ * Linux provides no synchronization for mount(2) system calls.
+ * resctrl_arch_pre_mount() and resctrl_arch_unmount() are called
+ * with no locks held. Mount/unmount may also race with CPU hotplug
+ * events that add/remove per-domain files and directories.
+ *
+ * Use cpus_read_lock() plus domain_list_lock to protect operations.
+ *
+ * Keep track locally at the architecture level whether the file
+ * system is mounted (or in process of being mounted).
+ */
+static bool arch_mounted;
+
+int resctrl_arch_pre_mount(void)
{
struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_PERF_PKG].r_resctrl;
+ int ret = -EBUSY;
int cpu;
+ cpus_read_lock();
+ mutex_lock(&domain_list_lock);
+ if (arch_mounted)
+ goto unlock;
+ arch_mounted = true;
+ ret = 0;
+
if (!intel_aet_pre_mount())
- return;
+ goto unlock;
/*
* Late discovery of telemetry events means the domains for the
* resource were not built. Do that now.
*/
- cpus_read_lock();
- mutex_lock(&domain_list_lock);
r->mon_capable = true;
for_each_online_cpu(cpu)
domain_add_cpu_mon(cpu, r);
+unlock:
mutex_unlock(&domain_list_lock);
cpus_read_unlock();
+
+ return ret;
}
void resctrl_arch_unmount(void)
@@ -833,16 +854,19 @@ void resctrl_arch_unmount(void)
struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_PERF_PKG].r_resctrl;
int cpu;
+ cpus_read_lock();
+ mutex_lock(&domain_list_lock);
+ arch_mounted = false;
+
if (!r->mon_capable)
- return;
+ goto unlock;
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;
+unlock:
mutex_unlock(&domain_list_lock);
cpus_read_unlock();
}
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 5859cc0f5e37..71125779484f 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -158,8 +158,9 @@ bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r)
return false;
}
-void resctrl_arch_pre_mount(void)
+int resctrl_arch_pre_mount(void)
{
+ return 0;
}
void resctrl_arch_unmount(void)
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH v10 13/17] fs/resctrl: Call architecture hooks for every mount/unmount
2026-07-29 17:27 [PATCH v10 00/17] Allow AET to use PMT as loadable module Tony Luck
` (11 preceding siblings ...)
2026-07-29 17:27 ` [PATCH v10 12/17] x86/resctrl: Prepare to handle nested mount requests Tony Luck
@ 2026-07-29 17:27 ` Tony Luck
2026-07-29 17:27 ` [PATCH v10 14/17] x86/resctrl: Export interface to report telemetry unbind/remove Tony Luck
` (4 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Tony Luck @ 2026-07-29 17:27 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 module should only be pinned while the resctrl file system
is mounted.
Add hooks for every mount/unmount of the resctrl file system so that
architecture code can increment the intel_pmt module reference count on
mount and decrement on unmount.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v10:
Don't call resctrl_arch_unmount() when failing a nested mount.
include/linux/resctrl.h | 2 +-
fs/resctrl/rdtgroup.c | 12 ++++++++++--
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 65245f2fdad0..1e4ca75a02de 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -576,7 +576,7 @@ 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.
+ * Architecture hook called before attempting to mount the file system.
* No locks are held.
*/
int resctrl_arch_pre_mount(void);
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 0a9645c35f43..6f12537f89b7 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -18,7 +18,6 @@
#include <linux/fs_parser.h>
#include <linux/sysfs.h>
#include <linux/kernfs.h>
-#include <linux/once.h>
#include <linux/resctrl.h>
#include <linux/seq_buf.h>
#include <linux/seq_file.h>
@@ -3166,6 +3165,8 @@ static void resctrl_unmount(void)
resctrl_mounted = false;
mutex_unlock(&rdtgroup_mutex);
cpus_read_unlock();
+
+ resctrl_arch_unmount();
}
static int rdt_get_tree(struct fs_context *fc)
@@ -3175,9 +3176,11 @@ static int rdt_get_tree(struct fs_context *fc)
struct kernfs_node *rdt_root_kn;
struct rdt_l3_mon_domain *dom;
struct rdt_resource *r;
+ bool cleanup = true;
int ret;
- DO_ONCE_SLEEPABLE(resctrl_arch_pre_mount);
+ if (resctrl_arch_pre_mount() == -EBUSY)
+ return -EBUSY;
cpus_read_lock();
mutex_lock(&rdtgroup_mutex);
@@ -3186,6 +3189,7 @@ static int rdt_get_tree(struct fs_context *fc)
*/
if (resctrl_mounted) {
ret = -EBUSY;
+ cleanup = false;
goto out;
}
@@ -3316,6 +3320,10 @@ static int rdt_get_tree(struct fs_context *fc)
out:
mutex_unlock(&rdtgroup_mutex);
cpus_read_unlock();
+
+ if (cleanup)
+ resctrl_arch_unmount();
+
return ret;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH v10 14/17] x86/resctrl: Export interface to report telemetry unbind/remove
2026-07-29 17:27 [PATCH v10 00/17] Allow AET to use PMT as loadable module Tony Luck
` (12 preceding siblings ...)
2026-07-29 17:27 ` [PATCH v10 13/17] fs/resctrl: Call architecture hooks for every mount/unmount Tony Luck
@ 2026-07-29 17:27 ` Tony Luck
2026-07-29 17:27 ` [PATCH v10 15/17] platform/x86/intel/pmt: Inform resctrl when MMIO maps are being removed Tony Luck
` (3 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Tony Luck @ 2026-07-29 17:27 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>
---
v10:
New patch
include/linux/intel_vsec.h | 2 ++
arch/x86/kernel/cpu/resctrl/intel_aet.c | 34 +++++++++++++++++++++++++
2 files changed, 36 insertions(+)
diff --git a/include/linux/intel_vsec.h b/include/linux/intel_vsec.h
index c04b1d0f3143..4da15ec03d20 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(u64 pkgmask);
#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(u64 pkgmask) { }
#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 65b70cc8d0a5..eab27e487da9 100644
--- a/arch/x86/kernel/cpu/resctrl/intel_aet.c
+++ b/arch/x86/kernel/cpu/resctrl/intel_aet.c
@@ -177,6 +177,11 @@ static bool skip_telem_region(struct telemetry_region *tr, struct event_group *e
tr->guid);
return true;
}
+ if (tr->plat_info.package_id >= BITS_PER_LONG_LONG) {
+ pr_warn("Package %u out of range in guid 0x%x\n", tr->plat_info.package_id,
+ tr->guid);
+ return true;
+ }
if (tr->size != e->mmio_size) {
pr_warn("MMIO space wrong size (%zu bytes) for guid 0x%x. Expected %zu bytes.\n",
tr->size, e->guid, e->mmio_size);
@@ -299,6 +304,13 @@ 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);
+/*
+ * Bitmask of packages where MMIO virtual mappings have been invalidated
+ * by device unbind/remove operations. May be set to ~0ULL to indicate that
+ * all mappings may have been removed.
+ */
+static u64 invalid_pkg_mask;
+
/*
* 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,
@@ -373,6 +385,18 @@ 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(u64 pkgmask)
+{
+ guard(mutex)(&aet_register_lock);
+ invalid_pkg_mask |= pkgmask;
+}
+EXPORT_SYMBOL_NS_GPL(intel_aet_invalidate, "INTEL_PMT");
+
bool intel_aet_pre_mount(void)
{
guard(mutex)(&aet_register_lock);
@@ -389,6 +413,11 @@ bool intel_aet_pre_mount(void)
}
pmt_in_use = true;
+ /*
+ * All the regions enumerated by intel_pmt_get_regions_by_feature()
+ * have valid MMIO mappings.
+ */
+ invalid_pkg_mask = 0ULL;
return true;
}
@@ -436,6 +465,11 @@ int intel_aet_read_event(int domid, u32 rmid, void *arch_priv, u64 *val)
void *pevt0;
u32 idx;
+ guard(mutex)(&aet_register_lock);
+
+ if (invalid_pkg_mask == ~0ULL || (invalid_pkg_mask & BIT_ULL(domid)))
+ return -EINVAL;
+
pevt0 = pevt - pevt->idx;
e = container_of(pevt0, struct event_group, evts);
idx = rmid * e->num_events;
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH v10 15/17] platform/x86/intel/pmt: Inform resctrl when MMIO maps are being removed
2026-07-29 17:27 [PATCH v10 00/17] Allow AET to use PMT as loadable module Tony Luck
` (13 preceding siblings ...)
2026-07-29 17:27 ` [PATCH v10 14/17] x86/resctrl: Export interface to report telemetry unbind/remove Tony Luck
@ 2026-07-29 17:27 ` Tony Luck
2026-07-29 17:27 ` [PATCH v10 16/17] x86/resctrl: Simplify Kconfig options for resctrl Tony Luck
` (2 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Tony Luck @ 2026-07-29 17:27 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.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v10:
New patch
drivers/platform/x86/intel/pmt/telemetry.c | 32 ++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/drivers/platform/x86/intel/pmt/telemetry.c b/drivers/platform/x86/intel/pmt/telemetry.c
index cafa2288600d..e0ad5cea2922 100644
--- a/drivers/platform/x86/intel/pmt/telemetry.c
+++ b/drivers/platform/x86/intel/pmt/telemetry.c
@@ -366,11 +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 u64 pmt_telem_pkg_mask(struct pmt_telem_priv *priv)
+{
+ u64 mask = 0;
+ int i;
+
+ mutex_lock(&ep_lock);
+ 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)) {
+ mask = ~0ULL;
+ break;
+ }
+ if (plat_info->package_id < BITS_PER_LONG_LONG)
+ mask |= BIT_ULL(plat_info->package_id);
+ else
+ mask = ~0ULL;
+ }
+ mutex_unlock(&ep_lock);
+
+ return mask;
+}
+
static void pmt_telem_remove(struct auxiliary_device *auxdev)
{
struct pmt_telem_priv *priv = auxiliary_get_drvdata(auxdev);
int i;
+ /*
+ * Tell resctrl/AET that virtual mappings for MMIO space in
+ * one or more CPU packages are about to be torn down.
+ */
+ intel_aet_invalidate(pmt_telem_pkg_mask(priv));
+
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 related [flat|nested] 19+ messages in thread* [PATCH v10 16/17] x86/resctrl: Simplify Kconfig options for resctrl
2026-07-29 17:27 [PATCH v10 00/17] Allow AET to use PMT as loadable module Tony Luck
` (14 preceding siblings ...)
2026-07-29 17:27 ` [PATCH v10 15/17] platform/x86/intel/pmt: Inform resctrl when MMIO maps are being removed Tony Luck
@ 2026-07-29 17:27 ` Tony Luck
2026-07-29 17:27 ` [PATCH v10 17/17] Documentation/filesystems/resctrl: Document telemetry mount timing caveat Tony Luck
2026-07-29 20:11 ` [PATCH v10 00/17] Allow AET to use PMT as loadable module Luck, Tony
17 siblings, 0 replies; 19+ messages in thread
From: Tony Luck @ 2026-07-29 17:27 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".
AET now resolves PMT symbols at runtime via the registration API,
so INTEL_PMT_TELEMETRY no longer needs to be built-in. This means
that AET can be included unconditionally as part of X86_CPU_RESCTRL.
Signed-off-by: Tony Luck <tony.luck@intel.com>
Link: https://lore.kernel.org/all/CAHk-=whigg3hvOy7c1j1MXFy6o6CHp0g4Tc3Y-MAk+XDssHU0A@mail.gmail.com # 1
---
v10:
Dependency on X86_64 moved to separate patch
include/linux/intel_vsec.h | 4 ++--
arch/x86/kernel/cpu/resctrl/internal.h | 2 +-
arch/x86/Kconfig | 13 -------------
arch/x86/kernel/cpu/resctrl/Makefile | 2 +-
4 files changed, 4 insertions(+), 17 deletions(-)
diff --git a/include/linux/intel_vsec.h b/include/linux/intel_vsec.h
index 4da15ec03d20..64c30b2f3a6d 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(u64 pkgmask) { }
-#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 099356e4328a..2215d257566e 100644
--- a/arch/x86/kernel/cpu/resctrl/internal.h
+++ b/arch/x86/kernel/cpu/resctrl/internal.h
@@ -233,7 +233,7 @@ 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);
-#ifdef CONFIG_X86_CPU_RESCTRL_INTEL_AET
+#ifdef CONFIG_X86_CPU_RESCTRL
void __init intel_aet_init(void);
bool intel_aet_pre_mount(void);
void intel_aet_unmount(void);
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 6685e120cff3..ae6fb01e8865 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -535,19 +535,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..97ceb4e44dfa 100644
--- a/arch/x86/kernel/cpu/resctrl/Makefile
+++ b/arch/x86/kernel/cpu/resctrl/Makefile
@@ -1,7 +1,7 @@
# 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) += 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 related [flat|nested] 19+ messages in thread* [PATCH v10 17/17] Documentation/filesystems/resctrl: Document telemetry mount timing caveat
2026-07-29 17:27 [PATCH v10 00/17] Allow AET to use PMT as loadable module Tony Luck
` (15 preceding siblings ...)
2026-07-29 17:27 ` [PATCH v10 16/17] x86/resctrl: Simplify Kconfig options for resctrl Tony Luck
@ 2026-07-29 17:27 ` Tony Luck
2026-07-29 20:11 ` [PATCH v10 00/17] Allow AET to use PMT as loadable module Luck, Tony
17 siblings, 0 replies; 19+ messages in thread
From: Tony Luck @ 2026-07-29 17:27 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 and provides example systemd service and udev
rule snippets that defer the mount until after the pmt_telemetry module
has loaded.
Assisted-by: Claude:Opus_4.7
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
v10:
Unchanged since v9
Documentation/filesystems/resctrl.rst | 60 ++++++++++++++++++++++++++-
1 file changed, 59 insertions(+), 1 deletion(-)
diff --git a/Documentation/filesystems/resctrl.rst b/Documentation/filesystems/resctrl.rst
index e4b66af55ffb..260a5eef675f 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,60 @@ 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. One way to do this is with a udev rule that triggers a systemd
+service when the module appears. A tmpfs mount onto /sys/fs/resctrl is
+needed to prevent daemon tasks from obtaining references to the resctrl
+file system in the other name spaces that systemd uses during startup.
+
+Example systemd tmpfs mount service (``/etc/systemd/system/sys-fs-resctrl.mount``)::
+
+ [Unit]
+ Description=Early Resctrl Namespace Firewall
+ DefaultDependencies=no
+ Before=basic.target local-fs.target
+
+ [Mount]
+ What=tmpfs
+ Where=/sys/fs/resctrl
+ Type=tmpfs
+ Options=private,nosuid,nodev,noexec,mode=755
+
+ [Install]
+ WantedBy=sysinit.target
+
+Example systemd service (``/etc/systemd/system/mount-resctrl.service``)::
+
+ [Unit]
+ Description=Mount real resctrl pseudo-filesystem natively
+ DefaultDependencies=no
+ Requires=sys-fs-resctrl.mount
+ After=sys-fs-resctrl.mount
+
+ [Service]
+ Type=oneshot
+ # Pause to let systemd start daemons
+ ExecStart=/usr/bin/sleep 10
+ # Mount the real resctrl file system
+ ExecStart=/usr/bin/mount -t resctrl resctrl /sys/fs/resctrl
+ RemainAfterExit=no
+
+ [Install]
+ WantedBy=multi-user.target
+
+Example udev rule (``/etc/udev/rules.d/99-rmid-telemetry.rules``)::
+
+ SUBSYSTEM=="module", KERNEL=="pmt_telemetry", ACTION=="add", RUN+="/usr/bin/systemctl start mount-resctrl.service"
+
Intel RDT Errata
================
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH v10 00/17] Allow AET to use PMT as loadable module
2026-07-29 17:27 [PATCH v10 00/17] Allow AET to use PMT as loadable module Tony Luck
` (16 preceding siblings ...)
2026-07-29 17:27 ` [PATCH v10 17/17] Documentation/filesystems/resctrl: Document telemetry mount timing caveat Tony Luck
@ 2026-07-29 20:11 ` Luck, Tony
17 siblings, 0 replies; 19+ messages in thread
From: Luck, Tony @ 2026-07-29 20:11 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
Sashiko review: https://sashiko.dev/#/patchset/20260729172752.11561-1-tony.luck%40intel.com
My responses to issues raised below. In some cases I've clipped just
part of Sashiko response. Use the link above to see the full details
and context for each.
--- Patch [1]: [PATCH v10 01/17] x86/resctrl: Fix enumeration of number of supported RMIDs ---
"Does this early return introduce a potential division-by-zero during boot ..."
Yes. I need to add this code to the start of get_rdt_mon_resources():
if (boot_cpu_data.x86_cache_max_rmid < 0)
return false;
--- Patch 7: [PATCH v10 07/17] arm,x86,fs/resctrl: Handle change in number of RMIDs on each mount ---
"Does this logic ignore Application Energy Telemetry (AET) if it relies on
RDT_RESOURCE_PERF_PKG instead of RDT_RESOURCE_L3?
If the system supports AET but lacks L3 cache monitoring, x86_cache_max_rmid
could be less than or equal to 0, causing this function to return 0.
Additionally, if the fallback to x86_cache_max_rmid is taken, x86_cache_max_rmid
represents a maximum index rather than a count. Could this cause an off-by-one
under-allocation, since a maximum index of N means there are N + 1 RMIDs?"
First part of this complaint is incorrect. If any monitoring is
supported (including AET) then boot_cpu_data.x86_cache_max_rmid will be
some number greater than zero from cpuid_ebx(0xf).
Second part is correct. I've muddled up the "max index" and the "number
of RMIDs" and need to add one to the max index when allocating data
structures.
"If resctrl_arch_system_max_rmid_idx() returns 0 for a system with AET but no
L3 monitoring, won't max_idx_limit be 0, leading to a zero-sized rmid_ptrs
array?"
Can't happen. See above.
--- Patch 8: [PATCH v10 08/17] x86/resctrl: Enforce system RMID limit on AET event groups ---
"Does bypassing rdt_get_l3_mon_config() when L3 events are disabled break
Sub-NUMA Cluster (SNC) detection?"
Yes. But that's the right thing to do. Sub-NUMA Cluster detection is
only needed for the L3 monitor events. If those don't exist (or have
been disabled with clearcpuid) then the full range of RMIDs are
available for use by AET.
"Will this result in an off-by-one truncation of the AET RMID limit if L3
monitoring is disabled?"
Yes. One of the places where fix is needed: num_rmids = max_idx + 1
"This is a pre-existing issue, but could this code encounter a divide-by-zero
during boot if the maximum RMID index evaluates to 0?"
As above. Maximum RMID index can't be zero.
--- Patch 9: [PATCH v10 09/17] x86/resctrl: Add PMT registration API for AET enumeration callbacks ---
"Is this description accurate given that CONFIG_X86_CPU_RESCTRL_INTEL_AET in
Kconfig strictly enforces INTEL_PMT_TELEMETRY=y, preventing it from being
built as a module?
Additionally, if that Kconfig dependency were relaxed to allow it to be a
module, wouldn't it immediately result in a link-time error? It appears
intel_aet_get_events() still directly calls the exported function
intel_pmt_get_regions_by_feature() rather than using the new callbacks."
Sashiko doesn't understand that I've broken some parts of this series
into "add some new infrastructure" and then subsequent patches "use that
new infrastructure". At this point in the series Sashiko correctly notes
that the telemetry driver is forced to be built-in. The issue raised
here is fixed by the point in the series that removes the Kconfig
restriction.
"Do these static variables cause a -Wunused-but-set-variable compiler
warning that breaks builds when CONFIG_WERROR=y is enabled?
It appears intel_aet_get_events() was not updated in this patch to use the
new get_feature callback, leaving these variables unread."
Ditto. Variables used in later patch.
"Since these variables are assigned here but never read, and the registration
function intel_aet_register_enumeration() doesn't seem to be called
anywhere in the kernel, does this leave the variables and function as dead
code?"
Yup. Dead code now. Gets used in later patch.
--- Patch 10: [PATCH v10 10/17] platform/x86/intel/pmt: Register enumeration functions with resctrl ---
"The commit message indicates the goal is to allow INTEL_PMT_TELEMETRY to be a
loadable module while resctrl remains built-in. However, are the callbacks
registered here actually used by the resctrl subsystem?
Looking at intel_aet_get_events() and intel_aet_exit() in
arch/x86/kernel/cpu/resctrl/intel_aet.c, it appears they still make direct
calls to the exported PMT functions:"
Another "defined now, used in later patch" issue.
--- Patch 11: [PATCH v10 11/17] arm,x86/resctrl: Resolve INTEL_PMT_TELEMETRY symbols at runtime ---
"Will the module reference acquired during mount permanently leak?"
At this point in the series the telemetry code is still built-in. So no
leak.
--- Patch 14: [PATCH v10 14/17] x86/resctrl: Export interface to report telemetry unbind/remove ---
"Is it possible for domid to be 64 or greater when evaluated here?"
This patch is new in the series and I'd like discussion on the approach.
My first internal version used an aggressive approach. If any of the
MMIO regions were unmapped by unbind/remove, then I disabled all AET
event reporting. An AI review said this was overkill, and I should only
disable event counts for the unmapped MMIO regions. So I added this
"per-package" logic. Using a u64 as a bitmap of affected packages seems
like it will handle real systems. But now I need to checks for
theoretical systems with 64 or more packages. Seems like make-work.
--- Patch 15: [PATCH v10 15/17] platform/x86/intel/pmt: Inform resctrl when MMIO maps are being removed ---
"Does this code safely handle non-PCI telemetry devices?"
No. But there are no such things. All telemetry devices are PCIe with
VSEC enumeration of events.
"This is a pre-existing issue, but does dropping this kref before unregistering
the sysfs file create a use-after-free window?"
"This is also a pre-existing issue, but does removing the PMT device leave
external consumers vulnerable to accessing unmapped memory?"
I can pass these two pre-existing issues to the telemetry maintainer.
--- Patch 16: [PATCH v10 16/17] x86/resctrl: Simplify Kconfig options for resctrl ---
"Does using a private mount point here break mount propagation to child mount
namespaces? This could isolate the final filesystem mount, preventing
container engines or virtualization daemons from accessing the resctrl
directory."
Yes. Deliberately so. Those things don't need access. Propagating the
mount to them makes the system harder to manage. Users must use the "-l"
option to umount to get the file system propely unmounted.
"Will this 10-second sleep inside a oneshot service cause the systemctl start
command in the udev rule to hang? This appears to synchronously block the udev
event worker during boot."
I haven't observed a hang. The udev rule seems to be running
asynchronously (on Fedora). The system boot completes, and then
the sleep completes and the filesystem is mounted.
"Does this rule make the mount entirely dependent on the pmt_telemetry module
load event?"
I'd expect users to only install this rule on systems that support AET.
I'm open to better suggestions on how to trigger resctrl mount after the telemetry
module loads.
-Tony
^ permalink raw reply [flat|nested] 19+ messages in thread