[PATCH v8 next 04/10] arm_mpam: Refactor rmid to reqPARTID/PMG mapping

Zeng Heng
2026-04-13T08:55:24Z

The Narrow-PARTID feature allows the MPAM driver to statically or
dynamically allocate request PARTIDs (reqPARTIDs) to internal
PARTIDs (intPARTIDs). This enables expanding the number of monitoring
groups beyond the hardware PMG limit.

For systems with mixed MSCs (Memory System Components), MSCs that do
not support Narrow-PARTID use PARTIDs exceeding the minimum number of
intPARTIDs as reqPARTIDs to expand monitoring groups.

Expand RMID to include reqPARTID information:

RMID = reqPARTID * NUM_PMG + PMG

To maintain compatibility with the existing resctrl layer, reqPARTIDs
are allocated statically with a linear mapping to intPARTIDs via
req2intpartid().

Mapping relationships (n = intPARTID count, m = reqPARTIDs per intPARTID):

P - Partition group
M - Monitoring group

Group closid rmid.reqPARTID MSCs w/ Narrow-PARTID MSCs w/o Narrow-PARTID
P1 0 intPARTID_1 PARTID_1
M1_1 0 0 ├── reqPARTID_1_1 ├── PARTID_1
M1_2 0 0+n ├── reqPARTID_1_2 ├── PARTID_1_2
M1_3 0 0+n*2 ├── reqPARTID_1_3 ├── PARTID_1_3
... ├── ... ├── ...
M1_m 0 0+n*(m-1) └── reqPARTID_1_m └── PARTID_1_m

P2 1 intPARTID_2 PARTID_2
M2_1 1 1 ├── reqPARTID_2_1 ├── PARTID_2
M2_2 1 1+n ├── reqPARTID_2_2 ├── PARTID_2_2
M2_3 1 1+n*2 ├── reqPARTID_2_3 ├── PARTID_2_3
... ├── ... ├── ...
M2_m 1 1+n*(m-1) └── reqPARTID_2_m └── PARTID_2_m

Pn n-1 intPARTID_n PARTID_n
Mn_1 n-1 n-1 ├── reqPARTID_n_1 ├── PARTID_n
Mn_2 n-1 n-1+n ├── reqPARTID_n_2 ├── PARTID_n_2
Mn_3 n-1 n-1+n*2 ├── reqPARTID_n_3 ├── PARTID_n_3
... ├── ... ├── ...
Mn_m n-1 n*m-1 └── reqPARTID_n_m └── PARTID_n_m

Refactor the glue layer between resctrl abstractions (rmid) and MPAM
hardware registers (reqPARTID/PMG) to support Narrow-PARTID. The resctrl
layer uses rmid2reqpartid() and rmid2pmg() to extract components from
rmid. The closid-to-intPARTID translation remains unchanged via
resctrl_get_config_index().

Since Narrow-PARTID is a monitoring enhancement, reqPARTID is only
used in monitoring paths while configuration paths maintain the original
semantics of closid.

Signed-off-by: Zeng Heng <zengheng4@huawei.com>
---
arch/arm64/include/asm/mpam.h | 12 +++-
drivers/resctrl/mpam_resctrl.c | 101 +++++++++++++++++++++++----------
2 files changed, 82 insertions(+), 31 deletions(-)

diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
index 70d396e7b6da..40d60b0ab0fd 100644
--- a/arch/arm64/include/asm/mpam.h
+++ b/arch/arm64/include/asm/mpam.h
@@ -63,6 +63,15 @@ static inline void mpam_set_task_partid_pmg(struct task_struct *tsk,
WRITE_ONCE(task_thread_info(tsk)->mpam_partid_pmg, regval);
}

+u16 req2intpartid(u16 reqpartid);
+
+static inline u16 mpam_get_regval_partid(u64 regval)
+{
+ u16 reqpartid = (regval & MPAMSM_EL1_PARTID_D_MASK) >> MPAMSM_EL1_PARTID_D_SHIFT;
+
+ return req2intpartid(reqpartid);
+}
+
static inline void mpam_thread_switch(struct task_struct *tsk)
{
u64 oldregval;
@@ -72,7 +81,8 @@ static inline void mpam_thread_switch(struct task_struct *tsk)
if (!static_branch_likely(&mpam_enabled))
return;

- if (regval == READ_ONCE(arm64_mpam_global_default))
+ if (regval == READ_ONCE(arm64_mpam_global_default) ||
+ !mpam_get_regval_partid(regval))
regval = READ_ONCE(per_cpu(arm64_mpam_default, cpu));

oldregval = READ_ONCE(per_cpu(arm64_mpam_current, cpu));
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 56859f354efa..9d0a7a4dffd1 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -303,15 +303,60 @@ u32 resctrl_arch_system_num_rmid_idx(void)
return (mpam_pmg_max + 1) * get_num_reqpartid();
}

+static u16 rmid2reqpartid(u32 rmid)
+{
+ rmid /= (mpam_pmg_max + 1);
+
+ if (cdp_enabled)
+ return resctrl_get_config_index(rmid, CDP_DATA);
+
+ return resctrl_get_config_index(rmid, CDP_NONE);
+}
+
+static u8 rmid2pmg(u32 rmid)
+{
+ return rmid % (mpam_pmg_max + 1);
+}
+
+u16 req2intpartid(u16 reqpartid)
+{
+ return reqpartid % (mpam_intpartid_max + 1);
+}
+
+/*
+ * To avoid the reuse of rmid across multiple control groups, check
+ * the incoming closid to prevent rmid from being reallocated by
+ * resctrl_find_free_rmid().
+ *
+ * If the closid and rmid do not match upon inspection, immediately
+ * returns an invalid rmid. A valid rmid must not exceed 24 bits.
+ */
u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid)
{
- return closid * (mpam_pmg_max + 1) + rmid;
+ u32 reqpartid = rmid2reqpartid(rmid);
+ u32 intpartid = req2intpartid(reqpartid);
+
+ if (cdp_enabled)
+ intpartid >>= 1;
+
+ if (closid != intpartid)
+ return U32_MAX;
+
+ return rmid;
}

void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid)
{
- *closid = idx / (mpam_pmg_max + 1);
- *rmid = idx % (mpam_pmg_max + 1);
+ u32 reqpartid = rmid2reqpartid(idx);
+ u32 intpartid = req2intpartid(reqpartid);
+
+ if (rmid)
+ *rmid = idx;
+ if (closid) {
+ if (cdp_enabled)
+ intpartid >>= 1;
+ *closid = intpartid;
+ }
}

void resctrl_arch_sched_in(struct task_struct *tsk)
@@ -323,21 +368,17 @@ void resctrl_arch_sched_in(struct task_struct *tsk)

void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid)
{
- WARN_ON_ONCE(closid > U16_MAX);
- WARN_ON_ONCE(rmid > U8_MAX);
+ u32 reqpartid = rmid2reqpartid(rmid);
+ u8 pmg = rmid2pmg(rmid);

- if (!cdp_enabled) {
- mpam_set_cpu_defaults(cpu, closid, closid, rmid, rmid);
- } else {
+ if (!cdp_enabled)
+ mpam_set_cpu_defaults(cpu, reqpartid, reqpartid, pmg, pmg);
+ else
/*
* When CDP is enabled, resctrl halves the closid range and we
* use odd/even partid for one closid.
*/
- u32 partid_d = resctrl_get_config_index(closid, CDP_DATA);
- u32 partid_i = resctrl_get_config_index(closid, CDP_CODE);
-
- mpam_set_cpu_defaults(cpu, partid_d, partid_i, rmid, rmid);
- }
+ mpam_set_cpu_defaults(cpu, reqpartid, reqpartid + 1, pmg, pmg);
}

void resctrl_arch_sync_cpu_closid_rmid(void *info)
@@ -356,17 +397,16 @@ void resctrl_arch_sync_cpu_closid_rmid(void *info)

void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
{
- WARN_ON_ONCE(closid > U16_MAX);
- WARN_ON_ONCE(rmid > U8_MAX);
+ u32 reqpartid = rmid2reqpartid(rmid);
+ u8 pmg = rmid2pmg(rmid);

- if (!cdp_enabled) {
- mpam_set_task_partid_pmg(tsk, closid, closid, rmid, rmid);
- } else {
- u32 partid_d = resctrl_get_config_index(closid, CDP_DATA);
- u32 partid_i = resctrl_get_config_index(closid, CDP_CODE);
+ WARN_ON_ONCE(reqpartid > U16_MAX);
+ WARN_ON_ONCE(pmg > U8_MAX);

- mpam_set_task_partid_pmg(tsk, partid_d, partid_i, rmid, rmid);
- }
+ if (!cdp_enabled)
+ mpam_set_task_partid_pmg(tsk, reqpartid, reqpartid, pmg, pmg);
+ else
+ mpam_set_task_partid_pmg(tsk, reqpartid, reqpartid + 1, pmg, pmg);
}

bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid)
@@ -374,6 +414,8 @@ bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid)
u64 regval = mpam_get_regval(tsk);
u32 tsk_closid = FIELD_GET(MPAM0_EL1_PARTID_D, regval);

+ tsk_closid = req2intpartid(tsk_closid);
+
if (cdp_enabled)
tsk_closid >>= 1;

@@ -384,13 +426,11 @@ bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid)
bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
{
u64 regval = mpam_get_regval(tsk);
- u32 tsk_closid = FIELD_GET(MPAM0_EL1_PARTID_D, regval);
- u32 tsk_rmid = FIELD_GET(MPAM0_EL1_PMG_D, regval);
-
- if (cdp_enabled)
- tsk_closid >>= 1;
+ u32 tsk_partid = FIELD_GET(MPAM0_EL1_PARTID_D, regval);
+ u32 tsk_pmg = FIELD_GET(MPAM0_EL1_PMG_D, regval);

- return (tsk_closid == closid) && (tsk_rmid == rmid);
+ return (tsk_partid == rmid2reqpartid(rmid)) &&
+ (tsk_pmg == rmid2pmg(rmid));
}

struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
@@ -478,6 +518,7 @@ static int __read_mon(struct mpam_resctrl_mon *mon, struct mpam_component *mon_c
enum resctrl_conf_type cdp_type, u32 closid, u32 rmid, u64 *val)
{
struct mon_cfg cfg;
+ u32 reqpartid = rmid2reqpartid(rmid);

if (!mpam_is_enabled())
return -EINVAL;
@@ -493,8 +534,8 @@ static int __read_mon(struct mpam_resctrl_mon *mon, struct mpam_component *mon_c
cfg = (struct mon_cfg) {
.mon = mon_idx,
.match_pmg = true,
- .partid = closid,
- .pmg = rmid,
+ .partid = (cdp_type == CDP_CODE) ? reqpartid + 1 : reqpartid,
+ .pmg = rmid2pmg(rmid),
};

return mpam_msmon_read(mon_comp, &cfg, mon_type, val);
--
2.25.1