* [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources
@ 2026-10-29 12:35 Jinjie Ruan
2026-10-29 12:35 ` [RFC PATCH v2 01/19] arm_mpam: resctrl: Leave CDP off when there are too few PARTIDs Jinjie Ruan
` (19 more replies)
0 siblings, 20 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:35 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
Resctrl only knows about monitoring at the L3 scope. MPAM monitors are
attached to a resource in an MSC, and firmware says which cache level that
resource is. The driver already finds L2 monitors, but resctrl has
nowhere to show them.
This is not MPAM specific. RISC-V can also place monitors at several
points in the system.
What this series does
=====================
The monitor event IDs lose the L3 from their names and the event
table is indexed by resource and event.
Then L2 can expose l2c_occupancy and mbm_core_bytes. The MBM state,
the overflow worker, RMID limbo and the assignable counters now work
per resource. The MBA software controller stays on the L3.
MPAM keeps its picked class per (resource, event), can pick L2 classes,
and reads L2 bandwidth from an assignable counter.
x86 never has an L2 monitor resource, so its behaviour does not change.
Testing
=======
QEMU with 2 clusters in 1 node: 2 L2 MSCs, 1 L3 MSC, 1 memory MSC.
- Now L2 has its own resctrl interfaces as below:
cat /sys/fs/resctrl/info/L3_MON/mon_features
# llc_occupancy mbm_total_bytes
cat /sys/fs/resctrl/info/L2_MON/mon_features
# l2c_occupancy mbm_core_bytes
ls /sys/fs/resctrl/mon_data
# mon_L2_33685504 mon_L3_33751040
cat /sys/fs/resctrl/mon_data/mon_L3_33751040/llc_occupancy
cat /sys/fs/resctrl/mon_data/mon_L3_33751040/mbm_total_bytes
cat /sys/fs/resctrl/mon_data/mon_L2_33685504/l2c_occupancy
cat /sys/fs/resctrl/mon_data/mon_L2_33685504/mbm_core_bytes
- l2c_occupancy and mbm_core_bytes has real monitoring data as below:
L2_MON: l2c_occupancy = 256 KiB, mbm_core_bytes ~20 GB in 2 s
L3_MON: llc_occupancy = 16 MiB, mbm_total_bytes unchanged
- CDP: the monitor count halves for every monitor resource.
- Unmount/remount and CPU hotplug were also exercised.
- Each patch built for arm64 and x86_64.
QEMU branch: https://github.com/ruanjinjie-eng/qemu/tree/mpam
Test cases: https://github.com/ruanjinjie-eng/mpam_testcase
If everyone agrees the approach is viable, we will next test it
on real hardware.
This series is also available at:
https://github.com/ruanjinjie-eng/linux/tree/mpam-l2mon-rfc_v2_2
Changes in RFC v2
=================
- As Ben suggested, the existing event types now apply to any resource,
instead of adding L2-only event IDs.
- As Ben suggested, L2 bandwidth uses an assignable counter that stays
with the monitoring group, not a monitor borrowed for each read.
- The CDP change also halves the assignable counter count, for every
monitor resource.
- Split by subsystem so resctrl, x86 and MPAM can be reviewed separately.
- Fix a CDP bug: a failed enable left the driver believing CDP was on.
- RFC v1: https://lore.kernel.org/all/20261022084821.4014873-1-ruanjinjie@huawei.com/
Jinjie Ruan (19):
arm_mpam: resctrl: Leave CDP off when there are too few PARTIDs
fs/resctrl: Generalize __l3_mon_event_count for non-L3 resources
fs/resctrl: Rename monitor events to drop the L3 prefix
x86/resctrl: Use the resource-agnostic monitor event names
arm_mpam: resctrl: Use the resource-agnostic monitor event names
resctrl: Remove the L3 monitor event names
arm_mpam: resctrl: Index monitor state by resource and event
arm_mpam: resctrl: Halve the monitor counts of every resource on CDP
x86,fs/resctrl: Pass the resource to the monitor event helpers
fs/resctrl: Track monitor events per resource
fs/resctrl: Add the L2 monitor events
fs/resctrl: Set up MBM state and workers for every monitor resource
fs/resctrl: Check RMID limbo on every resource with occupancy
fs/resctrl: Manage assignable counters for every monitor resource
arm_mpam: resctrl: Look up the monitor domain id from the components
arm_mpam: resctrl: Report counter assignment per resource
arm_mpam: resctrl: Allow monitoring on resources other than the L3
arm_mpam: resctrl: Expose the L2 monitor events
Documentation: arm64: mpam: Describe the L2 monitor events
Documentation/arch/arm64/mpam.rst | 23 +-
Documentation/filesystems/resctrl.rst | 6 +
arch/x86/kernel/cpu/resctrl/core.c | 13 +-
arch/x86/kernel/cpu/resctrl/intel_aet.c | 2 +-
arch/x86/kernel/cpu/resctrl/internal.h | 2 +-
arch/x86/kernel/cpu/resctrl/monitor.c | 4 +-
arch/x86/kernel/cpu/resctrl/rdtgroup.c | 8 +-
drivers/resctrl/mpam_resctrl.c | 362 ++++++++++++++----------
fs/resctrl/ctrlmondata.c | 13 +-
fs/resctrl/internal.h | 13 +-
fs/resctrl/monitor.c | 300 ++++++++++++--------
fs/resctrl/rdtgroup.c | 148 +++++-----
include/linux/resctrl.h | 27 +-
include/linux/resctrl_types.h | 16 +-
14 files changed, 541 insertions(+), 396 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 01/19] arm_mpam: resctrl: Leave CDP off when there are too few PARTIDs
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
@ 2026-10-29 12:35 ` Jinjie Ruan
2026-10-30 16:38 ` Ben Horgan
2026-10-29 12:35 ` [RFC PATCH v2 02/19] fs/resctrl: Generalize __l3_mon_event_count for non-L3 resources Jinjie Ruan
` (18 subsequent siblings)
19 siblings, 1 reply; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:35 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
Enabling CDP needs a second PARTID for the reserved closid. If firmware
reports too few PARTIDs, resctrl_arch_set_cdp_enabled() returns -EINVAL,
but only after it has recorded CDP as enabled, halved the monitor count
and turned off the mbw_max MBA control. resctrl then reports an error
and believes CDP is off, which leaves the two sides out of step and the
halved monitor count and the missing MBA control are not undone.
Check the PARTID limit, and work out the CDP PARTIDs, before anything is
changed so a failed enable has no effect.
Fixes: 6789fb99282c ("arm_mpam: resctrl: Add CDP emulation")
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
drivers/resctrl/mpam_resctrl.c | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 5468367776e2..886f0595d364 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -210,6 +210,18 @@ int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
if (enable)
pr_warn("CDP is an expert feature and may cause MPAM to malfunction.\n");
+ /*
+ * Check this before changing any state: if CDP can't be enabled the
+ * caller must see CDP left off.
+ */
+ if (enable) {
+ if (mpam_partid_max < 1)
+ return -EINVAL;
+
+ partid_d = resctrl_get_config_index(RESCTRL_RESERVED_CLOSID, CDP_DATA);
+ partid_i = resctrl_get_config_index(RESCTRL_RESERVED_CLOSID, CDP_CODE);
+ }
+
/*
* resctrl_arch_set_cdp_enabled() is only called with enable set to
* false on error and unmount.
@@ -238,14 +250,6 @@ int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
if (!cdp_enabled && mpam_resctrl_controls[RDT_RESOURCE_MBA].class)
mpam_resctrl_controls[RDT_RESOURCE_MBA].resctrl_res.alloc_capable = true;
- if (enable) {
- if (mpam_partid_max < 1)
- return -EINVAL;
-
- partid_d = resctrl_get_config_index(RESCTRL_RESERVED_CLOSID, CDP_DATA);
- partid_i = resctrl_get_config_index(RESCTRL_RESERVED_CLOSID, CDP_CODE);
- }
-
mpam_set_task_partid_pmg(current, partid_d, partid_i, 0, 0);
WRITE_ONCE(arm64_mpam_global_default, mpam_get_regval(current));
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 02/19] fs/resctrl: Generalize __l3_mon_event_count for non-L3 resources
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
2026-10-29 12:35 ` [RFC PATCH v2 01/19] arm_mpam: resctrl: Leave CDP off when there are too few PARTIDs Jinjie Ruan
@ 2026-10-29 12:35 ` Jinjie Ruan
2026-10-29 12:35 ` [RFC PATCH v2 03/19] fs/resctrl: Rename monitor events to drop the L3 prefix Jinjie Ruan
` (17 subsequent siblings)
19 siblings, 0 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:35 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
__l3_mon_event_count() reads a single monitor domain. Its only L3-specific
part is the resource id in the domain_header_is_valid() check; the rest
goes through rr->r and the monitor domain, which every monitor resource
uses. Check rr->r->rid instead and rename the helper to
__mon_event_count_one_domain().
No functional change.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
fs/resctrl/monitor.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index 04e4ea612b7c..9dc076f82fa4 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -422,7 +422,7 @@ static void mbm_cntr_free(struct rdt_l3_mon_domain *d, int cntr_id)
memset(&d->cntr_cfg[cntr_id], 0, sizeof(*d->cntr_cfg));
}
-static int __l3_mon_event_count(struct rdtgroup *rdtgrp, struct rmid_read *rr)
+static int __mon_event_count_one_domain(struct rdtgroup *rdtgrp, struct rmid_read *rr)
{
int cpu = smp_processor_id();
u32 closid = rdtgrp->closid;
@@ -432,7 +432,7 @@ static int __l3_mon_event_count(struct rdtgroup *rdtgrp, struct rmid_read *rr)
struct mbm_state *m;
u64 tval = 0;
- if (!domain_header_is_valid(rr->hdr, RESCTRL_MON_DOMAIN, RDT_RESOURCE_L3)) {
+ if (!domain_header_is_valid(rr->hdr, RESCTRL_MON_DOMAIN, rr->r->rid)) {
rr->err = -EIO;
return -EINVAL;
}
@@ -540,7 +540,7 @@ static int __mon_event_count(struct rdtgroup *rdtgrp, struct rmid_read *rr)
case RDT_RESOURCE_L3:
WARN_ON_ONCE(rr->evt->any_cpu);
if (rr->hdr)
- return __l3_mon_event_count(rdtgrp, rr);
+ return __mon_event_count_one_domain(rdtgrp, rr);
else
return __l3_mon_event_count_sum(rdtgrp, rr);
case RDT_RESOURCE_PERF_PKG: {
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 03/19] fs/resctrl: Rename monitor events to drop the L3 prefix
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
2026-10-29 12:35 ` [RFC PATCH v2 01/19] arm_mpam: resctrl: Leave CDP off when there are too few PARTIDs Jinjie Ruan
2026-10-29 12:35 ` [RFC PATCH v2 02/19] fs/resctrl: Generalize __l3_mon_event_count for non-L3 resources Jinjie Ruan
@ 2026-10-29 12:35 ` Jinjie Ruan
2026-10-29 12:35 ` [RFC PATCH v2 04/19] x86/resctrl: Use the resource-agnostic monitor event names Jinjie Ruan
` (16 subsequent siblings)
19 siblings, 0 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:35 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
The monitor event IDs have L3 in their names because L3 was the only
scope resctrl supported. MPAM can count the same things on an L2 cache,
so the scope belongs to the resource, not to the event.
Drop the L3 prefix from the event names and use the new names in
resctrl. The values stay the same: x86 writes them to IA32_QM_EVTSEL,
and MBM_STATE_IDX() needs the two MBM IDs to sit next to each other.
Keep the old names as aliases until the architectures have been
converted.
No functional change.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
fs/resctrl/ctrlmondata.c | 12 +++---
fs/resctrl/monitor.c | 72 +++++++++++++++++------------------
fs/resctrl/rdtgroup.c | 24 ++++++------
include/linux/resctrl.h | 16 ++++----
include/linux/resctrl_types.h | 21 ++++++----
5 files changed, 76 insertions(+), 69 deletions(-)
diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c
index cafebdff70dc..c70a9939d126 100644
--- a/fs/resctrl/ctrlmondata.c
+++ b/fs/resctrl/ctrlmondata.c
@@ -484,13 +484,13 @@ ssize_t rdtgroup_mba_mbps_event_write(struct kernfs_open_file *of,
buf[nbytes - 1] = '\0';
if (!strcmp(buf, "mbm_local_bytes")) {
- if (resctrl_is_mon_event_enabled(QOS_L3_MBM_LOCAL_EVENT_ID))
- rdtgrp->mba_mbps_event = QOS_L3_MBM_LOCAL_EVENT_ID;
+ if (resctrl_is_mon_event_enabled(QOS_MBM_LOCAL_EVENT_ID))
+ rdtgrp->mba_mbps_event = QOS_MBM_LOCAL_EVENT_ID;
else
ret = -EINVAL;
} else if (!strcmp(buf, "mbm_total_bytes")) {
- if (resctrl_is_mon_event_enabled(QOS_L3_MBM_TOTAL_EVENT_ID))
- rdtgrp->mba_mbps_event = QOS_L3_MBM_TOTAL_EVENT_ID;
+ if (resctrl_is_mon_event_enabled(QOS_MBM_TOTAL_EVENT_ID))
+ rdtgrp->mba_mbps_event = QOS_MBM_TOTAL_EVENT_ID;
else
ret = -EINVAL;
} else {
@@ -516,10 +516,10 @@ int rdtgroup_mba_mbps_event_show(struct kernfs_open_file *of,
if (rdtgrp) {
switch (rdtgrp->mba_mbps_event) {
- case QOS_L3_MBM_LOCAL_EVENT_ID:
+ case QOS_MBM_LOCAL_EVENT_ID:
seq_puts(s, "mbm_local_bytes\n");
break;
- case QOS_L3_MBM_TOTAL_EVENT_ID:
+ case QOS_MBM_TOTAL_EVENT_ID:
seq_puts(s, "mbm_total_bytes\n");
break;
default:
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index 9dc076f82fa4..b9c99c71f4f9 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -141,8 +141,8 @@ void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free)
void *arch_priv;
u64 val = 0;
- arch_priv = mon_event_all[QOS_L3_OCCUP_EVENT_ID].arch_priv;
- arch_mon_ctx = resctrl_arch_mon_ctx_alloc(r, QOS_L3_OCCUP_EVENT_ID);
+ arch_priv = mon_event_all[QOS_OCCUP_EVENT_ID].arch_priv;
+ arch_mon_ctx = resctrl_arch_mon_ctx_alloc(r, QOS_OCCUP_EVENT_ID);
if (IS_ERR(arch_mon_ctx)) {
pr_warn_ratelimited("Failed to allocate monitor context: %pe",
arch_mon_ctx);
@@ -163,7 +163,7 @@ void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free)
entry = __rmid_entry(idx);
if (!force_free) {
if (resctrl_arch_rmid_read(r, &d->hdr, entry->closid,
- entry->rmid, QOS_L3_OCCUP_EVENT_ID,
+ entry->rmid, QOS_OCCUP_EVENT_ID,
arch_priv, &val, arch_mon_ctx)) {
rmid_dirty = true;
} else {
@@ -192,7 +192,7 @@ void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free)
cur_idx = idx + 1;
}
- resctrl_arch_mon_ctx_free(r, QOS_L3_OCCUP_EVENT_ID, arch_mon_ctx);
+ resctrl_arch_mon_ctx_free(r, QOS_OCCUP_EVENT_ID, arch_mon_ctx);
}
bool has_busy_rmid(struct rdt_l3_mon_domain *d)
@@ -345,7 +345,7 @@ void free_rmid(u32 closid, u32 rmid)
entry = __rmid_entry(idx);
- if (resctrl_is_mon_event_enabled(QOS_L3_OCCUP_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(QOS_OCCUP_EVENT_ID))
add_rmid_to_limbo(entry);
else
list_add_tail(&entry->list, &rmid_free_lru);
@@ -801,11 +801,11 @@ static void mbm_update(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
* This is protected from concurrent reads from user as both
* the user and overflow handler hold the global mutex.
*/
- if (resctrl_is_mon_event_enabled(QOS_L3_MBM_TOTAL_EVENT_ID))
- mbm_update_one_event(r, d, rdtgrp, QOS_L3_MBM_TOTAL_EVENT_ID);
+ if (resctrl_is_mon_event_enabled(QOS_MBM_TOTAL_EVENT_ID))
+ mbm_update_one_event(r, d, rdtgrp, QOS_MBM_TOTAL_EVENT_ID);
- if (resctrl_is_mon_event_enabled(QOS_L3_MBM_LOCAL_EVENT_ID))
- mbm_update_one_event(r, d, rdtgrp, QOS_L3_MBM_LOCAL_EVENT_ID);
+ if (resctrl_is_mon_event_enabled(QOS_MBM_LOCAL_EVENT_ID))
+ mbm_update_one_event(r, d, rdtgrp, QOS_MBM_LOCAL_EVENT_ID);
}
/*
@@ -1029,9 +1029,9 @@ void free_rmid_lru_list(void)
* to set .enabled.
*/
struct mon_evt mon_event_all[QOS_NUM_EVENTS] = {
- MON_EVENT(QOS_L3_OCCUP_EVENT_ID, "llc_occupancy", RDT_RESOURCE_L3, false),
- MON_EVENT(QOS_L3_MBM_TOTAL_EVENT_ID, "mbm_total_bytes", RDT_RESOURCE_L3, false),
- MON_EVENT(QOS_L3_MBM_LOCAL_EVENT_ID, "mbm_local_bytes", RDT_RESOURCE_L3, false),
+ MON_EVENT(QOS_OCCUP_EVENT_ID, "llc_occupancy", RDT_RESOURCE_L3, false),
+ MON_EVENT(QOS_MBM_TOTAL_EVENT_ID, "mbm_total_bytes", RDT_RESOURCE_L3, false),
+ MON_EVENT(QOS_MBM_LOCAL_EVENT_ID, "mbm_local_bytes", RDT_RESOURCE_L3, false),
MON_EVENT(PMT_EVENT_ENERGY, "core_energy", RDT_RESOURCE_PERF_PKG, true),
MON_EVENT(PMT_EVENT_ACTIVITY, "activity", RDT_RESOURCE_PERF_PKG, true),
MON_EVENT(PMT_EVENT_STALLS_LLC_HIT, "stalls_llc_hit", RDT_RESOURCE_PERF_PKG, false),
@@ -1319,13 +1319,13 @@ void rdtgroup_assign_cntrs(struct rdtgroup *rdtgrp)
!r->mon.mbm_assign_on_mkdir)
return;
- if (resctrl_is_mon_event_enabled(QOS_L3_MBM_TOTAL_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(QOS_MBM_TOTAL_EVENT_ID))
rdtgroup_assign_cntr_event(NULL, rdtgrp,
- &mon_event_all[QOS_L3_MBM_TOTAL_EVENT_ID]);
+ &mon_event_all[QOS_MBM_TOTAL_EVENT_ID]);
- if (resctrl_is_mon_event_enabled(QOS_L3_MBM_LOCAL_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(QOS_MBM_LOCAL_EVENT_ID))
rdtgroup_assign_cntr_event(NULL, rdtgrp,
- &mon_event_all[QOS_L3_MBM_LOCAL_EVENT_ID]);
+ &mon_event_all[QOS_MBM_LOCAL_EVENT_ID]);
}
/*
@@ -1377,13 +1377,13 @@ void rdtgroup_unassign_cntrs(struct rdtgroup *rdtgrp)
if (!r->mon_capable || !resctrl_arch_mbm_cntr_assign_enabled(r))
return;
- if (resctrl_is_mon_event_enabled(QOS_L3_MBM_TOTAL_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(QOS_MBM_TOTAL_EVENT_ID))
rdtgroup_unassign_cntr_event(NULL, rdtgrp,
- &mon_event_all[QOS_L3_MBM_TOTAL_EVENT_ID]);
+ &mon_event_all[QOS_MBM_TOTAL_EVENT_ID]);
- if (resctrl_is_mon_event_enabled(QOS_L3_MBM_LOCAL_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(QOS_MBM_LOCAL_EVENT_ID))
rdtgroup_unassign_cntr_event(NULL, rdtgrp,
- &mon_event_all[QOS_L3_MBM_LOCAL_EVENT_ID]);
+ &mon_event_all[QOS_MBM_LOCAL_EVENT_ID]);
}
static int resctrl_parse_mem_transactions(char *tok, u32 *val)
@@ -1594,10 +1594,10 @@ ssize_t resctrl_mbm_assign_mode_write(struct kernfs_open_file *of, char *buf,
* Initialize the default memory transaction values for
* total and local events.
*/
- if (resctrl_is_mon_event_enabled(QOS_L3_MBM_TOTAL_EVENT_ID))
- mon_event_all[QOS_L3_MBM_TOTAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask;
- if (resctrl_is_mon_event_enabled(QOS_L3_MBM_LOCAL_EVENT_ID))
- mon_event_all[QOS_L3_MBM_LOCAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask &
+ if (resctrl_is_mon_event_enabled(QOS_MBM_TOTAL_EVENT_ID))
+ mon_event_all[QOS_MBM_TOTAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask;
+ if (resctrl_is_mon_event_enabled(QOS_MBM_LOCAL_EVENT_ID))
+ mon_event_all[QOS_MBM_LOCAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask &
(READS_TO_LOCAL_MEM |
READS_TO_LOCAL_S_MEM |
NON_TEMP_WRITE_TO_LOCAL_MEM);
@@ -1936,27 +1936,27 @@ int resctrl_l3_mon_resource_init(void)
if (ret)
return ret;
- if (resctrl_arch_is_evt_configurable(QOS_L3_MBM_TOTAL_EVENT_ID)) {
- mon_event_all[QOS_L3_MBM_TOTAL_EVENT_ID].configurable = true;
+ if (resctrl_arch_is_evt_configurable(QOS_MBM_TOTAL_EVENT_ID)) {
+ mon_event_all[QOS_MBM_TOTAL_EVENT_ID].configurable = true;
resctrl_file_fflags_init("mbm_total_bytes_config",
RFTYPE_MON_INFO | RFTYPE_RES_CACHE);
}
- if (resctrl_arch_is_evt_configurable(QOS_L3_MBM_LOCAL_EVENT_ID)) {
- mon_event_all[QOS_L3_MBM_LOCAL_EVENT_ID].configurable = true;
+ if (resctrl_arch_is_evt_configurable(QOS_MBM_LOCAL_EVENT_ID)) {
+ mon_event_all[QOS_MBM_LOCAL_EVENT_ID].configurable = true;
resctrl_file_fflags_init("mbm_local_bytes_config",
RFTYPE_MON_INFO | RFTYPE_RES_CACHE);
}
- if (resctrl_is_mon_event_enabled(QOS_L3_MBM_LOCAL_EVENT_ID))
- mba_mbps_default_event = QOS_L3_MBM_LOCAL_EVENT_ID;
- else if (resctrl_is_mon_event_enabled(QOS_L3_MBM_TOTAL_EVENT_ID))
- mba_mbps_default_event = QOS_L3_MBM_TOTAL_EVENT_ID;
+ if (resctrl_is_mon_event_enabled(QOS_MBM_LOCAL_EVENT_ID))
+ mba_mbps_default_event = QOS_MBM_LOCAL_EVENT_ID;
+ else if (resctrl_is_mon_event_enabled(QOS_MBM_TOTAL_EVENT_ID))
+ mba_mbps_default_event = QOS_MBM_TOTAL_EVENT_ID;
if (r->mon.mbm_cntr_assignable) {
- if (resctrl_is_mon_event_enabled(QOS_L3_MBM_TOTAL_EVENT_ID))
- mon_event_all[QOS_L3_MBM_TOTAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask;
- if (resctrl_is_mon_event_enabled(QOS_L3_MBM_LOCAL_EVENT_ID))
- mon_event_all[QOS_L3_MBM_LOCAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask &
+ if (resctrl_is_mon_event_enabled(QOS_MBM_TOTAL_EVENT_ID))
+ mon_event_all[QOS_MBM_TOTAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask;
+ if (resctrl_is_mon_event_enabled(QOS_MBM_LOCAL_EVENT_ID))
+ mon_event_all[QOS_MBM_LOCAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask &
(READS_TO_LOCAL_MEM |
READS_TO_LOCAL_S_MEM |
NON_TEMP_WRITE_TO_LOCAL_MEM);
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 57ab090072c2..92f0e3b68784 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -124,8 +124,8 @@ void rdt_staged_configs_clear(void)
static bool resctrl_is_mbm_enabled(void)
{
- return (resctrl_is_mon_event_enabled(QOS_L3_MBM_TOTAL_EVENT_ID) ||
- resctrl_is_mon_event_enabled(QOS_L3_MBM_LOCAL_EVENT_ID));
+ return (resctrl_is_mon_event_enabled(QOS_MBM_TOTAL_EVENT_ID) ||
+ resctrl_is_mon_event_enabled(QOS_MBM_LOCAL_EVENT_ID));
}
/*
@@ -191,7 +191,7 @@ static int closid_alloc(void)
lockdep_assert_held(&rdtgroup_mutex);
if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID) &&
- resctrl_is_mon_event_enabled(QOS_L3_OCCUP_EVENT_ID)) {
+ resctrl_is_mon_event_enabled(QOS_OCCUP_EVENT_ID)) {
cleanest_closid = resctrl_find_cleanest_closid();
if (cleanest_closid < 0)
return cleanest_closid;
@@ -1755,7 +1755,7 @@ static int mbm_total_bytes_config_show(struct kernfs_open_file *of,
if (!info_kn_lock(of->kn))
return -ENOENT;
- mbm_config_show(seq, r, QOS_L3_MBM_TOTAL_EVENT_ID);
+ mbm_config_show(seq, r, QOS_MBM_TOTAL_EVENT_ID);
info_kn_unlock(of->kn);
return 0;
@@ -1769,7 +1769,7 @@ static int mbm_local_bytes_config_show(struct kernfs_open_file *of,
if (!info_kn_lock(of->kn))
return -ENOENT;
- mbm_config_show(seq, r, QOS_L3_MBM_LOCAL_EVENT_ID);
+ mbm_config_show(seq, r, QOS_MBM_LOCAL_EVENT_ID);
info_kn_unlock(of->kn);
return 0;
@@ -1879,7 +1879,7 @@ static ssize_t mbm_total_bytes_config_write(struct kernfs_open_file *of,
buf[nbytes - 1] = '\0';
- ret = mon_config_write(r, buf, QOS_L3_MBM_TOTAL_EVENT_ID);
+ ret = mon_config_write(r, buf, QOS_MBM_TOTAL_EVENT_ID);
out_unlock:
info_kn_unlock(of->kn);
@@ -1908,7 +1908,7 @@ static ssize_t mbm_local_bytes_config_write(struct kernfs_open_file *of,
buf[nbytes - 1] = '\0';
- ret = mon_config_write(r, buf, QOS_L3_MBM_LOCAL_EVENT_ID);
+ ret = mon_config_write(r, buf, QOS_MBM_LOCAL_EVENT_ID);
out_unlock:
info_kn_unlock(of->kn);
@@ -4561,7 +4561,7 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *h
d = container_of(hdr, struct rdt_l3_mon_domain, hdr);
if (resctrl_is_mbm_enabled())
cancel_delayed_work_sync(&d->mbm_over);
- if (resctrl_is_mon_event_enabled(QOS_L3_OCCUP_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(QOS_OCCUP_EVENT_ID))
cancel_delayed_work_sync(&d->cqm_limbo);
}
@@ -4581,7 +4581,7 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *h
goto out_unlock;
d = container_of(hdr, struct rdt_l3_mon_domain, hdr);
- if (resctrl_is_mon_event_enabled(QOS_L3_OCCUP_EVENT_ID) && has_busy_rmid(d)) {
+ if (resctrl_is_mon_event_enabled(QOS_OCCUP_EVENT_ID) && has_busy_rmid(d)) {
/*
* When a package is going down, forcefully
* decrement rmid->ebusy. There is no way to know
@@ -4624,7 +4624,7 @@ static int domain_setup_l3_mon_state(struct rdt_resource *r, struct rdt_l3_mon_d
enum resctrl_event_id eventid;
int idx;
- if (resctrl_is_mon_event_enabled(QOS_L3_OCCUP_EVENT_ID)) {
+ if (resctrl_is_mon_event_enabled(QOS_OCCUP_EVENT_ID)) {
d->rmid_busy_llc = bitmap_zalloc(idx_limit, GFP_KERNEL);
if (!d->rmid_busy_llc)
return -ENOMEM;
@@ -4697,7 +4697,7 @@ int resctrl_online_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *hdr
RESCTRL_PICK_ANY_CPU);
}
- if (resctrl_is_mon_event_enabled(QOS_L3_OCCUP_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(QOS_OCCUP_EVENT_ID))
INIT_DELAYED_WORK(&d->cqm_limbo, cqm_handle_limbo);
mkdir:
@@ -4776,7 +4776,7 @@ void resctrl_offline_cpu(unsigned int cpu)
mutex_lock(&rdtgroup_mutex);
mbm_setup_overflow_handler(d, 0, cpu);
}
- if (resctrl_is_mon_event_enabled(QOS_L3_OCCUP_EVENT_ID) &&
+ if (resctrl_is_mon_event_enabled(QOS_OCCUP_EVENT_ID) &&
cpu == d->cqm_work_cpu && has_busy_rmid(d)) {
mutex_unlock(&rdtgroup_mutex);
cancel_delayed_work_sync(&d->cqm_limbo);
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 10dfdca7f4bf..c844f99fb824 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -198,7 +198,7 @@ struct rdt_l3_mon_domain {
struct rdt_domain_hdr hdr;
unsigned int ci_id;
unsigned long *rmid_busy_llc;
- struct mbm_state *mbm_states[QOS_NUM_L3_MBM_EVENTS];
+ struct mbm_state *mbm_states[QOS_NUM_MBM_EVENTS];
struct delayed_work mbm_over;
struct delayed_work cqm_limbo;
int mbm_work_cpu;
@@ -428,20 +428,20 @@ bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt);
static inline bool resctrl_is_mbm_event(enum resctrl_event_id eventid)
{
- return (eventid >= QOS_L3_MBM_TOTAL_EVENT_ID &&
- eventid <= QOS_L3_MBM_LOCAL_EVENT_ID);
+ return (eventid >= QOS_MBM_TOTAL_EVENT_ID &&
+ eventid <= QOS_MBM_LOCAL_EVENT_ID);
}
u32 resctrl_get_mon_evt_cfg(enum resctrl_event_id eventid);
/* Iterate over all memory bandwidth events */
#define for_each_mbm_event_id(eventid) \
- for (eventid = QOS_L3_MBM_TOTAL_EVENT_ID; \
- eventid <= QOS_L3_MBM_LOCAL_EVENT_ID; eventid++)
+ for (eventid = QOS_MBM_TOTAL_EVENT_ID; \
+ eventid <= QOS_MBM_LOCAL_EVENT_ID; eventid++)
/* Iterate over memory bandwidth arrays in domain structures */
#define for_each_mbm_idx(idx) \
- for (idx = 0; idx < QOS_NUM_L3_MBM_EVENTS; idx++)
+ for (idx = 0; idx < QOS_NUM_MBM_EVENTS; idx++)
/**
* resctrl_arch_mon_event_config_write() - Write the config for an event.
@@ -650,8 +650,8 @@ void resctrl_arch_reset_all_ctrls(struct rdt_resource *r);
* and event details.
* @r: Resource structure.
* @d: The domain in which counter with ID @cntr_id should be configured.
- * @evtid: Monitoring event type (e.g., QOS_L3_MBM_TOTAL_EVENT_ID
- * or QOS_L3_MBM_LOCAL_EVENT_ID).
+ * @evtid: Monitoring event type (e.g., QOS_MBM_TOTAL_EVENT_ID
+ * or QOS_MBM_LOCAL_EVENT_ID).
* @rmid: RMID.
* @closid: CLOSID.
* @cntr_id: Counter ID to configure.
diff --git a/include/linux/resctrl_types.h b/include/linux/resctrl_types.h
index e2e2cf3d9ff6..8679cbe589ec 100644
--- a/include/linux/resctrl_types.h
+++ b/include/linux/resctrl_types.h
@@ -43,12 +43,13 @@ enum resctrl_event_id {
QOS_FIRST_EVENT = 0x01,
/*
- * These values match those used to program IA32_QM_EVTSEL before
- * reading IA32_QM_CTR on RDT systems.
+ * Monitor event types. The resource an event belongs to is tracked
+ * separately. These values match those used to program IA32_QM_EVTSEL
+ * before reading IA32_QM_CTR on RDT systems.
*/
- QOS_L3_OCCUP_EVENT_ID = 0x01,
- QOS_L3_MBM_TOTAL_EVENT_ID = 0x02,
- QOS_L3_MBM_LOCAL_EVENT_ID = 0x03,
+ QOS_OCCUP_EVENT_ID = 0x01,
+ QOS_MBM_TOTAL_EVENT_ID = 0x02,
+ QOS_MBM_LOCAL_EVENT_ID = 0x03,
/* Intel Telemetry Events */
PMT_EVENT_ENERGY,
@@ -67,7 +68,13 @@ enum resctrl_event_id {
QOS_NUM_EVENTS,
};
-#define QOS_NUM_L3_MBM_EVENTS (QOS_L3_MBM_LOCAL_EVENT_ID - QOS_L3_MBM_TOTAL_EVENT_ID + 1)
-#define MBM_STATE_IDX(evt) ((evt) - QOS_L3_MBM_TOTAL_EVENT_ID)
+#define QOS_NUM_MBM_EVENTS (QOS_MBM_LOCAL_EVENT_ID - QOS_MBM_TOTAL_EVENT_ID + 1)
+#define MBM_STATE_IDX(evt) ((evt) - QOS_MBM_TOTAL_EVENT_ID)
+
+/* Old names, kept until every architecture has been converted. */
+#define QOS_L3_OCCUP_EVENT_ID QOS_OCCUP_EVENT_ID
+#define QOS_L3_MBM_TOTAL_EVENT_ID QOS_MBM_TOTAL_EVENT_ID
+#define QOS_L3_MBM_LOCAL_EVENT_ID QOS_MBM_LOCAL_EVENT_ID
+#define QOS_NUM_L3_MBM_EVENTS QOS_NUM_MBM_EVENTS
#endif /* __LINUX_RESCTRL_TYPES_H */
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 04/19] x86/resctrl: Use the resource-agnostic monitor event names
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
` (2 preceding siblings ...)
2026-10-29 12:35 ` [RFC PATCH v2 03/19] fs/resctrl: Rename monitor events to drop the L3 prefix Jinjie Ruan
@ 2026-10-29 12:35 ` Jinjie Ruan
2026-10-29 12:35 ` [RFC PATCH v2 05/19] arm_mpam: resctrl: " Jinjie Ruan
` (15 subsequent siblings)
19 siblings, 0 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:35 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
The monitor event IDs no longer carry L3 in their names. Switch x86 over
to the new names. The values are unchanged, so this does not change what
is written to IA32_QM_EVTSEL.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
arch/x86/kernel/cpu/resctrl/core.c | 10 +++++-----
arch/x86/kernel/cpu/resctrl/internal.h | 2 +-
arch/x86/kernel/cpu/resctrl/rdtgroup.c | 8 ++++----
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index 55214d6fdc49..8842e3406ca5 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -887,9 +887,9 @@ bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt)
return false;
switch (evt) {
- case QOS_L3_MBM_TOTAL_EVENT_ID:
+ case QOS_MBM_TOTAL_EVENT_ID:
return rdt_cpu_has(X86_FEATURE_CQM_MBM_TOTAL);
- case QOS_L3_MBM_LOCAL_EVENT_ID:
+ case QOS_MBM_LOCAL_EVENT_ID:
return rdt_cpu_has(X86_FEATURE_CQM_MBM_LOCAL);
default:
return false;
@@ -969,15 +969,15 @@ static __init bool get_rdt_mon_resources(void)
bool ret = false;
if (rdt_cpu_has(X86_FEATURE_CQM_OCCUP_LLC)) {
- resctrl_enable_mon_event(QOS_L3_OCCUP_EVENT_ID, false, 0, NULL);
+ resctrl_enable_mon_event(QOS_OCCUP_EVENT_ID, false, 0, NULL);
ret = true;
}
if (rdt_cpu_has(X86_FEATURE_CQM_MBM_TOTAL)) {
- resctrl_enable_mon_event(QOS_L3_MBM_TOTAL_EVENT_ID, false, 0, NULL);
+ resctrl_enable_mon_event(QOS_MBM_TOTAL_EVENT_ID, false, 0, NULL);
ret = true;
}
if (rdt_cpu_has(X86_FEATURE_CQM_MBM_LOCAL)) {
- resctrl_enable_mon_event(QOS_L3_MBM_LOCAL_EVENT_ID, false, 0, NULL);
+ resctrl_enable_mon_event(QOS_MBM_LOCAL_EVENT_ID, false, 0, NULL);
ret = true;
}
if (rdt_cpu_has(X86_FEATURE_ABMC))
diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h
index e3cfa0c10e92..1abb4b6d01e4 100644
--- a/arch/x86/kernel/cpu/resctrl/internal.h
+++ b/arch/x86/kernel/cpu/resctrl/internal.h
@@ -77,7 +77,7 @@ struct rdt_hw_ctrl_domain {
*/
struct rdt_hw_l3_mon_domain {
struct rdt_l3_mon_domain d_resctrl;
- struct arch_mbm_state *arch_mbm_states[QOS_NUM_L3_MBM_EVENTS];
+ struct arch_mbm_state *arch_mbm_states[QOS_NUM_MBM_EVENTS];
};
static inline struct rdt_hw_ctrl_domain *resctrl_to_arch_ctrl_dom(struct rdt_ctrl_domain *r)
diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
index 5ffa39fa86fa..825d71b14b4f 100644
--- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c
+++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
@@ -68,16 +68,16 @@ void resctrl_arch_sync_cpu_closid_rmid(void *info)
* configurable event
* @evtid: event id.
*
- * Return: 0 for evtid == QOS_L3_MBM_TOTAL_EVENT_ID
- * 1 for evtid == QOS_L3_MBM_LOCAL_EVENT_ID
+ * Return: 0 for evtid == QOS_MBM_TOTAL_EVENT_ID
+ * 1 for evtid == QOS_MBM_LOCAL_EVENT_ID
* INVALID_CONFIG_INDEX for invalid evtid
*/
static inline unsigned int mon_event_config_index_get(u32 evtid)
{
switch (evtid) {
- case QOS_L3_MBM_TOTAL_EVENT_ID:
+ case QOS_MBM_TOTAL_EVENT_ID:
return 0;
- case QOS_L3_MBM_LOCAL_EVENT_ID:
+ case QOS_MBM_LOCAL_EVENT_ID:
return 1;
default:
/* Should never reach here */
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 05/19] arm_mpam: resctrl: Use the resource-agnostic monitor event names
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
` (3 preceding siblings ...)
2026-10-29 12:35 ` [RFC PATCH v2 04/19] x86/resctrl: Use the resource-agnostic monitor event names Jinjie Ruan
@ 2026-10-29 12:35 ` Jinjie Ruan
2026-10-29 12:35 ` [RFC PATCH v2 06/19] resctrl: Remove the L3 " Jinjie Ruan
` (14 subsequent siblings)
19 siblings, 0 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:35 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
The monitor event IDs no longer carry L3 in their names. Switch the MPAM
driver over to the new names.
No functional change.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
drivers/resctrl/mpam_resctrl.c | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 886f0595d364..e436c3e6d4fc 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -45,7 +45,7 @@ static struct mpam_resctrl_res mpam_resctrl_controls[RDT_NUM_RESOURCES];
* to those supported by MPAM.
* Class pointer may be NULL.
*/
-#define MPAM_MAX_EVENT QOS_L3_MBM_TOTAL_EVENT_ID
+#define MPAM_MAX_EVENT QOS_MBM_TOTAL_EVENT_ID
static struct mpam_resctrl_mon mpam_resctrl_counters[MPAM_MAX_EVENT + 1];
#define for_each_mpam_resctrl_mon(mon, eventid) \
@@ -173,7 +173,7 @@ static void resctrl_reset_task_closids(void)
static void mpam_resctrl_monitor_sync_abmc_vals(struct rdt_resource *l3)
{
- struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[QOS_L3_MBM_TOTAL_EVENT_ID];
+ struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[QOS_MBM_TOTAL_EVENT_ID];
if (!mon->class)
return;
@@ -392,11 +392,11 @@ static int resctrl_arch_mon_ctx_alloc_no_wait(enum resctrl_event_id evtid)
return -EINVAL;
switch (evtid) {
- case QOS_L3_OCCUP_EVENT_ID:
+ case QOS_OCCUP_EVENT_ID:
/* With CDP, one monitor gets used for both code/data reads */
return mpam_alloc_csu_mon(mon->class);
- case QOS_L3_MBM_LOCAL_EVENT_ID:
- case QOS_L3_MBM_TOTAL_EVENT_ID:
+ case QOS_MBM_LOCAL_EVENT_ID:
+ case QOS_MBM_TOTAL_EVENT_ID:
return USE_PRE_ALLOCATED;
default:
return -EOPNOTSUPP;
@@ -436,7 +436,7 @@ static void resctrl_arch_mon_ctx_free_no_wait(enum resctrl_event_id evtid,
if (!mon->class)
return;
- if (evtid == QOS_L3_OCCUP_EVENT_ID)
+ if (evtid == QOS_OCCUP_EVENT_ID)
mpam_free_csu_mon(mon->class, mon_idx);
wake_up(&resctrl_mon_ctx_waiters);
@@ -536,7 +536,7 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain_hdr *hdr,
l3_dom = container_of(hdr, struct mpam_resctrl_dom, resctrl_mon_dom.hdr);
mon_comp = l3_dom->mon_comp[eventid];
- if (eventid != QOS_L3_OCCUP_EVENT_ID)
+ if (eventid != QOS_OCCUP_EVENT_ID)
return -EINVAL;
mon_type = mpam_feat_msmon_csu;
@@ -557,7 +557,7 @@ int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
if (!mpam_is_enabled())
return -EINVAL;
- if (eventid == QOS_L3_OCCUP_EVENT_ID || !mon->class)
+ if (eventid == QOS_OCCUP_EVENT_ID || !mon->class)
return -EINVAL;
l3_dom = container_of(d, struct mpam_resctrl_dom, resctrl_mon_dom);
@@ -614,7 +614,7 @@ void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d
if (!mpam_is_enabled())
return;
- if (eventid == QOS_L3_OCCUP_EVENT_ID || !mon->class)
+ if (eventid == QOS_OCCUP_EVENT_ID || !mon->class)
return;
l3_dom = container_of(d, struct mpam_resctrl_dom, resctrl_mon_dom);
@@ -1131,7 +1131,7 @@ static void mpam_resctrl_pick_counters(void)
if (update_rmid_limits(class))
break;
- counter_update_class(QOS_L3_OCCUP_EVENT_ID, class);
+ counter_update_class(QOS_OCCUP_EVENT_ID, class);
break;
default:
break;
@@ -1153,7 +1153,7 @@ static void mpam_resctrl_pick_counters(void)
* and it's equivalent to mbm_total and so always use
* mbm_total.
*/
- counter_update_class(QOS_L3_MBM_TOTAL_EVENT_ID, class);
+ counter_update_class(QOS_MBM_TOTAL_EVENT_ID, class);
}
}
}
@@ -1180,7 +1180,7 @@ void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *
{
struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid];
- if (evtid != QOS_L3_MBM_TOTAL_EVENT_ID) {
+ if (evtid != QOS_MBM_TOTAL_EVENT_ID) {
pr_debug("unexpected event id\n");
return;
}
@@ -1197,7 +1197,7 @@ void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *
__config_cntr(mon, cntr_id, CDP_NONE, closid, rmid, assign);
}
- resctrl_arch_reset_cntr(r, d, closid, rmid, cntr_id, QOS_L3_MBM_TOTAL_EVENT_ID);
+ resctrl_arch_reset_cntr(r, d, closid, rmid, cntr_id, QOS_MBM_TOTAL_EVENT_ID);
}
static int mpam_resctrl_control_init(struct mpam_resctrl_res *res)
@@ -1358,7 +1358,7 @@ static int mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
*/
l3->mon.num_rmid = resctrl_arch_system_num_rmid_idx();
- if (type == QOS_L3_MBM_TOTAL_EVENT_ID) {
+ if (type == QOS_MBM_TOTAL_EVENT_ID) {
int err;
err = mpam_resctrl_monitor_init_abmc(mon);
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 06/19] resctrl: Remove the L3 monitor event names
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
` (4 preceding siblings ...)
2026-10-29 12:35 ` [RFC PATCH v2 05/19] arm_mpam: resctrl: " Jinjie Ruan
@ 2026-10-29 12:35 ` Jinjie Ruan
2026-10-29 12:35 ` [RFC PATCH v2 07/19] arm_mpam: resctrl: Index monitor state by resource and event Jinjie Ruan
` (13 subsequent siblings)
19 siblings, 0 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:35 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
Every user has moved to the resource-agnostic monitor
event names. So remove the old ones.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
include/linux/resctrl_types.h | 6 ------
1 file changed, 6 deletions(-)
diff --git a/include/linux/resctrl_types.h b/include/linux/resctrl_types.h
index 8679cbe589ec..d0e56de038f0 100644
--- a/include/linux/resctrl_types.h
+++ b/include/linux/resctrl_types.h
@@ -71,10 +71,4 @@ enum resctrl_event_id {
#define QOS_NUM_MBM_EVENTS (QOS_MBM_LOCAL_EVENT_ID - QOS_MBM_TOTAL_EVENT_ID + 1)
#define MBM_STATE_IDX(evt) ((evt) - QOS_MBM_TOTAL_EVENT_ID)
-/* Old names, kept until every architecture has been converted. */
-#define QOS_L3_OCCUP_EVENT_ID QOS_OCCUP_EVENT_ID
-#define QOS_L3_MBM_TOTAL_EVENT_ID QOS_MBM_TOTAL_EVENT_ID
-#define QOS_L3_MBM_LOCAL_EVENT_ID QOS_MBM_LOCAL_EVENT_ID
-#define QOS_NUM_L3_MBM_EVENTS QOS_NUM_MBM_EVENTS
-
#endif /* __LINUX_RESCTRL_TYPES_H */
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 07/19] arm_mpam: resctrl: Index monitor state by resource and event
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
` (5 preceding siblings ...)
2026-10-29 12:35 ` [RFC PATCH v2 06/19] resctrl: Remove the L3 " Jinjie Ruan
@ 2026-10-29 12:35 ` Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 08/19] arm_mpam: resctrl: Halve the monitor counts of every resource on CDP Jinjie Ruan
` (12 subsequent siblings)
19 siblings, 0 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:35 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
The picked monitor class and the assignable counter state are kept in an
array indexed by event ID alone, and every monitor domain's component
array is filled from every event. Index the array by resource and event,
and fill a domain only from the events of its own resource.
This is plumbing for L2 support. It also replaces the MPAM_MAX_EVENT
bound with QOS_NUM_EVENTS, so an event ID is no longer used as an index
past the end of the array it indexes.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
drivers/resctrl/mpam_resctrl.c | 146 ++++++++++++++++++---------------
1 file changed, 82 insertions(+), 64 deletions(-)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index e436c3e6d4fc..abd4fbca48ab 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -37,21 +37,30 @@ static struct mpam_resctrl_res mpam_resctrl_controls[RDT_NUM_RESOURCES];
rid++, res = &mpam_resctrl_controls[rid])
/*
- * The classes we've picked to map to resctrl events.
- * Resctrl believes all the worlds a Xeon, and these are all on the L3. This
- * array lets us find the actual class backing the event counters. e.g.
+ * The classes we've picked to map to resctrl events, for each resource.
+ * This array lets us find the actual class backing the event counters. e.g.
* the only memory bandwidth counters may be on the memory controller, but to
- * make use of them, we pretend they are on L3. Restrict the events considered
- * to those supported by MPAM.
+ * make use of them, we pretend they are on L3.
* Class pointer may be NULL.
*/
-#define MPAM_MAX_EVENT QOS_MBM_TOTAL_EVENT_ID
-static struct mpam_resctrl_mon mpam_resctrl_counters[MPAM_MAX_EVENT + 1];
+static struct mpam_resctrl_mon mpam_resctrl_counters[RDT_NUM_RESOURCES][QOS_NUM_EVENTS];
-#define for_each_mpam_resctrl_mon(mon, eventid) \
- for (eventid = QOS_FIRST_EVENT, mon = &mpam_resctrl_counters[eventid]; \
- eventid <= MPAM_MAX_EVENT; \
- eventid++, mon = &mpam_resctrl_counters[eventid])
+static struct mpam_resctrl_mon *
+mpam_resctrl_mon_by_rid(enum resctrl_res_level rid, enum resctrl_event_id evtid)
+{
+ return &mpam_resctrl_counters[rid][evtid];
+}
+
+static struct mpam_resctrl_mon *
+mpam_resctrl_mon(struct rdt_resource *r, enum resctrl_event_id evtid)
+{
+ return mpam_resctrl_mon_by_rid(r->rid, evtid);
+}
+
+#define for_each_mpam_resctrl_mon(mon, r, eventid) \
+ for (eventid = QOS_FIRST_EVENT, mon = mpam_resctrl_mon(r, eventid); \
+ eventid < QOS_NUM_EVENTS; \
+ eventid++, mon = mpam_resctrl_mon(r, eventid))
/* The lock for modifying resctrl's domain lists from cpuhp callbacks. */
static DEFINE_MUTEX(domain_list_lock);
@@ -171,9 +180,9 @@ static void resctrl_reset_task_closids(void)
read_unlock(&tasklist_lock);
}
-static void mpam_resctrl_monitor_sync_abmc_vals(struct rdt_resource *l3)
+static void mpam_resctrl_monitor_sync_abmc_vals(struct rdt_resource *r)
{
- struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[QOS_MBM_TOTAL_EVENT_ID];
+ struct mpam_resctrl_mon *mon = mpam_resctrl_mon(r, QOS_MBM_TOTAL_EVENT_ID);
if (!mon->class)
return;
@@ -181,9 +190,9 @@ static void mpam_resctrl_monitor_sync_abmc_vals(struct rdt_resource *l3)
if (!mon->assigned_counters)
return;
- l3->mon.num_mbm_cntrs = mon->class->props.num_mbwu_mon;
+ r->mon.num_mbm_cntrs = mon->class->props.num_mbwu_mon;
if (cdp_enabled)
- l3->mon.num_mbm_cntrs /= 2;
+ r->mon.num_mbm_cntrs /= 2;
/*
* Continue as normal even if enabling cdp causes there to be
@@ -381,9 +390,10 @@ struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
return &mpam_resctrl_controls[l].resctrl_res;
}
-static int resctrl_arch_mon_ctx_alloc_no_wait(enum resctrl_event_id evtid)
+static int resctrl_arch_mon_ctx_alloc_no_wait(struct rdt_resource *r,
+ enum resctrl_event_id evtid)
{
- struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid];
+ struct mpam_resctrl_mon *mon = mpam_resctrl_mon(r, evtid);
if (!mpam_is_enabled())
return -EINVAL;
@@ -416,7 +426,7 @@ void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r,
do {
prepare_to_wait(&resctrl_mon_ctx_waiters, &wait,
TASK_INTERRUPTIBLE);
- *ret = resctrl_arch_mon_ctx_alloc_no_wait(evtid);
+ *ret = resctrl_arch_mon_ctx_alloc_no_wait(r, evtid);
if (*ret == -ENOSPC)
schedule();
} while (*ret == -ENOSPC && !signal_pending(current));
@@ -425,10 +435,11 @@ void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r,
return ret;
}
-static void resctrl_arch_mon_ctx_free_no_wait(enum resctrl_event_id evtid,
+static void resctrl_arch_mon_ctx_free_no_wait(struct rdt_resource *r,
+ enum resctrl_event_id evtid,
u32 mon_idx)
{
- struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid];
+ struct mpam_resctrl_mon *mon = mpam_resctrl_mon(r, evtid);
if (!mpam_is_enabled())
return;
@@ -449,7 +460,7 @@ void resctrl_arch_mon_ctx_free(struct rdt_resource *r,
kfree(arch_mon_ctx);
- resctrl_arch_mon_ctx_free_no_wait(evtid, mon_idx);
+ resctrl_arch_mon_ctx_free_no_wait(r, evtid, mon_idx);
}
static int __read_mon(struct mpam_resctrl_mon *mon, struct mpam_component *mon_comp,
@@ -523,7 +534,7 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain_hdr *hdr,
struct mpam_component *mon_comp;
u32 mon_idx = *(u32 *)arch_mon_ctx;
enum mpam_device_features mon_type;
- struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[eventid];
+ struct mpam_resctrl_mon *mon = mpam_resctrl_mon(r, eventid);
resctrl_arch_rmid_read_context_check();
@@ -550,7 +561,7 @@ int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
u32 closid, u32 rmid, int mon_idx,
enum resctrl_event_id eventid, u64 *val)
{
- struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[eventid];
+ struct mpam_resctrl_mon *mon = mpam_resctrl_mon(r, eventid);
struct mpam_resctrl_dom *l3_dom;
struct mpam_component *mon_comp;
@@ -607,7 +618,7 @@ void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d
u32 closid, u32 rmid, int cntr_id,
enum resctrl_event_id eventid)
{
- struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[eventid];
+ struct mpam_resctrl_mon *mon = mpam_resctrl_mon(r, eventid);
struct mpam_resctrl_dom *l3_dom;
struct mpam_component *mon_comp;
@@ -1079,10 +1090,11 @@ static int *__alloc_mbwu_array(struct mpam_class *class, u16 num_mbwu_mon)
return_ptr(array);
}
-static void counter_update_class(enum resctrl_event_id evt_id,
+static void counter_update_class(enum resctrl_res_level rid,
+ enum resctrl_event_id evt_id,
struct mpam_class *class)
{
- struct mpam_class *existing_class = mpam_resctrl_counters[evt_id].class;
+ struct mpam_class *existing_class = mpam_resctrl_mon_by_rid(rid, evt_id)->class;
if (existing_class) {
if (existing_class->level == 3) {
@@ -1097,7 +1109,7 @@ static void counter_update_class(enum resctrl_event_id evt_id,
}
}
- mpam_resctrl_counters[evt_id].class = class;
+ mpam_resctrl_mon_by_rid(rid, evt_id)->class = class;
}
static void mpam_resctrl_pick_counters(void)
@@ -1131,7 +1143,7 @@ static void mpam_resctrl_pick_counters(void)
if (update_rmid_limits(class))
break;
- counter_update_class(QOS_OCCUP_EVENT_ID, class);
+ counter_update_class(RDT_RESOURCE_L3, QOS_OCCUP_EVENT_ID, class);
break;
default:
break;
@@ -1153,7 +1165,7 @@ static void mpam_resctrl_pick_counters(void)
* and it's equivalent to mbm_total and so always use
* mbm_total.
*/
- counter_update_class(QOS_MBM_TOTAL_EVENT_ID, class);
+ counter_update_class(RDT_RESOURCE_L3, QOS_MBM_TOTAL_EVENT_ID, class);
}
}
}
@@ -1178,7 +1190,7 @@ void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *
enum resctrl_event_id evtid, u32 rmid, u32 closid,
u32 cntr_id, bool assign)
{
- struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid];
+ struct mpam_resctrl_mon *mon = mpam_resctrl_mon(r, evtid);
if (evtid != QOS_MBM_TOTAL_EVENT_ID) {
pr_debug("unexpected event id\n");
@@ -1281,11 +1293,10 @@ static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
* This must run after all event counters have been picked so that any free
* running counters have already been allocated.
*/
-static int mpam_resctrl_monitor_init_abmc(struct mpam_resctrl_mon *mon)
+static int mpam_resctrl_monitor_init_abmc(struct rdt_resource *r,
+ struct mpam_resctrl_mon *mon)
{
- struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
size_t num_rmid = resctrl_arch_system_num_rmid_idx();
- struct rdt_resource *l3 = &res->resctrl_res;
struct mpam_class *class = mon->class;
u16 num_mbwu_mon;
int *cntrs;
@@ -1304,21 +1315,22 @@ static int mpam_resctrl_monitor_init_abmc(struct mpam_resctrl_mon *mon)
mon->assigned_counters = cntrs;
mon->mbwu_idx_to_mon = no_free_ptr(rmid_array);
- l3->mon.mbm_cntr_assignable = true;
- l3->mon.mbm_assign_on_mkdir = true;
- l3->mon.mbm_cntr_configurable = false;
- l3->mon.mbm_cntr_assign_fixed = true;
+ r->mon.mbm_cntr_assignable = true;
+ r->mon.mbm_assign_on_mkdir = true;
+ r->mon.mbm_cntr_configurable = false;
+ r->mon.mbm_cntr_assign_fixed = true;
- mpam_resctrl_monitor_sync_abmc_vals(l3);
+ mpam_resctrl_monitor_sync_abmc_vals(r);
return 0;
}
-static int mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
+static int mpam_resctrl_monitor_init(struct rdt_resource *r,
enum resctrl_event_id type)
{
- struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
- struct rdt_resource *l3 = &res->resctrl_res;
+ struct mpam_resctrl_res *res = container_of(r, struct mpam_resctrl_res,
+ resctrl_res);
+ struct mpam_resctrl_mon *mon = mpam_resctrl_mon(r, type);
lockdep_assert_cpus_held();
@@ -1337,7 +1349,7 @@ static int mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
*/
if (!res->class) {
pr_warn_once("Faking L3 MSC to enable counters.\n");
- res->class = mpam_resctrl_counters[type].class;
+ res->class = mon->class;
}
/*
@@ -1345,8 +1357,8 @@ static int mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
* monitoring class.
* Setting name is necessary on monitor only platforms.
*/
- l3->name = "L3";
- l3->mon_scope = RESCTRL_L3_CACHE;
+ r->name = "L3";
+ r->mon_scope = RESCTRL_L3_CACHE;
/*
* num-rmid is the upper bound for the number of monitoring groups that
@@ -1356,23 +1368,23 @@ static int mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
* this does mean userspace needs to know the architecture to correctly
* interpret this value.
*/
- l3->mon.num_rmid = resctrl_arch_system_num_rmid_idx();
+ r->mon.num_rmid = resctrl_arch_system_num_rmid_idx();
if (type == QOS_MBM_TOTAL_EVENT_ID) {
int err;
- err = mpam_resctrl_monitor_init_abmc(mon);
+ err = mpam_resctrl_monitor_init_abmc(r, mon);
if (err)
return err;
static_assert(MAX_EVT_CONFIG_BITS == 0x7f);
- l3->mon.mbm_cfg_mask = MAX_EVT_CONFIG_BITS;
+ r->mon.mbm_cfg_mask = MAX_EVT_CONFIG_BITS;
}
if (!resctrl_enable_mon_event(type, false, 0, NULL))
return -EINVAL;
- l3->mon_capable = true;
+ r->mon_capable = true;
return 0;
}
@@ -1683,7 +1695,7 @@ mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
* overlapping CPUs and set up the dom->mon_comp array.
*/
- for_each_mpam_resctrl_mon(mon, eventid) {
+ for_each_mpam_resctrl_mon(mon, r, eventid) {
struct mpam_component *mon_comp;
if (!mon->class)
@@ -1859,11 +1871,12 @@ void mpam_resctrl_offline_cpu(unsigned int cpu)
int mpam_resctrl_setup(void)
{
- int err = 0;
+ enum resctrl_event_id eventid;
struct mpam_resctrl_res *res;
- enum resctrl_res_level rid;
struct mpam_resctrl_mon *mon;
- enum resctrl_event_id eventid;
+ enum resctrl_res_level rid;
+ struct rdt_resource *r;
+ int err = 0;
wait_event(wait_cacheinfo_ready, cacheinfo_ready);
@@ -1893,14 +1906,16 @@ int mpam_resctrl_setup(void)
/* Find some classes to use for monitors */
mpam_resctrl_pick_counters();
- for_each_mpam_resctrl_mon(mon, eventid) {
- if (!mon->class)
- continue; // dummy resource
+ for_each_rdt_resource(r) {
+ for_each_mpam_resctrl_mon(mon, r, eventid) {
+ if (!mon->class)
+ continue; // dummy resource
- err = mpam_resctrl_monitor_init(mon, eventid);
- if (err) {
- pr_debug("Failed to initialise event %u\n", eventid);
- goto internal_error;
+ err = mpam_resctrl_monitor_init(r, eventid);
+ if (err) {
+ pr_debug("Failed to initialise event %u\n", eventid);
+ goto internal_error;
+ }
}
}
@@ -1954,10 +1969,11 @@ static void mpam_resctrl_teardown_mon(struct mpam_resctrl_mon *mon, struct mpam_
void mpam_resctrl_teardown_class(struct mpam_class *class)
{
+ enum resctrl_event_id eventid;
+ struct mpam_resctrl_mon *mon;
struct mpam_resctrl_res *res;
enum resctrl_res_level rid;
- struct mpam_resctrl_mon *mon;
- enum resctrl_event_id eventid;
+ struct rdt_resource *r;
might_sleep();
@@ -1965,10 +1981,12 @@ void mpam_resctrl_teardown_class(struct mpam_class *class)
if (res->class == class)
res->class = NULL;
}
- for_each_mpam_resctrl_mon(mon, eventid) {
- if (mon->class == class) {
- mon->class = NULL;
+ for_each_rdt_resource(r) {
+ for_each_mpam_resctrl_mon(mon, r, eventid) {
+ if (mon->class != class)
+ continue;
+ mon->class = NULL;
mpam_resctrl_teardown_mon(mon, class);
}
}
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 08/19] arm_mpam: resctrl: Halve the monitor counts of every resource on CDP
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
` (6 preceding siblings ...)
2026-10-29 12:35 ` [RFC PATCH v2 07/19] arm_mpam: resctrl: Index monitor state by resource and event Jinjie Ruan
@ 2026-10-29 12:36 ` Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 09/19] x86,fs/resctrl: Pass the resource to the monitor event helpers Jinjie Ruan
` (11 subsequent siblings)
19 siblings, 0 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:36 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
CDP uses two PARTIDs per closid, which halves the number of monitoring
groups. resctrl_arch_set_cdp_enabled() only updates num_rmid and the
assignable counter count of the L3.
Update both counts for every resource that can monitor. Only the L3 has
monitors so far, so the counts do not change yet.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
drivers/resctrl/mpam_resctrl.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index abd4fbca48ab..2f1be12ec461 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -203,8 +203,7 @@ static void mpam_resctrl_monitor_sync_abmc_vals(struct rdt_resource *r)
int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
{
u32 partid_i = RESCTRL_RESERVED_CLOSID, partid_d = RESCTRL_RESERVED_CLOSID;
- struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
- struct rdt_resource *l3 = &res->resctrl_res;
+ struct rdt_resource *r;
int cpu;
if (!IS_ENABLED(CONFIG_EXPERT) && enable) {
@@ -238,11 +237,6 @@ int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
cdp_enabled = enable;
mpam_resctrl_controls[rid].cdp_enabled = enable;
- if (enable)
- l3->mon.num_rmid = resctrl_arch_system_num_rmid_idx() / 2;
- else
- l3->mon.num_rmid = resctrl_arch_system_num_rmid_idx();
-
/* The mbw_max feature can't hide cdp as it's a per-partid maximum. */
if (cdp_enabled && !mpam_resctrl_controls[RDT_RESOURCE_MBA].cdp_enabled)
mpam_resctrl_controls[RDT_RESOURCE_MBA].resctrl_res.alloc_capable = false;
@@ -263,7 +257,14 @@ int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
WRITE_ONCE(arm64_mpam_global_default, mpam_get_regval(current));
resctrl_reset_task_closids();
- mpam_resctrl_monitor_sync_abmc_vals(l3);
+
+ /* Each PARTID is split in two, which halves every monitor resource */
+ for_each_mon_capable_rdt_resource(r) {
+ r->mon.num_rmid = resctrl_arch_system_num_rmid_idx();
+ if (cdp_enabled)
+ r->mon.num_rmid /= 2;
+ mpam_resctrl_monitor_sync_abmc_vals(r);
+ }
for_each_possible_cpu(cpu)
mpam_set_cpu_defaults(cpu, partid_d, partid_i, 0, 0);
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 09/19] x86,fs/resctrl: Pass the resource to the monitor event helpers
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
` (7 preceding siblings ...)
2026-10-29 12:36 ` [RFC PATCH v2 08/19] arm_mpam: resctrl: Halve the monitor counts of every resource on CDP Jinjie Ruan
@ 2026-10-29 12:36 ` Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 10/19] fs/resctrl: Track monitor events per resource Jinjie Ruan
` (10 subsequent siblings)
19 siblings, 0 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:36 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
L2 and L3 caches support the same monitor event types, so the event
ID alone no longer says which resource an event belongs to.
So add the resource as an argument to below helper:
- resctrl_enable_mon_event()
- resctrl_is_mon_event_enabled()
- resctrl_get_mon_evt_cfg()
Code that only needs to know whether any resource has an event
uses the new resctrl_is_mon_event_enabled_any().
No functional change.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
arch/x86/kernel/cpu/resctrl/core.c | 9 +--
arch/x86/kernel/cpu/resctrl/intel_aet.c | 2 +-
arch/x86/kernel/cpu/resctrl/monitor.c | 4 +-
drivers/resctrl/mpam_resctrl.c | 2 +-
fs/resctrl/ctrlmondata.c | 5 +-
fs/resctrl/internal.h | 2 +
fs/resctrl/monitor.c | 74 ++++++++++++++++---------
fs/resctrl/rdtgroup.c | 34 ++++++------
include/linux/resctrl.h | 9 ++-
9 files changed, 84 insertions(+), 57 deletions(-)
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index 8842e3406ca5..f9fa9241bb16 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -433,12 +433,13 @@ static int domain_setup_ctrlval(struct rdt_resource *r, struct rdt_ctrl_domain *
*/
static int l3_mon_domain_mbm_alloc(u32 num_rmid, struct rdt_hw_l3_mon_domain *hw_dom)
{
+ struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
size_t tsize = sizeof(*hw_dom->arch_mbm_states[0]);
enum resctrl_event_id eventid;
int idx;
for_each_mbm_event_id(eventid) {
- if (!resctrl_is_mon_event_enabled(eventid))
+ if (!resctrl_is_mon_event_enabled(r, eventid))
continue;
idx = MBM_STATE_IDX(eventid);
hw_dom->arch_mbm_states[idx] = kcalloc(num_rmid, tsize, GFP_KERNEL);
@@ -969,15 +970,15 @@ static __init bool get_rdt_mon_resources(void)
bool ret = false;
if (rdt_cpu_has(X86_FEATURE_CQM_OCCUP_LLC)) {
- resctrl_enable_mon_event(QOS_OCCUP_EVENT_ID, false, 0, NULL);
+ resctrl_enable_mon_event(r, QOS_OCCUP_EVENT_ID, false, 0, NULL);
ret = true;
}
if (rdt_cpu_has(X86_FEATURE_CQM_MBM_TOTAL)) {
- resctrl_enable_mon_event(QOS_MBM_TOTAL_EVENT_ID, false, 0, NULL);
+ resctrl_enable_mon_event(r, QOS_MBM_TOTAL_EVENT_ID, false, 0, NULL);
ret = true;
}
if (rdt_cpu_has(X86_FEATURE_CQM_MBM_LOCAL)) {
- resctrl_enable_mon_event(QOS_MBM_LOCAL_EVENT_ID, false, 0, NULL);
+ resctrl_enable_mon_event(r, QOS_MBM_LOCAL_EVENT_ID, false, 0, NULL);
ret = true;
}
if (rdt_cpu_has(X86_FEATURE_ABMC))
diff --git a/arch/x86/kernel/cpu/resctrl/intel_aet.c b/arch/x86/kernel/cpu/resctrl/intel_aet.c
index 66cd8c2c7a51..a5978019a48c 100644
--- a/arch/x86/kernel/cpu/resctrl/intel_aet.c
+++ b/arch/x86/kernel/cpu/resctrl/intel_aet.c
@@ -290,7 +290,7 @@ static bool enable_events(struct event_group *e, struct pmt_feature_group *p)
}
for (int j = 0; j < e->num_events; j++) {
- if (!resctrl_enable_mon_event(e->evts[j].id, true,
+ if (!resctrl_enable_mon_event(r, e->evts[j].id, true,
e->evts[j].bin_bits, &e->evts[j]))
skipped_events++;
}
diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c
index 3838e0a13d36..b39950e08580 100644
--- a/arch/x86/kernel/cpu/resctrl/monitor.c
+++ b/arch/x86/kernel/cpu/resctrl/monitor.c
@@ -202,7 +202,7 @@ void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_l3_mon_domai
int idx;
for_each_mbm_event_id(eventid) {
- if (!resctrl_is_mon_event_enabled(eventid))
+ if (!resctrl_is_mon_event_enabled(r, eventid))
continue;
idx = MBM_STATE_IDX(eventid);
memset(hw_dom->arch_mbm_states[idx], 0,
@@ -561,7 +561,7 @@ void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *
abmc_cfg.split.cntr_id = cntr_id;
abmc_cfg.split.bw_src = rmid;
if (assign)
- abmc_cfg.split.bw_type = resctrl_get_mon_evt_cfg(evtid);
+ abmc_cfg.split.bw_type = resctrl_get_mon_evt_cfg(r, evtid);
smp_call_function_any(&d->hdr.cpu_mask, resctrl_abmc_config_one_amd, &abmc_cfg, 1);
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 2f1be12ec461..9779cef5dc04 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -1382,7 +1382,7 @@ static int mpam_resctrl_monitor_init(struct rdt_resource *r,
r->mon.mbm_cfg_mask = MAX_EVT_CONFIG_BITS;
}
- if (!resctrl_enable_mon_event(type, false, 0, NULL))
+ if (!resctrl_enable_mon_event(r, type, false, 0, NULL))
return -EINVAL;
r->mon_capable = true;
diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c
index c70a9939d126..2503970a1479 100644
--- a/fs/resctrl/ctrlmondata.c
+++ b/fs/resctrl/ctrlmondata.c
@@ -465,6 +465,7 @@ static int smp_mon_event_count(void *arg)
ssize_t rdtgroup_mba_mbps_event_write(struct kernfs_open_file *of,
char *buf, size_t nbytes, loff_t off)
{
+ struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
struct rdtgroup *rdtgrp;
int ret = 0;
@@ -484,12 +485,12 @@ ssize_t rdtgroup_mba_mbps_event_write(struct kernfs_open_file *of,
buf[nbytes - 1] = '\0';
if (!strcmp(buf, "mbm_local_bytes")) {
- if (resctrl_is_mon_event_enabled(QOS_MBM_LOCAL_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(r, QOS_MBM_LOCAL_EVENT_ID))
rdtgrp->mba_mbps_event = QOS_MBM_LOCAL_EVENT_ID;
else
ret = -EINVAL;
} else if (!strcmp(buf, "mbm_total_bytes")) {
- if (resctrl_is_mon_event_enabled(QOS_MBM_TOTAL_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(r, QOS_MBM_TOTAL_EVENT_ID))
rdtgrp->mba_mbps_event = QOS_MBM_TOTAL_EVENT_ID;
else
ret = -EINVAL;
diff --git a/fs/resctrl/internal.h b/fs/resctrl/internal.h
index e62a277dee85..0368e19df24a 100644
--- a/fs/resctrl/internal.h
+++ b/fs/resctrl/internal.h
@@ -85,6 +85,8 @@ struct mon_evt {
extern struct mon_evt mon_event_all[QOS_NUM_EVENTS];
+bool resctrl_is_mon_event_enabled_any(enum resctrl_event_id eventid);
+
#define for_each_mon_event(mevt) for (mevt = &mon_event_all[QOS_FIRST_EVENT]; \
mevt < &mon_event_all[QOS_NUM_EVENTS]; mevt++)
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index b9c99c71f4f9..a19733fae36e 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -345,7 +345,7 @@ void free_rmid(u32 closid, u32 rmid)
entry = __rmid_entry(idx);
- if (resctrl_is_mon_event_enabled(QOS_OCCUP_EVENT_ID))
+ if (resctrl_is_mon_event_enabled_any(QOS_OCCUP_EVENT_ID))
add_rmid_to_limbo(entry);
else
list_add_tail(&entry->list, &rmid_free_lru);
@@ -797,15 +797,16 @@ static void mbm_update_one_event(struct rdt_resource *r, struct rdt_l3_mon_domai
static void mbm_update(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
struct rdtgroup *rdtgrp)
{
+ enum resctrl_event_id evtid;
+
/*
* This is protected from concurrent reads from user as both
* the user and overflow handler hold the global mutex.
*/
- if (resctrl_is_mon_event_enabled(QOS_MBM_TOTAL_EVENT_ID))
- mbm_update_one_event(r, d, rdtgrp, QOS_MBM_TOTAL_EVENT_ID);
-
- if (resctrl_is_mon_event_enabled(QOS_MBM_LOCAL_EVENT_ID))
- mbm_update_one_event(r, d, rdtgrp, QOS_MBM_LOCAL_EVENT_ID);
+ for_each_mbm_event_id(evtid) {
+ if (resctrl_is_mon_event_enabled(r, evtid))
+ mbm_update_one_event(r, d, rdtgrp, evtid);
+ }
}
/*
@@ -1045,36 +1046,55 @@ struct mon_evt mon_event_all[QOS_NUM_EVENTS] = {
MON_EVENT(PMT_EVENT_PCNT, "pcnt", RDT_RESOURCE_PERF_PKG, false),
};
-bool resctrl_enable_mon_event(enum resctrl_event_id eventid, bool any_cpu,
+bool resctrl_enable_mon_event(struct rdt_resource *r,
+ enum resctrl_event_id eventid, bool any_cpu,
unsigned int binary_bits, void *arch_priv)
{
+ struct mon_evt *mevt;
+
if (WARN_ON_ONCE(eventid < QOS_FIRST_EVENT || eventid >= QOS_NUM_EVENTS ||
binary_bits > MAX_BINARY_BITS))
return false;
- if (mon_event_all[eventid].enabled) {
- pr_warn("Duplicate enable for event %d\n", eventid);
+
+ mevt = &mon_event_all[eventid];
+ if (mevt->enabled) {
+ pr_warn("Duplicate enable for event %d on resource %d\n",
+ eventid, r->rid);
return false;
}
- if (binary_bits && !mon_event_all[eventid].is_floating_point) {
+ if (binary_bits && !mevt->is_floating_point) {
pr_warn("Event %d may not be floating point\n", eventid);
return false;
}
- mon_event_all[eventid].any_cpu = any_cpu;
- mon_event_all[eventid].binary_bits = binary_bits;
- mon_event_all[eventid].arch_priv = arch_priv;
- mon_event_all[eventid].enabled = true;
+ mevt->any_cpu = any_cpu;
+ mevt->binary_bits = binary_bits;
+ mevt->arch_priv = arch_priv;
+ mevt->enabled = true;
return true;
}
-bool resctrl_is_mon_event_enabled(enum resctrl_event_id eventid)
+bool resctrl_is_mon_event_enabled(struct rdt_resource *r,
+ enum resctrl_event_id eventid)
{
return eventid >= QOS_FIRST_EVENT && eventid < QOS_NUM_EVENTS &&
mon_event_all[eventid].enabled;
}
-u32 resctrl_get_mon_evt_cfg(enum resctrl_event_id evtid)
+bool resctrl_is_mon_event_enabled_any(enum resctrl_event_id eventid)
+{
+ struct rdt_resource *r;
+
+ for_each_mon_capable_rdt_resource(r) {
+ if (resctrl_is_mon_event_enabled(r, eventid))
+ return true;
+ }
+
+ return false;
+}
+
+u32 resctrl_get_mon_evt_cfg(struct rdt_resource *r, enum resctrl_event_id evtid)
{
return mon_event_all[evtid].evt_cfg;
}
@@ -1210,7 +1230,7 @@ static void resctrl_reset_rmid_all(struct rdt_resource *r, struct rdt_l3_mon_dom
int idx;
for_each_mbm_event_id(evt) {
- if (!resctrl_is_mon_event_enabled(evt))
+ if (!resctrl_is_mon_event_enabled(r, evt))
continue;
idx = MBM_STATE_IDX(evt);
memset(d->mbm_states[idx], 0, sizeof(*d->mbm_states[0]) * idx_limit);
@@ -1319,11 +1339,11 @@ void rdtgroup_assign_cntrs(struct rdtgroup *rdtgrp)
!r->mon.mbm_assign_on_mkdir)
return;
- if (resctrl_is_mon_event_enabled(QOS_MBM_TOTAL_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(r, QOS_MBM_TOTAL_EVENT_ID))
rdtgroup_assign_cntr_event(NULL, rdtgrp,
&mon_event_all[QOS_MBM_TOTAL_EVENT_ID]);
- if (resctrl_is_mon_event_enabled(QOS_MBM_LOCAL_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(r, QOS_MBM_LOCAL_EVENT_ID))
rdtgroup_assign_cntr_event(NULL, rdtgrp,
&mon_event_all[QOS_MBM_LOCAL_EVENT_ID]);
}
@@ -1377,11 +1397,11 @@ void rdtgroup_unassign_cntrs(struct rdtgroup *rdtgrp)
if (!r->mon_capable || !resctrl_arch_mbm_cntr_assign_enabled(r))
return;
- if (resctrl_is_mon_event_enabled(QOS_MBM_TOTAL_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(r, QOS_MBM_TOTAL_EVENT_ID))
rdtgroup_unassign_cntr_event(NULL, rdtgrp,
&mon_event_all[QOS_MBM_TOTAL_EVENT_ID]);
- if (resctrl_is_mon_event_enabled(QOS_MBM_LOCAL_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(r, QOS_MBM_LOCAL_EVENT_ID))
rdtgroup_unassign_cntr_event(NULL, rdtgrp,
&mon_event_all[QOS_MBM_LOCAL_EVENT_ID]);
}
@@ -1594,9 +1614,9 @@ ssize_t resctrl_mbm_assign_mode_write(struct kernfs_open_file *of, char *buf,
* Initialize the default memory transaction values for
* total and local events.
*/
- if (resctrl_is_mon_event_enabled(QOS_MBM_TOTAL_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(r, QOS_MBM_TOTAL_EVENT_ID))
mon_event_all[QOS_MBM_TOTAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask;
- if (resctrl_is_mon_event_enabled(QOS_MBM_LOCAL_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(r, QOS_MBM_LOCAL_EVENT_ID))
mon_event_all[QOS_MBM_LOCAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask &
(READS_TO_LOCAL_MEM |
READS_TO_LOCAL_S_MEM |
@@ -1947,15 +1967,15 @@ int resctrl_l3_mon_resource_init(void)
RFTYPE_MON_INFO | RFTYPE_RES_CACHE);
}
- if (resctrl_is_mon_event_enabled(QOS_MBM_LOCAL_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(r, QOS_MBM_LOCAL_EVENT_ID))
mba_mbps_default_event = QOS_MBM_LOCAL_EVENT_ID;
- else if (resctrl_is_mon_event_enabled(QOS_MBM_TOTAL_EVENT_ID))
+ else if (resctrl_is_mon_event_enabled(r, QOS_MBM_TOTAL_EVENT_ID))
mba_mbps_default_event = QOS_MBM_TOTAL_EVENT_ID;
if (r->mon.mbm_cntr_assignable) {
- if (resctrl_is_mon_event_enabled(QOS_MBM_TOTAL_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(r, QOS_MBM_TOTAL_EVENT_ID))
mon_event_all[QOS_MBM_TOTAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask;
- if (resctrl_is_mon_event_enabled(QOS_MBM_LOCAL_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(r, QOS_MBM_LOCAL_EVENT_ID))
mon_event_all[QOS_MBM_LOCAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask &
(READS_TO_LOCAL_MEM |
READS_TO_LOCAL_S_MEM |
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 92f0e3b68784..5804921c57c8 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -122,10 +122,10 @@ void rdt_staged_configs_clear(void)
}
}
-static bool resctrl_is_mbm_enabled(void)
+static bool resctrl_is_mbm_enabled(struct rdt_resource *r)
{
- return (resctrl_is_mon_event_enabled(QOS_MBM_TOTAL_EVENT_ID) ||
- resctrl_is_mon_event_enabled(QOS_MBM_LOCAL_EVENT_ID));
+ return (resctrl_is_mon_event_enabled(r, QOS_MBM_TOTAL_EVENT_ID) ||
+ resctrl_is_mon_event_enabled(r, QOS_MBM_LOCAL_EVENT_ID));
}
/*
@@ -191,7 +191,7 @@ static int closid_alloc(void)
lockdep_assert_held(&rdtgroup_mutex);
if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID) &&
- resctrl_is_mon_event_enabled(QOS_OCCUP_EVENT_ID)) {
+ resctrl_is_mon_event_enabled_any(QOS_OCCUP_EVENT_ID)) {
cleanest_closid = resctrl_find_cleanest_closid();
if (cleanest_closid < 0)
return cleanest_closid;
@@ -2620,7 +2620,7 @@ static bool supports_mba_mbps(void)
struct rdt_resource *rmbm = resctrl_arch_get_resource(RDT_RESOURCE_L3);
struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_MBA);
- return (resctrl_is_mbm_enabled() &&
+ return (resctrl_is_mbm_enabled(rmbm) &&
r->alloc_capable && is_mba_linear() &&
r->ctrl_scope == rmbm->mon_scope &&
!rmbm->mon.mbm_cntr_assignable);
@@ -3254,8 +3254,8 @@ static int rdt_get_tree(struct fs_context *fc)
if (resctrl_arch_alloc_capable() || resctrl_arch_mon_capable())
resctrl_mounted = true;
- if (resctrl_is_mbm_enabled()) {
- r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
+ r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
+ if (resctrl_is_mbm_enabled(r)) {
list_for_each_entry_rcu(dom, &r->mon_domains, hdr.list, lockdep_is_cpus_held())
mbm_setup_overflow_handler(dom, MBM_OVERFLOW_INTERVAL,
RESCTRL_PICK_ANY_CPU);
@@ -4559,9 +4559,9 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *h
if (r->rid == RDT_RESOURCE_L3 &&
domain_header_is_valid(hdr, RESCTRL_MON_DOMAIN, RDT_RESOURCE_L3)) {
d = container_of(hdr, struct rdt_l3_mon_domain, hdr);
- if (resctrl_is_mbm_enabled())
+ if (resctrl_is_mbm_enabled(r))
cancel_delayed_work_sync(&d->mbm_over);
- if (resctrl_is_mon_event_enabled(QOS_OCCUP_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(r, QOS_OCCUP_EVENT_ID))
cancel_delayed_work_sync(&d->cqm_limbo);
}
@@ -4581,7 +4581,7 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *h
goto out_unlock;
d = container_of(hdr, struct rdt_l3_mon_domain, hdr);
- if (resctrl_is_mon_event_enabled(QOS_OCCUP_EVENT_ID) && has_busy_rmid(d)) {
+ if (resctrl_is_mon_event_enabled(r, QOS_OCCUP_EVENT_ID) && has_busy_rmid(d)) {
/*
* When a package is going down, forcefully
* decrement rmid->ebusy. There is no way to know
@@ -4624,14 +4624,14 @@ static int domain_setup_l3_mon_state(struct rdt_resource *r, struct rdt_l3_mon_d
enum resctrl_event_id eventid;
int idx;
- if (resctrl_is_mon_event_enabled(QOS_OCCUP_EVENT_ID)) {
+ if (resctrl_is_mon_event_enabled(r, QOS_OCCUP_EVENT_ID)) {
d->rmid_busy_llc = bitmap_zalloc(idx_limit, GFP_KERNEL);
if (!d->rmid_busy_llc)
return -ENOMEM;
}
for_each_mbm_event_id(eventid) {
- if (!resctrl_is_mon_event_enabled(eventid))
+ if (!resctrl_is_mon_event_enabled(r, eventid))
continue;
idx = MBM_STATE_IDX(eventid);
d->mbm_states[idx] = kcalloc(idx_limit, tsize, GFP_KERNEL);
@@ -4639,7 +4639,7 @@ static int domain_setup_l3_mon_state(struct rdt_resource *r, struct rdt_l3_mon_d
goto cleanup;
}
- if (resctrl_is_mbm_enabled() && r->mon.mbm_cntr_assignable) {
+ if (resctrl_is_mbm_enabled(r) && r->mon.mbm_cntr_assignable) {
tsize = sizeof(*d->cntr_cfg);
d->cntr_cfg = kcalloc(r->mon.num_mbm_cntrs, tsize, GFP_KERNEL);
if (!d->cntr_cfg)
@@ -4691,13 +4691,13 @@ int resctrl_online_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *hdr
if (err)
goto out_unlock;
- if (resctrl_is_mbm_enabled()) {
+ if (resctrl_is_mbm_enabled(r)) {
INIT_DELAYED_WORK(&d->mbm_over, mbm_handle_overflow);
mbm_setup_overflow_handler(d, MBM_OVERFLOW_INTERVAL,
RESCTRL_PICK_ANY_CPU);
}
- if (resctrl_is_mon_event_enabled(QOS_OCCUP_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(r, QOS_OCCUP_EVENT_ID))
INIT_DELAYED_WORK(&d->cqm_limbo, cqm_handle_limbo);
mkdir:
@@ -4770,13 +4770,13 @@ void resctrl_offline_cpu(unsigned int cpu)
d = get_mon_domain_from_cpu(cpu, l3);
if (d) {
- if (resctrl_is_mbm_enabled() && cpu == d->mbm_work_cpu) {
+ if (resctrl_is_mbm_enabled(l3) && cpu == d->mbm_work_cpu) {
mutex_unlock(&rdtgroup_mutex);
cancel_delayed_work_sync(&d->mbm_over);
mutex_lock(&rdtgroup_mutex);
mbm_setup_overflow_handler(d, 0, cpu);
}
- if (resctrl_is_mon_event_enabled(QOS_OCCUP_EVENT_ID) &&
+ if (resctrl_is_mon_event_enabled(l3, QOS_OCCUP_EVENT_ID) &&
cpu == d->cqm_work_cpu && has_busy_rmid(d)) {
mutex_unlock(&rdtgroup_mutex);
cancel_delayed_work_sync(&d->cqm_limbo);
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index c844f99fb824..0a60372299c5 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -419,10 +419,12 @@ 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);
-bool resctrl_enable_mon_event(enum resctrl_event_id eventid, bool any_cpu,
+bool resctrl_enable_mon_event(struct rdt_resource *r,
+ enum resctrl_event_id eventid, bool any_cpu,
unsigned int binary_bits, void *arch_priv);
-bool resctrl_is_mon_event_enabled(enum resctrl_event_id eventid);
+bool resctrl_is_mon_event_enabled(struct rdt_resource *r,
+ enum resctrl_event_id eventid);
bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt);
@@ -432,7 +434,8 @@ static inline bool resctrl_is_mbm_event(enum resctrl_event_id eventid)
eventid <= QOS_MBM_LOCAL_EVENT_ID);
}
-u32 resctrl_get_mon_evt_cfg(enum resctrl_event_id eventid);
+u32 resctrl_get_mon_evt_cfg(struct rdt_resource *r,
+ enum resctrl_event_id eventid);
/* Iterate over all memory bandwidth events */
#define for_each_mbm_event_id(eventid) \
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 10/19] fs/resctrl: Track monitor events per resource
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
` (8 preceding siblings ...)
2026-10-29 12:36 ` [RFC PATCH v2 09/19] x86,fs/resctrl: Pass the resource to the monitor event helpers Jinjie Ruan
@ 2026-10-29 12:36 ` Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 11/19] fs/resctrl: Add the L2 monitor events Jinjie Ruan
` (9 subsequent siblings)
19 siblings, 0 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:36 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
The event table is indexed by event ID alone, so an event type can only
belong to one resource.
To support L2 monitor event, index it by resource and event ID instead.
Arch code enables events before resctrl can set anything up in the
resource, so look the row up by r->rid. A resource supports an event
when the entry has a name.
No functional change.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
fs/resctrl/internal.h | 7 +--
fs/resctrl/monitor.c | 88 +++++++++++++++++++----------------
fs/resctrl/rdtgroup.c | 12 ++---
include/linux/resctrl_types.h | 7 +--
4 files changed, 62 insertions(+), 52 deletions(-)
diff --git a/fs/resctrl/internal.h b/fs/resctrl/internal.h
index 0368e19df24a..f84152734fd1 100644
--- a/fs/resctrl/internal.h
+++ b/fs/resctrl/internal.h
@@ -83,12 +83,13 @@ struct mon_evt {
void *arch_priv;
};
-extern struct mon_evt mon_event_all[QOS_NUM_EVENTS];
+extern struct mon_evt mon_event_all[RDT_NUM_RESOURCES][QOS_NUM_EVENTS];
bool resctrl_is_mon_event_enabled_any(enum resctrl_event_id eventid);
-#define for_each_mon_event(mevt) for (mevt = &mon_event_all[QOS_FIRST_EVENT]; \
- mevt < &mon_event_all[QOS_NUM_EVENTS]; mevt++)
+#define for_each_mon_event(r, mevt) \
+ for (mevt = &mon_event_all[(r)->rid][QOS_FIRST_EVENT]; \
+ mevt < &mon_event_all[(r)->rid][QOS_NUM_EVENTS]; mevt++)
/* Limit for mon_evt::binary_bits */
#define MAX_BINARY_BITS 27
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index a19733fae36e..9b747b88fd6b 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -141,7 +141,7 @@ void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free)
void *arch_priv;
u64 val = 0;
- arch_priv = mon_event_all[QOS_OCCUP_EVENT_ID].arch_priv;
+ arch_priv = mon_event_all[r->rid][QOS_OCCUP_EVENT_ID].arch_priv;
arch_mon_ctx = resctrl_arch_mon_ctx_alloc(r, QOS_OCCUP_EVENT_ID);
if (IS_ERR(arch_mon_ctx)) {
pr_warn_ratelimited("Failed to allocate monitor context: %pe",
@@ -769,7 +769,7 @@ static void mbm_update_one_event(struct rdt_resource *r, struct rdt_l3_mon_domai
rr.r = r;
rr.hdr = &d->hdr;
- rr.evt = &mon_event_all[evtid];
+ rr.evt = &mon_event_all[r->rid][evtid];
if (resctrl_arch_mbm_cntr_assign_enabled(r)) {
rr.is_mbm_cntr = true;
} else {
@@ -1016,34 +1016,38 @@ void free_rmid_lru_list(void)
mutex_unlock(&rdtgroup_mutex);
}
-#define MON_EVENT(_eventid, _name, _res, _fp) \
+#define MON_EVENT(_eventid, _name, _fp) \
[_eventid] = { \
.name = _name, \
.evtid = _eventid, \
- .rid = _res, \
.is_floating_point = _fp, \
}
/*
- * All available events. Architecture code marks the ones that
- * are supported by a system using resctrl_enable_mon_event()
- * to set .enabled.
+ * All available events, indexed by resource and event type. Architecture
+ * code marks the ones that are supported by a system using
+ * resctrl_enable_mon_event() to set .enabled. A resource supports an event
+ * when the entry has a name.
*/
-struct mon_evt mon_event_all[QOS_NUM_EVENTS] = {
- MON_EVENT(QOS_OCCUP_EVENT_ID, "llc_occupancy", RDT_RESOURCE_L3, false),
- MON_EVENT(QOS_MBM_TOTAL_EVENT_ID, "mbm_total_bytes", RDT_RESOURCE_L3, false),
- MON_EVENT(QOS_MBM_LOCAL_EVENT_ID, "mbm_local_bytes", RDT_RESOURCE_L3, false),
- MON_EVENT(PMT_EVENT_ENERGY, "core_energy", RDT_RESOURCE_PERF_PKG, true),
- MON_EVENT(PMT_EVENT_ACTIVITY, "activity", RDT_RESOURCE_PERF_PKG, true),
- MON_EVENT(PMT_EVENT_STALLS_LLC_HIT, "stalls_llc_hit", RDT_RESOURCE_PERF_PKG, false),
- MON_EVENT(PMT_EVENT_C1_RES, "c1_res", RDT_RESOURCE_PERF_PKG, false),
- MON_EVENT(PMT_EVENT_UNHALTED_CORE_CYCLES, "unhalted_core_cycles", RDT_RESOURCE_PERF_PKG, false),
- MON_EVENT(PMT_EVENT_STALLS_LLC_MISS, "stalls_llc_miss", RDT_RESOURCE_PERF_PKG, false),
- MON_EVENT(PMT_EVENT_AUTO_C6_RES, "c6_res", RDT_RESOURCE_PERF_PKG, false),
- MON_EVENT(PMT_EVENT_UNHALTED_REF_CYCLES, "unhalted_ref_cycles", RDT_RESOURCE_PERF_PKG, false),
- MON_EVENT(PMT_EVENT_UOPS_RETIRED, "uops_retired", RDT_RESOURCE_PERF_PKG, false),
- MON_EVENT(PMT_EVENT_INST_RETIRED, "inst_retired", RDT_RESOURCE_PERF_PKG, false),
- MON_EVENT(PMT_EVENT_PCNT, "pcnt", RDT_RESOURCE_PERF_PKG, false),
+struct mon_evt mon_event_all[RDT_NUM_RESOURCES][QOS_NUM_EVENTS] = {
+ [RDT_RESOURCE_L3] = {
+ MON_EVENT(QOS_OCCUP_EVENT_ID, "llc_occupancy", false),
+ MON_EVENT(QOS_MBM_TOTAL_EVENT_ID, "mbm_total_bytes", false),
+ MON_EVENT(QOS_MBM_LOCAL_EVENT_ID, "mbm_local_bytes", false),
+ },
+ [RDT_RESOURCE_PERF_PKG] = {
+ MON_EVENT(PMT_EVENT_ENERGY, "core_energy", true),
+ MON_EVENT(PMT_EVENT_ACTIVITY, "activity", true),
+ MON_EVENT(PMT_EVENT_STALLS_LLC_HIT, "stalls_llc_hit", false),
+ MON_EVENT(PMT_EVENT_C1_RES, "c1_res", false),
+ MON_EVENT(PMT_EVENT_UNHALTED_CORE_CYCLES, "unhalted_core_cycles", false),
+ MON_EVENT(PMT_EVENT_STALLS_LLC_MISS, "stalls_llc_miss", false),
+ MON_EVENT(PMT_EVENT_AUTO_C6_RES, "c6_res", false),
+ MON_EVENT(PMT_EVENT_UNHALTED_REF_CYCLES, "unhalted_ref_cycles", false),
+ MON_EVENT(PMT_EVENT_UOPS_RETIRED, "uops_retired", false),
+ MON_EVENT(PMT_EVENT_INST_RETIRED, "inst_retired", false),
+ MON_EVENT(PMT_EVENT_PCNT, "pcnt", false),
+ },
};
bool resctrl_enable_mon_event(struct rdt_resource *r,
@@ -1056,7 +1060,11 @@ bool resctrl_enable_mon_event(struct rdt_resource *r,
binary_bits > MAX_BINARY_BITS))
return false;
- mevt = &mon_event_all[eventid];
+ mevt = &mon_event_all[r->rid][eventid];
+ if (!mevt->name) {
+ pr_warn("Resource %d does not support event %d\n", r->rid, eventid);
+ return false;
+ }
if (mevt->enabled) {
pr_warn("Duplicate enable for event %d on resource %d\n",
eventid, r->rid);
@@ -1067,6 +1075,7 @@ bool resctrl_enable_mon_event(struct rdt_resource *r,
return false;
}
+ mevt->rid = r->rid;
mevt->any_cpu = any_cpu;
mevt->binary_bits = binary_bits;
mevt->arch_priv = arch_priv;
@@ -1079,7 +1088,7 @@ bool resctrl_is_mon_event_enabled(struct rdt_resource *r,
enum resctrl_event_id eventid)
{
return eventid >= QOS_FIRST_EVENT && eventid < QOS_NUM_EVENTS &&
- mon_event_all[eventid].enabled;
+ mon_event_all[r->rid][eventid].enabled;
}
bool resctrl_is_mon_event_enabled_any(enum resctrl_event_id eventid)
@@ -1096,7 +1105,7 @@ bool resctrl_is_mon_event_enabled_any(enum resctrl_event_id eventid)
u32 resctrl_get_mon_evt_cfg(struct rdt_resource *r, enum resctrl_event_id evtid)
{
- return mon_event_all[evtid].evt_cfg;
+ return mon_event_all[r->rid][evtid].evt_cfg;
}
/**
@@ -1341,11 +1350,11 @@ void rdtgroup_assign_cntrs(struct rdtgroup *rdtgrp)
if (resctrl_is_mon_event_enabled(r, QOS_MBM_TOTAL_EVENT_ID))
rdtgroup_assign_cntr_event(NULL, rdtgrp,
- &mon_event_all[QOS_MBM_TOTAL_EVENT_ID]);
+ &mon_event_all[r->rid][QOS_MBM_TOTAL_EVENT_ID]);
if (resctrl_is_mon_event_enabled(r, QOS_MBM_LOCAL_EVENT_ID))
rdtgroup_assign_cntr_event(NULL, rdtgrp,
- &mon_event_all[QOS_MBM_LOCAL_EVENT_ID]);
+ &mon_event_all[r->rid][QOS_MBM_LOCAL_EVENT_ID]);
}
/*
@@ -1399,11 +1408,11 @@ void rdtgroup_unassign_cntrs(struct rdtgroup *rdtgrp)
if (resctrl_is_mon_event_enabled(r, QOS_MBM_TOTAL_EVENT_ID))
rdtgroup_unassign_cntr_event(NULL, rdtgrp,
- &mon_event_all[QOS_MBM_TOTAL_EVENT_ID]);
+ &mon_event_all[r->rid][QOS_MBM_TOTAL_EVENT_ID]);
if (resctrl_is_mon_event_enabled(r, QOS_MBM_LOCAL_EVENT_ID))
rdtgroup_unassign_cntr_event(NULL, rdtgrp,
- &mon_event_all[QOS_MBM_LOCAL_EVENT_ID]);
+ &mon_event_all[r->rid][QOS_MBM_LOCAL_EVENT_ID]);
}
static int resctrl_parse_mem_transactions(char *tok, u32 *val)
@@ -1615,9 +1624,9 @@ ssize_t resctrl_mbm_assign_mode_write(struct kernfs_open_file *of, char *buf,
* total and local events.
*/
if (resctrl_is_mon_event_enabled(r, QOS_MBM_TOTAL_EVENT_ID))
- mon_event_all[QOS_MBM_TOTAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask;
+ mon_event_all[r->rid][QOS_MBM_TOTAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask;
if (resctrl_is_mon_event_enabled(r, QOS_MBM_LOCAL_EVENT_ID))
- mon_event_all[QOS_MBM_LOCAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask &
+ mon_event_all[r->rid][QOS_MBM_LOCAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask &
(READS_TO_LOCAL_MEM |
READS_TO_LOCAL_S_MEM |
NON_TEMP_WRITE_TO_LOCAL_MEM);
@@ -1724,8 +1733,8 @@ int mbm_L3_assignments_show(struct kernfs_open_file *of, struct seq_file *s, voi
goto out_unlock;
}
- for_each_mon_event(mevt) {
- if (mevt->rid != r->rid || !mevt->enabled || !resctrl_is_mbm_event(mevt->evtid))
+ for_each_mon_event(r, mevt) {
+ if (!mevt->enabled || !resctrl_is_mbm_event(mevt->evtid))
continue;
sep = false;
@@ -1758,9 +1767,8 @@ static struct mon_evt *mbm_get_mon_event_by_name(struct rdt_resource *r, char *n
{
struct mon_evt *mevt;
- for_each_mon_event(mevt) {
- if (mevt->rid == r->rid && mevt->enabled &&
- resctrl_is_mbm_event(mevt->evtid) &&
+ for_each_mon_event(r, mevt) {
+ if (mevt->enabled && resctrl_is_mbm_event(mevt->evtid) &&
!strcmp(mevt->name, name))
return mevt;
}
@@ -1957,12 +1965,12 @@ int resctrl_l3_mon_resource_init(void)
return ret;
if (resctrl_arch_is_evt_configurable(QOS_MBM_TOTAL_EVENT_ID)) {
- mon_event_all[QOS_MBM_TOTAL_EVENT_ID].configurable = true;
+ mon_event_all[r->rid][QOS_MBM_TOTAL_EVENT_ID].configurable = true;
resctrl_file_fflags_init("mbm_total_bytes_config",
RFTYPE_MON_INFO | RFTYPE_RES_CACHE);
}
if (resctrl_arch_is_evt_configurable(QOS_MBM_LOCAL_EVENT_ID)) {
- mon_event_all[QOS_MBM_LOCAL_EVENT_ID].configurable = true;
+ mon_event_all[r->rid][QOS_MBM_LOCAL_EVENT_ID].configurable = true;
resctrl_file_fflags_init("mbm_local_bytes_config",
RFTYPE_MON_INFO | RFTYPE_RES_CACHE);
}
@@ -1974,9 +1982,9 @@ int resctrl_l3_mon_resource_init(void)
if (r->mon.mbm_cntr_assignable) {
if (resctrl_is_mon_event_enabled(r, QOS_MBM_TOTAL_EVENT_ID))
- mon_event_all[QOS_MBM_TOTAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask;
+ mon_event_all[r->rid][QOS_MBM_TOTAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask;
if (resctrl_is_mon_event_enabled(r, QOS_MBM_LOCAL_EVENT_ID))
- mon_event_all[QOS_MBM_LOCAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask &
+ mon_event_all[r->rid][QOS_MBM_LOCAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask &
(READS_TO_LOCAL_MEM |
READS_TO_LOCAL_S_MEM |
NON_TEMP_WRITE_TO_LOCAL_MEM);
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 5804921c57c8..8154e02b3d1c 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -1208,8 +1208,8 @@ static int rdt_mon_features_show(struct kernfs_open_file *of,
if (!info_kn_lock(of->kn))
return -ENOENT;
- for_each_mon_event(mevt) {
- if (mevt->rid != r->rid || !mevt->enabled)
+ for_each_mon_event(r, mevt) {
+ if (!mevt->enabled)
continue;
seq_printf(seq, "%s\n", mevt->name);
if (mevt->configurable &&
@@ -2426,8 +2426,8 @@ static int resctrl_mkdir_event_configs(struct rdt_resource *r, struct kernfs_nod
if (ret)
return ret;
- for_each_mon_event(mevt) {
- if (mevt->rid != r->rid || !mevt->enabled || !resctrl_is_mbm_event(mevt->evtid))
+ for_each_mon_event(r, mevt) {
+ if (!mevt->enabled || !resctrl_is_mbm_event(mevt->evtid))
continue;
kn_subdir2 = kernfs_create_dir(kn_subdir, mevt->name, kn_subdir->mode, mevt);
@@ -3520,8 +3520,8 @@ static struct kernfs_node *_mkdir_mondata_subdir(struct kernfs_node *parent_kn,
if (ret)
goto out_destroy;
- for_each_mon_event(mevt) {
- if (mevt->rid != r->rid || !mevt->enabled)
+ for_each_mon_event(r, mevt) {
+ if (!mevt->enabled)
continue;
priv = mon_get_kn_priv(r->rid, domid, mevt, !hdr);
if (WARN_ON_ONCE(!priv)) {
diff --git a/include/linux/resctrl_types.h b/include/linux/resctrl_types.h
index d0e56de038f0..307a74d3c928 100644
--- a/include/linux/resctrl_types.h
+++ b/include/linux/resctrl_types.h
@@ -43,9 +43,10 @@ enum resctrl_event_id {
QOS_FIRST_EVENT = 0x01,
/*
- * Monitor event types. The resource an event belongs to is tracked
- * separately. These values match those used to program IA32_QM_EVTSEL
- * before reading IA32_QM_CTR on RDT systems.
+ * Monitor event types. More than one resource may support the same
+ * event type; the resource supplies the scope. These values match
+ * those used to program IA32_QM_EVTSEL before reading IA32_QM_CTR on
+ * RDT systems.
*/
QOS_OCCUP_EVENT_ID = 0x01,
QOS_MBM_TOTAL_EVENT_ID = 0x02,
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 11/19] fs/resctrl: Add the L2 monitor events
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
` (9 preceding siblings ...)
2026-10-29 12:36 ` [RFC PATCH v2 10/19] fs/resctrl: Track monitor events per resource Jinjie Ruan
@ 2026-10-29 12:36 ` Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 12/19] fs/resctrl: Set up MBM state and workers for every monitor resource Jinjie Ruan
` (8 subsequent siblings)
19 siblings, 0 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:36 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
MPAM monitors belong to a cache, and firmware says which level that
cache is. Add the L2 entries to the event table: l2c_occupancy for
occupancy and mbm_core_bytes for bandwidth. They have their own names
because an L2 counts the traffic the cache sees, not memory bandwidth.
Read the L2 events through the same per-domain path as the L3. The L2
has no domains to sum, so a read without a domain fails. The events only
show up once an architecture enables them; x86 never does.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
fs/resctrl/monitor.c | 9 ++++++++-
include/linux/resctrl.h | 2 +-
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index 9b747b88fd6b..3544dd2a983a 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -537,12 +537,15 @@ static int __l3_mon_event_count_sum(struct rdtgroup *rdtgrp, struct rmid_read *r
static int __mon_event_count(struct rdtgroup *rdtgrp, struct rmid_read *rr)
{
switch (rr->r->rid) {
+ case RDT_RESOURCE_L2:
case RDT_RESOURCE_L3:
WARN_ON_ONCE(rr->evt->any_cpu);
if (rr->hdr)
return __mon_event_count_one_domain(rdtgrp, rr);
- else
+ if (rr->r->rid == RDT_RESOURCE_L3)
return __l3_mon_event_count_sum(rdtgrp, rr);
+ rr->err = -EINVAL;
+ return -EINVAL;
case RDT_RESOURCE_PERF_PKG: {
u64 tval = 0;
@@ -1035,6 +1038,10 @@ struct mon_evt mon_event_all[RDT_NUM_RESOURCES][QOS_NUM_EVENTS] = {
MON_EVENT(QOS_MBM_TOTAL_EVENT_ID, "mbm_total_bytes", false),
MON_EVENT(QOS_MBM_LOCAL_EVENT_ID, "mbm_local_bytes", false),
},
+ [RDT_RESOURCE_L2] = {
+ MON_EVENT(QOS_OCCUP_EVENT_ID, "l2c_occupancy", false),
+ MON_EVENT(QOS_MBM_TOTAL_EVENT_ID, "mbm_core_bytes", false),
+ },
[RDT_RESOURCE_PERF_PKG] = {
MON_EVENT(PMT_EVENT_ENERGY, "core_energy", true),
MON_EVENT(PMT_EVENT_ACTIVITY, "activity", true),
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 0a60372299c5..95ffff4c7925 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -180,7 +180,7 @@ struct mbm_cntr_cfg {
};
/**
- * struct rdt_l3_mon_domain - group of CPUs sharing RDT_RESOURCE_L3 monitoring
+ * struct rdt_l3_mon_domain - group of CPUs sharing L2 or L3 cache 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
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 12/19] fs/resctrl: Set up MBM state and workers for every monitor resource
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
` (10 preceding siblings ...)
2026-10-29 12:36 ` [RFC PATCH v2 11/19] fs/resctrl: Add the L2 monitor events Jinjie Ruan
@ 2026-10-29 12:36 ` Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 13/19] fs/resctrl: Check RMID limbo on every resource with occupancy Jinjie Ruan
` (7 subsequent siblings)
19 siblings, 0 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:36 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
Monitor domain state and the MBM overflow worker are only set up for L3
domains. Set them up for any resource that has the matching events
enabled, and let the overflow worker find the resource from its domain.
The MBA software controller still uses the L3, so only the L3 worker
updates its bandwidth numbers.
No functional change as only the L3 has monitoring enabled.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
fs/resctrl/monitor.c | 8 ++---
fs/resctrl/rdtgroup.c | 78 ++++++++++++++++++++++---------------------
2 files changed, 44 insertions(+), 42 deletions(-)
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index 3544dd2a983a..4d90f784a4cf 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -586,7 +586,7 @@ static void mbm_bw_count(struct rdtgroup *rdtgrp, struct rmid_read *rr)
struct rdt_l3_mon_domain *d;
struct mbm_state *m;
- if (!domain_header_is_valid(rr->hdr, RESCTRL_MON_DOMAIN, RDT_RESOURCE_L3))
+ if (!domain_header_is_valid(rr->hdr, RESCTRL_MON_DOMAIN, rr->r->rid))
return;
d = container_of(rr->hdr, struct rdt_l3_mon_domain, hdr);
m = get_mbm_state(d, closid, rmid, rr->evt->evtid);
@@ -790,7 +790,7 @@ static void mbm_update_one_event(struct rdt_resource *r, struct rdt_l3_mon_domai
* If the software controller is enabled, compute the
* bandwidth for this event id.
*/
- if (is_mba_sc(NULL))
+ if (is_mba_sc(NULL) && r->rid == RDT_RESOURCE_L3)
mbm_bw_count(rdtgrp, &rr);
if (rr.arch_mon_ctx)
@@ -906,8 +906,8 @@ void mbm_handle_overflow(struct work_struct *work)
if (!is_percpu_thread())
goto out_unlock;
- r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
d = container_of(work, struct rdt_l3_mon_domain, mbm_over.work);
+ r = resctrl_arch_get_resource(d->hdr.rid);
/* Domain is going offline */
if (cpumask_empty(&d->hdr.cpu_mask))
@@ -920,7 +920,7 @@ void mbm_handle_overflow(struct work_struct *work)
list_for_each_entry(crgrp, head, mon.crdtgrp_list)
mbm_update(r, d, crgrp);
- if (is_mba_sc(NULL))
+ if (is_mba_sc(NULL) && r->rid == RDT_RESOURCE_L3)
update_mba_bw(prgrp, d);
}
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 8154e02b3d1c..b992f4b5270f 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -3254,9 +3254,11 @@ static int rdt_get_tree(struct fs_context *fc)
if (resctrl_arch_alloc_capable() || resctrl_arch_mon_capable())
resctrl_mounted = true;
- r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
- if (resctrl_is_mbm_enabled(r)) {
- list_for_each_entry_rcu(dom, &r->mon_domains, hdr.list, lockdep_is_cpus_held())
+ for_each_mon_capable_rdt_resource(r) {
+ if (!resctrl_is_mbm_enabled(r))
+ continue;
+ list_for_each_entry_rcu(dom, &r->mon_domains, hdr.list,
+ lockdep_is_cpus_held())
mbm_setup_overflow_handler(dom, MBM_OVERFLOW_INTERVAL,
RESCTRL_PICK_ANY_CPU);
}
@@ -4498,7 +4500,13 @@ static void rdtgroup_setup_default(void)
mutex_unlock(&rdtgroup_mutex);
}
-static void domain_destroy_l3_mon_state(struct rdt_l3_mon_domain *d)
+/* Only cache resources use the struct rdt_l3_mon_domain layout. */
+static bool rdt_mon_domain_is_cache(const struct rdt_domain_hdr *hdr)
+{
+ return hdr->rid == RDT_RESOURCE_L2 || hdr->rid == RDT_RESOURCE_L3;
+}
+
+static void domain_destroy_mon_state(struct rdt_l3_mon_domain *d)
{
int idx;
@@ -4556,8 +4564,8 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *h
* the domain that has the workers' struct delayed_work embedded.
* Do so before taking rdtgroup_mutex since the workers also acquire it.
*/
- if (r->rid == RDT_RESOURCE_L3 &&
- domain_header_is_valid(hdr, RESCTRL_MON_DOMAIN, RDT_RESOURCE_L3)) {
+ if (rdt_mon_domain_is_cache(hdr) &&
+ domain_header_is_valid(hdr, RESCTRL_MON_DOMAIN, r->rid)) {
d = container_of(hdr, struct rdt_l3_mon_domain, hdr);
if (resctrl_is_mbm_enabled(r))
cancel_delayed_work_sync(&d->mbm_over);
@@ -4574,10 +4582,8 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *h
if (resctrl_mounted && resctrl_arch_mon_capable())
rmdir_mondata_subdir_allrdtgrp(r, hdr);
- if (r->rid != RDT_RESOURCE_L3)
- goto out_unlock;
-
- if (!domain_header_is_valid(hdr, RESCTRL_MON_DOMAIN, RDT_RESOURCE_L3))
+ if (!rdt_mon_domain_is_cache(hdr) ||
+ !domain_header_is_valid(hdr, RESCTRL_MON_DOMAIN, r->rid))
goto out_unlock;
d = container_of(hdr, struct rdt_l3_mon_domain, hdr);
@@ -4593,13 +4599,13 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *h
__check_limbo(d, true);
}
- domain_destroy_l3_mon_state(d);
+ domain_destroy_mon_state(d);
out_unlock:
mutex_unlock(&rdtgroup_mutex);
}
/**
- * domain_setup_l3_mon_state() - Initialise domain monitoring structures.
+ * domain_setup_mon_state() - Initialise domain monitoring structures.
* @r: The resource for the newly online domain.
* @d: The newly online domain.
*
@@ -4617,7 +4623,7 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *h
*
* Return: 0 for success, or -ENOMEM.
*/
-static int domain_setup_l3_mon_state(struct rdt_resource *r, struct rdt_l3_mon_domain *d)
+static int domain_setup_mon_state(struct rdt_resource *r, struct rdt_l3_mon_domain *d)
{
u32 idx_limit = resctrl_arch_system_num_rmid_idx();
size_t tsize = sizeof(*d->mbm_states[0]);
@@ -4680,27 +4686,25 @@ int resctrl_online_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *hdr
mutex_lock(&rdtgroup_mutex);
- if (r->rid != RDT_RESOURCE_L3)
- goto mkdir;
+ if (rdt_mon_domain_is_cache(hdr)) {
+ if (!domain_header_is_valid(hdr, RESCTRL_MON_DOMAIN, r->rid))
+ goto out_unlock;
- if (!domain_header_is_valid(hdr, RESCTRL_MON_DOMAIN, RDT_RESOURCE_L3))
- goto out_unlock;
+ d = container_of(hdr, struct rdt_l3_mon_domain, hdr);
+ err = domain_setup_mon_state(r, d);
+ if (err)
+ goto out_unlock;
- d = container_of(hdr, struct rdt_l3_mon_domain, hdr);
- err = domain_setup_l3_mon_state(r, d);
- if (err)
- goto out_unlock;
+ if (resctrl_is_mbm_enabled(r)) {
+ INIT_DELAYED_WORK(&d->mbm_over, mbm_handle_overflow);
+ mbm_setup_overflow_handler(d, MBM_OVERFLOW_INTERVAL,
+ RESCTRL_PICK_ANY_CPU);
+ }
- if (resctrl_is_mbm_enabled(r)) {
- INIT_DELAYED_WORK(&d->mbm_over, mbm_handle_overflow);
- mbm_setup_overflow_handler(d, MBM_OVERFLOW_INTERVAL,
- RESCTRL_PICK_ANY_CPU);
+ if (resctrl_is_mon_event_enabled(r, QOS_OCCUP_EVENT_ID))
+ INIT_DELAYED_WORK(&d->cqm_limbo, cqm_handle_limbo);
}
- if (resctrl_is_mon_event_enabled(r, QOS_OCCUP_EVENT_ID))
- INIT_DELAYED_WORK(&d->cqm_limbo, cqm_handle_limbo);
-
-mkdir:
err = 0;
/*
* If the filesystem is not mounted then only the default resource group
@@ -4753,7 +4757,7 @@ static struct rdt_l3_mon_domain *get_mon_domain_from_cpu(int cpu,
void resctrl_offline_cpu(unsigned int cpu)
{
- struct rdt_resource *l3 = resctrl_arch_get_resource(RDT_RESOURCE_L3);
+ struct rdt_resource *r;
struct rdt_l3_mon_domain *d;
struct rdtgroup *rdtgrp;
@@ -4765,18 +4769,17 @@ void resctrl_offline_cpu(unsigned int cpu)
}
}
- if (!l3->mon_capable)
- goto out_unlock;
-
- d = get_mon_domain_from_cpu(cpu, l3);
- if (d) {
- if (resctrl_is_mbm_enabled(l3) && cpu == d->mbm_work_cpu) {
+ for_each_mon_capable_rdt_resource(r) {
+ d = get_mon_domain_from_cpu(cpu, r);
+ if (!d)
+ continue;
+ if (resctrl_is_mbm_enabled(r) && cpu == d->mbm_work_cpu) {
mutex_unlock(&rdtgroup_mutex);
cancel_delayed_work_sync(&d->mbm_over);
mutex_lock(&rdtgroup_mutex);
mbm_setup_overflow_handler(d, 0, cpu);
}
- if (resctrl_is_mon_event_enabled(l3, QOS_OCCUP_EVENT_ID) &&
+ if (resctrl_is_mon_event_enabled(r, QOS_OCCUP_EVENT_ID) &&
cpu == d->cqm_work_cpu && has_busy_rmid(d)) {
mutex_unlock(&rdtgroup_mutex);
cancel_delayed_work_sync(&d->cqm_limbo);
@@ -4785,7 +4788,6 @@ void resctrl_offline_cpu(unsigned int cpu)
}
}
-out_unlock:
mutex_unlock(&rdtgroup_mutex);
}
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 13/19] fs/resctrl: Check RMID limbo on every resource with occupancy
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
` (11 preceding siblings ...)
2026-10-29 12:36 ` [RFC PATCH v2 12/19] fs/resctrl: Set up MBM state and workers for every monitor resource Jinjie Ruan
@ 2026-10-29 12:36 ` Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 14/19] fs/resctrl: Manage assignable counters for every monitor resource Jinjie Ruan
` (6 subsequent siblings)
19 siblings, 0 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:36 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
An RMID is only reused once the L3 occupancy counter shows the cache has
gone cold. When occupancy is monitored on more than one resource, the
RMID has to wait for all of them.
Mark the RMID busy in the domains of every resource that has the
occupancy event, and have the limbo worker read the occupancy of the
resource its domain belongs to. The threshold is one byte value for all
of them; MPAM already sets the limit from the smallest monitored cache.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
fs/resctrl/monitor.c | 33 ++++++++++++++++++++-------------
1 file changed, 20 insertions(+), 13 deletions(-)
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index 4d90f784a4cf..739134e2ff77 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -126,13 +126,13 @@ static void limbo_release_entry(struct rmid_entry *entry)
/*
* Check the RMIDs that are marked as busy for this domain. If the
- * reported LLC occupancy is below the threshold clear the busy bit and
+ * reported occupancy is below the threshold clear the busy bit and
* decrement the count. If the busy count gets to zero on an RMID, we
* free the RMID
*/
void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free)
{
- struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
+ struct rdt_resource *r = resctrl_arch_get_resource(d->hdr.rid);
u32 idx_limit = resctrl_arch_system_num_rmid_idx();
struct rmid_entry *entry;
bool rmid_dirty = true;
@@ -297,8 +297,8 @@ int alloc_rmid(u32 closid)
static void add_rmid_to_limbo(struct rmid_entry *entry)
{
- struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
struct rdt_l3_mon_domain *d;
+ struct rdt_resource *r;
u32 idx;
lockdep_assert_held(&rdtgroup_mutex);
@@ -309,16 +309,23 @@ static void add_rmid_to_limbo(struct rmid_entry *entry)
idx = resctrl_arch_rmid_idx_encode(entry->closid, entry->rmid);
entry->busy = 0;
- list_for_each_entry_rcu(d, &r->mon_domains, hdr.list, lockdep_is_cpus_held()) {
- /*
- * For the first limbo RMID in the domain,
- * setup up the limbo worker.
- */
- if (!has_busy_rmid(d))
- cqm_setup_limbo_handler(d, CQM_LIMBOCHECK_INTERVAL,
- RESCTRL_PICK_ANY_CPU);
- set_bit(idx, d->rmid_busy_llc);
- entry->busy++;
+ for_each_mon_capable_rdt_resource(r) {
+ /* Only resources with the occupancy event have a busy bitmap */
+ if (!resctrl_is_mon_event_enabled(r, QOS_OCCUP_EVENT_ID))
+ continue;
+
+ list_for_each_entry_rcu(d, &r->mon_domains, hdr.list,
+ lockdep_is_cpus_held()) {
+ /*
+ * For the first limbo RMID in the domain,
+ * setup up the limbo worker.
+ */
+ if (!has_busy_rmid(d))
+ cqm_setup_limbo_handler(d, CQM_LIMBOCHECK_INTERVAL,
+ RESCTRL_PICK_ANY_CPU);
+ set_bit(idx, d->rmid_busy_llc);
+ entry->busy++;
+ }
}
rmid_limbo_count++;
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 14/19] fs/resctrl: Manage assignable counters for every monitor resource
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
` (12 preceding siblings ...)
2026-10-29 12:36 ` [RFC PATCH v2 13/19] fs/resctrl: Check RMID limbo on every resource with occupancy Jinjie Ruan
@ 2026-10-29 12:36 ` Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 15/19] arm_mpam: resctrl: Look up the monitor domain id from the components Jinjie Ruan
` (5 subsequent siblings)
19 siblings, 0 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:36 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
Creating or removing a monitor group only assigns or frees counters for
the L3 MBM events. Walk every resource that has assignable counters and
handle each of its MBM events.
Set the default event filter for each such resource, build the BMEC file
names from the event names, and register the shared info files once.
resctrl_l3_mon_resource_init() now covers more than the L3, so drop L3
from its name. mbm_L3_assignments keeps its name and stays L3 only.
No functional change as only the L3 can have assignable counters.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
fs/resctrl/internal.h | 4 +-
fs/resctrl/monitor.c | 94 ++++++++++++++++++++++++++-----------------
fs/resctrl/rdtgroup.c | 28 +++++++------
3 files changed, 74 insertions(+), 52 deletions(-)
diff --git a/fs/resctrl/internal.h b/fs/resctrl/internal.h
index f84152734fd1..32bc6bda31b7 100644
--- a/fs/resctrl/internal.h
+++ b/fs/resctrl/internal.h
@@ -381,9 +381,9 @@ int alloc_rmid(u32 closid);
void free_rmid(u32 closid, u32 rmid);
-int resctrl_l3_mon_resource_init(void);
+int resctrl_mon_resource_init(void);
-void resctrl_l3_mon_resource_exit(void);
+void resctrl_mon_resource_exit(void);
void mon_event_count(void *info);
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index 739134e2ff77..9032456ad7c9 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -1356,19 +1356,20 @@ static int rdtgroup_assign_cntr_event(struct rdt_l3_mon_domain *d, struct rdtgro
*/
void rdtgroup_assign_cntrs(struct rdtgroup *rdtgrp)
{
- struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
-
- if (!r->mon_capable || !resctrl_arch_mbm_cntr_assign_enabled(r) ||
- !r->mon.mbm_assign_on_mkdir)
- return;
+ struct mon_evt *mevt;
+ struct rdt_resource *r;
- if (resctrl_is_mon_event_enabled(r, QOS_MBM_TOTAL_EVENT_ID))
- rdtgroup_assign_cntr_event(NULL, rdtgrp,
- &mon_event_all[r->rid][QOS_MBM_TOTAL_EVENT_ID]);
+ for_each_mon_capable_rdt_resource(r) {
+ if (!resctrl_arch_mbm_cntr_assign_enabled(r) ||
+ !r->mon.mbm_assign_on_mkdir)
+ continue;
- if (resctrl_is_mon_event_enabled(r, QOS_MBM_LOCAL_EVENT_ID))
- rdtgroup_assign_cntr_event(NULL, rdtgrp,
- &mon_event_all[r->rid][QOS_MBM_LOCAL_EVENT_ID]);
+ for_each_mon_event(r, mevt) {
+ if (!mevt->enabled || !resctrl_is_mbm_event(mevt->evtid))
+ continue;
+ rdtgroup_assign_cntr_event(NULL, rdtgrp, mevt);
+ }
+ }
}
/*
@@ -1415,18 +1416,19 @@ static void rdtgroup_unassign_cntr_event(struct rdt_l3_mon_domain *d, struct rdt
*/
void rdtgroup_unassign_cntrs(struct rdtgroup *rdtgrp)
{
- struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
-
- if (!r->mon_capable || !resctrl_arch_mbm_cntr_assign_enabled(r))
- return;
+ struct mon_evt *mevt;
+ struct rdt_resource *r;
- if (resctrl_is_mon_event_enabled(r, QOS_MBM_TOTAL_EVENT_ID))
- rdtgroup_unassign_cntr_event(NULL, rdtgrp,
- &mon_event_all[r->rid][QOS_MBM_TOTAL_EVENT_ID]);
+ for_each_mon_capable_rdt_resource(r) {
+ if (!resctrl_arch_mbm_cntr_assign_enabled(r))
+ continue;
- if (resctrl_is_mon_event_enabled(r, QOS_MBM_LOCAL_EVENT_ID))
- rdtgroup_unassign_cntr_event(NULL, rdtgrp,
- &mon_event_all[r->rid][QOS_MBM_LOCAL_EVENT_ID]);
+ for_each_mon_event(r, mevt) {
+ if (!mevt->enabled || !resctrl_is_mbm_event(mevt->evtid))
+ continue;
+ rdtgroup_unassign_cntr_event(NULL, rdtgrp, mevt);
+ }
+ }
}
static int resctrl_parse_mem_transactions(char *tok, u32 *val)
@@ -1954,7 +1956,7 @@ static void closid_num_dirty_rmid_free(void)
}
/**
- * resctrl_l3_mon_resource_init() - Initialise global monitoring structures.
+ * resctrl_mon_resource_init() - Initialise global monitoring structures.
*
* Allocate and initialise global monitor resources that do not belong to a
* specific domain. i.e. the closid_num_dirty_rmid[] used to find the CLOSID
@@ -1964,37 +1966,49 @@ static void closid_num_dirty_rmid_free(void)
* Resctrl's cpuhp callbacks may be called before this point to bring a domain
* online.
*
+ * The L3 events remain the backing for the MBA software controller and for the
+ * event configuration files, which are named after the L3 events.
+ *
* Return: 0 for success, or -ENOMEM.
*/
-int resctrl_l3_mon_resource_init(void)
+int resctrl_mon_resource_init(void)
{
- struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
+ struct rdt_resource *l3 = resctrl_arch_get_resource(RDT_RESOURCE_L3);
+ bool assignable = false, configurable = false;
+ struct rdt_resource *r;
int ret;
- if (!r->mon_capable)
+ if (!resctrl_arch_mon_capable())
return 0;
- ret = closid_num_dirty_rmid_alloc(r);
+ ret = closid_num_dirty_rmid_alloc(l3);
if (ret)
return ret;
+ /*
+ * BMEC is L3 only: resctrl_arch_is_evt_configurable() has no resource
+ * argument. The L2 events are not configurable.
+ */
if (resctrl_arch_is_evt_configurable(QOS_MBM_TOTAL_EVENT_ID)) {
- mon_event_all[r->rid][QOS_MBM_TOTAL_EVENT_ID].configurable = true;
+ mon_event_all[l3->rid][QOS_MBM_TOTAL_EVENT_ID].configurable = true;
resctrl_file_fflags_init("mbm_total_bytes_config",
RFTYPE_MON_INFO | RFTYPE_RES_CACHE);
}
if (resctrl_arch_is_evt_configurable(QOS_MBM_LOCAL_EVENT_ID)) {
- mon_event_all[r->rid][QOS_MBM_LOCAL_EVENT_ID].configurable = true;
+ mon_event_all[l3->rid][QOS_MBM_LOCAL_EVENT_ID].configurable = true;
resctrl_file_fflags_init("mbm_local_bytes_config",
RFTYPE_MON_INFO | RFTYPE_RES_CACHE);
}
- if (resctrl_is_mon_event_enabled(r, QOS_MBM_LOCAL_EVENT_ID))
+ if (resctrl_is_mon_event_enabled(l3, QOS_MBM_LOCAL_EVENT_ID))
mba_mbps_default_event = QOS_MBM_LOCAL_EVENT_ID;
- else if (resctrl_is_mon_event_enabled(r, QOS_MBM_TOTAL_EVENT_ID))
+ else if (resctrl_is_mon_event_enabled(l3, QOS_MBM_TOTAL_EVENT_ID))
mba_mbps_default_event = QOS_MBM_TOTAL_EVENT_ID;
- if (r->mon.mbm_cntr_assignable) {
+ for_each_mon_capable_rdt_resource(r) {
+ if (!r->mon.mbm_cntr_assignable)
+ continue;
+
if (resctrl_is_mon_event_enabled(r, QOS_MBM_TOTAL_EVENT_ID))
mon_event_all[r->rid][QOS_MBM_TOTAL_EVENT_ID].evt_cfg = r->mon.mbm_cfg_mask;
if (resctrl_is_mon_event_enabled(r, QOS_MBM_LOCAL_EVENT_ID))
@@ -2003,26 +2017,32 @@ int resctrl_l3_mon_resource_init(void)
READS_TO_LOCAL_S_MEM |
NON_TEMP_WRITE_TO_LOCAL_MEM);
r->mon.mbm_assign_on_mkdir = true;
+ assignable = true;
+ configurable |= r->mon.mbm_cntr_configurable;
+ }
+
+ if (assignable) {
resctrl_file_fflags_init("num_mbm_cntrs",
RFTYPE_MON_INFO | RFTYPE_RES_CACHE);
resctrl_file_fflags_init("available_mbm_cntrs",
RFTYPE_MON_INFO | RFTYPE_RES_CACHE);
resctrl_file_fflags_init("event_filter", RFTYPE_ASSIGN_CONFIG);
- if (r->mon.mbm_cntr_configurable)
+ if (configurable)
resctrl_file_mode_init("event_filter", 0644);
resctrl_file_fflags_init("mbm_assign_on_mkdir", RFTYPE_MON_INFO |
RFTYPE_RES_CACHE);
- resctrl_file_fflags_init("mbm_L3_assignments", RFTYPE_MON_BASE);
}
+ /* The counter assignment interface is named after the L3 events. */
+ if (l3->mon.mbm_cntr_assignable)
+ resctrl_file_fflags_init("mbm_L3_assignments", RFTYPE_MON_BASE);
+
return 0;
}
-void resctrl_l3_mon_resource_exit(void)
+void resctrl_mon_resource_exit(void)
{
- struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
-
- if (!r->mon_capable)
+ if (!resctrl_arch_mon_capable())
return;
closid_num_dirty_rmid_free();
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index b992f4b5270f..ba36b6b0c085 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -1927,6 +1927,7 @@ void resctrl_bmec_files_show(struct rdt_resource *r, struct kernfs_node *l3_mon_
bool show)
{
struct kernfs_node *kn_config, *mon_kn = NULL;
+ struct mon_evt *mevt;
char name[32];
if (!l3_mon_kn) {
@@ -1937,14 +1938,15 @@ void resctrl_bmec_files_show(struct rdt_resource *r, struct kernfs_node *l3_mon_
l3_mon_kn = mon_kn;
}
- kn_config = kernfs_find_and_get(l3_mon_kn, "mbm_total_bytes_config");
- if (kn_config) {
- kernfs_show(kn_config, show);
- kernfs_put(kn_config);
- }
+ for_each_mon_event(r, mevt) {
+ if (!mevt->configurable)
+ continue;
+
+ sprintf(name, "%s_config", mevt->name);
+ kn_config = kernfs_find_and_get(l3_mon_kn, name);
+ if (!kn_config)
+ continue;
- kn_config = kernfs_find_and_get(l3_mon_kn, "mbm_local_bytes_config");
- if (kn_config) {
kernfs_show(kn_config, show);
kernfs_put(kn_config);
}
@@ -4613,7 +4615,7 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *h
* Called when the first CPU of a domain comes online, regardless of whether
* the filesystem is mounted.
* During boot this may be called before global allocations have been made by
- * resctrl_l3_mon_resource_init().
+ * resctrl_mon_resource_init().
*
* Called during CPU online that may run as soon as CPU online callbacks
* are set up during resctrl initialization. The number of supported RMIDs
@@ -4812,13 +4814,13 @@ int resctrl_init(void)
io_alloc_init();
- ret = resctrl_l3_mon_resource_init();
+ ret = resctrl_mon_resource_init();
if (ret)
return ret;
ret = sysfs_create_mount_point(fs_kobj, "resctrl");
if (ret) {
- resctrl_l3_mon_resource_exit();
+ resctrl_mon_resource_exit();
return ret;
}
@@ -4853,7 +4855,7 @@ int resctrl_init(void)
cleanup_mountpoint:
sysfs_remove_mount_point(fs_kobj, "resctrl");
- resctrl_l3_mon_resource_exit();
+ resctrl_mon_resource_exit();
return ret;
}
@@ -4889,7 +4891,7 @@ static bool resctrl_online_domains_exist(void)
* When called by the architecture code, all CPUs and resctrl domains must be
* offline. This ensures the limbo and overflow handlers are not scheduled to
* run, meaning the data structures they access can be freed by
- * resctrl_l3_mon_resource_exit().
+ * resctrl_mon_resource_exit().
*
* After resctrl_exit() returns, the architecture code should return an
* error from all resctrl_arch_ functions that can do this.
@@ -4916,6 +4918,6 @@ void resctrl_exit(void)
* it can be used to umount resctrl.
*/
- resctrl_l3_mon_resource_exit();
+ resctrl_mon_resource_exit();
free_rmid_lru_list();
}
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 15/19] arm_mpam: resctrl: Look up the monitor domain id from the components
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
` (13 preceding siblings ...)
2026-10-29 12:36 ` [RFC PATCH v2 14/19] fs/resctrl: Manage assignable counters for every monitor resource Jinjie Ruan
@ 2026-10-29 12:36 ` Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 16/19] arm_mpam: resctrl: Report counter assignment per resource Jinjie Ruan
` (4 subsequent siblings)
19 siblings, 0 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:36 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
The monitor domain id comes from whichever monitoring component the loop
happened to find last, and the monitor domain lookup uses the L3
cache-id. Neither works if the monitors of a resource are in a different
component from its controls, or if there are no controls at all, which
is the case on monitor only platforms.
Add mpam_resctrl_domain_id() to find the component that covers a CPU for
each of the resource's events. It returns the id of the first component
found and warns if another component reports a different id. Also pass
the id, not the component, to mpam_resctrl_domain_hdr_init().
No functional change: every resource has a single component covering a
CPU today, so the same id is returned.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
drivers/resctrl/mpam_resctrl.c | 66 +++++++++++++++++++++++-----------
1 file changed, 45 insertions(+), 21 deletions(-)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 9779cef5dc04..4de3ad5a8ca2 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -1563,14 +1563,14 @@ void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
mpam_reset_class_locked(res->class);
}
-static void mpam_resctrl_domain_hdr_init(int cpu, struct mpam_component *comp,
+static void mpam_resctrl_domain_hdr_init(int cpu, int id,
enum resctrl_res_level rid,
struct rdt_domain_hdr *hdr)
{
lockdep_assert_cpus_held();
INIT_LIST_HEAD(&hdr->list);
- hdr->id = mpam_resctrl_pick_domain_id(cpu, comp);
+ hdr->id = id;
hdr->rid = rid;
cpumask_set_cpu(cpu, &hdr->cpu_mask);
}
@@ -1637,6 +1637,43 @@ static struct mpam_component *find_component(struct mpam_class *class, int cpu)
return NULL;
}
+/*
+ * Find the domain ID for @cpu from the monitoring components of @r. Also
+ * fill @mon_comp, if not NULL, with the component that covers @cpu for each
+ * event. A negative ID means no component covers this CPU.
+ */
+static int mpam_resctrl_domain_id(int cpu, struct rdt_resource *r,
+ struct mpam_component **mon_comp)
+{
+ struct mpam_resctrl_mon *mon;
+ enum resctrl_event_id eventid;
+ int id = -1;
+
+ lockdep_assert_cpus_held();
+
+ for_each_mpam_resctrl_mon(mon, r, eventid) {
+ struct mpam_component *comp;
+ int comp_id;
+
+ if (!mon->class)
+ continue; // dummy resource
+
+ comp = find_component(mon->class, cpu);
+ if (mon_comp)
+ mon_comp[eventid] = comp;
+ if (!comp)
+ continue;
+
+ comp_id = mpam_resctrl_pick_domain_id(cpu, comp);
+ if (id < 0)
+ id = comp_id;
+ else
+ WARN_ON_ONCE(id != comp_id);
+ }
+
+ return id;
+}
+
static struct mpam_resctrl_dom *
mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
{
@@ -1672,7 +1709,8 @@ mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
dom->ctrl_comp = ctrl_comp;
ctrl_d = &dom->resctrl_ctrl_dom;
- mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, r->rid, &ctrl_d->hdr);
+ mpam_resctrl_domain_hdr_init(cpu, mpam_resctrl_pick_domain_id(cpu, ctrl_comp),
+ r->rid, &ctrl_d->hdr);
ctrl_d->hdr.type = RESCTRL_CTRL_DOMAIN;
err = resctrl_online_ctrl_domain(r, ctrl_d);
if (err)
@@ -1684,9 +1722,7 @@ mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
}
if (r->mon_capable) {
- struct mpam_component *any_mon_comp = NULL;
- struct mpam_resctrl_mon *mon;
- enum resctrl_event_id eventid;
+ int id;
/*
* Even if the monitor domain is backed by a different
@@ -1695,26 +1731,14 @@ mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
* Search each event's class list for a component with
* overlapping CPUs and set up the dom->mon_comp array.
*/
-
- for_each_mpam_resctrl_mon(mon, r, eventid) {
- struct mpam_component *mon_comp;
-
- if (!mon->class)
- continue; // dummy resource
-
- mon_comp = find_component(mon->class, cpu);
- dom->mon_comp[eventid] = mon_comp;
- if (mon_comp)
- any_mon_comp = mon_comp;
- }
- if (!any_mon_comp) {
- WARN_ON_ONCE(0);
+ id = mpam_resctrl_domain_id(cpu, r, dom->mon_comp);
+ if (WARN_ON_ONCE(id < 0)) {
err = -EFAULT;
goto offline_ctrl_domain;
}
mon_d = &dom->resctrl_mon_dom;
- mpam_resctrl_domain_hdr_init(cpu, any_mon_comp, r->rid, &mon_d->hdr);
+ mpam_resctrl_domain_hdr_init(cpu, id, r->rid, &mon_d->hdr);
mon_d->hdr.type = RESCTRL_MON_DOMAIN;
err = resctrl_online_mon_domain(r, &mon_d->hdr);
if (err)
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 16/19] arm_mpam: resctrl: Report counter assignment per resource
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
` (14 preceding siblings ...)
2026-10-29 12:36 ` [RFC PATCH v2 15/19] arm_mpam: resctrl: Look up the monitor domain id from the components Jinjie Ruan
@ 2026-10-29 12:36 ` Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 17/19] arm_mpam: resctrl: Allow monitoring on resources other than the L3 Jinjie Ruan
` (3 subsequent siblings)
19 siblings, 0 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:36 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
resctrl_arch_mbm_cntr_assign_enabled() says assignment is on by checking
whether the resource is the L3. A platform whose L3 has no bandwidth
counters is then told assignment is on, although no counters were set
up.
Report the per-resource flag MPAM sets when it sets up the assignable
counters. Other resources can then report their own state.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
drivers/resctrl/mpam_resctrl.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 4de3ad5a8ca2..b5416f589698 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -130,7 +130,7 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_l3_mon_domain *d
bool resctrl_arch_mbm_cntr_assign_enabled(struct rdt_resource *r)
{
- return (r == &mpam_resctrl_controls[RDT_RESOURCE_L3].resctrl_res);
+ return r->mon.mbm_cntr_assignable;
}
int resctrl_arch_mbm_cntr_assign_set(struct rdt_resource *r, bool enable)
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 17/19] arm_mpam: resctrl: Allow monitoring on resources other than the L3
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
` (15 preceding siblings ...)
2026-10-29 12:36 ` [RFC PATCH v2 16/19] arm_mpam: resctrl: Report counter assignment per resource Jinjie Ruan
@ 2026-10-29 12:36 ` Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 18/19] arm_mpam: resctrl: Expose the L2 monitor events Jinjie Ruan
` (2 subsequent siblings)
19 siblings, 0 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:36 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
The MPAM driver assumes only the L3 monitors. resctrl_arch_mon_capable()
looks at the L3 only, a CPU's monitor-only domain is found with the L3
cache-id, and mpam_resctrl_monitor_init() always names the resource L3.
Check every resource for monitoring, find a monitor domain by the id its
component reports, and set the name and scope from the resource.
No functional change as only the L3 has monitors so far.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
drivers/resctrl/mpam_resctrl.c | 85 +++++++++++++++++-----------------
1 file changed, 42 insertions(+), 43 deletions(-)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index b5416f589698..b9487f3c648d 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -99,11 +99,12 @@ bool resctrl_arch_alloc_capable(void)
bool resctrl_arch_mon_capable(void)
{
- struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
- struct rdt_resource *l3 = &res->resctrl_res;
+ struct rdt_resource *r;
+
+ for_each_mon_capable_rdt_resource(r)
+ return true;
- /* All monitors are presented as being on the L3 cache */
- return l3->mon_capable;
+ return false;
}
bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt)
@@ -1332,35 +1333,39 @@ static int mpam_resctrl_monitor_init(struct rdt_resource *r,
struct mpam_resctrl_res *res = container_of(r, struct mpam_resctrl_res,
resctrl_res);
struct mpam_resctrl_mon *mon = mpam_resctrl_mon(r, type);
+ unsigned int level;
lockdep_assert_cpus_held();
+ /* Called once per event. The name is needed on monitor only platforms. */
+ if (r->rid == RDT_RESOURCE_L2) {
+ level = 2;
+ r->name = "L2";
+ r->mon_scope = RESCTRL_L2_CACHE;
+ } else {
+ level = 3;
+ r->name = "L3";
+ r->mon_scope = RESCTRL_L3_CACHE;
+ }
+
/*
- * There also needs to be an L3 cache present.
+ * There also needs to be a cache at this level present.
* The check just requires any online CPU and it can't go offline as we
* hold the cpu lock.
*/
- if (get_cpu_cacheinfo_id(raw_smp_processor_id(), 3) == -1)
+ if (get_cpu_cacheinfo_id(raw_smp_processor_id(), level) == -1)
return 0;
/*
- * If there are no MPAM resources on L3, force it into existence.
- * topology_matches_l3() already ensures this looks like the L3.
- * The domain-ids will be fixed up by mpam_resctrl_domain_hdr_init().
+ * If there are no MPAM resources on this cache level, force it into
+ * existence. The domain-ids will be fixed up by
+ * mpam_resctrl_domain_hdr_init().
*/
if (!res->class) {
- pr_warn_once("Faking L3 MSC to enable counters.\n");
+ pr_warn_once("Faking L%u MSC to enable counters.\n", level);
res->class = mon->class;
}
- /*
- * Called multiple times!, once per event type that has a
- * monitoring class.
- * Setting name is necessary on monitor only platforms.
- */
- r->name = "L3";
- r->mon_scope = RESCTRL_L3_CACHE;
-
/*
* num-rmid is the upper bound for the number of monitoring groups that
* can exist simultaneously, including the default monitoring group for
@@ -1638,9 +1643,9 @@ static struct mpam_component *find_component(struct mpam_class *class, int cpu)
}
/*
- * Find the domain ID for @cpu from the monitoring components of @r. Also
- * fill @mon_comp, if not NULL, with the component that covers @cpu for each
- * event. A negative ID means no component covers this CPU.
+ * Fill @mon_comp, if not NULL, with the component that covers @cpu for each
+ * of the resource's events, and return the domain ID of the first one found.
+ * A negative ID means no component covers this CPU.
*/
static int mpam_resctrl_domain_id(int cpu, struct rdt_resource *r,
struct mpam_component **mon_comp)
@@ -1656,7 +1661,7 @@ static int mpam_resctrl_domain_id(int cpu, struct rdt_resource *r,
int comp_id;
if (!mon->class)
- continue; // dummy resource
+ continue;
comp = find_component(mon->class, cpu);
if (mon_comp)
@@ -1725,9 +1730,8 @@ mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
int id;
/*
- * Even if the monitor domain is backed by a different
- * component, the L3 component IDs need to be used... only
- * there may be no ctrl_comp for the L3.
+ * The monitor domain ID comes from the monitor components, as
+ * there may be no ctrl_comp for this resource.
* Search each event's class list for a component with
* overlapping CPUs and set up the dom->mon_comp array.
*/
@@ -1764,28 +1768,26 @@ mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
}
/*
- * We know all the monitors are associated with the L3, even if there are no
- * controls and therefore no control component. Find the cache-id for the CPU
- * and use that to search for existing resctrl domains.
- * This relies on mpam_resctrl_pick_domain_id() using the L3 cache-id
- * for anything that is not a cache.
+ * There may be no control component to search, for example on monitor only
+ * platforms. Find the domain-id the monitors' component would report for
+ * this CPU and use that to search the resource's monitor domains.
+ * This relies on mpam_resctrl_pick_domain_id() giving the same id for every
+ * CPU that shares the component.
*/
-static struct mpam_resctrl_dom *mpam_resctrl_get_mon_domain_from_cpu(int cpu)
+static struct mpam_resctrl_dom *
+mpam_resctrl_get_mon_domain_from_cpu(int cpu, struct rdt_resource *r)
{
- int cache_id;
struct mpam_resctrl_dom *dom;
- struct mpam_resctrl_res *l3 = &mpam_resctrl_controls[RDT_RESOURCE_L3];
+ int id;
lockdep_assert_cpus_held();
- if (!l3->class)
- return NULL;
- cache_id = get_cpu_cacheinfo_id(cpu, 3);
- if (cache_id < 0)
+ id = mpam_resctrl_domain_id(cpu, r, NULL);
+ if (id < 0)
return NULL;
- list_for_each_entry_rcu(dom, &l3->resctrl_res.mon_domains, resctrl_mon_dom.hdr.list) {
- if (dom->resctrl_mon_dom.hdr.id == cache_id)
+ list_for_each_entry_rcu(dom, &r->mon_domains, resctrl_mon_dom.hdr.list) {
+ if (dom->resctrl_mon_dom.hdr.id == id)
return dom;
}
@@ -1805,11 +1807,8 @@ mpam_resctrl_get_domain_from_cpu(int cpu, struct mpam_resctrl_res *res)
return dom;
}
- if (r->rid != RDT_RESOURCE_L3)
- return NULL;
-
/* Search the mon domain list too - needed on monitor only platforms. */
- return mpam_resctrl_get_mon_domain_from_cpu(cpu);
+ return mpam_resctrl_get_mon_domain_from_cpu(cpu, r);
}
int mpam_resctrl_online_cpu(unsigned int cpu)
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 18/19] arm_mpam: resctrl: Expose the L2 monitor events
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
` (16 preceding siblings ...)
2026-10-29 12:36 ` [RFC PATCH v2 17/19] arm_mpam: resctrl: Allow monitoring on resources other than the L3 Jinjie Ruan
@ 2026-10-29 12:36 ` Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 19/19] Documentation: arm64: mpam: Describe " Jinjie Ruan
2026-10-30 17:09 ` [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Reinette Chatre
19 siblings, 0 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:36 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
Allow an L2 cache class to supply the CSU counters for l2c_occupancy and
the MBWU counters for mbm_core_bytes.
The L2 bandwidth event is a normal MBM event, so resctrl gives it a
counter for the life of the monitoring group. MBWU needs that: rewriting
the PARTID/PMG filter restarts the byte count, so the filter must stay
in place while traffic is counted. CSU occupancy is only a snapshot and
can still borrow a monitor for each read.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
drivers/resctrl/mpam_resctrl.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index b9487f3c648d..62214557b673 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -1123,9 +1123,10 @@ static void mpam_resctrl_pick_counters(void)
guard(srcu)(&mpam_srcu);
list_for_each_entry_srcu(class, &mpam_classes, classes_list,
srcu_read_lock_held(&mpam_srcu)) {
- /* The name of the resource is L3... */
- if (class->type == MPAM_CLASS_CACHE && class->level != 3) {
- pr_debug("class %u is a cache but not the L3", class->level);
+ if (class->type == MPAM_CLASS_CACHE && class->level != 2 &&
+ class->level != 3) {
+ pr_debug("class %u is a cache but not L2 or L3",
+ class->level);
continue;
}
@@ -1145,7 +1146,10 @@ static void mpam_resctrl_pick_counters(void)
if (update_rmid_limits(class))
break;
- counter_update_class(RDT_RESOURCE_L3, QOS_OCCUP_EVENT_ID, class);
+ counter_update_class(class->level == 2 ?
+ RDT_RESOURCE_L2 :
+ RDT_RESOURCE_L3,
+ QOS_OCCUP_EVENT_ID, class);
break;
default:
break;
@@ -1169,6 +1173,14 @@ static void mpam_resctrl_pick_counters(void)
*/
counter_update_class(RDT_RESOURCE_L3, QOS_MBM_TOTAL_EVENT_ID, class);
}
+
+ if (class->type == MPAM_CLASS_CACHE && class->level == 2 &&
+ class_has_usable_mbwu(class)) {
+ pr_debug("class %u has usable MBWU for the L2 resource\n",
+ class->level);
+ counter_update_class(RDT_RESOURCE_L2,
+ QOS_MBM_TOTAL_EVENT_ID, class);
+ }
}
}
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v2 19/19] Documentation: arm64: mpam: Describe the L2 monitor events
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
` (17 preceding siblings ...)
2026-10-29 12:36 ` [RFC PATCH v2 18/19] arm_mpam: resctrl: Expose the L2 monitor events Jinjie Ruan
@ 2026-10-29 12:36 ` Jinjie Ruan
2026-10-30 17:09 ` [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Reinette Chatre
19 siblings, 0 replies; 22+ messages in thread
From: Jinjie Ruan @ 2026-10-29 12:36 UTC (permalink / raw)
To: reinette.chatre, james.morse, ben.horgan, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Cc: ruanjinjie
resctrl can now monitor at the L2 scope, so MPAM exposes the CSU and
MBWU counters of an L2 group as l2c_occupancy and mbm_core_bytes.
Update the list of supported features. Say why a bandwidth counter is
assigned for the life of the monitoring group: rewriting its filter
restarts the count.
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
Documentation/arch/arm64/mpam.rst | 23 ++++++++++++++---------
Documentation/filesystems/resctrl.rst | 6 ++++++
2 files changed, 20 insertions(+), 9 deletions(-)
diff --git a/Documentation/arch/arm64/mpam.rst b/Documentation/arch/arm64/mpam.rst
index e445f4078ee1..9c0a08ef74bf 100644
--- a/Documentation/arch/arm64/mpam.rst
+++ b/Documentation/arch/arm64/mpam.rst
@@ -32,8 +32,9 @@ Because the user interface to MPAM is via resctrl, only MPAM features that are
compatible with resctrl can be exposed to user-space.
MSC are considered as a group based on the topology. MSC that correspond with
-the L3 cache are considered together, it is not possible to mix MSC between L2
-and L3 to 'cover' a resctrl schema.
+the L3 cache are considered together, as are MSC that correspond with the L2
+cache; it is not possible to mix MSC between L2 and L3 to 'cover' a resctrl
+schema.
The supported features are:
@@ -61,9 +62,11 @@ The supported features are:
When the MPAM driver finds multiple groups of MSC it can use for the 'MB'
schema, it prefers the group closest to the L3 cache.
-* Cache Storage Usage (CSU) counters can expose the 'llc_occupancy' provided
- there is at least one CSU monitor on each MSC that makes up the L3 group.
- Exposing CSU counters from other caches or devices is not supported.
+* Cache Storage Usage (CSU) counters expose the occupancy of the cache they
+ monitor: 'llc_occupancy' for the L3 group and 'l2c_occupancy' for the L2
+ group, provided there is at least one CSU monitor on each MSC that makes up
+ the group. Exposing CSU counters from other caches or devices is not
+ supported.
* Memory Bandwidth Usage (MBWU) on or after the L3 cache. resctrl uses the
L3 cache-id to identify where the memory bandwidth is measured. For this
@@ -82,10 +85,12 @@ The supported features are:
have a corresponding L3 cache. 'mbm_local_bytes' is not exposed as MPAM
cannot distinguish local traffic from global traffic.
- All these restrictions based on L3 cache are due to resctrl, currently, only
- supporting monitoring at the L3 scope. It is expected that going forward more
- MBWU monitors can be exposed to the user after support for more monitoring
- scopes is added to resctrl.
+ MBWU monitors on an L2 MSC expose the bandwidth the cache sees as the
+ 'mbm_core_bytes' event on the L2 resource.
+
+ These restrictions are due to resctrl only supporting monitoring at the L2
+ and L3 cache scopes. MBWU monitors on caches at other levels, or on devices,
+ are not exposed.
Command line parameters
=======================
diff --git a/Documentation/filesystems/resctrl.rst b/Documentation/filesystems/resctrl.rst
index b52795e03303..c07d8f7223ff 100644
--- a/Documentation/filesystems/resctrl.rst
+++ b/Documentation/filesystems/resctrl.rst
@@ -495,6 +495,12 @@ with the following files:
bytes) at which a previously used LLC_occupancy
counter can be considered for reuse.
+If monitoring is available at other cache levels there will be a
+"<LEVEL>_MON" directory for each of them, with the same "num_rmids" and
+"mon_features" files. For example an L2 cache exposes "l2c_occupancy" and
+"mbm_core_bytes" in "L2_MON". The counter assignment interface
+("mbm_assign_mode", "mbm_L3_assignments") is specific to the L3.
+
If telemetry monitoring is available there will be a "PERF_PKG_MON" directory
with the following files:
--
2.34.1
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v2 01/19] arm_mpam: resctrl: Leave CDP off when there are too few PARTIDs
2026-10-29 12:35 ` [RFC PATCH v2 01/19] arm_mpam: resctrl: Leave CDP off when there are too few PARTIDs Jinjie Ruan
@ 2026-10-30 16:38 ` Ben Horgan
0 siblings, 0 replies; 22+ messages in thread
From: Ben Horgan @ 2026-10-30 16:38 UTC (permalink / raw)
To: Jinjie Ruan, reinette.chatre, james.morse, fenghuay,
catalin.marinas, will, mark.rutland, corbet, skhan, rdunlap,
tony.luck, Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen,
hpa, tan.shaopeng, jic23, zengheng4, gshan, x86,
linux-arm-kernel, linux-doc, linux-kernel, linux-riscv
Hi Jinjie,
Thanks for this fix!
On 29/10/2026 12:35, Jinjie Ruan wrote:
> Enabling CDP needs a second PARTID for the reserved closid.
I'm not sure what a 'reserved closid' is here but you could just say:
Enabling CDP requires at least 2 PARTIDs.
> If firmware
> reports too few PARTIDs, resctrl_arch_set_cdp_enabled() returns -EINVAL,
Not all systems are firmware backed. This can be:
If there are too few PARTIDs, ... .
> but only after it has recorded CDP as enabled, halved the monitor count
> and turned off the mbw_max MBA control.
> resctrl then reports an error
> and believes CDP is off, which leaves the two sides out of step and the
> halved monitor count and the missing MBA control are not undone.
I think the 'reports an error part' can be dropped leaving 'resctrl then believes CDP is off...' as
exactly what resctrl does is not important here.
>
> Check the PARTID limit, and work out the CDP PARTIDs, before anything is
Why work out the CDP PARTIDs so early if they aren't going to be used?
> changed so a failed enable has no effect.
>
> Fixes: 6789fb99282c ("arm_mpam: resctrl: Add CDP emulation")
> Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
> ---
> drivers/resctrl/mpam_resctrl.c | 20 ++++++++++++--------
> 1 file changed, 12 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index 5468367776e2..886f0595d364 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c
> @@ -210,6 +210,18 @@ int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
> if (enable)
> pr_warn("CDP is an expert feature and may cause MPAM to malfunction.\n");
>
> + /*
> + * Check this before changing any state: if CDP can't be enabled the
> + * caller must see CDP left off.
> + */
I don't think this comment is needed. Failing early rather than failing late after some side effects
have happened is clearly better.
> + if (enable) {
> + if (mpam_partid_max < 1)
> + return -EINVAL;
> +
> + partid_d = resctrl_get_config_index(RESCTRL_RESERVED_CLOSID, CDP_DATA);
> + partid_i = resctrl_get_config_index(RESCTRL_RESERVED_CLOSID, CDP_CODE);
The partid_d/partid_i determination can stay below so it's close to the user.
I think we can just have the check here:
if (enable && mpam_partid_max < 1)
return -EINVAL;
Thanks,
Ben
> + }
> +
> /*
> * resctrl_arch_set_cdp_enabled() is only called with enable set to
> * false on error and unmount.
> @@ -238,14 +250,6 @@ int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
> if (!cdp_enabled && mpam_resctrl_controls[RDT_RESOURCE_MBA].class)
> mpam_resctrl_controls[RDT_RESOURCE_MBA].resctrl_res.alloc_capable = true;
>
> - if (enable) {
> - if (mpam_partid_max < 1)
> - return -EINVAL;
> -
> - partid_d = resctrl_get_config_index(RESCTRL_RESERVED_CLOSID, CDP_DATA);
> - partid_i = resctrl_get_config_index(RESCTRL_RESERVED_CLOSID, CDP_CODE);
> - }
> -
> mpam_set_task_partid_pmg(current, partid_d, partid_i, 0, 0);
> WRITE_ONCE(arm64_mpam_global_default, mpam_get_regval(current));
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
` (18 preceding siblings ...)
2026-10-29 12:36 ` [RFC PATCH v2 19/19] Documentation: arm64: mpam: Describe " Jinjie Ruan
@ 2026-10-30 17:09 ` Reinette Chatre
19 siblings, 0 replies; 22+ messages in thread
From: Reinette Chatre @ 2026-10-30 17:09 UTC (permalink / raw)
To: Jinjie Ruan, james.morse, ben.horgan, fenghuay, catalin.marinas,
will, mark.rutland, corbet, skhan, rdunlap, tony.luck,
Dave.Martin, babu.moger, tglx, mingo, bp, dave.hansen, hpa,
tan.shaopeng, jic23, zengheng4, gshan, x86, linux-arm-kernel,
linux-doc, linux-kernel, linux-riscv
Hi Jinjie,
On 10/29/26 5:35 AM, Jinjie Ruan wrote:
> Resctrl only knows about monitoring at the L3 scope. MPAM monitors are
> attached to a resource in an MSC, and firmware says which cache level that
> resource is. The driver already finds L2 monitors, but resctrl has
> nowhere to show them.
>
> This is not MPAM specific. RISC-V can also place monitors at several
> points in the system.
>
One key to this is in the first sentence of this cover letter: "Resctrl only knows
about monitoring at the L3 *scope*.".
When it comes to exposing monitoring data to user space resctrl has been using "L3"
interchangeable as resource and scope.
The existing resctrl user interface already establishes that the "L3" in
"L3_MON" and the per monitor group "mon_data/mon_L3_xx" refers to the L3 *scope*,
not the L3 resource. More specifically, consider the existing user interface:
# find mon_data/
mon_data/
mon_data/mon_L3_00
mon_data/mon_L3_00/mbm_local_bytes <=== monitoring data associated with MB resource at L3 scope
mon_data/mon_L3_00/mbm_total_bytes <=== monitoring data associated with MB resource at L3 scope
mon_data/mon_L3_00/llc_occupancy <=== monitoring data associated with L3 resource at L3 scope
Associating the monitor events with the L3 resource was an implementation choice
that was convenient at the time. Since L2 can similarly be used interchangeably for resource
and scope associating the L2 scope monitoring with the L2 resource may similarly be convenient
when considering how to support L2 monitors as is done in this series.
Even so, I do not believe that associating monitoring with the resource will be
able to cleanly support all MPAM monitoring capability. Specifically the upcoming CPU-less
memory bandwidth monitoring.
As I see the plan at this time: CPU-less memory bandwidth allocation will be
backed by a new MB_NODE resource. For these systems the expectation is that their
monitoring data will be exposed to user space via NODE scope and will appear to user space as:
mon_data/
mon_data/mon_NODE_00
mon_data/mon_NODE_00/mbm_total_bytes <=== monitoring data associated with MB resource at NODE scope
The cover-letter is titled "Generalize monitor events across resources". As I see it such
generalization does not prepare resctrl for all MPAM monitoring capabilities. Could this
work do so?
Reinette
^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2026-10-30 17:09 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-29 12:35 [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Jinjie Ruan
2026-10-29 12:35 ` [RFC PATCH v2 01/19] arm_mpam: resctrl: Leave CDP off when there are too few PARTIDs Jinjie Ruan
2026-10-30 16:38 ` Ben Horgan
2026-10-29 12:35 ` [RFC PATCH v2 02/19] fs/resctrl: Generalize __l3_mon_event_count for non-L3 resources Jinjie Ruan
2026-10-29 12:35 ` [RFC PATCH v2 03/19] fs/resctrl: Rename monitor events to drop the L3 prefix Jinjie Ruan
2026-10-29 12:35 ` [RFC PATCH v2 04/19] x86/resctrl: Use the resource-agnostic monitor event names Jinjie Ruan
2026-10-29 12:35 ` [RFC PATCH v2 05/19] arm_mpam: resctrl: " Jinjie Ruan
2026-10-29 12:35 ` [RFC PATCH v2 06/19] resctrl: Remove the L3 " Jinjie Ruan
2026-10-29 12:35 ` [RFC PATCH v2 07/19] arm_mpam: resctrl: Index monitor state by resource and event Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 08/19] arm_mpam: resctrl: Halve the monitor counts of every resource on CDP Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 09/19] x86,fs/resctrl: Pass the resource to the monitor event helpers Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 10/19] fs/resctrl: Track monitor events per resource Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 11/19] fs/resctrl: Add the L2 monitor events Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 12/19] fs/resctrl: Set up MBM state and workers for every monitor resource Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 13/19] fs/resctrl: Check RMID limbo on every resource with occupancy Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 14/19] fs/resctrl: Manage assignable counters for every monitor resource Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 15/19] arm_mpam: resctrl: Look up the monitor domain id from the components Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 16/19] arm_mpam: resctrl: Report counter assignment per resource Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 17/19] arm_mpam: resctrl: Allow monitoring on resources other than the L3 Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 18/19] arm_mpam: resctrl: Expose the L2 monitor events Jinjie Ruan
2026-10-29 12:36 ` [RFC PATCH v2 19/19] Documentation: arm64: mpam: Describe " Jinjie Ruan
2026-10-30 17:09 ` [RFC PATCH v2 00/19] resctrl: Generalize monitor events across resources Reinette Chatre
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®