[RFC PATCH 7/7] arm_mpam: resctrl: Add the L2 monitor read paths

Jinjie Ruan ruanjinjie at huawei.com
Thu Oct 22 01:48:21 PDT 2026


Wire the L2 events through the borrowed-monitor paths:
l2c_occupancy borrows a CSU monitor like the L3 occupancy event, while
mbm_core_bytes borrows a bandwidth monitor. The L2 bandwidth event is
outside resctrl's L3 MBM event range, so the assignable-counter
machinery never applies to it; with CDP, borrow one monitor per partid
so code and data both accumulate.

Accept both events in resctrl_arch_rmid_read() and skip them in the
assignable-counter paths.

Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 drivers/resctrl/mpam_resctrl.c | 62 +++++++++++++++++++++++++++++++---
 1 file changed, 58 insertions(+), 4 deletions(-)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 293122c0d0d9..3aa7ea996511 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -412,6 +412,7 @@ static int resctrl_arch_mon_ctx_alloc_no_wait(enum resctrl_event_id evtid,
 
 	switch (evtid) {
 	case QOS_L3_OCCUP_EVENT_ID:
+	case QOS_L2_OCCUP_EVENT_ID:
 		/* With CDP, one monitor gets used for both code/data reads */
 		mon_ctx[MON_CTX_DATA] = mpam_alloc_csu_mon(mon->class);
 		mon_ctx[MON_CTX_CODE] = mon_ctx[MON_CTX_DATA];
@@ -422,6 +423,31 @@ static int resctrl_arch_mon_ctx_alloc_no_wait(enum resctrl_event_id evtid,
 		mon_ctx[MON_CTX_DATA] = USE_PRE_ALLOCATED;
 		mon_ctx[MON_CTX_CODE] = USE_PRE_ALLOCATED;
 		return USE_PRE_ALLOCATED;
+	case QOS_L2_MBM_CORE_EVENT_ID:
+		/*
+		 * The L2 event is not part of resctrl's L3 MBM event range,
+		 * so the assignable-counter machinery never applies: borrow a
+		 * bandwidth monitor for the duration of the read, like the
+		 * occupancy events do with CSU monitors. With CDP, borrow one
+		 * monitor per partid so code and data both accumulate.
+		 */
+		mon_ctx[MON_CTX_DATA] = mpam_alloc_mbwu_mon(mon->class);
+		if (mon_ctx[MON_CTX_DATA] < 0)
+			return mon_ctx[MON_CTX_DATA];
+
+		if (!cdp_enabled) {
+			mon_ctx[MON_CTX_CODE] = mon_ctx[MON_CTX_DATA];
+			return mon_ctx[MON_CTX_DATA];
+		}
+
+		mon_ctx[MON_CTX_CODE] = mpam_alloc_mbwu_mon(mon->class);
+		if (mon_ctx[MON_CTX_CODE] < 0) {
+			int err = mon_ctx[MON_CTX_CODE];
+
+			mpam_free_mbwu_mon(mon->class, mon_ctx[MON_CTX_DATA]);
+			return err;
+		}
+		return mon_ctx[MON_CTX_DATA];
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -460,8 +486,24 @@ 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)
+	switch (evtid) {
+	case QOS_L3_OCCUP_EVENT_ID:
+	case QOS_L2_OCCUP_EVENT_ID:
+		/* With CDP, one monitor is used for both code/data reads */
 		mpam_free_csu_mon(mon->class, mon_ctx[MON_CTX_DATA]);
+		break;
+	case QOS_L3_MBM_LOCAL_EVENT_ID:
+	case QOS_L3_MBM_TOTAL_EVENT_ID:
+		/* Served by the pre-assigned ABMC counters */
+		break;
+	case QOS_L2_MBM_CORE_EVENT_ID:
+		mpam_free_mbwu_mon(mon->class, mon_ctx[MON_CTX_DATA]);
+		if (mon_ctx[MON_CTX_CODE] != mon_ctx[MON_CTX_DATA])
+			mpam_free_mbwu_mon(mon->class, mon_ctx[MON_CTX_CODE]);
+		break;
+	default:
+		break;
+	}
 
 	wake_up(&resctrl_mon_ctx_waiters);
 }
@@ -557,10 +599,22 @@ 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)
+	switch (eventid) {
+	case QOS_L3_OCCUP_EVENT_ID:
+	case QOS_L2_OCCUP_EVENT_ID:
+		mon_type = mpam_feat_msmon_csu;
+		break;
+	case QOS_L2_MBM_CORE_EVENT_ID:
+		/*
+		 * Served by a bandwidth monitor borrowed for the read via
+		 * resctrl_arch_mon_ctx_alloc(); the L3 MBWU events use the
+		 * ABMC resctrl_arch_cntr_read() path instead.
+		 */
+		mon_type = mpam_feat_msmon_mbwu;
+		break;
+	default:
 		return -EINVAL;
-
-	mon_type = mpam_feat_msmon_csu;
+	}
 
 	return read_mon_cdp_safe(mon, mon_comp, mon_type, arch_mon_ctx,
 				 closid, rmid, val);
-- 
2.43.0




More information about the linux-arm-kernel mailing list