[RFC PATCH 02/10] arm_mpam: Carry mbw_min and the hard limit in mpam_config

From: Jinjie Ruan

Date: Thu Oct 22 2026 - 22:49:15 EST


Add mbw_min and max_limit to mpam_config so the bandwidth minimum and
the MBW_MAX hard-limit bit can be programmed per PARTID through resctrl.

The hard limit is a config bit of MPAMCFG_MBW_MAX, not a discoverable
capability, so mpam_feat_max_limit is set alongside mpam_feat_mbw_max.
mpam_reprogram_ris_partid() writes the config's mbw_min when its feature
bit is set, and sets the hard-limit bit from its own feature bit so
MBHDL can be set without MBW_MAX being written.

Signed-off-by: Jinjie Ruan <ruanjinjie@xxxxxxxxxx>
---
drivers/resctrl/mpam_devices.c | 25 +++++++++++++++++++++----
drivers/resctrl/mpam_internal.h | 3 +++
2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 0fbf3464e744..806bf61b6dbe 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -848,8 +848,11 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
*/
props->bwa_wd = min(props->bwa_wd, 16);

- if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_MAX, mbw_features))
+ if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_MAX, mbw_features)) {
mpam_set_feature(mpam_feat_mbw_max, props);
+ /* The hard-limit bit is a config bit, not a capability */
+ mpam_set_feature(mpam_feat_max_limit, props);
+ }

if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_MIN, mbw_features))
mpam_set_feature(mpam_feat_mbw_min, props);
@@ -1586,6 +1589,9 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
if (mpam_has_feature(mpam_feat_mbw_min, rprops)) {
u16 val = 0;

+ if (mpam_has_feature(mpam_feat_mbw_min, cfg))
+ val = cfg->mbw_min;
+
if (mpam_has_quirk(T241_FORCE_MBW_MIN_TO_ONE, msc)) {
u16 min = mpam_wa_t241_force_mbw_min_to_one(rprops);

@@ -1597,10 +1603,19 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
}

if (mpam_has_feature(mpam_feat_mbw_max, rprops)) {
+ u32 val = MPAMCFG_MBW_MAX_MAX;
+
if (mpam_has_feature(mpam_feat_mbw_max, cfg))
- mpam_write_partsel_reg(msc, MBW_MAX, cfg->mbw_max);
- else
- mpam_write_partsel_reg(msc, MBW_MAX, MPAMCFG_MBW_MAX_MAX);
+ val = cfg->mbw_max;
+
+ /*
+ * The hard-limit bit follows its own feature bit: MBHDL can
+ * be configured without MBW_MAX ever being written.
+ */
+ if (mpam_has_feature(mpam_feat_max_limit, cfg) && cfg->max_limit)
+ val |= MPAMCFG_MBW_MAX_HARDLIM;
+
+ mpam_write_partsel_reg(msc, MBW_MAX, val);
}

if (mpam_has_feature(mpam_feat_mbw_prop, rprops))
@@ -2922,6 +2937,8 @@ static bool mpam_update_config(struct mpam_config *cfg,
maybe_update_config(cfg, mpam_feat_cpor_part, newcfg, cpbm, has_changes);
maybe_update_config(cfg, mpam_feat_mbw_part, newcfg, mbw_pbm, has_changes);
maybe_update_config(cfg, mpam_feat_mbw_max, newcfg, mbw_max, has_changes);
+ maybe_update_config(cfg, mpam_feat_mbw_min, newcfg, mbw_min, has_changes);
+ maybe_update_config(cfg, mpam_feat_max_limit, newcfg, max_limit, has_changes);

return has_changes;
}
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index def0e3a65c23..f5efebde3c2c 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -188,6 +188,7 @@ enum mpam_device_features {
mpam_feat_msmon_mbwu_capture,
mpam_feat_msmon_mbwu_rwbw,
mpam_feat_partid_nrw,
+ mpam_feat_max_limit,
MPAM_FEATURE_LAST
};

@@ -318,6 +319,8 @@ struct mpam_config {
u32 cpbm;
u32 mbw_pbm;
u16 mbw_max;
+ u16 mbw_min;
+ bool max_limit;

struct mpam_garbage garbage;
};
--
2.34.1