From a269da198b1ccaabccd4f7909b60307c6716c652 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Jul 2025 14:14:39 +0800 Subject: [PATCH 1/6] driver core: Use kasprintf() instead of fixed buffer formatting ANBZ: #34115 commit a355a4655ec660fc68b60b909776290cb88e1124 upstream. Improve readability and maintainability by replacing a hardcoded string allocation and formatting by the use of the kasprintf() helper. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240821154839.604259-3-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Zeng Heng Signed-off-by: zhangxinghao --- drivers/base/core.c | 66 ++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 732787134416..56be3f45cbe4 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -560,20 +561,11 @@ static struct class devlink_class = { static int devlink_add_symlinks(struct device *dev) { + char *buf_con __free(kfree) = NULL, *buf_sup __free(kfree) = NULL; int ret; - size_t len; struct device_link *link = to_devlink(dev); struct device *sup = link->supplier; struct device *con = link->consumer; - char *buf; - - len = max(strlen(dev_bus_name(sup)) + strlen(dev_name(sup)), - strlen(dev_bus_name(con)) + strlen(dev_name(con))); - len += strlen(":"); - len += strlen("supplier:") + 1; - buf = kzalloc(len, GFP_KERNEL); - if (!buf) - return -ENOMEM; ret = sysfs_create_link(&link->link_dev.kobj, &sup->kobj, "supplier"); if (ret) @@ -583,58 +575,64 @@ static int devlink_add_symlinks(struct device *dev) if (ret) goto err_con; - snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con)); - ret = sysfs_create_link(&sup->kobj, &link->link_dev.kobj, buf); + buf_con = kasprintf(GFP_KERNEL, "consumer:%s:%s", dev_bus_name(con), dev_name(con)); + if (!buf_con) { + ret = -ENOMEM; + goto err_con_dev; + } + + ret = sysfs_create_link(&sup->kobj, &link->link_dev.kobj, buf_con); if (ret) goto err_con_dev; - snprintf(buf, len, "supplier:%s:%s", dev_bus_name(sup), dev_name(sup)); - ret = sysfs_create_link(&con->kobj, &link->link_dev.kobj, buf); + buf_sup = kasprintf(GFP_KERNEL, "supplier:%s:%s", dev_bus_name(sup), dev_name(sup)); + if (!buf_sup) { + ret = -ENOMEM; + goto err_sup_dev; + } + + ret = sysfs_create_link(&con->kobj, &link->link_dev.kobj, buf_sup); if (ret) goto err_sup_dev; goto out; err_sup_dev: - snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con)); - sysfs_remove_link(&sup->kobj, buf); + sysfs_remove_link(&sup->kobj, buf_con); err_con_dev: sysfs_remove_link(&link->link_dev.kobj, "consumer"); err_con: sysfs_remove_link(&link->link_dev.kobj, "supplier"); out: - kfree(buf); return ret; } static void devlink_remove_symlinks(struct device *dev) { + char *buf_con __free(kfree) = NULL, *buf_sup __free(kfree) = NULL; struct device_link *link = to_devlink(dev); - size_t len; struct device *sup = link->supplier; struct device *con = link->consumer; - char *buf; sysfs_remove_link(&link->link_dev.kobj, "consumer"); sysfs_remove_link(&link->link_dev.kobj, "supplier"); - len = max(strlen(dev_bus_name(sup)) + strlen(dev_name(sup)), - strlen(dev_bus_name(con)) + strlen(dev_name(con))); - len += strlen(":"); - len += strlen("supplier:") + 1; - buf = kzalloc(len, GFP_KERNEL); - if (!buf) { - WARN(1, "Unable to properly free device link symlinks!\n"); - return; - } - if (device_is_registered(con)) { - snprintf(buf, len, "supplier:%s:%s", dev_bus_name(sup), dev_name(sup)); - sysfs_remove_link(&con->kobj, buf); + buf_sup = kasprintf(GFP_KERNEL, "supplier:%s:%s", dev_bus_name(sup), dev_name(sup)); + if (!buf_sup) + goto out; + sysfs_remove_link(&con->kobj, buf_sup); } - snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con)); - sysfs_remove_link(&sup->kobj, buf); - kfree(buf); + + buf_con = kasprintf(GFP_KERNEL, "consumer:%s:%s", dev_bus_name(con), dev_name(con)); + if (!buf_con) + goto out; + sysfs_remove_link(&sup->kobj, buf_con); + + return; + +out: + WARN(1, "Unable to properly free device link symlinks!\n"); } static struct class_interface devlink_class_intf = { -- Gitee From ef4a8c3133640d375487e217b4f7819967822aa7 Mon Sep 17 00:00:00 2001 From: Zeng Heng Date: Sat, 22 Feb 2025 11:55:16 +0800 Subject: [PATCH 2/6] arm64/mpam: Add write memory barrier to guarantee monitor results ANBZ: #34115 commit 4f0960840acea48f0e82b09cbe4b8def42646015 openEuler. hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8T2RT -------------------------------- Before configure the PARTID of monitor instances, make sure CFG_MON_SEL register has already selected the target instance self. By the same reason, ensure the PARTID has been configured properly before reading counter result of the monitor instance. Fixes: bb66b4d115e5 ("arm_mpam: Add mpam_msmon_read() to read monitor value") Signed-off-by: Zeng Heng [Fixes context conflicts.] Signed-off-by: zhangxinghao --- drivers/resctrl/mpam_devices.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c index e3008215ab2d..e6c48b22d512 100644 --- a/drivers/resctrl/mpam_devices.c +++ b/drivers/resctrl/mpam_devices.c @@ -1209,6 +1209,9 @@ static void __ris_msmon_read(void *arg) FIELD_PREP(MSMON_CFG_MON_SEL_RIS, ris->ris_idx); mpam_write_monsel_reg(msc, CFG_MON_SEL, mon_sel); + /* Selects a monitor instance to configure PARTID. */ + wmb(); + switch (m->type) { case mpam_feat_msmon_mbwu_31counter: case mpam_feat_msmon_mbwu_44counter: @@ -1250,6 +1253,12 @@ static void __ris_msmon_read(void *arg) MSMON_CFG_MBWU_CTL_OFLOW_STATUS_L)); } + /* + * Selects the monitor instance associated to the specified PARTID + * to read counter value. + */ + wmb(); + switch (m->type) { case mpam_feat_msmon_csu: now = mpam_read_monsel_reg(msc, CSU); -- Gitee From be3ed3708ef4167d226c7762d6ff068f031ed52c Mon Sep 17 00:00:00 2001 From: zhangxinghao Date: Fri, 8 May 2026 15:42:57 +0800 Subject: [PATCH 3/6] anolis: arm64/mpam: Add ACPI platform matching for quirk framework ANBZ: #34115 Certain hardware implementations have MPAMF_IIDR set to 0. Introduce ACPI platform matching in the quirk framework to enable the workarounds based on ACPI firmware. Signed-off-by: zhangxinghao --- drivers/resctrl/mpam_devices.c | 3 +++ drivers/resctrl/mpam_internal.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c index e6c48b22d512..e18d014491e2 100644 --- a/drivers/resctrl/mpam_devices.c +++ b/drivers/resctrl/mpam_devices.c @@ -39,6 +39,9 @@ #define SMCCC_SOC_ID_T241 0x036b0241 static void __iomem *t241_scratch_regs[T241_CHIPS_MAX]; +/* Values for the HISI workaround */ +#define HIP12_ACPI_PLAT { "HISI ", "HIP12 ", 0, ACPI_SIG_MPAM, all_versions } + /* * mpam_list_lock protects the SRCU lists when writing. Once the * mpam_enabled key is enabled these lists are read-only, diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h index dbb99d9b0795..91ae69b1af21 100644 --- a/drivers/resctrl/mpam_internal.h +++ b/drivers/resctrl/mpam_internal.h @@ -239,6 +239,7 @@ struct mpam_quirk { u32 iidr; u32 iidr_mask; + struct acpi_platform_list *plat; enum mpam_device_quirks workaround; }; -- Gitee From 20d877eb9a8af6ac269e38b3ad6bdce55ad19723 Mon Sep 17 00:00:00 2001 From: Zeng Heng Date: Thu, 11 Sep 2025 15:18:45 +0800 Subject: [PATCH 4/6] arm64/mpam: Add quirk for L3 CSU counters ANBZ: #34115 commit 8668e586e4bef556d5fe779282c6acbc8c1ad944 openEuler. hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/ICXIBU -------------------------------- On certain platforms, the Cache Storage Usage monitor statistics need to half. Due to the L3 cache compression feature on some hisi chips, the L3 CSU counter shows a value twice the actual usage, which does not reflect the real occupancy. To mitigate this effect as much as possible, the statistic method needs to half the statistic. With L3 compression disabled, the halved value matches the real L3 usage. However, with L3 compression enabled, it becomes slightly lower than the real L3 occupancy. Fixes: bb66b4d115e5 ("arm_mpam: Add mpam_msmon_read() to read monitor value") Signed-off-by: Zeng Heng [Refactor using mpam_device_quirks framework.] Signed-off-by: zhangxinghao --- drivers/resctrl/mpam_devices.c | 27 +++++++++++++++++++++++++++ drivers/resctrl/mpam_internal.h | 1 + 2 files changed, 28 insertions(+) diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c index e18d014491e2..25044900da8b 100644 --- a/drivers/resctrl/mpam_devices.c +++ b/drivers/resctrl/mpam_devices.c @@ -674,6 +674,23 @@ static int mpam_enable_quirk_nvidia_t241_1(struct mpam_msc *msc, return 0; } +static int mpam_enable_quirk_hisi_csu(struct mpam_msc *msc, + const struct mpam_quirk *quirk) +{ + struct mpam_msc_ris *ris; + + if (!quirk->plat || acpi_match_platform_list(quirk->plat) < 0) + return -EINVAL; + + list_for_each_entry(ris, &msc->ris, msc_list) { + struct mpam_class *class = ris->vmsc->comp->class; + + if (class->type == MPAM_CLASS_CACHE && class->level == 3) + return 0; + } + return -EINVAL; +} + static const struct mpam_quirk mpam_quirks[] = { { /* NVIDIA t241 erratum T241-MPAM-1 */ @@ -700,6 +717,14 @@ static const struct mpam_quirk mpam_quirks[] = { .iidr_mask = MPAM_IIDR_MATCH_ONE, .workaround = IGNORE_CSU_NRDY, }, + { + .init = mpam_enable_quirk_hisi_csu, + .iidr_mask = MPAM_IIDR_MATCH_ONE, + .plat = (struct acpi_platform_list[]) { + HIP12_ACPI_PLAT, + {} }, + .workaround = HISI_CSU_WORKAROUND, + }, { NULL } /* Sentinel */ }; @@ -1268,6 +1293,8 @@ static void __ris_msmon_read(void *arg) if (mpam_has_feature(mpam_feat_msmon_csu_hw_nrdy, rprops)) nrdy = now & MSMON___NRDY; now = FIELD_GET(MSMON___VALUE, now); + if (mpam_has_quirk(HISI_CSU_WORKAROUND, ris->vmsc->msc)) + now >>= 1; if (mpam_has_quirk(IGNORE_CSU_NRDY, msc) && m->waited_timeout) nrdy = false; diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h index 91ae69b1af21..343c220bf2b1 100644 --- a/drivers/resctrl/mpam_internal.h +++ b/drivers/resctrl/mpam_internal.h @@ -227,6 +227,7 @@ enum mpam_device_quirks { T241_FORCE_MBW_MIN_TO_ONE, T241_MBW_COUNTER_SCALE_64, IGNORE_CSU_NRDY, + HISI_CSU_WORKAROUND, MPAM_QUIRK_LAST }; -- Gitee From bb167fb2a03c63c16b821fafac22c782f86ae9ec Mon Sep 17 00:00:00 2001 From: Zeng Heng Date: Tue, 23 Sep 2025 19:44:40 +0800 Subject: [PATCH 5/6] arm64/mpam: Add quirk for hisi cpbm_wd field ANBZ: #34115 commit f3a3763f845e7f8a5072a183ed14d0a98eb7fede openEuler. hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/ICX9YF -------------------------------- The bit mask width indicated in the MPAMF_CPOR_IDR_CPBM_WD IDR register of MPAM is inconsistent with the actual hardware capability. This incorrectly limits the L3 capacity in real use. Therefore, software has to hard-code a workaround to align with the actual CPBM bit width. Fixes: 051d021d1c1a ("arm_mpam: Probe the hardware features resctrl supports") Signed-off-by: Zeng Heng [Refactor using mpam_device_quirks framework. Remove modifications to non-existent functions.] Signed-off-by: zhangxinghao --- drivers/resctrl/mpam_devices.c | 74 ++++++++++++++++++++++++++++++--- drivers/resctrl/mpam_internal.h | 1 + 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c index 25044900da8b..6f1d8e77f774 100644 --- a/drivers/resctrl/mpam_devices.c +++ b/drivers/resctrl/mpam_devices.c @@ -41,6 +41,8 @@ static void __iomem *t241_scratch_regs[T241_CHIPS_MAX]; /* Values for the HISI workaround */ #define HIP12_ACPI_PLAT { "HISI ", "HIP12 ", 0, ACPI_SIG_MPAM, all_versions } +#define HISI_CONFIGURE_CPBM_WD 19 +#define HISI_HARDWARE_CPBM_WD 21 /* * mpam_list_lock protects the SRCU lists when writing. Once the @@ -691,6 +693,45 @@ static int mpam_enable_quirk_hisi_csu(struct mpam_msc *msc, return -EINVAL; } +static int mpam_enable_quirk_hisi_cpbm_wd(struct mpam_msc *msc, + const struct mpam_quirk *quirk) +{ + struct mpam_msc_ris *ris; + + if (!quirk->plat || acpi_match_platform_list(quirk->plat) < 0) + return -EINVAL; + + list_for_each_entry(ris, &msc->ris, msc_list) { + struct mpam_class *class = ris->vmsc->comp->class; + + if (class->type == MPAM_CLASS_CACHE && class->level == 3) { + mpam_set_quirk(quirk->workaround, msc); + class->quirks |= msc->quirks; + return -EEXIST; + } + } + return -EINVAL; +} + +/* + * Hardware restriction: Cacheways 17 to 20 only have half the normal capacity. + * To meet the expected capacity requirements: + * 1. Configuring BIT(17) requires using both BIT(17) and BIT(18). + * 2. Configuring BIT(18) requires using both BIT(19) and BIT(20). + */ +static u32 mpam_cpbm_hisi_workaround(u32 cpbm) +{ + if (cpbm & BIT(18)) + cpbm |= (BIT(19) | BIT(20)); + + if (cpbm & BIT(17)) + cpbm |= BIT(18); + else + cpbm &= ~BIT(18); + + return cpbm; +} + static const struct mpam_quirk mpam_quirks[] = { { /* NVIDIA t241 erratum T241-MPAM-1 */ @@ -725,6 +766,14 @@ static const struct mpam_quirk mpam_quirks[] = { {} }, .workaround = HISI_CSU_WORKAROUND, }, + { + .init = mpam_enable_quirk_hisi_cpbm_wd, + .iidr_mask = MPAM_IIDR_MATCH_ONE, + .plat = (struct acpi_platform_list[]) { + HIP12_ACPI_PLAT, + {} }, + .workaround = HISI_EXPAND_CPBM_WD, + }, { NULL } /* Sentinel */ }; @@ -823,7 +872,11 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris) if (FIELD_GET(MPAMF_IDR_HAS_CPOR_PART, ris->idr)) { u32 cpor_features = mpam_read_partsel_reg(msc, CPOR_IDR); - props->cpbm_wd = FIELD_GET(MPAMF_CPOR_IDR_CPBM_WD, cpor_features); + if (mpam_has_quirk(HISI_EXPAND_CPBM_WD, class)) + props->cpbm_wd = HISI_CONFIGURE_CPBM_WD; + else + props->cpbm_wd = FIELD_GET(MPAMF_CPOR_IDR_CPBM_WD, cpor_features); + if (props->cpbm_wd) mpam_set_feature(mpam_feat_cpor_part, props); } @@ -1601,10 +1654,21 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, } if (mpam_has_feature(mpam_feat_cpor_part, rprops)) { - if (mpam_has_feature(mpam_feat_cpor_part, cfg)) - mpam_write_partsel_reg(msc, CPBM, cfg->cpbm); - else - mpam_reset_msc_bitmap(msc, MPAMCFG_CPBM, rprops->cpbm_wd); + if (mpam_has_feature(mpam_feat_cpor_part, cfg)) { + u32 cpbm = cfg->cpbm; + + if (mpam_has_quirk(HISI_EXPAND_CPBM_WD, ris->vmsc->comp->class)) + cpbm = mpam_cpbm_hisi_workaround(cpbm); + + mpam_write_partsel_reg(msc, CPBM, cpbm); + } else { + u16 cpbm_wd = rprops->cpbm_wd; + + if (mpam_has_quirk(HISI_EXPAND_CPBM_WD, ris->vmsc->comp->class)) + cpbm_wd = HISI_HARDWARE_CPBM_WD; + + mpam_reset_msc_bitmap(msc, MPAMCFG_CPBM, cpbm_wd); + } } if (mpam_has_feature(mpam_feat_mbw_part, rprops)) { diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h index 343c220bf2b1..0d0c9ba25b5a 100644 --- a/drivers/resctrl/mpam_internal.h +++ b/drivers/resctrl/mpam_internal.h @@ -228,6 +228,7 @@ enum mpam_device_quirks { T241_MBW_COUNTER_SCALE_64, IGNORE_CSU_NRDY, HISI_CSU_WORKAROUND, + HISI_EXPAND_CPBM_WD, MPAM_QUIRK_LAST }; -- Gitee From 8eff98b0161525146b5042c3e6878579f8f3937f Mon Sep 17 00:00:00 2001 From: Zeng Heng Date: Thu, 6 Nov 2025 15:46:10 +0800 Subject: [PATCH 6/6] arm64/mpam: Add quirk for L3 CPBM validity check ANBZ: #34115 commit 7d075bdfddcbf00cd4fc9d2673da7a527d545bbb openEuler. hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/ICX9YF -------------------------------- On specific chip models, the CPBM interface does not permit bits 18 and 17 to be set independently. Therefore, add the validity check for L3 CPBM. Fixes: f3a3763f845e ("arm64/mpam: Add quirk for hisi cpbm_wd field") Signed-off-by: Zeng Heng [Refactor using mpam_device_quirks framework.] Signed-off-by: zhangxinghao --- drivers/resctrl/mpam_resctrl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c index 5ebc56c515a7..1dd3bbd0772c 100644 --- a/drivers/resctrl/mpam_resctrl.c +++ b/drivers/resctrl/mpam_resctrl.c @@ -22,6 +22,9 @@ #include "mpam_internal.h" +/* Values for the HISI workaround */ +#define HISI_VALID_CPBM_MASK ~(BIT(17) | BIT(18)) + DECLARE_WAIT_QUEUE_HEAD(resctrl_mon_ctx_waiters); /* @@ -1218,6 +1221,10 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d, switch (r->rid) { case RDT_RESOURCE_L2: case RDT_RESOURCE_L3: + if (mpam_has_quirk(HISI_EXPAND_CPBM_WD, res->class) && + !(cfg_val & HISI_VALID_CPBM_MASK)) + return -EINVAL; + cfg.cpbm = cfg_val; mpam_set_feature(mpam_feat_cpor_part, &cfg); break; -- Gitee