mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature
@ 2026-03-17 13:21 Zeng Heng
  2026-03-17 13:21 ` [PATCH v3 1/9] fs/resctrl: Fix MPAM Partid parsing errors by preserving CDP state during umount Zeng Heng
                   ` (10 more replies)
  0 siblings, 11 replies; 22+ messages in thread
From: Zeng Heng @ 2026-03-17 13:21 UTC (permalink / raw)
  To: ben.horgan, james.morse, Dave.Martin, reinette.chatre, fenghuay
  Cc: dave.hansen, tglx, mingo, hpa, bp, tony.luck, babu.moger, x86,
	linux-kernel, wangkefeng.wang

This series applies on top of the mpam_resctrl_glue_v5_debugfs branch of:
https://gitlab.arm.com/linux-arm/linux-bh.git

Background
==========

On x86, the resctrl allows creating up to num_rmids monitoring groups
under parent control group. However, ARM64 MPAM is currently limited by
the PMG (Performance Monitoring Group) count, which is typically much
smaller than the theoretical RMID limit. This creates a significant
scalability gap: users expecting fine-grained per-process or per-thread
monitoring quickly exhaust the PMG space, even when plenty of reqPARTIDs
remain available.

The Narrow-PARTID feature, defined in the ARM MPAM architecture,
addresses this by associating reqPARTIDs with intPARTIDs through a
programmable many-to-one mapping. This allows the kernel to present more
logical monitoring contexts.

Design Overview
===============

The implementation extends the RMID encoding to carry reqPARTID
information:

  RMID = reqPARTID * NUM_PMG + PMG

In this patchset, a monitoring group is uniquely identified by the
combination of reqPARTID and PMG. The closid is represented by intPARTID,
which is exactly the original PARTID.

For systems with homogeneous MSCs (all supporting Narrow-PARTID), the
driver exposes the full reqPARTID range directly. For heterogeneous
systems where some MSCs lack Narrow-PARTID support, the driver utilizes
PARTIDs beyond the intPARTID range as reqPARTIDs to expand monitoring
capacity. The sole exception is when MBA MSCs lack Narrow-PARTID support,
their percentage-based control mechanism prevents the use of PARTIDs as
reqPARTIDs.

Capacity Improvements
=====================

--------------------------------------------------------------------------
The maximum        |  Sub-monitoring groups            | System-wide
number of          |  under a control group            | monitoring groups
--------------------------------------------------------------------------
Without            |                                   |
reqPARTID          |  PMG                              | intPARTID * PMG
--------------------------------------------------------------------------
reqPARTID          |                                   |
static allocation  | (reqPARTID // intPARTID) * PMG    | reqPARTID * PMG
--------------------------------------------------------------------------
reqPARTID          |                                   |
dynamic allocation | (reqPARTID − intPARTID + 1) * PMG | reqPARTID * PMG
--------------------------------------------------------------------------

Under MPAM, the number of reqPARTID is always greater than or equal to
intPARTID.

Series Structure
================

Patch 1: Fix pre-existing out-of-range PARTID issue between mount sessions.
Patches 2-5: Implement static reqPARTID allocation.
Patches 6-9: Implement dynamic reqPARTID allocation.

---
Compared with v2:
  - Add dynamic reqPARTID allocation implementation.
  - Add Patch 1 to fix pre-existing out-of-range PARTID issue.
  - Drop original patch 4 which has been merged into the baseline.

Compared with v1:
  - Redefine the RMID information.
  - Refactor the resctrl_arch_rmid_idx_decode() and
    resctrl_arch_rmid_idx_encode().
  - Simplify closid_rmid2reqpartid() to rmid2reqpartid() and replace it
    accordingly.

Compared with RFC-v4:
  - Rebase the patch set on the v6.14-rc1 branch.

Compared with RFC-v3:
  - Add limitation of the Narrow-PARTID feature (See Patch 2).
  - Remove redundant reqpartid2closid() and reqpartid_pmg2rmid().
  - Refactor closid_rmid2reqpartid() partially.
  - Merge the PARTID conversion-related patches into a single patch for
    bisectability.
  - Skip adaptation of resctrl_arch_set_rmid() which is going to be
    removed.

Compared with RFC-v2:
  - Refactor closid/rmid pair translation.
  - Simplify the logic of synchronize configuration.
  - Remove reqPARTID source bitmap.

Compared with RFC-v1:
  - Rebase this patch set on latest MPAM driver of the v6.12-rc1 branch.

    v2: https://lore.kernel.org/all/20250222112448.2438586-1-zengheng4@huawei.com/
    v1: https://lore.kernel.org/all/20250217031852.2014939-1-zengheng4@huawei.com/
RFC-v4: https://lore.kernel.org/all/20250104101224.873926-1-zengheng4@huawei.com/
RFC-v3: https://lore.kernel.org/all/20241207092136.2488426-1-zengheng4@huawei.com/
RFC-v2: https://lore.kernel.org/all/20241119135104.595630-1-zengheng4@huawei.com/
RFC-v1: https://lore.kernel.org/all/20241114135037.918470-1-zengheng4@huawei.com/
---

Zeng Heng (9):
  fs/resctrl: Fix MPAM Partid parsing errors by preserving CDP state
    during umount
  arm_mpam: Add intPARTID and reqPARTID support for narrow PARTID
    feature
  arm_mpam: Disable Narrow-PARTID when MBA lacks support
  arm_mpam: Refactor rmid to reqPARTID/PMG mapping
  arm_mpam: Propagate control group config to sub-monitoring groups
  fs/resctrl: Add rmid_entry state helpers
  arm_mpam: Implement dynamic reqPARTID allocation for monitoring groups
  fs/resctrl: Wire up rmid expansion and reclaim functions
  arm64/mpam: Add mpam_sync_config() for dynamic rmid expansion

 arch/x86/include/asm/resctrl.h  |   7 +
 drivers/resctrl/mpam_devices.c  |  83 ++++++---
 drivers/resctrl/mpam_internal.h |   7 +-
 drivers/resctrl/mpam_resctrl.c  | 289 ++++++++++++++++++++++++++++----
 fs/resctrl/monitor.c            |  50 +++++-
 fs/resctrl/rdtgroup.c           |  24 ++-
 include/linux/arm_mpam.h        |  17 ++
 include/linux/resctrl.h         |  21 +++
 8 files changed, 434 insertions(+), 64 deletions(-)

--
2.25.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v3 1/9] fs/resctrl: Fix MPAM Partid parsing errors by preserving CDP state during umount
  2026-03-17 13:21 [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature Zeng Heng
@ 2026-03-17 13:21 ` Zeng Heng
  2026-03-20 17:07   ` Ben Horgan
  2026-03-17 13:21 ` [PATCH v3 2/9] arm_mpam: Add intPARTID and reqPARTID support for narrow PARTID feature Zeng Heng
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 22+ messages in thread
From: Zeng Heng @ 2026-03-17 13:21 UTC (permalink / raw)
  To: ben.horgan, james.morse, Dave.Martin, reinette.chatre, fenghuay
  Cc: dave.hansen, tglx, mingo, hpa, bp, tony.luck, babu.moger, x86,
	linux-kernel, wangkefeng.wang

This patch fixes a pre-existing issue in the resctrl filesystem teardown
sequence where premature clearing of cdp_enabled could lead to MPAM Partid
parsing errors.

The closid to partid conversion logic inherently depends on the global
cdp_enabled state. However, rdt_disable_ctx() clears this flag early in
the umount path, while free_rmid() operations will reference after that.
This creates a window where partid parsing operates with inconsistent CDP
state, potentially make monitor reads with wrong partid mapping.

Additionally, rmid_entry remaining in limbo between mount sessions may
trigger potential partid out-of-range errors, leading to MPAM fault
interrupts and subsequent MPAM disablement.

Reorder rdt_kill_sb() to delay rdt_disable_ctx() until after
rmdir_all_sub() and resctrl_fs_teardown() complete. This ensures
all rmid-related operations finish with correct CDP state.

Introduce rdt_flush_limbo() to flush and cancel limbo work before the
filesystem teardown completes. An alternative approach would be to cancel
limbo work on umount and restart it on remount with remaked bitmap.
However, this would require substantial changes in the resctrl layer to
handle CDP state transitions across mount sessions, which is beyond the
scope of the reqpartid feature work this patchset focuses on. The current
fix addresses the immediate correctness issue with minimal churn.

Signed-off-by: Zeng Heng <zengheng4@huawei.com>
---
 fs/resctrl/rdtgroup.c | 24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 5da305bd36c9..bc0735eef92a 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -3165,6 +3165,25 @@ static void resctrl_fs_teardown(void)
 	rdtgroup_destroy_root();
 }
 
+static void rdt_flush_limbo(void)
+{
+	struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
+	struct rdt_l3_mon_domain *d;
+
+	if (!IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID))
+		return;
+
+	if (!resctrl_is_mon_event_enabled(QOS_L3_OCCUP_EVENT_ID))
+		return;
+
+	list_for_each_entry(d, &r->mon_domains, hdr.list) {
+		if (has_busy_rmid(d)) {
+			__check_limbo(d, true);
+			cancel_delayed_work(&d->cqm_limbo);
+		}
+	}
+}
+
 static void rdt_kill_sb(struct super_block *sb)
 {
 	struct rdt_resource *r;
@@ -3172,13 +3191,14 @@ static void rdt_kill_sb(struct super_block *sb)
 	cpus_read_lock();
 	mutex_lock(&rdtgroup_mutex);
 
-	rdt_disable_ctx();
-
 	/* Put everything back to default values. */
 	for_each_alloc_capable_rdt_resource(r)
 		resctrl_arch_reset_all_ctrls(r);
 
 	resctrl_fs_teardown();
+	rdt_flush_limbo();
+	rdt_disable_ctx();
+
 	if (resctrl_arch_alloc_capable())
 		resctrl_arch_disable_alloc();
 	if (resctrl_arch_mon_capable())
-- 
2.25.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v3 2/9] arm_mpam: Add intPARTID and reqPARTID support for narrow PARTID feature
  2026-03-17 13:21 [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature Zeng Heng
  2026-03-17 13:21 ` [PATCH v3 1/9] fs/resctrl: Fix MPAM Partid parsing errors by preserving CDP state during umount Zeng Heng
@ 2026-03-17 13:21 ` Zeng Heng
  2026-03-17 13:21 ` [PATCH v3 3/9] arm_mpam: Disable Narrow-PARTID when MBA lacks support Zeng Heng
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 22+ messages in thread
From: Zeng Heng @ 2026-03-17 13:21 UTC (permalink / raw)
  To: ben.horgan, james.morse, Dave.Martin, reinette.chatre, fenghuay
  Cc: dave.hansen, tglx, mingo, hpa, bp, tony.luck, babu.moger, x86,
	linux-kernel, wangkefeng.wang

Introduce narrow PARTID (partid_nrw) feature support, which enables
many-to-one mapping of request PARTIDs (reqPARTID) to internal PARTIDs
(intPARTID). This expands monitoring capability by allowing a single
control group to track more task types through multiple reqPARTIDs
per intPARTID, bypassing the PMG limit in some extent.

intPARTID: Internal PARTID used for control group configuration.
Configurations are synchronized to all reqPARTIDs mapped to the same
intPARTID. Count is indicated by MPAMF_PARTID_NRW_IDR.INTPARTID_MAX, or
defaults to PARTID count if narrow PARTID is unsupported.

reqPARTID: Request PARTID used to expand monitoring groups. Enables
a single control group to monitor more task types by multiple reqPARTIDs
within one intPARTID, overcoming the PMG count limitation.

For systems with homogeneous MSCs (all supporting Narrow-PARTID), the
driver exposes the full reqPARTID range directly. For heterogeneous
systems where some MSCs lack Narrow-PARTID support, the driver utilizes
PARTIDs beyond the intPARTID range as reqPARTIDs to expand monitoring
capacity.

So, the numbers of control group and monitoring group are calculated as:

  n = min(intPARTID, PARTID)  /* the number of control groups */
  l = min(reqPARTID, PARTID)  /* the number of monitoring groups */
  m = l // n                  /* monitoring groups per control group */

Where:

  intPARTID: intPARTIDs on narrow-PARTID-capable MSCs
  reqPARTID: reqPARTIDs on narrow-PARTID-capable MSCs
  PARTID:    PARTIDs on non-narrow-PARTID-capable MSCs

Example: L3 cache (256 PARTIDs, without narrow PARTID feature) +
         MATA (32 intPARTIDs, 256 reqPARTIDs):

  n = min( 32, 256) =  32 intPARTIDs
  l = min(256, 256) = 256 reqPARTIDs
  m = 256 / 32 = 8 reqPARTIDs per intPARTID

Implementation notes:
  * Handle mixed MSC systems (some support narrow PARTID, some don't) by
    taking minimum number of intPARTIDs across all MSCs.
  * resctrl_arch_get_num_closid() now returns the number of intPARTIDs
    (was PARTID).

Signed-off-by: Zeng Heng <zengheng4@huawei.com>
---
 drivers/resctrl/mpam_devices.c  | 30 ++++++++++++++++++++----------
 drivers/resctrl/mpam_internal.h |  2 ++
 drivers/resctrl/mpam_resctrl.c  |  4 ++--
 3 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 924d68b86948..2634afc41c6a 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -63,6 +63,7 @@ static DEFINE_MUTEX(mpam_cpuhp_state_lock);
  * Generating traffic outside this range will result in screaming interrupts.
  */
 u16 mpam_partid_max;
+u16 mpam_intpartid_max;
 u8 mpam_pmg_max;
 static bool partid_max_init, partid_max_published;
 static DEFINE_SPINLOCK(partid_max_lock);
@@ -290,10 +291,12 @@ int mpam_register_requestor(u16 partid_max, u8 pmg_max)
 {
 	guard(spinlock)(&partid_max_lock);
 	if (!partid_max_init) {
+		mpam_intpartid_max = partid_max;
 		mpam_partid_max = partid_max;
 		mpam_pmg_max = pmg_max;
 		partid_max_init = true;
 	} else if (!partid_max_published) {
+		mpam_intpartid_max = min(mpam_intpartid_max, partid_max);
 		mpam_partid_max = min(mpam_partid_max, partid_max);
 		mpam_pmg_max = min(mpam_pmg_max, pmg_max);
 	} else {
@@ -933,7 +936,9 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
 		u16 partid_max = FIELD_GET(MPAMF_PARTID_NRW_IDR_INTPARTID_MAX, nrwidr);
 
 		mpam_set_feature(mpam_feat_partid_nrw, props);
-		msc->partid_max = min(msc->partid_max, partid_max);
+		msc->intpartid_max = min(msc->partid_max, partid_max);
+	} else {
+		msc->intpartid_max = msc->partid_max;
 	}
 }
 
@@ -997,6 +1002,7 @@ static int mpam_msc_hw_probe(struct mpam_msc *msc)
 
 	spin_lock(&partid_max_lock);
 	mpam_partid_max = min(mpam_partid_max, msc->partid_max);
+	mpam_intpartid_max = min(mpam_intpartid_max, msc->intpartid_max);
 	mpam_pmg_max = min(mpam_pmg_max, msc->pmg_max);
 	spin_unlock(&partid_max_lock);
 
@@ -1722,7 +1728,7 @@ static int mpam_reset_ris(void *arg)
 	mpam_init_reset_cfg(&reset_cfg);
 
 	spin_lock(&partid_max_lock);
-	partid_max = mpam_partid_max;
+	partid_max = mpam_intpartid_max;
 	spin_unlock(&partid_max_lock);
 	for (partid = 0; partid <= partid_max; partid++)
 		mpam_reprogram_ris_partid(ris, partid, &reset_cfg);
@@ -1778,7 +1784,7 @@ static void mpam_reprogram_msc(struct mpam_msc *msc)
 	struct mpam_write_config_arg arg;
 
 	/*
-	 * No lock for mpam_partid_max as partid_max_published has been
+	 * No lock for mpam_intpartid_max as partid_max_published has been
 	 * set by mpam_enabled(), so the values can no longer change.
 	 */
 	mpam_assert_partid_sizes_fixed();
@@ -1795,7 +1801,7 @@ static void mpam_reprogram_msc(struct mpam_msc *msc)
 		arg.comp = ris->vmsc->comp;
 		arg.ris = ris;
 		reset = true;
-		for (partid = 0; partid <= mpam_partid_max; partid++) {
+		for (partid = 0; partid <= mpam_intpartid_max; partid++) {
 			cfg = &ris->vmsc->comp->cfg[partid];
 			if (!bitmap_empty(cfg->features, MPAM_FEATURE_LAST))
 				reset = false;
@@ -2626,7 +2632,7 @@ static void mpam_reset_component_cfg(struct mpam_component *comp)
 	if (!comp->cfg)
 		return;
 
-	for (i = 0; i <= mpam_partid_max; i++) {
+	for (i = 0; i <= mpam_intpartid_max; i++) {
 		comp->cfg[i] = (struct mpam_config) {};
 		if (cprops->cpbm_wd)
 			comp->cfg[i].cpbm = GENMASK(cprops->cpbm_wd - 1, 0);
@@ -2646,7 +2652,7 @@ static int __allocate_component_cfg(struct mpam_component *comp)
 	if (comp->cfg)
 		return 0;
 
-	comp->cfg = kzalloc_objs(*comp->cfg, mpam_partid_max + 1);
+	comp->cfg = kzalloc_objs(*comp->cfg, mpam_intpartid_max + 1);
 	if (!comp->cfg)
 		return -ENOMEM;
 
@@ -2809,7 +2815,7 @@ static void mpam_enable_once(void)
 	int err;
 
 	/*
-	 * Once the cpuhp callbacks have been changed, mpam_partid_max can no
+	 * Once the cpuhp callbacks have been changed, mpam_intpartid_max can no
 	 * longer change.
 	 */
 	spin_lock(&partid_max_lock);
@@ -2860,9 +2866,13 @@ static void mpam_enable_once(void)
 	mpam_register_cpuhp_callbacks(mpam_cpu_online, mpam_cpu_offline,
 				      "mpam:online");
 
-	/* Use printk() to avoid the pr_fmt adding the function name. */
-	printk(KERN_INFO "MPAM enabled with %u PARTIDs and %u PMGs\n",
-	       mpam_partid_max + 1, mpam_pmg_max + 1);
+	if (mpam_partid_max == mpam_intpartid_max)
+		/* Use printk() to avoid the pr_fmt adding the function name. */
+		printk(KERN_INFO "MPAM enabled with %u PARTIDs and %u PMGs\n",
+		       mpam_partid_max + 1, mpam_pmg_max + 1);
+	else
+		printk(KERN_INFO "MPAM enabled with %u reqPARTIDs, %u intPARTIDs and %u PMGs\n",
+		       mpam_partid_max + 1, mpam_intpartid_max + 1, mpam_pmg_max + 1);
 }
 
 static void mpam_reset_component_locked(struct mpam_component *comp)
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 2a67b5f501bd..2029a5b7283e 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -82,6 +82,7 @@ struct mpam_msc {
 	 */
 	struct mutex		probe_lock;
 	bool			probed;
+	u16			intpartid_max;
 	u16			partid_max;
 	u8			pmg_max;
 	unsigned long		ris_idxs;
@@ -466,6 +467,7 @@ extern struct list_head mpam_classes;
 
 /* System wide partid/pmg values */
 extern u16 mpam_partid_max;
+extern u16 mpam_intpartid_max;
 extern u8 mpam_pmg_max;
 
 /* Scheduled work callback to enable mpam once all MSC have been probed */
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 19b306017845..222ea1d199e1 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -206,7 +206,7 @@ int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
 		mpam_resctrl_controls[RDT_RESOURCE_MBA].resctrl_res.alloc_capable = true;
 
 	if (enable) {
-		if (mpam_partid_max < 1)
+		if (mpam_intpartid_max < 1)
 			return -EINVAL;
 
 		partid_d = resctrl_get_config_index(RESCTRL_RESERVED_CLOSID, CDP_DATA);
@@ -237,7 +237,7 @@ static bool mpam_resctrl_hide_cdp(enum resctrl_res_level rid)
  */
 u32 resctrl_arch_get_num_closid(struct rdt_resource *ignored)
 {
-	return mpam_partid_max + 1;
+	return mpam_intpartid_max + 1;
 }
 
 u32 resctrl_arch_system_num_rmid_idx(void)
-- 
2.25.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v3 3/9] arm_mpam: Disable Narrow-PARTID when MBA lacks support
  2026-03-17 13:21 [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature Zeng Heng
  2026-03-17 13:21 ` [PATCH v3 1/9] fs/resctrl: Fix MPAM Partid parsing errors by preserving CDP state during umount Zeng Heng
  2026-03-17 13:21 ` [PATCH v3 2/9] arm_mpam: Add intPARTID and reqPARTID support for narrow PARTID feature Zeng Heng
@ 2026-03-17 13:21 ` Zeng Heng
  2026-04-10  1:07   ` Shaopeng Tan (Fujitsu)
  2026-03-17 13:21 ` [PATCH v3 4/9] arm_mpam: Refactor rmid to reqPARTID/PMG mapping Zeng Heng
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 22+ messages in thread
From: Zeng Heng @ 2026-03-17 13:21 UTC (permalink / raw)
  To: ben.horgan, james.morse, Dave.Martin, reinette.chatre, fenghuay
  Cc: dave.hansen, tglx, mingo, hpa, bp, tony.luck, babu.moger, x86,
	linux-kernel, wangkefeng.wang

MPAM supports mixed systems with MSCs that may or may not implement
Narrow-PARTID. However, when the MBA MSC uses percentage-based throttling
(non-bitmap partition control) and lacks Narrow-PARTID support,
resctrl cannot correctly apply control group configurations across
multiple PARTIDs.

Since there is no straightforward way to program compatible control
values in this scenario, disable Narrow-PARTID system-wide when
detected. The detection occurs at initialization time on the first
call to get_num_reqpartid() from mpam_resctrl_pick_counters(),
which is guaranteed to occur after mpam_resctrl_pick_mba() has
set up the MBA resource class.

If MBA MSCs lack Narrow-PARTID support, get_num_reqpartid() falls back
to returning the number of internal PARTIDs (mpam_intpartid_max).

Signed-off-by: Zeng Heng <zengheng4@huawei.com>
---
 drivers/resctrl/mpam_resctrl.c | 38 +++++++++++++++++++++++++++++++++-
 1 file changed, 37 insertions(+), 1 deletion(-)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 222ea1d199e1..1b18c095cfce 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -240,9 +240,45 @@ u32 resctrl_arch_get_num_closid(struct rdt_resource *ignored)
 	return mpam_intpartid_max + 1;
 }
 
+/*
+ * Determine the effective number of PARTIDs available for resctrl.
+ *
+ * This function performs a one-time check to determine if Narrow-PARTID
+ * can be used. It must be called after mpam_resctrl_pick_mba() has
+ * initialized the MBA resource, as the MBA class properties are used
+ * to detect Narrow-PARTID support.
+ *
+ * The first call occurs in mpam_resctrl_pick_counters(), ensuring the
+ * prerequisite initialization is complete.
+ */
+static u32 get_num_reqpartid(void)
+{
+	struct mpam_resctrl_res *res;
+	struct rdt_resource *r_mba;
+	struct mpam_props *cprops;
+	static bool first = true;
+
+	if (first) {
+		r_mba = resctrl_arch_get_resource(RDT_RESOURCE_MBA);
+		res = container_of(r_mba, struct mpam_resctrl_res, resctrl_res);
+		if (!res->class)
+			goto out;
+
+		/* If MBA MSCs lack Narrow-PARTID support, roll back. */
+		cprops = &res->class->props;
+		if (!mpam_has_feature(mpam_feat_partid_nrw, cprops))
+			mpam_partid_max = mpam_intpartid_max;
+
+	}
+
+out:
+	first = false;
+	return mpam_partid_max + 1;
+}
+
 u32 resctrl_arch_system_num_rmid_idx(void)
 {
-	return (mpam_pmg_max + 1) * (mpam_partid_max + 1);
+	return (mpam_pmg_max + 1) * get_num_reqpartid();
 }
 
 u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid)
-- 
2.25.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v3 4/9] arm_mpam: Refactor rmid to reqPARTID/PMG mapping
  2026-03-17 13:21 [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature Zeng Heng
                   ` (2 preceding siblings ...)
  2026-03-17 13:21 ` [PATCH v3 3/9] arm_mpam: Disable Narrow-PARTID when MBA lacks support Zeng Heng
@ 2026-03-17 13:21 ` Zeng Heng
  2026-03-17 13:21 ` [PATCH v3 5/9] arm_mpam: Propagate control group config to sub-monitoring groups Zeng Heng
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 22+ messages in thread
From: Zeng Heng @ 2026-03-17 13:21 UTC (permalink / raw)
  To: ben.horgan, james.morse, Dave.Martin, reinette.chatre, fenghuay
  Cc: dave.hansen, tglx, mingo, hpa, bp, tony.luck, babu.moger, x86,
	linux-kernel, wangkefeng.wang

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 original
semantics of closid.

Signed-off-by: Zeng Heng <zengheng4@huawei.com>
---
 drivers/resctrl/mpam_resctrl.c | 101 +++++++++++++++++++++++----------
 1 file changed, 71 insertions(+), 30 deletions(-)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 1b18c095cfce..15e8cf7d8f1f 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -281,15 +281,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);
+}
+
+static 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)
@@ -301,21 +346,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)
@@ -334,17 +375,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)
@@ -352,6 +392,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;
 
@@ -362,13 +404,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)
@@ -456,6 +496,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;
@@ -479,8 +520,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


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v3 5/9] arm_mpam: Propagate control group config to sub-monitoring groups
  2026-03-17 13:21 [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature Zeng Heng
                   ` (3 preceding siblings ...)
  2026-03-17 13:21 ` [PATCH v3 4/9] arm_mpam: Refactor rmid to reqPARTID/PMG mapping Zeng Heng
@ 2026-03-17 13:21 ` Zeng Heng
  2026-03-17 13:21 ` [PATCH v3 6/9] fs/resctrl: Add rmid_entry state helpers Zeng Heng
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 22+ messages in thread
From: Zeng Heng @ 2026-03-17 13:21 UTC (permalink / raw)
  To: ben.horgan, james.morse, Dave.Martin, reinette.chatre, fenghuay
  Cc: dave.hansen, tglx, mingo, hpa, bp, tony.luck, babu.moger, x86,
	linux-kernel, wangkefeng.wang

With the narrow PARTID feature, each control group is assigned multiple
(req)PARTIDs to expand monitoring capacity. When a control group's
configuration is updated, all associated sub-monitoring groups (each
identified by a unique reqPARTID) should be synchronized.

In __write_config(), iterate over all reqPARTIDs belonging to the
control group and propagate the configuration to each sub-monitoring
group:

  * For MSCs supporting narrow PARTID, establish the reqPARTID to
    intPARTID mapping.
  * For MSCs without narrow PARTID support, synchronize the configuration
    to new PARTIDs directly.

Signed-off-by: Zeng Heng <zengheng4@huawei.com>
---
 drivers/resctrl/mpam_devices.c  | 33 +++++++++++++++++++++++++++------
 drivers/resctrl/mpam_internal.h |  2 ++
 drivers/resctrl/mpam_resctrl.c  |  2 +-
 3 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 2634afc41c6a..d98f81621be1 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -1543,6 +1543,7 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
 {
 	u32 pri_val = 0;
 	u16 cmax = MPAMCFG_CMAX_CMAX;
+	u16 intpartid = req2intpartid(partid);
 	struct mpam_msc *msc = ris->vmsc->msc;
 	struct mpam_props *rprops = &ris->props;
 	u16 dspri = GENMASK(rprops->dspri_wd, 0);
@@ -1552,15 +1553,17 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
 	__mpam_part_sel(ris->ris_idx, partid, msc);
 
 	if (mpam_has_feature(mpam_feat_partid_nrw, rprops)) {
-		/* Update the intpartid mapping */
 		mpam_write_partsel_reg(msc, INTPARTID,
-				       MPAMCFG_INTPARTID_INTERNAL | partid);
+				       MPAMCFG_INTPARTID_INTERNAL | intpartid);
 
 		/*
-		 * Then switch to the 'internal' partid to update the
-		 * configuration.
+		 * Mapping from reqpartid to intpartid already established.
+		 * Sub-monitoring groups share the parent's configuration.
 		 */
-		__mpam_intpart_sel(ris->ris_idx, partid, msc);
+		if (partid != intpartid)
+			goto out;
+
+		__mpam_intpart_sel(ris->ris_idx, intpartid, msc);
 	}
 
 	if (mpam_has_feature(mpam_feat_cpor_part, rprops) &&
@@ -1632,6 +1635,7 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
 
 	mpam_quirk_post_config_change(ris, partid, cfg);
 
+out:
 	mutex_unlock(&msc->part_sel_lock);
 }
 
@@ -1766,11 +1770,28 @@ struct mpam_write_config_arg {
 	u16 partid;
 };
 
+static u32 get_num_reqpartid_per_intpartid(void)
+{
+	return (mpam_partid_max + 1) / (mpam_intpartid_max + 1);
+}
+
 static int __write_config(void *arg)
 {
+	int closid_num = resctrl_arch_get_num_closid(NULL);
 	struct mpam_write_config_arg *c = arg;
+	u32 reqpartid, req_idx;
 
-	mpam_reprogram_ris_partid(c->ris, c->partid, &c->comp->cfg[c->partid]);
+	/* c->partid should be within the range of intPARTIDs */
+	WARN_ON_ONCE(c->partid >= closid_num);
+
+	/* Synchronize the configuration to each sub-monitoring group. */
+	for (req_idx = 0; req_idx < get_num_reqpartid_per_intpartid();
+	     req_idx++) {
+		reqpartid = req_idx * closid_num + c->partid;
+
+		mpam_reprogram_ris_partid(c->ris, reqpartid,
+					 &c->comp->cfg[c->partid]);
+	}
 
 	return 0;
 }
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 2029a5b7283e..9069e2314d77 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -487,6 +487,8 @@ void mpam_msmon_reset_mbwu(struct mpam_component *comp, struct mon_cfg *ctx);
 int mpam_get_cpumask_from_cache_id(unsigned long cache_id, u32 cache_level,
 				   cpumask_t *affinity);
 
+u16 req2intpartid(u16 reqpartid);
+
 #ifdef CONFIG_RESCTRL_FS
 int mpam_resctrl_setup(void);
 void mpam_resctrl_exit(void);
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 15e8cf7d8f1f..725583d7bd07 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -296,7 +296,7 @@ static u8 rmid2pmg(u32 rmid)
 	return rmid % (mpam_pmg_max + 1);
 }
 
-static u16 req2intpartid(u16 reqpartid)
+u16 req2intpartid(u16 reqpartid)
 {
 	return reqpartid % (mpam_intpartid_max + 1);
 }
-- 
2.25.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v3 6/9] fs/resctrl: Add rmid_entry state helpers
  2026-03-17 13:21 [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature Zeng Heng
                   ` (4 preceding siblings ...)
  2026-03-17 13:21 ` [PATCH v3 5/9] arm_mpam: Propagate control group config to sub-monitoring groups Zeng Heng
@ 2026-03-17 13:21 ` Zeng Heng
  2026-03-17 13:21 ` [PATCH v3 7/9] arm_mpam: Implement dynamic reqPARTID allocation for monitoring groups Zeng Heng
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 22+ messages in thread
From: Zeng Heng @ 2026-03-17 13:21 UTC (permalink / raw)
  To: ben.horgan, james.morse, Dave.Martin, reinette.chatre, fenghuay
  Cc: dave.hansen, tglx, mingo, hpa, bp, tony.luck, babu.moger, x86,
	linux-kernel, wangkefeng.wang

Introduce helper functions for rmid_entry management, in preparation
for upcoming patches supporting dynamic monitoring group allocation:

* rmid_is_occupied(): Query whether a rmid_entry is currently allocated
  by checking if its list node has been removed from the free list.

* rmid_entry_reassign_closid(): Update the closid associated with a rmid
  entry.

Fix list node initialization in alloc_rmid() and dom_data_init() by
using list_del_init() instead of list_del(). This ensures list_empty()
checks in rmid_is_occupied() work correctly without encountering
LIST_POISON values.

Signed-off-by: Zeng Heng <zengheng4@huawei.com>
---
 fs/resctrl/monitor.c    | 18 ++++++++++++++++--
 include/linux/resctrl.h | 21 +++++++++++++++++++++
 2 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index 49f3f6b846b2..4e78fb194c16 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -284,7 +284,7 @@ int alloc_rmid(u32 closid)
 	if (IS_ERR(entry))
 		return PTR_ERR(entry);
 
-	list_del(&entry->list);
+	list_del_init(&entry->list);
 	return entry->rmid;
 }
 
@@ -344,6 +344,20 @@ void free_rmid(u32 closid, u32 rmid)
 		list_add_tail(&entry->list, &rmid_free_lru);
 }
 
+bool rmid_is_occupied(u32 closid, u32 rmid)
+{
+	u32 idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+
+	return list_empty(&rmid_ptrs[idx].list);
+}
+
+void rmid_entry_reassign_closid(u32 closid, u32 rmid)
+{
+	u32 idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+
+	rmid_ptrs[idx].closid = closid;
+}
+
 static struct mbm_state *get_mbm_state(struct rdt_l3_mon_domain *d, u32 closid,
 				       u32 rmid, enum resctrl_event_id evtid)
 {
@@ -943,7 +957,7 @@ int setup_rmid_lru_list(void)
 	idx = resctrl_arch_rmid_idx_encode(RESCTRL_RESERVED_CLOSID,
 					   RESCTRL_RESERVED_RMID);
 	entry = __rmid_entry(idx);
-	list_del(&entry->list);
+	list_del_init(&entry->list);
 
 	return 0;
 }
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 006e57fd7ca5..b636e7250c20 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -702,6 +702,27 @@ bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r);
 extern unsigned int resctrl_rmid_realloc_threshold;
 extern unsigned int resctrl_rmid_realloc_limit;
 
+/**
+ * rmid_is_occupied() - Check whether the specified rmid has been
+ *                      allocated.
+ * @closid:	Specify the closid that matches the rmid.
+ * @rmid:	Specify the rmid entry to check status.
+ *
+ * This function checks if the rmid_entry is currently allocated by testing
+ * whether its list node is empty (removed from the free list).
+ *
+ * Return:
+ * True if the specified rmid is still in use.
+ */
+bool rmid_is_occupied(u32 closid, u32 rmid);
+
+/**
+ * rmid_entry_reassign_closid() - Update the closid field of a rmid_entry.
+ * @closid:	Specify the reassigned closid.
+ * @rmid:	Specify the rmid entry to update closid.
+ */
+void rmid_entry_reassign_closid(u32 closid, u32 rmid);
+
 int resctrl_init(void);
 void resctrl_exit(void);
 
-- 
2.25.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v3 7/9] arm_mpam: Implement dynamic reqPARTID allocation for monitoring groups
  2026-03-17 13:21 [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature Zeng Heng
                   ` (5 preceding siblings ...)
  2026-03-17 13:21 ` [PATCH v3 6/9] fs/resctrl: Add rmid_entry state helpers Zeng Heng
@ 2026-03-17 13:21 ` Zeng Heng
  2026-03-17 13:21 ` [PATCH v3 8/9] fs/resctrl: Wire up rmid expansion and reclaim functions Zeng Heng
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 22+ messages in thread
From: Zeng Heng @ 2026-03-17 13:21 UTC (permalink / raw)
  To: ben.horgan, james.morse, Dave.Martin, reinette.chatre, fenghuay
  Cc: dave.hansen, tglx, mingo, hpa, bp, tony.luck, babu.moger, x86,
	linux-kernel, wangkefeng.wang

Replace static reqPARTID allocation with dynamic binding to maximize
monitoring group utilization. Static allocation wastes resources when
control groups create fewer sub-groups than the pre-allocated limit.

Add a lookup table (reqpartid_map) to dynamically bind reqPARTIDs to
control groups needing extended monitoring capacity:

  * resctrl_arch_rmid_expand(): Find and bind a free reqPARTID to the
    specified closid when creating monitoring groups.

  * resctrl_arch_rmid_reclaim(): Unbind reqPARTID when all monitoring
    groups associated with pmg are freed, making it available for reuse.

Update conversion helpers for dynamic mapping:
  * req2intpartid() switches to lookup table for dynamic allocation.
  * Add partid2closid() and req_pmg2rmid() helpers.

Refactor __write_config() to iterate over all reqPARTIDs that match
by intPARTID, removing fixed per-closid slot assumption.

Signed-off-by: Zeng Heng <zengheng4@huawei.com>
---
 drivers/resctrl/mpam_devices.c  |  21 ++---
 drivers/resctrl/mpam_internal.h |   1 +
 drivers/resctrl/mpam_resctrl.c  | 141 +++++++++++++++++++++++++++++---
 include/linux/arm_mpam.h        |  17 ++++
 4 files changed, 156 insertions(+), 24 deletions(-)

diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index d98f81621be1..20ad06f66b88 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -1770,27 +1770,24 @@ struct mpam_write_config_arg {
 	u16 partid;
 };
 
-static u32 get_num_reqpartid_per_intpartid(void)
-{
-	return (mpam_partid_max + 1) / (mpam_intpartid_max + 1);
-}
-
 static int __write_config(void *arg)
 {
 	int closid_num = resctrl_arch_get_num_closid(NULL);
 	struct mpam_write_config_arg *c = arg;
-	u32 reqpartid, req_idx;
+	u32 reqpartid;
 
 	/* c->partid should be within the range of intPARTIDs */
 	WARN_ON_ONCE(c->partid >= closid_num);
 
-	/* Synchronize the configuration to each sub-monitoring group. */
-	for (req_idx = 0; req_idx < get_num_reqpartid_per_intpartid();
-	     req_idx++) {
-		reqpartid = req_idx * closid_num + c->partid;
+	mpam_reprogram_ris_partid(c->ris, c->partid,
+				 &c->comp->cfg[c->partid]);
 
-		mpam_reprogram_ris_partid(c->ris, reqpartid,
-					 &c->comp->cfg[c->partid]);
+	/* Synchronize the configuration to each sub-monitoring group. */
+	for (reqpartid = closid_num;
+	     reqpartid < get_num_reqpartid(); reqpartid++) {
+		if (req2intpartid(reqpartid) == c->partid)
+			mpam_reprogram_ris_partid(c->ris, reqpartid,
+						 &c->comp->cfg[c->partid]);
 	}
 
 	return 0;
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 9069e2314d77..91f6d5f14a9e 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -488,6 +488,7 @@ int mpam_get_cpumask_from_cache_id(unsigned long cache_id, u32 cache_level,
 				   cpumask_t *affinity);
 
 u16 req2intpartid(u16 reqpartid);
+u32 get_num_reqpartid(void);
 
 #ifdef CONFIG_RESCTRL_FS
 int mpam_resctrl_setup(void);
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 725583d7bd07..a91c0e22ef6b 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -251,7 +251,7 @@ u32 resctrl_arch_get_num_closid(struct rdt_resource *ignored)
  * The first call occurs in mpam_resctrl_pick_counters(), ensuring the
  * prerequisite initialization is complete.
  */
-static u32 get_num_reqpartid(void)
+u32 get_num_reqpartid(void)
 {
 	struct mpam_resctrl_res *res;
 	struct rdt_resource *r_mba;
@@ -296,9 +296,36 @@ static u8 rmid2pmg(u32 rmid)
 	return rmid % (mpam_pmg_max + 1);
 }
 
+static u32 req_pmg2rmid(u32 reqpartid, u8 pmg)
+{
+	if (cdp_enabled)
+		reqpartid >>= 1;
+
+	return reqpartid * (mpam_pmg_max + 1) + pmg;
+}
+
+static u32 *reqpartid_map;
+
 u16 req2intpartid(u16 reqpartid)
 {
-	return reqpartid % (mpam_intpartid_max + 1);
+	WARN_ON_ONCE(reqpartid >= get_num_reqpartid());
+
+	/*
+	 * Directly return intPartid in case that mpam_reset_ris() access
+	 * NULL pointer.
+	 */
+	if (reqpartid < (mpam_intpartid_max + 1))
+		return reqpartid;
+
+	return reqpartid_map[reqpartid];
+}
+
+static u32 partid2closid(u32 partid)
+{
+	if (cdp_enabled)
+		partid >>= 1;
+
+	return partid;
 }
 
 /*
@@ -312,12 +339,12 @@ u16 req2intpartid(u16 reqpartid)
 u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid)
 {
 	u32 reqpartid = rmid2reqpartid(rmid);
-	u32 intpartid = req2intpartid(reqpartid);
 
-	if (cdp_enabled)
-		intpartid >>= 1;
+	/* When enable CDP mode, needs to filter invalid rmid entry out */
+	if (reqpartid >= get_num_reqpartid())
+		return U32_MAX;
 
-	if (closid != intpartid)
+	if (closid != partid2closid(req2intpartid(reqpartid)))
 		return U32_MAX;
 
 	return rmid;
@@ -330,11 +357,9 @@ void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid)
 
 	if (rmid)
 		*rmid = idx;
-	if (closid) {
-		if (cdp_enabled)
-			intpartid >>= 1;
-		*closid = intpartid;
-	}
+
+	if (closid)
+		*closid = partid2closid(intpartid);
 }
 
 void resctrl_arch_sched_in(struct task_struct *tsk)
@@ -1822,6 +1847,91 @@ void mpam_resctrl_offline_cpu(unsigned int cpu)
 	}
 }
 
+static int reqpartid_init(void)
+{
+	int req_num, idx;
+
+	req_num = get_num_reqpartid();
+	reqpartid_map = kcalloc(req_num, sizeof(u32), GFP_KERNEL);
+	if (!reqpartid_map)
+		return -ENOMEM;
+
+	for (idx = 0; idx < req_num; idx++)
+		reqpartid_map[idx] = idx;
+
+	return 0;
+}
+
+static void reqpartid_exit(void)
+{
+	kfree(reqpartid_map);
+}
+
+static void update_rmid_entries_for_reqpartid(u32 reqpartid)
+{
+	int pmg;
+	u32 intpartid = reqpartid_map[reqpartid];
+	u32 closid = partid2closid(intpartid);
+
+	for (pmg = 0; pmg <= mpam_pmg_max; pmg++)
+		rmid_entry_reassign_closid(closid, req_pmg2rmid(reqpartid, pmg));
+}
+
+int resctrl_arch_rmid_expand(u32 closid)
+{
+	int i;
+
+	for (i = resctrl_arch_get_num_closid(NULL);
+	     i < get_num_reqpartid(); i++) {
+		/*
+		 * If reqpartid_map[i] > mpam_intpartid_max,
+		 * it means the reqpartid 'i' is free.
+		 */
+		if (reqpartid_map[i] >= resctrl_arch_get_num_closid(NULL)) {
+			if (cdp_enabled) {
+				reqpartid_map[i] = resctrl_get_config_index(closid, CDP_DATA);
+				reqpartid_map[i + 1] = resctrl_get_config_index(closid, CDP_CODE);
+			} else {
+				reqpartid_map[i] = resctrl_get_config_index(closid, CDP_NONE);
+			}
+			update_rmid_entries_for_reqpartid(i);
+			return i;
+		}
+	}
+
+	return -ENOSPC;
+}
+
+void resctrl_arch_rmid_reclaim(u32 closid, u32 rmid)
+{
+	int pmg;
+	u32 intpartid;
+	int reqpartid = rmid2reqpartid(rmid);
+
+	if (reqpartid < resctrl_arch_get_num_closid(NULL))
+		return;
+
+	if (cdp_enabled)
+		intpartid = resctrl_get_config_index(closid, CDP_DATA);
+	else
+		intpartid = resctrl_get_config_index(closid, CDP_NONE);
+
+	WARN_ON_ONCE(intpartid != req2intpartid(reqpartid));
+
+	for (pmg = 0; pmg <= mpam_pmg_max; pmg++) {
+		if (rmid_is_occupied(closid, req_pmg2rmid(reqpartid, pmg)))
+			break;
+	}
+
+	if (pmg > mpam_pmg_max) {
+		reqpartid_map[reqpartid] = reqpartid;
+		if (cdp_enabled)
+			reqpartid_map[reqpartid + 1] = reqpartid + 1;
+
+		update_rmid_entries_for_reqpartid(reqpartid);
+	}
+}
+
 int mpam_resctrl_setup(void)
 {
 	int err = 0;
@@ -1877,10 +1987,16 @@ int mpam_resctrl_setup(void)
 		return -EOPNOTSUPP;
 	}
 
-	err = resctrl_init();
+	err = reqpartid_init();
 	if (err)
 		return err;
 
+	err = resctrl_init();
+	if (err) {
+		reqpartid_exit();
+		return err;
+	}
+
 	WRITE_ONCE(resctrl_enabled, true);
 
 	return 0;
@@ -1898,6 +2014,7 @@ void mpam_resctrl_exit(void)
 
 	WRITE_ONCE(resctrl_enabled, false);
 	resctrl_exit();
+	reqpartid_exit();
 }
 
 static void mpam_resctrl_teardown_mon(struct mpam_resctrl_mon *mon, struct mpam_class *class)
diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
index f92a36187a52..d45422965907 100644
--- a/include/linux/arm_mpam.h
+++ b/include/linux/arm_mpam.h
@@ -59,6 +59,23 @@ void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid);
 void resctrl_arch_sched_in(struct task_struct *tsk);
 bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid);
 bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
+
+/**
+ * resctrl_arch_rmid_expand() - Expand the RMID resources for the specified closid.
+ * @closid:    closid that matches the rmid.
+ *
+ * Return:
+ * 0 on success, or -ENOSPC etc on error.
+ */
+int resctrl_arch_rmid_expand(u32 closid);
+
+/**
+ * resctrl_arch_rmid_reclaim() - Reclaim the rmid resources for the specified closid.
+ * @closid:    closid that matches the rmid.
+ * @rmid:      Reclaim the rmid specified.
+ */
+void resctrl_arch_rmid_reclaim(u32 closid, u32 rmid);
+
 u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid);
 void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid);
 u32 resctrl_arch_system_num_rmid_idx(void);
-- 
2.25.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v3 8/9] fs/resctrl: Wire up rmid expansion and reclaim functions
  2026-03-17 13:21 [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature Zeng Heng
                   ` (6 preceding siblings ...)
  2026-03-17 13:21 ` [PATCH v3 7/9] arm_mpam: Implement dynamic reqPARTID allocation for monitoring groups Zeng Heng
@ 2026-03-17 13:21 ` Zeng Heng
  2026-03-17 13:21 ` [PATCH v3 9/9] arm64/mpam: Add mpam_sync_config() for dynamic rmid expansion Zeng Heng
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 22+ messages in thread
From: Zeng Heng @ 2026-03-17 13:21 UTC (permalink / raw)
  To: ben.horgan, james.morse, Dave.Martin, reinette.chatre, fenghuay
  Cc: dave.hansen, tglx, mingo, hpa, bp, tony.luck, babu.moger, x86,
	linux-kernel, wangkefeng.wang

The previous patch implemented resctrl_arch_rmid_expand() and
resctrl_arch_rmid_reclaim() for ARM MPAM. This patch integrates
these architecture-specific functions into the generic resctrl layer.

Refactor resctrl_find_free_rmid() to support dynamic rmid expansion.
If no free rmid is available for the current closid, attempt to expand
via resctrl_arch_expand_rmid(). On success, retry the rmid allocation.

As this capability is architecture-specific, x86 maintains existing
behavior by returning -ENOSPC when rmid resources are exhausted.

Additionally, invoke resctrl_arch_rmid_reclaim() when rmids are released
to enable architecture-specific resource cleanup.

Signed-off-by: Zeng Heng <zengheng4@huawei.com>
---
 arch/x86/include/asm/resctrl.h |  7 +++++++
 fs/resctrl/monitor.c           | 32 ++++++++++++++++++++++++++++++--
 2 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h
index 575f8408a9e7..7f8c8d84f2a0 100644
--- a/arch/x86/include/asm/resctrl.h
+++ b/arch/x86/include/asm/resctrl.h
@@ -167,6 +167,13 @@ static inline void resctrl_arch_sched_in(struct task_struct *tsk)
 		__resctrl_sched_in(tsk);
 }
 
+static inline int resctrl_arch_rmid_expand(u32 closid)
+{
+	return -ENOSPC;
+}
+
+static inline void resctrl_arch_rmid_reclaim(u32 closid, u32 rmid) {}
+
 static inline void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid)
 {
 	*rmid = idx;
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index 4e78fb194c16..c58440eb7cc9 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -122,6 +122,8 @@ static void limbo_release_entry(struct rmid_entry *entry)
 
 	if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID))
 		closid_num_dirty_rmid[entry->closid]--;
+
+	resctrl_arch_rmid_reclaim(entry->closid, entry->rmid);
 }
 
 /*
@@ -197,7 +199,7 @@ bool has_busy_rmid(struct rdt_l3_mon_domain *d)
 	return find_first_bit(d->rmid_busy_llc, idx_limit) != idx_limit;
 }
 
-static struct rmid_entry *resctrl_find_free_rmid(u32 closid)
+static struct rmid_entry *__resctrl_find_free_rmid(u32 closid)
 {
 	struct rmid_entry *itr;
 	u32 itr_idx, cmp_idx;
@@ -214,7 +216,12 @@ static struct rmid_entry *resctrl_find_free_rmid(u32 closid)
 		 * very first entry will be returned.
 		 */
 		itr_idx = resctrl_arch_rmid_idx_encode(itr->closid, itr->rmid);
+		if (itr_idx == U32_MAX)
+			continue;
+
 		cmp_idx = resctrl_arch_rmid_idx_encode(closid, itr->rmid);
+		if (cmp_idx == U32_MAX)
+			continue;
 
 		if (itr_idx == cmp_idx)
 			return itr;
@@ -223,6 +230,25 @@ static struct rmid_entry *resctrl_find_free_rmid(u32 closid)
 	return ERR_PTR(-ENOSPC);
 }
 
+static struct rmid_entry *resctrl_find_free_rmid(u32 closid)
+{
+	struct rmid_entry *err;
+	int ret;
+
+	err = __resctrl_find_free_rmid(closid);
+	if (err == ERR_PTR(-ENOSPC)) {
+		ret = resctrl_arch_rmid_expand(closid);
+		if (ret < 0)
+			/* Out of rmid */
+			goto out;
+
+		/* Try it again */
+		return __resctrl_find_free_rmid(closid);
+	}
+out:
+	return err;
+}
+
 /**
  * resctrl_find_cleanest_closid() - Find a CLOSID where all the associated
  *                                  RMID are clean, or the CLOSID that has
@@ -340,8 +366,10 @@ void free_rmid(u32 closid, u32 rmid)
 
 	if (resctrl_is_mon_event_enabled(QOS_L3_OCCUP_EVENT_ID))
 		add_rmid_to_limbo(entry);
-	else
+	else {
 		list_add_tail(&entry->list, &rmid_free_lru);
+		resctrl_arch_rmid_reclaim(closid, rmid);
+	}
 }
 
 bool rmid_is_occupied(u32 closid, u32 rmid)
-- 
2.25.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v3 9/9] arm64/mpam: Add mpam_sync_config() for dynamic rmid expansion
  2026-03-17 13:21 [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature Zeng Heng
                   ` (7 preceding siblings ...)
  2026-03-17 13:21 ` [PATCH v3 8/9] fs/resctrl: Wire up rmid expansion and reclaim functions Zeng Heng
@ 2026-03-17 13:21 ` Zeng Heng
  2026-03-20 16:14 ` [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature Ben Horgan
  2026-04-10  0:13 ` Shaopeng Tan (Fujitsu)
  10 siblings, 0 replies; 22+ messages in thread
From: Zeng Heng @ 2026-03-17 13:21 UTC (permalink / raw)
  To: ben.horgan, james.morse, Dave.Martin, reinette.chatre, fenghuay
  Cc: dave.hansen, tglx, mingo, hpa, bp, tony.luck, babu.moger, x86,
	linux-kernel, wangkefeng.wang

Add mpam_sync_config() to synchronize configuration when dynamically
expanding rmid resources. When binding a new reqpartid to a control group,
the driver maps the reqpartid to the corresponding intpartid or applies
the control group's existing configuration to new partid if without Narrow
partid feature.

Extend mpam_apply_config() with 'sync' work mode:
  * Sync mode: mpam_sync_config() calls this to apply existing
    configuration without updating config.
  * Update(Non-sync) mode: resctrl_arch_update_one() calls this to compare,
    update, and apply configuration. This mode retains the original
    behavior.

Signed-off-by: Zeng Heng <zengheng4@huawei.com>
---
 drivers/resctrl/mpam_devices.c  | 23 ++++++++++++++++++-----
 drivers/resctrl/mpam_internal.h |  2 +-
 drivers/resctrl/mpam_resctrl.c  | 29 ++++++++++++++++++++++++++---
 3 files changed, 45 insertions(+), 9 deletions(-)

diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 20ad06f66b88..b9a9c92a6367 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -1768,6 +1768,7 @@ struct mpam_write_config_arg {
 	struct mpam_msc_ris *ris;
 	struct mpam_component *comp;
 	u16 partid;
+	bool sync;
 };
 
 static int __write_config(void *arg)
@@ -1776,6 +1777,15 @@ static int __write_config(void *arg)
 	struct mpam_write_config_arg *c = arg;
 	u32 reqpartid;
 
+	if (c->sync) {
+		/* c->partid should be within the range of reqPARTIDs */
+		WARN_ON_ONCE(c->partid < closid_num);
+
+		mpam_reprogram_ris_partid(c->ris, c->partid,
+					 &c->comp->cfg[req2intpartid(c->partid)]);
+		return 0;
+	}
+
 	/* c->partid should be within the range of intPARTIDs */
 	WARN_ON_ONCE(c->partid >= closid_num);
 
@@ -3039,7 +3049,7 @@ static bool mpam_update_config(struct mpam_config *cfg,
 }
 
 int mpam_apply_config(struct mpam_component *comp, u16 partid,
-		      struct mpam_config *cfg)
+		      struct mpam_config *cfg, bool sync)
 {
 	struct mpam_write_config_arg arg;
 	struct mpam_msc_ris *ris;
@@ -3048,14 +3058,17 @@ int mpam_apply_config(struct mpam_component *comp, u16 partid,
 
 	lockdep_assert_cpus_held();
 
-	/* Don't pass in the current config! */
-	WARN_ON_ONCE(&comp->cfg[partid] == cfg);
+	if (!sync) {
+		/* The partid is within the range of intPARTIDs */
+		WARN_ON_ONCE(partid >= resctrl_arch_get_num_closid(NULL));
 
-	if (!mpam_update_config(&comp->cfg[partid], cfg))
-		return 0;
+		if (!mpam_update_config(&comp->cfg[partid], cfg))
+			return 0;
+	}
 
 	arg.comp = comp;
 	arg.partid = partid;
+	arg.sync = sync;
 
 	guard(srcu)(&mpam_srcu);
 	list_for_each_entry_srcu(vmsc, &comp->vmsc, comp_list,
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 91f6d5f14a9e..321f60e909ba 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -478,7 +478,7 @@ void mpam_disable(struct work_struct *work);
 void mpam_reset_class_locked(struct mpam_class *class);
 
 int mpam_apply_config(struct mpam_component *comp, u16 partid,
-		      struct mpam_config *cfg);
+		      struct mpam_config *cfg, bool sync);
 
 int mpam_msmon_read(struct mpam_component *comp, struct mon_cfg *ctx,
 		    enum mpam_device_features, u64 *val);
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index a91c0e22ef6b..0c6c97a0386f 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -1488,15 +1488,15 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 	 */
 	if (mpam_resctrl_hide_cdp(r->rid)) {
 		partid = resctrl_get_config_index(closid, CDP_CODE);
-		err = mpam_apply_config(dom->ctrl_comp, partid, &cfg);
+		err = mpam_apply_config(dom->ctrl_comp, partid, &cfg, false);
 		if (err)
 			return err;
 
 		partid = resctrl_get_config_index(closid, CDP_DATA);
-		return mpam_apply_config(dom->ctrl_comp, partid, &cfg);
+		return mpam_apply_config(dom->ctrl_comp, partid, &cfg, false);
 	}
 
-	return mpam_apply_config(dom->ctrl_comp, partid, &cfg);
+	return mpam_apply_config(dom->ctrl_comp, partid, &cfg, false);
 }
 
 int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
@@ -1877,6 +1877,23 @@ static void update_rmid_entries_for_reqpartid(u32 reqpartid)
 		rmid_entry_reassign_closid(closid, req_pmg2rmid(reqpartid, pmg));
 }
 
+static int mpam_sync_config(u32 reqpartid)
+{
+	struct mpam_component *comp;
+	struct mpam_class *class;
+	int err;
+
+	list_for_each_entry(class, &mpam_classes, classes_list) {
+		list_for_each_entry(comp, &class->components, class_list) {
+			err = mpam_apply_config(comp, reqpartid, NULL, true);
+			if (err)
+				return err;
+		}
+	}
+
+	return 0;
+}
+
 int resctrl_arch_rmid_expand(u32 closid)
 {
 	int i;
@@ -1890,10 +1907,16 @@ int resctrl_arch_rmid_expand(u32 closid)
 		if (reqpartid_map[i] >= resctrl_arch_get_num_closid(NULL)) {
 			if (cdp_enabled) {
 				reqpartid_map[i] = resctrl_get_config_index(closid, CDP_DATA);
+				mpam_sync_config(i);
+
 				reqpartid_map[i + 1] = resctrl_get_config_index(closid, CDP_CODE);
+				mpam_sync_config(i + 1);
+
 			} else {
 				reqpartid_map[i] = resctrl_get_config_index(closid, CDP_NONE);
+				mpam_sync_config(i);
 			}
+
 			update_rmid_entries_for_reqpartid(i);
 			return i;
 		}
-- 
2.25.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature
  2026-03-17 13:21 [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature Zeng Heng
                   ` (8 preceding siblings ...)
  2026-03-17 13:21 ` [PATCH v3 9/9] arm64/mpam: Add mpam_sync_config() for dynamic rmid expansion Zeng Heng
@ 2026-03-20 16:14 ` Ben Horgan
  2026-03-21  7:18   ` Zeng Heng
  2026-04-10  0:13 ` Shaopeng Tan (Fujitsu)
  10 siblings, 1 reply; 22+ messages in thread
From: Ben Horgan @ 2026-03-20 16:14 UTC (permalink / raw)
  To: Zeng Heng, james.morse, Dave.Martin, reinette.chatre, fenghuay
  Cc: dave.hansen, tglx, mingo, hpa, bp, tony.luck, babu.moger, x86,
	linux-kernel, wangkefeng.wang

Hi Zeng,

On 3/17/26 13:21, Zeng Heng wrote:
> This series applies on top of the mpam_resctrl_glue_v5_debugfs branch of:
> https://gitlab.arm.com/linux-arm/linux-bh.git
> 
> Background
> ==========
> 
> On x86, the resctrl allows creating up to num_rmids monitoring groups
> under parent control group. However, ARM64 MPAM is currently limited by
> the PMG (Performance Monitoring Group) count, which is typically much
> smaller than the theoretical RMID limit. This creates a significant
> scalability gap: users expecting fine-grained per-process or per-thread
> monitoring quickly exhaust the PMG space, even when plenty of reqPARTIDs
> remain available.
> 
> The Narrow-PARTID feature, defined in the ARM MPAM architecture,
> addresses this by associating reqPARTIDs with intPARTIDs through a
> programmable many-to-one mapping. This allows the kernel to present more
> logical monitoring contexts.

Thanks for this series and all your help with MPAM driver. Using PARTID
narrowing to allow more resctrl monitoring groups is a good idea.

> 
> Design Overview
> ===============
> 
> The implementation extends the RMID encoding to carry reqPARTID
> information:
> 
>   RMID = reqPARTID * NUM_PMG + PMG
> 
> In this patchset, a monitoring group is uniquely identified by the
> combination of reqPARTID and PMG. The closid is represented by intPARTID,
> which is exactly the original PARTID.
> 
> For systems with homogeneous MSCs (all supporting Narrow-PARTID), the
> driver exposes the full reqPARTID range directly. For heterogeneous
> systems where some MSCs lack Narrow-PARTID support, the driver utilizes
> PARTIDs beyond the intPARTID range as reqPARTIDs to expand monitoring
> capacity. The sole exception is when MBA MSCs lack Narrow-PARTID support,
> their percentage-based control mechanism prevents the use of PARTIDs as
> reqPARTIDs.

We also need to consider how this will interact with cache capacity controls
(CMAX/CMIN). Although, they are not exposed by the driver yet.

> 
> Capacity Improvements
> =====================
> 
> --------------------------------------------------------------------------
> The maximum        |  Sub-monitoring groups            | System-wide
> number of          |  under a control group            | monitoring groups
> --------------------------------------------------------------------------
> Without            |                                   |
> reqPARTID          |  PMG                              | intPARTID * PMG
> --------------------------------------------------------------------------
> reqPARTID          |                                   |
> static allocation  | (reqPARTID // intPARTID) * PMG    | reqPARTID * PMG
> --------------------------------------------------------------------------
> reqPARTID          |                                   |
> dynamic allocation | (reqPARTID − intPARTID + 1) * PMG | reqPARTID * PMG
> --------------------------------------------------------------------------

Does the quest for more monitoring groups stop here or do you see a usecase
for limiting the number of control groups to get more monitoring groups?

Thanks

Ben


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 1/9] fs/resctrl: Fix MPAM Partid parsing errors by preserving CDP state during umount
  2026-03-17 13:21 ` [PATCH v3 1/9] fs/resctrl: Fix MPAM Partid parsing errors by preserving CDP state during umount Zeng Heng
@ 2026-03-20 17:07   ` Ben Horgan
  2026-03-21  4:11     ` Zeng Heng
  0 siblings, 1 reply; 22+ messages in thread
From: Ben Horgan @ 2026-03-20 17:07 UTC (permalink / raw)
  To: Zeng Heng, james.morse, Dave.Martin, reinette.chatre, fenghuay
  Cc: dave.hansen, tglx, mingo, hpa, bp, tony.luck, babu.moger, x86,
	linux-kernel, wangkefeng.wang

Hi Zeng,

On 3/17/26 13:21, Zeng Heng wrote:
> This patch fixes a pre-existing issue in the resctrl filesystem teardown
> sequence where premature clearing of cdp_enabled could lead to MPAM Partid
> parsing errors.
> 
> The closid to partid conversion logic inherently depends on the global
> cdp_enabled state. However, rdt_disable_ctx() clears this flag early in
> the umount path, while free_rmid() operations will reference after that.
> This creates a window where partid parsing operates with inconsistent CDP
> state, potentially make monitor reads with wrong partid mapping.
> 
> Additionally, rmid_entry remaining in limbo between mount sessions may
> trigger potential partid out-of-range errors, leading to MPAM fault
> interrupts and subsequent MPAM disablement.
> 
> Reorder rdt_kill_sb() to delay rdt_disable_ctx() until after
> rmdir_all_sub() and resctrl_fs_teardown() complete. This ensures
> all rmid-related operations finish with correct CDP state.
> 
> Introduce rdt_flush_limbo() to flush and cancel limbo work before the
> filesystem teardown completes. An alternative approach would be to cancel

The code looks correct but it does introduce a subtle change of behaviour which
may or may not be acceptable. A busy rmid may now be allocated after remount.
Clean rmids were never guaranteed, e.g. when a domain goes offline, but this
weakens the guarantee.

> limbo work on umount and restart it on remount with remaked bitmap.
> However, this would require substantial changes in the resctrl layer to
> handle CDP state transitions across mount sessions, which is beyond the
> scope of the reqpartid feature work this patchset focuses on. The current

Another option to consider is whether limbo could be replaced by checking whether
an rmid is busy at allocation.

Do your changes here to resctrl_arch_rmid_idx_encode() have an impact on how
limbo works?

Thanks,

Ben

> fix addresses the immediate correctness issue with minimal churn.
> 
> Signed-off-by: Zeng Heng <zengheng4@huawei.com>
> ---
>  fs/resctrl/rdtgroup.c | 24 ++++++++++++++++++++++--
>  1 file changed, 22 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
> index 5da305bd36c9..bc0735eef92a 100644
> --- a/fs/resctrl/rdtgroup.c
> +++ b/fs/resctrl/rdtgroup.c
> @@ -3165,6 +3165,25 @@ static void resctrl_fs_teardown(void)
>  	rdtgroup_destroy_root();
>  }
>  
> +static void rdt_flush_limbo(void)
> +{
> +	struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
> +	struct rdt_l3_mon_domain *d;
> +
> +	if (!IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID))
> +		return;
> +
> +	if (!resctrl_is_mon_event_enabled(QOS_L3_OCCUP_EVENT_ID))
> +		return;
> +
> +	list_for_each_entry(d, &r->mon_domains, hdr.list) {
> +		if (has_busy_rmid(d)) {
> +			__check_limbo(d, true);
> +			cancel_delayed_work(&d->cqm_limbo);
> +		}
> +	}
> +}
> +
>  static void rdt_kill_sb(struct super_block *sb)
>  {
>  	struct rdt_resource *r;
> @@ -3172,13 +3191,14 @@ static void rdt_kill_sb(struct super_block *sb)
>  	cpus_read_lock();
>  	mutex_lock(&rdtgroup_mutex);
>  
> -	rdt_disable_ctx();
> -
>  	/* Put everything back to default values. */
>  	for_each_alloc_capable_rdt_resource(r)
>  		resctrl_arch_reset_all_ctrls(r);
>  
>  	resctrl_fs_teardown();
> +	rdt_flush_limbo();
> +	rdt_disable_ctx();
> +
>  	if (resctrl_arch_alloc_capable())
>  		resctrl_arch_disable_alloc();
>  	if (resctrl_arch_mon_capable())


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 1/9] fs/resctrl: Fix MPAM Partid parsing errors by preserving CDP state during umount
  2026-03-20 17:07   ` Ben Horgan
@ 2026-03-21  4:11     ` Zeng Heng
  2026-03-21  6:39       ` Zeng Heng
  0 siblings, 1 reply; 22+ messages in thread
From: Zeng Heng @ 2026-03-21  4:11 UTC (permalink / raw)
  To: Ben Horgan, james.morse, Dave.Martin, reinette.chatre, fenghuay
  Cc: dave.hansen, tglx, mingo, hpa, bp, tony.luck, babu.moger, x86,
	linux-kernel, wangkefeng.wang

Hi Ben,

On 2026/3/21 1:07, Ben Horgan wrote:
> Hi Zeng,
> 
> On 3/17/26 13:21, Zeng Heng wrote:
>> This patch fixes a pre-existing issue in the resctrl filesystem teardown
>> sequence where premature clearing of cdp_enabled could lead to MPAM Partid
>> parsing errors.
>>
>> The closid to partid conversion logic inherently depends on the global
>> cdp_enabled state. However, rdt_disable_ctx() clears this flag early in
>> the umount path, while free_rmid() operations will reference after that.
>> This creates a window where partid parsing operates with inconsistent CDP
>> state, potentially make monitor reads with wrong partid mapping.
>>
>> Additionally, rmid_entry remaining in limbo between mount sessions may
>> trigger potential partid out-of-range errors, leading to MPAM fault
>> interrupts and subsequent MPAM disablement.
>>
>> Reorder rdt_kill_sb() to delay rdt_disable_ctx() until after
>> rmdir_all_sub() and resctrl_fs_teardown() complete. This ensures
>> all rmid-related operations finish with correct CDP state.
>>
>> Introduce rdt_flush_limbo() to flush and cancel limbo work before the
>> filesystem teardown completes. An alternative approach would be to cancel
> 
> The code looks correct but it does introduce a subtle change of behaviour which
> may or may not be acceptable. A busy rmid may now be allocated after remount.
> Clean rmids were never guaranteed, e.g. when a domain goes offline, but this
> weakens the guarantee.

Yes, this would indeed weaken MPAM's guarantee for clean RMIDs.

Hopefully, no one is doing this in production, repeatedly switching
resctrl mount modes while monitoring workloads (which sounds more like
testing to me), and still expecting strict guarantees of clean RMID
allocation.

> 
>> limbo work on umount and restart it on remount with remaked bitmap.
>> However, this would require substantial changes in the resctrl layer to
>> handle CDP state transitions across mount sessions, which is beyond the
>> scope of the reqpartid feature work this patchset focuses on. The current
> 
> Another option to consider is whether limbo could be replaced by checking whether
> an rmid is busy at allocation.
> 
> Do your changes here to resctrl_arch_rmid_idx_encode() have an impact on how
> limbo works?


In follow-up patches, resctrl_arch_rmid_idx_encode() also needs to
depend on the CDP state because it needs to check out the intpartid and
reqpartid. Between remount sessions, RMIDs residing in limbo also have a
parsing error issue.


Best Regards,
Zeng Heng


> 
> Thanks,
> 
> Ben
> 
>> fix addresses the immediate correctness issue with minimal churn.
>>
>> Signed-off-by: Zeng Heng <zengheng4@huawei.com>


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 1/9] fs/resctrl: Fix MPAM Partid parsing errors by preserving CDP state during umount
  2026-03-21  4:11     ` Zeng Heng
@ 2026-03-21  6:39       ` Zeng Heng
  0 siblings, 0 replies; 22+ messages in thread
From: Zeng Heng @ 2026-03-21  6:39 UTC (permalink / raw)
  To: Ben Horgan, james.morse, Dave.Martin, reinette.chatre, fenghuay
  Cc: dave.hansen, tglx, mingo, hpa, bp, tony.luck, babu.moger, x86,
	linux-kernel, wangkefeng.wang



On 2026/3/21 12:11, Zeng Heng wrote:
> Hi Ben,
> 
> On 2026/3/21 1:07, Ben Horgan wrote:
>> Hi Zeng,
>>
>> On 3/17/26 13:21, Zeng Heng wrote:
>>> This patch fixes a pre-existing issue in the resctrl filesystem teardown
>>> sequence where premature clearing of cdp_enabled could lead to MPAM 
>>> Partid
>>> parsing errors.
>>>
>>> The closid to partid conversion logic inherently depends on the global
>>> cdp_enabled state. However, rdt_disable_ctx() clears this flag early in
>>> the umount path, while free_rmid() operations will reference after that.
>>> This creates a window where partid parsing operates with inconsistent 
>>> CDP
>>> state, potentially make monitor reads with wrong partid mapping.
>>>
>>> Additionally, rmid_entry remaining in limbo between mount sessions may
>>> trigger potential partid out-of-range errors, leading to MPAM fault
>>> interrupts and subsequent MPAM disablement.
>>>
>>> Reorder rdt_kill_sb() to delay rdt_disable_ctx() until after
>>> rmdir_all_sub() and resctrl_fs_teardown() complete. This ensures
>>> all rmid-related operations finish with correct CDP state.
>>>
>>> Introduce rdt_flush_limbo() to flush and cancel limbo work before the
>>> filesystem teardown completes. An alternative approach would be to 
>>> cancel
>>
>> The code looks correct but it does introduce a subtle change of 
>> behaviour which
>> may or may not be acceptable. A busy rmid may now be allocated after 
>> remount.
>> Clean rmids were never guaranteed, e.g. when a domain goes offline, 
>> but this
>> weakens the guarantee.
> 
> Yes, this would indeed weaken MPAM's guarantee for clean RMIDs.
> 
> Hopefully, no one is doing this in production, repeatedly switching
> resctrl mount modes while monitoring workloads (which sounds more like
> testing to me), and still expecting strict guarantees of clean RMID
> allocation.
> 
>>
>>> limbo work on umount and restart it on remount with remaked bitmap.
>>> However, this would require substantial changes in the resctrl layer to
>>> handle CDP state transitions across mount sessions, which is beyond the
>>> scope of the reqpartid feature work this patchset focuses on. The 
>>> current
>>
>> Another option to consider is whether limbo could be replaced by 
>> checking whether
>> an rmid is busy at allocation.
>>
>> Do your changes here to resctrl_arch_rmid_idx_encode() have an impact 
>> on how
>> limbo works?
> 
> 
> In follow-up patches, resctrl_arch_rmid_idx_encode() also needs to
> depend on the CDP state because it needs to check out the intpartid and
> reqpartid. Between remount sessions, RMIDs residing in limbo also have a
> parsing error issue.
> 
> 

For this reason, had to make this patch as a prerequisite fix in the
patch series.


Best Regards,
Zeng Heng

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature
  2026-03-20 16:14 ` [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature Ben Horgan
@ 2026-03-21  7:18   ` Zeng Heng
  0 siblings, 0 replies; 22+ messages in thread
From: Zeng Heng @ 2026-03-21  7:18 UTC (permalink / raw)
  To: Ben Horgan, james.morse, Dave.Martin, reinette.chatre, fenghuay
  Cc: dave.hansen, tglx, mingo, hpa, bp, tony.luck, babu.moger, x86,
	linux-kernel, wangkefeng.wang

Hi Ben,

On 2026/3/21 0:14, Ben Horgan wrote:
> Hi Zeng,
> 
> On 3/17/26 13:21, Zeng Heng wrote:
>> This series applies on top of the mpam_resctrl_glue_v5_debugfs branch of:
>> https://gitlab.arm.com/linux-arm/linux-bh.git
>>
>> Background
>> ==========
>>
>> On x86, the resctrl allows creating up to num_rmids monitoring groups
>> under parent control group. However, ARM64 MPAM is currently limited by
>> the PMG (Performance Monitoring Group) count, which is typically much
>> smaller than the theoretical RMID limit. This creates a significant
>> scalability gap: users expecting fine-grained per-process or per-thread
>> monitoring quickly exhaust the PMG space, even when plenty of reqPARTIDs
>> remain available.
>>
>> The Narrow-PARTID feature, defined in the ARM MPAM architecture,
>> addresses this by associating reqPARTIDs with intPARTIDs through a
>> programmable many-to-one mapping. This allows the kernel to present more
>> logical monitoring contexts.
> 
> Thanks for this series and all your help with MPAM driver. Using PARTID
> narrowing to allow more resctrl monitoring groups is a good idea.
> 
>>
>> Design Overview
>> ===============
>>
>> The implementation extends the RMID encoding to carry reqPARTID
>> information:
>>
>>    RMID = reqPARTID * NUM_PMG + PMG
>>
>> In this patchset, a monitoring group is uniquely identified by the
>> combination of reqPARTID and PMG. The closid is represented by intPARTID,
>> which is exactly the original PARTID.
>>
>> For systems with homogeneous MSCs (all supporting Narrow-PARTID), the
>> driver exposes the full reqPARTID range directly. For heterogeneous
>> systems where some MSCs lack Narrow-PARTID support, the driver utilizes
>> PARTIDs beyond the intPARTID range as reqPARTIDs to expand monitoring
>> capacity. The sole exception is when MBA MSCs lack Narrow-PARTID support,
>> their percentage-based control mechanism prevents the use of PARTIDs as
>> reqPARTIDs.
> 
> We also need to consider how this will interact with cache capacity controls
> (CMAX/CMIN). Although, they are not exposed by the driver yet.

For MSRs that support percentage-based control mechanisms, if Narrow-
PARTID is not supported, the functionality needs to be rolled back.
The limitation will be included in the next version.


> 
>>
>> Capacity Improvements
>> =====================
>>
>> --------------------------------------------------------------------------
>> The maximum        |  Sub-monitoring groups            | System-wide
>> number of          |  under a control group            | monitoring groups
>> --------------------------------------------------------------------------
>> Without            |                                   |
>> reqPARTID          |  PMG                              | intPARTID * PMG
>> --------------------------------------------------------------------------
>> reqPARTID          |                                   |
>> static allocation  | (reqPARTID // intPARTID) * PMG    | reqPARTID * PMG
>> --------------------------------------------------------------------------
>> reqPARTID          |                                   |
>> dynamic allocation | (reqPARTID − intPARTID + 1) * PMG | reqPARTID * PMG
>> --------------------------------------------------------------------------
> 
> Does the quest for more monitoring groups stop here or do you see a usecase
> for limiting the number of control groups to get more monitoring groups?
> 

Plan to build upon the original patches by introducing an enhancement
that allows users to limit the number of control groups via a new boot
parameter, with a range of [1, intpartid], thereby achieving the goal of
expanding the number of monitoring groups.


Thanks for your review comments.


Best regards,
Zeng Heng

^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature
  2026-03-17 13:21 [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature Zeng Heng
                   ` (9 preceding siblings ...)
  2026-03-20 16:14 ` [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature Ben Horgan
@ 2026-04-10  0:13 ` Shaopeng Tan (Fujitsu)
  2026-04-11  6:32   ` Zeng Heng
  10 siblings, 1 reply; 22+ messages in thread
From: Shaopeng Tan (Fujitsu) @ 2026-04-10  0:13 UTC (permalink / raw)
  To: 'Zeng Heng', 'ben.horgan@arm.com',
	'james.morse@arm.com', 'Dave.Martin@arm.com',
	'reinette.chatre@intel.com',
	'fenghuay@nvidia.com'
  Cc: 'dave.hansen@linux.intel.com', 'tglx@kernel.org',
	'mingo@redhat.com', 'hpa@zytor.com',
	'bp@alien8.de', 'tony.luck@intel.com',
	'babu.moger@amd.com', 'x86@kernel.org',
	'linux-kernel@vger.kernel.org',
	'wangkefeng.wang@huawei.com'

Hello Zeng Heng,

> This series applies on top of the mpam_resctrl_glue_v5_debugfs branch of:
> https://gitlab.arm.com/linux-arm/linux-bh.git
> 
> Background
> ==========
> 
> On x86, the resctrl allows creating up to num_rmids monitoring groups under
> parent control group. However, ARM64 MPAM is currently limited by the PMG
> (Performance Monitoring Group) count, which is typically much smaller than
> the theoretical RMID limit. This creates a significant scalability gap: users
> expecting fine-grained per-process or per-thread monitoring quickly exhaust
> the PMG space, even when plenty of reqPARTIDs remain available.
> 
> The Narrow-PARTID feature, defined in the ARM MPAM architecture,
> addresses this by associating reqPARTIDs with intPARTIDs through a
> programmable many-to-one mapping. This allows the kernel to present more
> logical monitoring contexts.
> 
> Design Overview
> ===============
> 
> The implementation extends the RMID encoding to carry reqPARTID
> information:
> 
>   RMID = reqPARTID * NUM_PMG + PMG
> 
> In this patchset, a monitoring group is uniquely identified by the combination of
> reqPARTID and PMG. The closid is represented by intPARTID, which is exactly
> the original PARTID.
> 
> For systems with homogeneous MSCs (all supporting Narrow-PARTID), the
> driver exposes the full reqPARTID range directly. For heterogeneous systems
> where some MSCs lack Narrow-PARTID support, the driver utilizes PARTIDs
> beyond the intPARTID range as reqPARTIDs to expand monitoring capacity.
> The sole exception is when MBA MSCs lack Narrow-PARTID support, their
> percentage-based control mechanism prevents the use of PARTIDs as
> reqPARTIDs.
> 
> Capacity Improvements
> =====================
> 
> --------------------------------------------------------------------------
> The maximum        |  Sub-monitoring groups            | System-wide
> number of          |  under a control group            | monitoring groups
> --------------------------------------------------------------------------
> Without            |                                   |
> reqPARTID          |  PMG                              | intPARTID *
> PMG
> --------------------------------------------------------------------------
> reqPARTID          |                                   |
> static allocation  | (reqPARTID // intPARTID) * PMG    | reqPARTID * PMG
> --------------------------------------------------------------------------
> reqPARTID          |                                   |
> dynamic allocation | (reqPARTID − intPARTID + 1) * PMG | reqPARTID * PMG
> --------------------------------------------------------------------------
> 
> Under MPAM, the number of reqPARTID is always greater than or equal to
> intPARTID.

If reqPARTID % intPARTID > 0, does that mean we cann’t fully use reqPARTIDs?
Some chips have a large number of intPARTIDs, is it possible to use only a limited number of intPARTIDs?

As you know, Arm (Dave) has also implemented the partid narrowing feature[1],
are there aspects of Arm's proposal that do not meet Huawei's requirements?
Also, could you tell me about your future plans?
https://lore.kernel.org/lkml/20250117151033.1517882-1-Dave.Martin@arm.com/ [1]

Best regards,
Shaopeng TAN

^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: [PATCH v3 3/9] arm_mpam: Disable Narrow-PARTID when MBA lacks support
  2026-03-17 13:21 ` [PATCH v3 3/9] arm_mpam: Disable Narrow-PARTID when MBA lacks support Zeng Heng
@ 2026-04-10  1:07   ` Shaopeng Tan (Fujitsu)
  2026-04-11  6:50     ` Zeng Heng
  0 siblings, 1 reply; 22+ messages in thread
From: Shaopeng Tan (Fujitsu) @ 2026-04-10  1:07 UTC (permalink / raw)
  To: 'Zeng Heng', 'ben.horgan@arm.com',
	'james.morse@arm.com', 'Dave.Martin@arm.com',
	'reinette.chatre@intel.com',
	'fenghuay@nvidia.com'
  Cc: 'dave.hansen@linux.intel.com', 'tglx@kernel.org',
	'mingo@redhat.com', 'hpa@zytor.com',
	'bp@alien8.de', 'tony.luck@intel.com',
	'babu.moger@amd.com', 'x86@kernel.org',
	'linux-kernel@vger.kernel.org',
	'wangkefeng.wang@huawei.com'

Hello Zeng Heng,

> MPAM supports mixed systems with MSCs that may or may not implement
> Narrow-PARTID. However, when the MBA MSC uses percentage-based
> throttling (non-bitmap partition control) and lacks Narrow-PARTID support,
> resctrl cannot correctly apply control group configurations across multiple
> PARTIDs.
> 
> Since there is no straightforward way to program compatible control values in
> this scenario, disable Narrow-PARTID system-wide when detected. The
> detection occurs at initialization time on the first call to get_num_reqpartid()
> from mpam_resctrl_pick_counters(), which is guaranteed to occur after
> mpam_resctrl_pick_mba() has set up the MBA resource class.
> 
> If MBA MSCs lack Narrow-PARTID support, get_num_reqpartid() falls back to
> returning the number of internal PARTIDs (mpam_intpartid_max).
> 
> Signed-off-by: Zeng Heng <zengheng4@huawei.com>
> ---
>  drivers/resctrl/mpam_resctrl.c | 38
> +++++++++++++++++++++++++++++++++-
>  1 file changed, 37 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index 222ea1d199e1..1b18c095cfce 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c
> @@ -240,9 +240,45 @@ u32 resctrl_arch_get_num_closid(struct rdt_resource
> *ignored)
>  	return mpam_intpartid_max + 1;
>  }
> 
> +/*
> + * Determine the effective number of PARTIDs available for resctrl.
> + *
> + * This function performs a one-time check to determine if
> +Narrow-PARTID
> + * can be used. It must be called after mpam_resctrl_pick_mba() has
> + * initialized the MBA resource, as the MBA class properties are used
> + * to detect Narrow-PARTID support.
> + *
> + * The first call occurs in mpam_resctrl_pick_counters(), ensuring the
> + * prerequisite initialization is complete.
> + */
> +static u32 get_num_reqpartid(void)
> +{
> +	struct mpam_resctrl_res *res;
> +	struct rdt_resource *r_mba;
> +	struct mpam_props *cprops;
> +	static bool first = true;
> +
> +	if (first) {
> +		r_mba = resctrl_arch_get_resource(RDT_RESOURCE_MBA);
> +		res = container_of(r_mba, struct mpam_resctrl_res,
> resctrl_res);
> +		if (!res->class)
> +			goto out;
> +
> +		/* If MBA MSCs lack Narrow-PARTID support, roll back. */
> +		cprops = &res->class->props;
> +		if (!mpam_has_feature(mpam_feat_partid_nrw, cprops))
> +			mpam_partid_max = mpam_intpartid_max;

Isn't max reqpartid stored in mpam_partid_max? Why is a rollback necessary?

Best regards,
Shaopeng TAN

> +	}
> +
> +out:
> +	first = false;
> +	return mpam_partid_max + 1;
> +}
> +
>  u32 resctrl_arch_system_num_rmid_idx(void)
>  {
> -	return (mpam_pmg_max + 1) * (mpam_partid_max + 1);
> +	return (mpam_pmg_max + 1) * get_num_reqpartid();
>  }
> 
>  u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid)
> --
> 2.25.1
> 


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature
  2026-04-10  0:13 ` Shaopeng Tan (Fujitsu)
@ 2026-04-11  6:32   ` Zeng Heng
  2026-04-16  6:11     ` Shaopeng Tan (Fujitsu)
  0 siblings, 1 reply; 22+ messages in thread
From: Zeng Heng @ 2026-04-11  6:32 UTC (permalink / raw)
  To: Shaopeng Tan (Fujitsu), 'ben.horgan@arm.com',
	'james.morse@arm.com', 'Dave.Martin@arm.com',
	'reinette.chatre@intel.com',
	'fenghuay@nvidia.com'
  Cc: 'dave.hansen@linux.intel.com', 'tglx@kernel.org',
	'mingo@redhat.com', 'hpa@zytor.com',
	'bp@alien8.de', 'tony.luck@intel.com',
	'babu.moger@amd.com', 'x86@kernel.org',
	'linux-kernel@vger.kernel.org',
	'wangkefeng.wang@huawei.com',
	leijitang

Hi Shaopeng,

On 2026/4/10 8:13, Shaopeng Tan (Fujitsu) wrote:
> Hello Zeng Heng,
> 
>> This series applies on top of the mpam_resctrl_glue_v5_debugfs branch of:
>> https://gitlab.arm.com/linux-arm/linux-bh.git
>>
>> Background
>> ==========
>>
>> On x86, the resctrl allows creating up to num_rmids monitoring groups under
>> parent control group. However, ARM64 MPAM is currently limited by the PMG
>> (Performance Monitoring Group) count, which is typically much smaller than
>> the theoretical RMID limit. This creates a significant scalability gap: users
>> expecting fine-grained per-process or per-thread monitoring quickly exhaust
>> the PMG space, even when plenty of reqPARTIDs remain available.
>>
>> The Narrow-PARTID feature, defined in the ARM MPAM architecture,
>> addresses this by associating reqPARTIDs with intPARTIDs through a
>> programmable many-to-one mapping. This allows the kernel to present more
>> logical monitoring contexts.
>>
>> Design Overview
>> ===============
>>
>> The implementation extends the RMID encoding to carry reqPARTID
>> information:
>>
>>    RMID = reqPARTID * NUM_PMG + PMG
>>
>> In this patchset, a monitoring group is uniquely identified by the combination of
>> reqPARTID and PMG. The closid is represented by intPARTID, which is exactly
>> the original PARTID.
>>
>> For systems with homogeneous MSCs (all supporting Narrow-PARTID), the
>> driver exposes the full reqPARTID range directly. For heterogeneous systems
>> where some MSCs lack Narrow-PARTID support, the driver utilizes PARTIDs
>> beyond the intPARTID range as reqPARTIDs to expand monitoring capacity.
>> The sole exception is when MBA MSCs lack Narrow-PARTID support, their
>> percentage-based control mechanism prevents the use of PARTIDs as
>> reqPARTIDs.
>>
>> Capacity Improvements
>> =====================
>>
>> --------------------------------------------------------------------------
>> The maximum        |  Sub-monitoring groups            | System-wide
>> number of          |  under a control group            | monitoring groups
>> --------------------------------------------------------------------------
>> Without            |                                   |
>> reqPARTID          |  PMG                              | intPARTID *
>> PMG
>> --------------------------------------------------------------------------
>> reqPARTID          |                                   |
>> static allocation  | (reqPARTID // intPARTID) * PMG    | reqPARTID * PMG
>> --------------------------------------------------------------------------
>> reqPARTID          |                                   |
>> dynamic allocation | (reqPARTID − intPARTID + 1) * PMG | reqPARTID * PMG
>> --------------------------------------------------------------------------
>>
>> Under MPAM, the number of reqPARTID is always greater than or equal to
>> intPARTID.
> 
> If reqPARTID % intPARTID > 0, does that mean we cann’t fully use reqPARTIDs?
> Some chips have a large number of intPARTIDs, is it possible to use only a limited number of intPARTIDs?

Thanks for the feedback.
Consider adding a boot parameter to allow users to limit the number of
intPARTIDs, and this parameter should satisfy the constraint:

reqPARTID % intPARTID == 0

Alternatively, we also provided dynamic allocation of reqPARTIDs. This
approach would maximize resource utilization, providing number of
monitor groups up to:

(reqPARTID - intPARTID + 1) * PMG

> 
> As you know, Arm (Dave) has also implemented the partid narrowing feature[1],
> are there aspects of Arm's proposal that do not meet Huawei's requirements?
> Also, could you tell me about your future plans?
> https://lore.kernel.org/lkml/20250117151033.1517882-1-Dave.Martin@arm.com/ [1]
> 

Huawei does not have any specific requirements or constraints for this
feature. When we initially tried to send this patch series, there was no
existing implementation of this capability in the community.

In addition to the static allocation approach similar to Dave's
proposal, we have also provided the dynamic allocation scheme mentioned
above. However, this would require moderate changes to the resctrl core
layer.

If the community has not yet implemented this feature and would be
willing to provide review feedback, we are committed to continuously
updating and iterating on this patch series for general MPAM hardware
platforms.


Best regards,
Zeng Heng

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 3/9] arm_mpam: Disable Narrow-PARTID when MBA lacks support
  2026-04-10  1:07   ` Shaopeng Tan (Fujitsu)
@ 2026-04-11  6:50     ` Zeng Heng
  2026-04-13  9:12       ` Zeng Heng
  0 siblings, 1 reply; 22+ messages in thread
From: Zeng Heng @ 2026-04-11  6:50 UTC (permalink / raw)
  To: Shaopeng Tan (Fujitsu), 'ben.horgan@arm.com',
	'james.morse@arm.com', 'Dave.Martin@arm.com',
	'reinette.chatre@intel.com',
	'fenghuay@nvidia.com'
  Cc: 'dave.hansen@linux.intel.com', 'tglx@kernel.org',
	'mingo@redhat.com', 'hpa@zytor.com',
	'bp@alien8.de', 'tony.luck@intel.com',
	'babu.moger@amd.com', 'x86@kernel.org',
	'linux-kernel@vger.kernel.org',
	'wangkefeng.wang@huawei.com'



On 2026/4/10 9:07, Shaopeng Tan (Fujitsu) wrote:
> Hello Zeng Heng,
> 
>> MPAM supports mixed systems with MSCs that may or may not implement
>> Narrow-PARTID. However, when the MBA MSC uses percentage-based
>> throttling (non-bitmap partition control) and lacks Narrow-PARTID support,
>> resctrl cannot correctly apply control group configurations across multiple
>> PARTIDs.
>>
>> Since there is no straightforward way to program compatible control values in
>> this scenario, disable Narrow-PARTID system-wide when detected. The
>> detection occurs at initialization time on the first call to get_num_reqpartid()
>> from mpam_resctrl_pick_counters(), which is guaranteed to occur after
>> mpam_resctrl_pick_mba() has set up the MBA resource class.
>>
>> If MBA MSCs lack Narrow-PARTID support, get_num_reqpartid() falls back to
>> returning the number of internal PARTIDs (mpam_intpartid_max).
>>
>> Signed-off-by: Zeng Heng <zengheng4@huawei.com>
>> ---
>>   drivers/resctrl/mpam_resctrl.c | 38
>> +++++++++++++++++++++++++++++++++-
>>   1 file changed, 37 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
>> index 222ea1d199e1..1b18c095cfce 100644
>> --- a/drivers/resctrl/mpam_resctrl.c
>> +++ b/drivers/resctrl/mpam_resctrl.c
>> @@ -240,9 +240,45 @@ u32 resctrl_arch_get_num_closid(struct rdt_resource
>> *ignored)
>>   	return mpam_intpartid_max + 1;
>>   }
>>
>> +/*
>> + * Determine the effective number of PARTIDs available for resctrl.
>> + *
>> + * This function performs a one-time check to determine if
>> +Narrow-PARTID
>> + * can be used. It must be called after mpam_resctrl_pick_mba() has
>> + * initialized the MBA resource, as the MBA class properties are used
>> + * to detect Narrow-PARTID support.
>> + *
>> + * The first call occurs in mpam_resctrl_pick_counters(), ensuring the
>> + * prerequisite initialization is complete.
>> + */
>> +static u32 get_num_reqpartid(void)
>> +{
>> +	struct mpam_resctrl_res *res;
>> +	struct rdt_resource *r_mba;
>> +	struct mpam_props *cprops;
>> +	static bool first = true;
>> +
>> +	if (first) {
>> +		r_mba = resctrl_arch_get_resource(RDT_RESOURCE_MBA);
>> +		res = container_of(r_mba, struct mpam_resctrl_res,
>> resctrl_res);
>> +		if (!res->class)
>> +			goto out;
>> +
>> +		/* If MBA MSCs lack Narrow-PARTID support, roll back. */
>> +		cprops = &res->class->props;
>> +		if (!mpam_has_feature(mpam_feat_partid_nrw, cprops))
>> +			mpam_partid_max = mpam_intpartid_max;
> 
> Isn't max reqpartid stored in mpam_partid_max? Why is a rollback necessary?
> 

"In order to be able to assign multiple reqPARTIDs freely to resource
control groups, it is necessary that all MSCs that are used by resctrl
either implement Narrow PARTID (so that PARTIDs can be remapped
explicitly) or otherwise only have controls whose resource regulation
is stateless and so whose behaviour would not be affected by splitting
a control group across multiple PARTIDs."



Best regards,
Zeng Heng


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 3/9] arm_mpam: Disable Narrow-PARTID when MBA lacks support
  2026-04-11  6:50     ` Zeng Heng
@ 2026-04-13  9:12       ` Zeng Heng
  0 siblings, 0 replies; 22+ messages in thread
From: Zeng Heng @ 2026-04-13  9:12 UTC (permalink / raw)
  To: Shaopeng Tan (Fujitsu), 'ben.horgan@arm.com',
	'james.morse@arm.com', 'Dave.Martin@arm.com',
	'reinette.chatre@intel.com',
	'fenghuay@nvidia.com'
  Cc: 'dave.hansen@linux.intel.com', 'tglx@kernel.org',
	'mingo@redhat.com', 'hpa@zytor.com',
	'bp@alien8.de', 'tony.luck@intel.com',
	'babu.moger@amd.com', 'x86@kernel.org',
	'linux-kernel@vger.kernel.org',
	'wangkefeng.wang@huawei.com'

Hi Shaopeng,

On 2026/4/11 14:50, Zeng Heng wrote:
> 
> 
> On 2026/4/10 9:07, Shaopeng Tan (Fujitsu) wrote:
>> Hello Zeng Heng,
>>
>>> MPAM supports mixed systems with MSCs that may or may not implement
>>> Narrow-PARTID. However, when the MBA MSC uses percentage-based
>>> throttling (non-bitmap partition control) and lacks Narrow-PARTID 
>>> support,
>>> resctrl cannot correctly apply control group configurations across 
>>> multiple
>>> PARTIDs.
>>>
>>> Since there is no straightforward way to program compatible control 
>>> values in
>>> this scenario, disable Narrow-PARTID system-wide when detected. The
>>> detection occurs at initialization time on the first call to 
>>> get_num_reqpartid()
>>> from mpam_resctrl_pick_counters(), which is guaranteed to occur after
>>> mpam_resctrl_pick_mba() has set up the MBA resource class.
>>>
>>> If MBA MSCs lack Narrow-PARTID support, get_num_reqpartid() falls 
>>> back to
>>> returning the number of internal PARTIDs (mpam_intpartid_max).
>>>
>>> Signed-off-by: Zeng Heng <zengheng4@huawei.com>
>>> ---
>>>   drivers/resctrl/mpam_resctrl.c | 38
>>> +++++++++++++++++++++++++++++++++-
>>>   1 file changed, 37 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/resctrl/mpam_resctrl.c 
>>> b/drivers/resctrl/mpam_resctrl.c
>>> index 222ea1d199e1..1b18c095cfce 100644
>>> --- a/drivers/resctrl/mpam_resctrl.c
>>> +++ b/drivers/resctrl/mpam_resctrl.c
>>> @@ -240,9 +240,45 @@ u32 resctrl_arch_get_num_closid(struct rdt_resource
>>> *ignored)
>>>       return mpam_intpartid_max + 1;
>>>   }
>>>
>>> +/*
>>> + * Determine the effective number of PARTIDs available for resctrl.
>>> + *
>>> + * This function performs a one-time check to determine if
>>> +Narrow-PARTID
>>> + * can be used. It must be called after mpam_resctrl_pick_mba() has
>>> + * initialized the MBA resource, as the MBA class properties are used
>>> + * to detect Narrow-PARTID support.
>>> + *
>>> + * The first call occurs in mpam_resctrl_pick_counters(), ensuring the
>>> + * prerequisite initialization is complete.
>>> + */
>>> +static u32 get_num_reqpartid(void)
>>> +{
>>> +    struct mpam_resctrl_res *res;
>>> +    struct rdt_resource *r_mba;
>>> +    struct mpam_props *cprops;
>>> +    static bool first = true;
>>> +
>>> +    if (first) {
>>> +        r_mba = resctrl_arch_get_resource(RDT_RESOURCE_MBA);
>>> +        res = container_of(r_mba, struct mpam_resctrl_res,
>>> resctrl_res);
>>> +        if (!res->class)
>>> +            goto out;
>>> +
>>> +        /* If MBA MSCs lack Narrow-PARTID support, roll back. */
>>> +        cprops = &res->class->props;
>>> +        if (!mpam_has_feature(mpam_feat_partid_nrw, cprops))
>>> +            mpam_partid_max = mpam_intpartid_max;
>>
>> Isn't max reqpartid stored in mpam_partid_max? Why is a rollback 
>> necessary?
>>
> 
> "In order to be able to assign multiple reqPARTIDs freely to resource
> control groups, it is necessary that all MSCs that are used by resctrl
> either implement Narrow PARTID (so that PARTIDs can be remapped
> explicitly) or otherwise only have controls whose resource regulation
> is stateless and so whose behaviour would not be affected by splitting
> a control group across multiple PARTIDs."
> 
> 

I've rewritten the commit message in an attempt to explain this more
clearly:
https://lore.kernel.org/all/20260413085405.1166412-4-zengheng4@huawei.com/


Thanks for your review in advance,
Zeng Heng

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature
  2026-04-11  6:32   ` Zeng Heng
@ 2026-04-16  6:11     ` Shaopeng Tan (Fujitsu)
  2026-04-20  8:19       ` Zeng Heng
  0 siblings, 1 reply; 22+ messages in thread
From: Shaopeng Tan (Fujitsu) @ 2026-04-16  6:11 UTC (permalink / raw)
  To: Zeng Heng, 'ben.horgan@arm.com',
	'james.morse@arm.com', 'Dave.Martin@arm.com',
	'reinette.chatre@intel.com',
	'fenghuay@nvidia.com'
  Cc: 'dave.hansen@linux.intel.com', 'tglx@kernel.org',
	'mingo@redhat.com', 'hpa@zytor.com',
	'bp@alien8.de', 'tony.luck@intel.com',
	'babu.moger@amd.com', 'x86@kernel.org',
	'linux-kernel@vger.kernel.org',
	'wangkefeng.wang@huawei.com',
	leijitang

Hello Zeng Heng,

>Hi Shaopeng,
>
>On 2026/4/10 8:13, Shaopeng Tan (Fujitsu) wrote:
>> Hello Zeng Heng,
>>
>>> This series applies on top of the mpam_resctrl_glue_v5_debugfs branch of:
>>> https://gitlab.arm.com/linux-arm/linux-bh.git
>>>
>>> Background
>>> ==========
>>>
>>> On x86, the resctrl allows creating up to num_rmids monitoring groups under
>>> parent control group. However, ARM64 MPAM is currently limited by the PMG
>>> (Performance Monitoring Group) count, which is typically much smaller than
>>> the theoretical RMID limit. This creates a significant scalability gap: users
>>> expecting fine-grained per-process or per-thread monitoring quickly exhaust
>>> the PMG space, even when plenty of reqPARTIDs remain available.
>>>
>>> The Narrow-PARTID feature, defined in the ARM MPAM architecture,
>>> addresses this by associating reqPARTIDs with intPARTIDs through a
>>> programmable many-to-one mapping. This allows the kernel to present more
>>> logical monitoring contexts.
>>>
>>> Design Overview
>>> ===============
>>>
>>> The implementation extends the RMID encoding to carry reqPARTID
>>> information:
>>>
>>>    RMID = reqPARTID * NUM_PMG + PMG
>>>
>>> In this patchset, a monitoring group is uniquely identified by the combination of
>>> reqPARTID and PMG. The closid is represented by intPARTID, which is exactly
>>> the original PARTID.
>>>
>>> For systems with homogeneous MSCs (all supporting Narrow-PARTID), the
>>> driver exposes the full reqPARTID range directly. For heterogeneous systems
>>> where some MSCs lack Narrow-PARTID support, the driver utilizes PARTIDs
>>> beyond the intPARTID range as reqPARTIDs to expand monitoring capacity.
>>> The sole exception is when MBA MSCs lack Narrow-PARTID support, their
>>> percentage-based control mechanism prevents the use of PARTIDs as
>>> reqPARTIDs.
>>>
>>> Capacity Improvements
>>> =====================
>>>
>>> --------------------------------------------------------------------------
>>> The maximum        |  Sub-monitoring groups            | System-wide
>>> number of          |  under a control group            | monitoring groups
>>> --------------------------------------------------------------------------
>>> Without            |                                   |
>>> reqPARTID          |  PMG                              | intPARTID *
>>> PMG
>>> --------------------------------------------------------------------------
>>> reqPARTID          |                                   |
>>> static allocation  | (reqPARTID // intPARTID) * PMG    | reqPARTID * PMG
>>> --------------------------------------------------------------------------
>>> reqPARTID          |                                   |
>>> dynamic allocation | (reqPARTID − intPARTID + 1) * PMG | reqPARTID * PMG
>>> --------------------------------------------------------------------------
>>>
>>> Under MPAM, the number of reqPARTID is always greater than or equal to
>>> intPARTID.
>>
>> If reqPARTID % intPARTID > 0, does that mean we cann’t fully use reqPARTIDs?
>> Some chips have a large number of intPARTIDs, is it possible to use only a limited number of intPARTIDs?
>
>Thanks for the feedback.
>Consider adding a boot parameter to allow users to limit the number of
>intPARTIDs, and this parameter should satisfy the constraint:
>
>reqPARTID % intPARTID == 0
>
>Alternatively, we also provided dynamic allocation of reqPARTIDs. This
>approach would maximize resource utilization, providing number of
>monitor groups up to:
>
>(reqPARTID - intPARTID + 1) * PMG
>
>>
>> As you know, Arm (Dave) has also implemented the partid narrowing feature[1],
>> are there aspects of Arm's proposal that do not meet Huawei's requirements?
>> Also, could you tell me about your future plans?
>> https://lore.kernel.org/lkml/20250117151033.1517882-1-Dave.Martin@arm.com/ [1]
>>
>
>Huawei does not have any specific requirements or constraints for this
>feature. When we initially tried to send this patch series, there was no
>existing implementation of this capability in the community.
>
>In addition to the static allocation approach similar to Dave's
>proposal, we have also provided the dynamic allocation scheme mentioned
>above. However, this would require moderate changes to the resctrl core
>layer.
>
>If the community has not yet implemented this feature and would be
>willing to provide review feedback, we are committed to continuously
>updating and iterating on this patch series for general MPAM hardware
>platforms.


About two years ago, Fujitsu discussed the PARTID narrowing proposal with ARM, 
a year ago, I ran Arm's PARTID narrowing implementation (static allocation approach) and confirmed that it worked properly.
Although Arm's implementation requires refactoring based on the latest MPAM branch,
would it be better to proceed with Arm's implementation?

Additionally, since implementing the dynamic allocation approach requires significant changes to the resctrl side, 
how about posting the dynamic allocation approach until the static allocation approach has been merged?


Best regards,
Shaopent TAN

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature
  2026-04-16  6:11     ` Shaopeng Tan (Fujitsu)
@ 2026-04-20  8:19       ` Zeng Heng
  0 siblings, 0 replies; 22+ messages in thread
From: Zeng Heng @ 2026-04-20  8:19 UTC (permalink / raw)
  To: Shaopeng Tan (Fujitsu), 'ben.horgan@arm.com',
	'james.morse@arm.com', 'Dave.Martin@arm.com',
	'reinette.chatre@intel.com',
	'fenghuay@nvidia.com'
  Cc: 'dave.hansen@linux.intel.com', 'tglx@kernel.org',
	'mingo@redhat.com', 'hpa@zytor.com',
	'bp@alien8.de', 'tony.luck@intel.com',
	'babu.moger@amd.com', 'x86@kernel.org',
	'linux-kernel@vger.kernel.org',
	'wangkefeng.wang@huawei.com',
	leijitang

Hi Shaopeng,

On 2026/4/16 14:11, Shaopeng Tan (Fujitsu) wrote:
> Hello Zeng Heng,
> 
>> Hi Shaopeng,
>>
>> On 2026/4/10 8:13, Shaopeng Tan (Fujitsu) wrote:
>>> Hello Zeng Heng,
>>>
>>>> This series applies on top of the mpam_resctrl_glue_v5_debugfs branch of:
>>>> https://gitlab.arm.com/linux-arm/linux-bh.git
>>>>
>>>> Background
>>>> ==========
>>>>
>>>> On x86, the resctrl allows creating up to num_rmids monitoring groups under
>>>> parent control group. However, ARM64 MPAM is currently limited by the PMG
>>>> (Performance Monitoring Group) count, which is typically much smaller than
>>>> the theoretical RMID limit. This creates a significant scalability gap: users
>>>> expecting fine-grained per-process or per-thread monitoring quickly exhaust
>>>> the PMG space, even when plenty of reqPARTIDs remain available.
>>>>
>>>> The Narrow-PARTID feature, defined in the ARM MPAM architecture,
>>>> addresses this by associating reqPARTIDs with intPARTIDs through a
>>>> programmable many-to-one mapping. This allows the kernel to present more
>>>> logical monitoring contexts.
>>>>
>>>> Design Overview
>>>> ===============
>>>>
>>>> The implementation extends the RMID encoding to carry reqPARTID
>>>> information:
>>>>
>>>>     RMID = reqPARTID * NUM_PMG + PMG
>>>>
>>>> In this patchset, a monitoring group is uniquely identified by the combination of
>>>> reqPARTID and PMG. The closid is represented by intPARTID, which is exactly
>>>> the original PARTID.
>>>>
>>>> For systems with homogeneous MSCs (all supporting Narrow-PARTID), the
>>>> driver exposes the full reqPARTID range directly. For heterogeneous systems
>>>> where some MSCs lack Narrow-PARTID support, the driver utilizes PARTIDs
>>>> beyond the intPARTID range as reqPARTIDs to expand monitoring capacity.
>>>> The sole exception is when MBA MSCs lack Narrow-PARTID support, their
>>>> percentage-based control mechanism prevents the use of PARTIDs as
>>>> reqPARTIDs.
>>>>
>>>> Capacity Improvements
>>>> =====================
>>>>
>>>> --------------------------------------------------------------------------
>>>> The maximum        |  Sub-monitoring groups            | System-wide
>>>> number of          |  under a control group            | monitoring groups
>>>> --------------------------------------------------------------------------
>>>> Without            |                                   |
>>>> reqPARTID          |  PMG                              | intPARTID *
>>>> PMG
>>>> --------------------------------------------------------------------------
>>>> reqPARTID          |                                   |
>>>> static allocation  | (reqPARTID // intPARTID) * PMG    | reqPARTID * PMG
>>>> --------------------------------------------------------------------------
>>>> reqPARTID          |                                   |
>>>> dynamic allocation | (reqPARTID − intPARTID + 1) * PMG | reqPARTID * PMG
>>>> --------------------------------------------------------------------------
>>>>
>>>> Under MPAM, the number of reqPARTID is always greater than or equal to
>>>> intPARTID.
>>>
>>> If reqPARTID % intPARTID > 0, does that mean we cann’t fully use reqPARTIDs?
>>> Some chips have a large number of intPARTIDs, is it possible to use only a limited number of intPARTIDs?
>>
>> Thanks for the feedback.
>> Consider adding a boot parameter to allow users to limit the number of
>> intPARTIDs, and this parameter should satisfy the constraint:
>>
>> reqPARTID % intPARTID == 0
>>
>> Alternatively, we also provided dynamic allocation of reqPARTIDs. This
>> approach would maximize resource utilization, providing number of
>> monitor groups up to:
>>
>> (reqPARTID - intPARTID + 1) * PMG
>>
>>>
>>> As you know, Arm (Dave) has also implemented the partid narrowing feature[1],
>>> are there aspects of Arm's proposal that do not meet Huawei's requirements?
>>> Also, could you tell me about your future plans?
>>> https://lore.kernel.org/lkml/20250117151033.1517882-1-Dave.Martin@arm.com/ [1]
>>>
>>
>> Huawei does not have any specific requirements or constraints for this
>> feature. When we initially tried to send this patch series, there was no
>> existing implementation of this capability in the community.
>>
>> In addition to the static allocation approach similar to Dave's
>> proposal, we have also provided the dynamic allocation scheme mentioned
>> above. However, this would require moderate changes to the resctrl core
>> layer.
>>
>> If the community has not yet implemented this feature and would be
>> willing to provide review feedback, we are committed to continuously
>> updating and iterating on this patch series for general MPAM hardware
>> platforms.
> 
> 
> About two years ago, Fujitsu discussed the PARTID narrowing proposal with ARM,
> a year ago, I ran Arm's PARTID narrowing implementation (static allocation approach) and confirmed that it worked properly.
> Although Arm's implementation requires refactoring based on the latest MPAM branch,
> would it be better to proceed with Arm's implementation?
> 
> Additionally, since implementing the dynamic allocation approach requires significant changes to the resctrl side,
> how about posting the dynamic allocation approach until the static allocation approach has been merged?
> 
> 

 From a long-term perspective, the Narrow PARTID static allocation scheme
must maintain software extensibility for dynamic allocation.

To demonstrate this, we sent the dynamic allocation approach alongside
the static allocation scheme. This shows that under the static
allocation scheme, while keeping the RMID encoding intact, only a
small amount of incremental code changes are required to achieve
reqPARTID dynamic allocation.


Kind regards,
Zeng Heng

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2026-04-20  8:20 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-03-17 13:21 [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature Zeng Heng
2026-03-17 13:21 ` [PATCH v3 1/9] fs/resctrl: Fix MPAM Partid parsing errors by preserving CDP state during umount Zeng Heng
2026-03-20 17:07   ` Ben Horgan
2026-03-21  4:11     ` Zeng Heng
2026-03-21  6:39       ` Zeng Heng
2026-03-17 13:21 ` [PATCH v3 2/9] arm_mpam: Add intPARTID and reqPARTID support for narrow PARTID feature Zeng Heng
2026-03-17 13:21 ` [PATCH v3 3/9] arm_mpam: Disable Narrow-PARTID when MBA lacks support Zeng Heng
2026-04-10  1:07   ` Shaopeng Tan (Fujitsu)
2026-04-11  6:50     ` Zeng Heng
2026-04-13  9:12       ` Zeng Heng
2026-03-17 13:21 ` [PATCH v3 4/9] arm_mpam: Refactor rmid to reqPARTID/PMG mapping Zeng Heng
2026-03-17 13:21 ` [PATCH v3 5/9] arm_mpam: Propagate control group config to sub-monitoring groups Zeng Heng
2026-03-17 13:21 ` [PATCH v3 6/9] fs/resctrl: Add rmid_entry state helpers Zeng Heng
2026-03-17 13:21 ` [PATCH v3 7/9] arm_mpam: Implement dynamic reqPARTID allocation for monitoring groups Zeng Heng
2026-03-17 13:21 ` [PATCH v3 8/9] fs/resctrl: Wire up rmid expansion and reclaim functions Zeng Heng
2026-03-17 13:21 ` [PATCH v3 9/9] arm64/mpam: Add mpam_sync_config() for dynamic rmid expansion Zeng Heng
2026-03-20 16:14 ` [PATCH v3 0/9] arm_mpam: Introduce Narrow-PARTID feature Ben Horgan
2026-03-21  7:18   ` Zeng Heng
2026-04-10  0:13 ` Shaopeng Tan (Fujitsu)
2026-04-11  6:32   ` Zeng Heng
2026-04-16  6:11     ` Shaopeng Tan (Fujitsu)
2026-04-20  8:19       ` Zeng Heng

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®