[RFC PATCH 10/10] arm_mpam: resctrl: Expose the bandwidth minimum and limit as pseudo resources

From: Jinjie Ruan

Date: Thu Oct 22 2026 - 22:53:22 EST


Expose MBMIN, MBHDL and MBOPT, re-using the class picked for MBA.

MBMIN carries the bandwidth minimum as a percentage; MBHDL toggles the
MBW_MAX hard-limit bit; MBOPT exposes the raw MBW_MAX fraction without
the percentage scaling.

control_init() describes them as RESCTRL_SCHEMA_RANGE, with the ranges
derived from bwa_wd. update_one() and get_config() carry the values
through the mpam_config fields added earlier.

Signed-off-by: Jinjie Ruan <ruanjinjie@xxxxxxxxxx>
---
drivers/resctrl/mpam_resctrl.c | 73 ++++++++++++++++++++++++++++++++++
1 file changed, 73 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 008db81e734b..346ee3729ddf 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -1064,8 +1064,14 @@ static void mpam_resctrl_pick_mba(void)
res->class = candidate_class;

/* As with the caches, re-use the class for the pseudo resources */
+ if (mpam_has_feature(mpam_feat_mbw_min, cprops))
+ mpam_resctrl_controls[RDT_RESOURCE_MB_MIN].class = candidate_class;
if (mpam_has_feature(mpam_feat_intpri_part, cprops))
mpam_resctrl_controls[RDT_RESOURCE_MB_PRI].class = candidate_class;
+ if (mpam_has_feature(mpam_feat_max_limit, cprops))
+ mpam_resctrl_controls[RDT_RESOURCE_MB_HDL].class = candidate_class;
+ if (mba_class_use_mbw_max(cprops))
+ mpam_resctrl_controls[RDT_RESOURCE_MB_OPT].class = candidate_class;
}
}

@@ -1317,6 +1323,19 @@ static int mpam_resctrl_control_init(struct mpam_resctrl_res *res)
r->name = (r->rid == RDT_RESOURCE_L2_MIN) ? "L2MIN" : "L3MIN";
r->alloc_capable = true;
break;
+ case RDT_RESOURCE_MB_MIN:
+ r->schema_fmt = RESCTRL_SCHEMA_RANGE;
+ r->ctrl_scope = RESCTRL_L3_CACHE;
+
+ r->membw.delay_linear = true;
+ r->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
+ r->membw.min_bw = 0;
+ r->membw.max_bw = MAX_MBA_BW;
+ r->membw.bw_gran = 1;
+
+ r->name = "MBMIN";
+ r->alloc_capable = true;
+ break;
case RDT_RESOURCE_L3_PRI:
case RDT_RESOURCE_L2_PRI:
case RDT_RESOURCE_MB_PRI:
@@ -1334,6 +1353,32 @@ static int mpam_resctrl_control_init(struct mpam_resctrl_res *res)
((r->rid == RDT_RESOURCE_L2_PRI) ? "L2PRI" : "L3PRI");
r->alloc_capable = true;
break;
+ case RDT_RESOURCE_MB_HDL:
+ r->schema_fmt = RESCTRL_SCHEMA_RANGE;
+ r->ctrl_scope = RESCTRL_L3_CACHE;
+
+ r->membw.delay_linear = true;
+ r->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
+ r->membw.min_bw = 0;
+ r->membw.max_bw = 1;
+ r->membw.bw_gran = 1;
+
+ r->name = "MBHDL";
+ r->alloc_capable = true;
+ break;
+ case RDT_RESOURCE_MB_OPT:
+ r->schema_fmt = RESCTRL_SCHEMA_RANGE;
+ r->ctrl_scope = RESCTRL_L3_CACHE;
+
+ r->membw.delay_linear = true;
+ r->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
+ r->membw.min_bw = 1;
+ r->membw.max_bw = GENMASK(cprops->bwa_wd - 1, 0);
+ r->membw.bw_gran = 1;
+
+ r->name = "MBOPT";
+ r->alloc_capable = true;
+ break;
default:
return -EINVAL;
}
@@ -1511,6 +1556,15 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
case RDT_RESOURCE_MB_PRI:
configured_by = mpam_feat_intpri_part;
break;
+ case RDT_RESOURCE_MB_MIN:
+ configured_by = mpam_feat_mbw_min;
+ break;
+ case RDT_RESOURCE_MB_HDL:
+ configured_by = mpam_feat_max_limit;
+ break;
+ case RDT_RESOURCE_MB_OPT:
+ configured_by = mpam_feat_mbw_max;
+ break;
case RDT_RESOURCE_MBA:
if (mpam_has_feature(mpam_feat_mbw_max, cprops)) {
configured_by = mpam_feat_mbw_max;
@@ -1534,7 +1588,14 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
return ca_max_to_percent(cfg->cmin, cprops);
case mpam_feat_intpri_part:
return cfg->intpri;
+ case mpam_feat_mbw_min:
+ return mbw_max_to_percent(cfg->mbw_min, cprops);
+ case mpam_feat_max_limit:
+ return cfg->max_limit;
case mpam_feat_mbw_max:
+ /* MB_OPT exposes the raw fraction, without the percent scaling */
+ if (r->rid == RDT_RESOURCE_MB_OPT)
+ return cfg->mbw_max >> (16 - cprops->bwa_wd);
return mbw_max_to_percent(cfg->mbw_max, cprops);
default:
return resctrl_get_default_ctrl(r);
@@ -1602,6 +1663,18 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
cfg.intpri = cfg_val;
mpam_set_feature(mpam_feat_intpri_part, &cfg);
break;
+ case RDT_RESOURCE_MB_MIN:
+ cfg.mbw_min = percent_to_mbw_max(cfg_val, cprops);
+ mpam_set_feature(mpam_feat_mbw_min, &cfg);
+ break;
+ case RDT_RESOURCE_MB_HDL:
+ cfg.max_limit = !!cfg_val;
+ mpam_set_feature(mpam_feat_max_limit, &cfg);
+ break;
+ case RDT_RESOURCE_MB_OPT:
+ cfg.mbw_max = cfg_val << (16 - cprops->bwa_wd);
+ mpam_set_feature(mpam_feat_mbw_max, &cfg);
+ break;
case RDT_RESOURCE_MBA:
if (mpam_has_feature(mpam_feat_mbw_max, cprops)) {
cfg.mbw_max = percent_to_mbw_max(cfg_val, cprops);
--
2.34.1