From a269da198b1ccaabccd4f7909b60307c6716c652 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Jul 2025 14:14:39 +0800 Subject: [PATCH 1/5] 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/5] 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 e117ed5765c9b2d3629b461cf6f3dcefe109c96e Mon Sep 17 00:00:00 2001 From: Zeng Heng Date: Thu, 11 Sep 2025 15:18:45 +0800 Subject: [PATCH 3/5] 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 [Fixes context conflicts.] Signed-off-by: zhangxinghao --- drivers/resctrl/mpam_devices.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c index e6c48b22d512..f62d1e6f0aa4 100644 --- a/drivers/resctrl/mpam_devices.c +++ b/drivers/resctrl/mpam_devices.c @@ -720,6 +720,23 @@ static void mpam_enable_quirks(struct mpam_msc *msc) } } +static const struct midr_range hip12_cpus[] = { + MIDR_ALL_VERSIONS(MIDR_HISI_HIP12), + { /* sentinel */ } +}; + +static u64 mpam_csu_hisi_need_halved(struct mpam_msc_ris *ris, u64 now) +{ + if (!is_midr_in_range_list(read_cpuid_id(), hip12_cpus)) + return now; + + if (ris->vmsc->comp->class->type != MPAM_CLASS_CACHE || + ris->vmsc->comp->class->level != 3) + return now; + + return now >> 1; +} + /* * IHI009A.a has this nugget: "If a monitor does not support automatic behaviour * of NRDY, software can use this bit for any purpose" - so hardware might not @@ -1265,6 +1282,7 @@ 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); + now = mpam_csu_hisi_need_halved(ris, now); if (mpam_has_quirk(IGNORE_CSU_NRDY, msc) && m->waited_timeout) nrdy = false; -- Gitee From 689ed4e7dc146ab37cb82d36b16f18f661d26b37 Mon Sep 17 00:00:00 2001 From: Zeng Heng Date: Tue, 23 Sep 2025 19:44:40 +0800 Subject: [PATCH 4/5] 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 [Remove modifications to non-existent functions.] Signed-off-by: zhangxinghao --- drivers/resctrl/mpam_devices.c | 48 +++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c index f62d1e6f0aa4..395ab19b6584 100644 --- a/drivers/resctrl/mpam_devices.c +++ b/drivers/resctrl/mpam_devices.c @@ -737,6 +737,40 @@ static u64 mpam_csu_hisi_need_halved(struct mpam_msc_ris *ris, u64 now) return now >> 1; } +static u16 mpam_cpbm_wd_hisi_workaround(u16 cpbm_wd, enum mpam_device_features feat, + u8 cache_level) +{ + if (cache_level != 3) + return cpbm_wd; + + if (is_midr_in_range_list(read_cpuid_id(), hip12_cpus)) { + if (feat == mpam_feat_cpor_part) + return 19; + else if ((feat == mpam_feat_cmax_cmax) || + (feat == mpam_feat_cmax_cmin)) + return 21; + } + + return cpbm_wd; +} + +static u32 mpam_cpbm_hisi_workaround(u32 cpbm, u8 cache_level) +{ + if (cache_level != 3 || + !is_midr_in_range_list(read_cpuid_id(), hip12_cpus)) + return cpbm; + + if (cpbm & BIT(18)) + cpbm |= (BIT(19) | BIT(20)); + + if (cpbm & BIT(17)) + cpbm |= BIT(18); + else + cpbm &= ~BIT(18); + + return cpbm; +} + /* * IHI009A.a has this nugget: "If a monitor does not support automatic behaviour * of NRDY, software can use this bit for any purpose" - so hardware might not @@ -812,7 +846,9 @@ 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); + props->cpbm_wd = mpam_cpbm_wd_hisi_workaround( + FIELD_GET(MPAMF_CPOR_IDR_CPBM_WD, cpor_features), + mpam_feat_cpor_part, class->level); if (props->cpbm_wd) mpam_set_feature(mpam_feat_cpor_part, props); } @@ -1590,9 +1626,15 @@ 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); + mpam_write_partsel_reg(msc, CPBM, + mpam_cpbm_hisi_workaround(cfg->cpbm, + ris->vmsc->comp->class->level)); else - mpam_reset_msc_bitmap(msc, MPAMCFG_CPBM, rprops->cpbm_wd); + mpam_reset_msc_bitmap(msc, MPAMCFG_CPBM, + mpam_cpbm_wd_hisi_workaround( + rprops->cpbm_wd, + mpam_feat_cpor_part, + ris->vmsc->comp->class->level)); } if (mpam_has_feature(mpam_feat_mbw_part, rprops)) { -- Gitee From 7794c48b288adbee81b9eadd48c65e1b1820608c Mon Sep 17 00:00:00 2001 From: Zeng Heng Date: Thu, 6 Nov 2025 15:46:10 +0800 Subject: [PATCH 5/5] 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 [Fixes context conflicts.] Signed-off-by: zhangxinghao --- drivers/resctrl/mpam_devices.c | 15 +++++++++++++++ drivers/resctrl/mpam_internal.h | 2 ++ drivers/resctrl/mpam_resctrl.c | 3 +++ 3 files changed, 20 insertions(+) diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c index 395ab19b6584..99da1927207d 100644 --- a/drivers/resctrl/mpam_devices.c +++ b/drivers/resctrl/mpam_devices.c @@ -771,6 +771,21 @@ static u32 mpam_cpbm_hisi_workaround(u32 cpbm, u8 cache_level) return cpbm; } +bool mpam_cpbm_hisi_check_invalid(struct rdt_resource *r, + unsigned long val) +{ + if (!is_midr_in_range_list(read_cpuid_id(), hip12_cpus)) + return false; + + if (r->ctrl_scope != RESCTRL_L3_CACHE) + return false; + + if (val & ~(BIT(18) | BIT(17))) + return false; + + return true; +} + /* * IHI009A.a has this nugget: "If a monitor does not support automatic behaviour * of NRDY, software can use this bit for any purpose" - so hardware might not diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h index dbb99d9b0795..c0a86f42948e 100644 --- a/drivers/resctrl/mpam_internal.h +++ b/drivers/resctrl/mpam_internal.h @@ -489,6 +489,8 @@ static inline void mpam_resctrl_offline_cpu(unsigned int cpu) { } static inline void mpam_resctrl_teardown_class(struct mpam_class *class) { } #endif /* CONFIG_RESCTRL_FS */ +bool mpam_cpbm_hisi_check_invalid(struct rdt_resource *r, unsigned long val); + /* * MPAM MSCs have the following register layout. See: * Arm Memory System Resource Partitioning and Monitoring (MPAM) System diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c index 5ebc56c515a7..1f3fe5344614 100644 --- a/drivers/resctrl/mpam_resctrl.c +++ b/drivers/resctrl/mpam_resctrl.c @@ -1218,6 +1218,9 @@ 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_cpbm_hisi_check_invalid(r, cfg_val)) + return -EINVAL; + cfg.cpbm = cfg_val; mpam_set_feature(mpam_feat_cpor_part, &cfg); break; -- Gitee