]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
arm_mpam: Add workaround for T241-MPAM-4
authorShanker Donthineni <sdonthineni@nvidia.com>
Fri, 13 Mar 2026 14:46:14 +0000 (14:46 +0000)
committerJames Morse <james.morse@arm.com>
Fri, 27 Mar 2026 15:32:41 +0000 (15:32 +0000)
In the T241 implementation of memory-bandwidth partitioning, in the absence
of contention for bandwidth, the minimum bandwidth setting can affect the
amount of achieved bandwidth. Specifically, the achieved bandwidth in the
absence of contention can settle to any value between the values of
MPAMCFG_MBW_MIN and MPAMCFG_MBW_MAX.  Also, if MPAMCFG_MBW_MIN is set
zero (below 0.78125%), once a core enters a throttled state, it will never
leave that state.

The first issue is not a concern if the MPAM software allows to program
MPAMCFG_MBW_MIN through the sysfs interface. This patch ensures program
MBW_MIN=1 (0.78125%) whenever MPAMCFG_MBW_MIN=0 is programmed.

In the scenario where the resctrl doesn't support the MBW_MIN interface via
sysfs, to achieve bandwidth closer to MBW_MAX in the absence of contention,
software should configure a relatively narrow gap between MBW_MIN and
MBW_MAX. The recommendation is to use a 5% gap to mitigate the problem.

Clear the feature MBW_MIN feature from the class to ensure we don't
accidentally change behaviour when resctrl adds support for a MBW_MIN
interface.

Tested-by: Gavin Shan <gshan@redhat.com>
Tested-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
Tested-by: Jesse Chick <jessechick@os.amperecomputing.com>
Reviewed-by: Zeng Heng <zengheng4@huawei.com>
Reviewed-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
Reviewed-by: Fenghua Yu <fenghuay@nvidia.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
Signed-off-by: Shanker Donthineni <sdonthineni@nvidia.com>
Signed-off-by: Ben Horgan <ben.horgan@arm.com>
Signed-off-by: James Morse <james.morse@arm.com>
Documentation/arch/arm64/silicon-errata.rst
drivers/resctrl/mpam_devices.c
drivers/resctrl/mpam_internal.h

index a65620f98e3aab46cee7e16b39175273f65ff67a..a4b246655e37e26e9a7851c12b5dd00a7a1c1014 100644 (file)
@@ -249,6 +249,8 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | NVIDIA         | T241 MPAM       | T241-MPAM-1     | N/A                         |
 +----------------+-----------------+-----------------+-----------------------------+
+| NVIDIA         | T241 MPAM       | T241-MPAM-4     | N/A                         |
++----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
 | Freescale/NXP  | LS2080A/LS1043A | A-008585        | FSL_ERRATUM_A008585         |
 +----------------+-----------------+-----------------+-----------------------------+
index b1fe6f171b68a91ce2b6e45cf6739c42f157a8dc..142e7ea960e5bbe7efe70c64d29cdcf44bac9bad 100644 (file)
@@ -679,6 +679,12 @@ static const struct mpam_quirk mpam_quirks[] = {
                .iidr_mask  = MPAM_IIDR_MATCH_ONE,
                .workaround = T241_SCRUB_SHADOW_REGS,
        },
+       {
+               /* NVIDIA t241 erratum T241-MPAM-4 */
+               .iidr       = MPAM_IIDR_NVIDIA_T241,
+               .iidr_mask  = MPAM_IIDR_MATCH_ONE,
+               .workaround = T241_FORCE_MBW_MIN_TO_ONE,
+       },
        { NULL } /* Sentinel */
 };
 
@@ -1464,6 +1470,37 @@ static void mpam_quirk_post_config_change(struct mpam_msc_ris *ris, u16 partid,
                mpam_apply_t241_erratum(ris, partid);
 }
 
+static u16 mpam_wa_t241_force_mbw_min_to_one(struct mpam_props *props)
+{
+       u16 max_hw_value, min_hw_granule, res0_bits;
+
+       res0_bits = 16 - props->bwa_wd;
+       max_hw_value = ((1 << props->bwa_wd) - 1) << res0_bits;
+       min_hw_granule = ~max_hw_value;
+
+       return min_hw_granule + 1;
+}
+
+static u16 mpam_wa_t241_calc_min_from_max(struct mpam_props *props,
+                                         struct mpam_config *cfg)
+{
+       u16 val = 0;
+       u16 max;
+       u16 delta = ((5 * MPAMCFG_MBW_MAX_MAX) / 100) - 1;
+
+       if (mpam_has_feature(mpam_feat_mbw_max, cfg)) {
+               max = cfg->mbw_max;
+       } else {
+               /* Resetting. Hence, use the ris specific default. */
+               max = GENMASK(15, 16 - props->bwa_wd);
+       }
+
+       if (max > delta)
+               val = max - delta;
+
+       return val;
+}
+
 /* Called via IPI. Call while holding an SRCU reference */
 static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
                                      struct mpam_config *cfg)
@@ -1504,9 +1541,18 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
                        mpam_write_partsel_reg(msc, MBW_PBM, cfg->mbw_pbm);
        }
 
-       if (mpam_has_feature(mpam_feat_mbw_min, rprops) &&
-           mpam_has_feature(mpam_feat_mbw_min, cfg))
-               mpam_write_partsel_reg(msc, MBW_MIN, 0);
+       if (mpam_has_feature(mpam_feat_mbw_min, rprops)) {
+               u16 val = 0;
+
+               if (mpam_has_quirk(T241_FORCE_MBW_MIN_TO_ONE, msc)) {
+                       u16 min = mpam_wa_t241_force_mbw_min_to_one(rprops);
+
+                       val = mpam_wa_t241_calc_min_from_max(rprops, cfg);
+                       val = max(val, min);
+               }
+
+               mpam_write_partsel_reg(msc, MBW_MIN, val);
+       }
 
        if (mpam_has_feature(mpam_feat_mbw_max, rprops)) {
                if (mpam_has_feature(mpam_feat_mbw_max, cfg))
@@ -2288,6 +2334,9 @@ static void mpam_enable_merge_class_features(struct mpam_component *comp)
 
        list_for_each_entry(vmsc, &comp->vmsc, comp_list)
                __class_props_mismatch(class, vmsc);
+
+       if (mpam_has_quirk(T241_FORCE_MBW_MIN_TO_ONE, class))
+               mpam_clear_feature(mpam_feat_mbw_min, &class->props);
 }
 
 /*
index d9eb342ba2220d19ce08c7f744c57ebec149abd4..f1adbdad39696228fe02e5aa38a4a4b710b48545 100644 (file)
@@ -224,6 +224,7 @@ struct mpam_props {
 /* Workaround bits for msc->quirks */
 enum mpam_device_quirks {
        T241_SCRUB_SHADOW_REGS,
+       T241_FORCE_MBW_MIN_TO_ONE,
        MPAM_QUIRK_LAST
 };