[PATCH OLK-6.6 v2 00/17] fs/resctrl: Introduce the resctrl_feat_type

Zeng Heng (17): arm64/mpam: fix memleak in resctrl_arch_mon_ctx_alloc_no_wait() arm64/mpam: fix impossible condition in get_cpumask_from_cache_id() arm64/mpam: fix impossible condition in resctrl_arch_rmid_read() arm64/mpam: Optimize CSU/MBWU monitor multiplexing fs/resctrl: Determine whether the MBM monitors require overflow checking arm64/mpam: Set the cpbm width of msc class with the minimum arm64/mpam: Correct the judgment condition of the CMAX feature fs/resctrl: Fix kmemleak caused by closid_init() fs/resctrl: Introduce the resctrl_feat_type fs/resctrl: Add mbw_min and cmin features arm64/mpam: Add PRIO feature arm64/mpam: Add CMAX feature arm64/mpam: Add PBM feature arm64/mpam: Add limit feature arm64/mpam: Fix allocated cache size information fs/resctrl: Fix configuration to wrong control group when CDP is enabled arm64/mpam: Add debugging information about CDP monitor value arch/x86/include/asm/resctrl.h | 29 ++ arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 39 +-- drivers/platform/mpam/mpam_devices.c | 111 +++++-- drivers/platform/mpam/mpam_internal.h | 25 +- drivers/platform/mpam/mpam_resctrl.c | 347 +++++++++++++++++----- fs/resctrl/ctrlmondata.c | 141 ++++++++- fs/resctrl/monitor.c | 5 +- fs/resctrl/rdtgroup.c | 135 +++++---- include/linux/arm_mpam.h | 7 + include/linux/resctrl.h | 17 +- include/linux/resctrl_types.h | 10 + 11 files changed, 670 insertions(+), 196 deletions(-) -- 2.25.1

反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/15878 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/PQI... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/15878 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/PQI...

hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IAJUN4 -------------------------------- The smatch tool complains about possible memory leak warning shown below: drivers/platform/mpam/mpam_resctrl.c:323 resctrl_arch_mon_ctx_alloc_no_wait() warn: possible memory leak of 'ret' drivers/platform/mpam/mpam_resctrl.c:326 resctrl_arch_mon_ctx_alloc_no_wait() warn: possible memory leak of 'ret' Only the QOS_L3_OCCUP_EVENT_ID path will return the allocated object, and other case paths will cause memory leaks. In the QOS_L3_MBM_LOCAL_EVENT_ID and QOS_L3_MBM_TOTAL_EVENT_ID cases, resctrl_arch_mon_ctx_alloc_no_wait() should return a pointer to the allocated object, not an invalid pointer. Fixes: 9119da143939 ("arm_mpam: resctrl: Allow resctrl to allocate monitors") Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/platform/mpam/mpam_resctrl.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index dd1ccca8edcb..9aadf009b6a8 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -57,7 +57,6 @@ static DECLARE_WAIT_QUEUE_HEAD(wait_cacheinfo_ready); /* A dummy mon context to use when the monitors were allocated up front */ u32 __mon_is_rmid_idx = USE_RMID_IDX; -void *mon_is_rmid_idx = &__mon_is_rmid_idx; bool resctrl_arch_alloc_capable(void) { @@ -267,12 +266,16 @@ static void *resctrl_arch_mon_ctx_alloc_no_wait(struct rdt_resource *r, *ret = mpam_alloc_csu_mon(res->class); return ret; + case QOS_L3_MBM_LOCAL_EVENT_ID: case QOS_L3_MBM_TOTAL_EVENT_ID: - return mon_is_rmid_idx; - } + *ret = __mon_is_rmid_idx; + return ret; - return ERR_PTR(-EOPNOTSUPP); + default: + kfree(ret); + return ERR_PTR(-EOPNOTSUPP); + } } void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r, int evtid) @@ -300,15 +303,11 @@ void resctrl_arch_mon_ctx_free(struct rdt_resource *r, int evtid, struct mpam_resctrl_res *res; u32 mon = *(u32 *)arch_mon_ctx; - if (mon == USE_RMID_IDX) - return; kfree(arch_mon_ctx); - arch_mon_ctx = NULL; - - res = container_of(r, struct mpam_resctrl_res, resctrl_res); switch (evtid) { case QOS_L3_OCCUP_EVENT_ID: + res = container_of(r, struct mpam_resctrl_res, resctrl_res); mpam_free_csu_mon(res->class, mon); wake_up(&resctrl_mon_ctx_waiters); return; -- 2.25.1

hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IAJUN4 -------------------------------- The smatch tool complains about impossible condition warning shown below: drivers/platform/mpam/mpam_devices.c:391 get_cpumask_from_cache_id() warn: impossible condition '(cache_id == ~0) => (0-u32max == u64max)' cache_id is an unsigned 32-bit object, so when comparing conditions, keep the data types consistent. Fixes: 848cefee5a21 ("arm_mpam: Add the class and component structures for ris firmware described") Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/platform/mpam/mpam_devices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/mpam/mpam_devices.c b/drivers/platform/mpam/mpam_devices.c index 56bbd7290cd9..e99f6b0b3d59 100644 --- a/drivers/platform/mpam/mpam_devices.c +++ b/drivers/platform/mpam/mpam_devices.c @@ -388,7 +388,7 @@ static int get_cpumask_from_cache_id(u32 cache_id, u32 cache_level, * during device_initcall(). Use cache_of_get_id(). */ iter_cache_id = cache_of_get_id(iter); - if (cache_id == ~0UL) { + if (cache_id == (~0)) { of_node_put(iter); continue; } -- 2.25.1

hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IAJUN4 -------------------------------- The smatch tool complains about impossible condition warning shown below: drivers/platform/mpam/mpam_resctrl.c:414 resctrl_arch_rmid_read() warn: impossible condition '(cfg.mon == ((~0) + 1)) => (0-u16max == 65536)' The USE_RMID_IDX macro is a 32-bit data type, as the assignment object, cfg.mon should also be a 32-bit unsigned variable. Fixes: 21ac9fc8f275 ("arm_mpam: Track bandwidth counter state for overflow and power management") Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/platform/mpam/mpam_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/mpam/mpam_internal.h b/drivers/platform/mpam/mpam_internal.h index 119660a53e16..a613e5a77a85 100644 --- a/drivers/platform/mpam/mpam_internal.h +++ b/drivers/platform/mpam/mpam_internal.h @@ -194,7 +194,7 @@ enum mon_filter_options { }; struct mon_cfg { - u16 mon; + u32 mon; u8 pmg; bool match_pmg; u32 partid; -- 2.25.1

hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IAJUN4 -------------------------------- When MBM is implemented according to the *DDI0598* protocol, that is, mbm_total_bytes interface returns the statistical results of instantaneous bandwidth traffic, there is no need to create a delay_work to handle MBM statistical overflow. No matter it is MBWU or CSU monitors, using per-CLOSID monitoring instances avoids inaccurate statistical results caused by monitor multiplexing, which can occur when multiple control groups are monitored simultaneously. Fixes: 9119da143939 ("arm_mpam: resctrl: Allow resctrl to allocate monitors") Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/platform/mpam/mpam_resctrl.c | 33 +++++++--------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index 9aadf009b6a8..728f03a2a3f6 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -254,7 +254,6 @@ struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l) static void *resctrl_arch_mon_ctx_alloc_no_wait(struct rdt_resource *r, int evtid) { - struct mpam_resctrl_res *res; u32 *ret = kmalloc(sizeof(*ret), GFP_KERNEL); if (!ret) @@ -262,11 +261,6 @@ static void *resctrl_arch_mon_ctx_alloc_no_wait(struct rdt_resource *r, switch (evtid) { case QOS_L3_OCCUP_EVENT_ID: - res = container_of(r, struct mpam_resctrl_res, resctrl_res); - - *ret = mpam_alloc_csu_mon(res->class); - return ret; - case QOS_L3_MBM_LOCAL_EVENT_ID: case QOS_L3_MBM_TOTAL_EVENT_ID: *ret = __mon_is_rmid_idx; @@ -300,21 +294,7 @@ void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r, int evtid) void resctrl_arch_mon_ctx_free(struct rdt_resource *r, int evtid, void *arch_mon_ctx) { - struct mpam_resctrl_res *res; - u32 mon = *(u32 *)arch_mon_ctx; - kfree(arch_mon_ctx); - - switch (evtid) { - case QOS_L3_OCCUP_EVENT_ID: - res = container_of(r, struct mpam_resctrl_res, resctrl_res); - mpam_free_csu_mon(res->class, mon); - wake_up(&resctrl_mon_ctx_waiters); - return; - case QOS_L3_MBM_TOTAL_EVENT_ID: - case QOS_L3_MBM_LOCAL_EVENT_ID: - return; - } } static enum mon_filter_options resctrl_evt_config_to_mpam(u32 local_evt_cfg) @@ -335,7 +315,7 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d, { int err; u64 cdp_val; - u16 num_mbwu_mon; + u16 num_mon; struct mon_cfg cfg; struct mpam_resctrl_dom *dom; struct mpam_resctrl_res *res; @@ -362,12 +342,15 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d, if (cfg.mon == USE_RMID_IDX) { /* * The number of mbwu monitors can't support free run mode, - * adapt the remainder of rmid to the num_mbwu_mon as a - * compromise. + * adapt the remainder of rmid to the num_mon as compromise. */ res = container_of(r, struct mpam_resctrl_res, resctrl_res); - num_mbwu_mon = res->class->props.num_mbwu_mon; - cfg.mon = resctrl_arch_rmid_idx_encode(closid, rmid) % num_mbwu_mon; + if (type == mpam_feat_msmon_mbwu) + num_mon = res->class->props.num_mbwu_mon; + else + num_mon = res->class->props.num_csu_mon; + + cfg.mon = closid % num_mon; } cfg.match_pmg = true; -- 2.25.1

hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IAJUN4 -------------------------------- When MBM is implemented according to the *DDI0598* protocol, that is, mbm_total_bytes interface returns the statistical results of instantaneous bandwidth traffic, there is no need to create a delay_work to handle MBM statistical overflow. Fixes: 9119da143939 ("arm_mpam: resctrl: Allow resctrl to allocate monitors") Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- arch/x86/include/asm/resctrl.h | 2 ++ drivers/platform/mpam/mpam_devices.c | 10 +++++++++- fs/resctrl/rdtgroup.c | 9 +++++---- include/linux/arm_mpam.h | 1 + 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h index 37b8d7dfcfed..c5f90edc3e20 100644 --- a/arch/x86/include/asm/resctrl.h +++ b/arch/x86/include/asm/resctrl.h @@ -94,6 +94,8 @@ static inline bool resctrl_arch_is_mbm_total_enabled(void) return (rdt_mon_features & (1 << QOS_L3_MBM_TOTAL_EVENT_ID)); } +static inline bool resctrl_arch_would_mbm_overflow(void) { return true; } + static inline bool resctrl_arch_is_mbm_local_enabled(void) { return (rdt_mon_features & (1 << QOS_L3_MBM_LOCAL_EVENT_ID)); diff --git a/drivers/platform/mpam/mpam_devices.c b/drivers/platform/mpam/mpam_devices.c index e99f6b0b3d59..c148ecd47613 100644 --- a/drivers/platform/mpam/mpam_devices.c +++ b/drivers/platform/mpam/mpam_devices.c @@ -921,6 +921,14 @@ static const struct midr_range mbwu_flowrate_list[] = { { /* sentinel */ } }; +bool resctrl_arch_would_mbm_overflow(void) +{ + if (is_midr_in_range_list(read_cpuid_id(), mbwu_flowrate_list)) + return false; + + return true; +} + static void __ris_msmon_read(void *arg) { bool nrdy = false; @@ -1009,7 +1017,7 @@ static void __ris_msmon_read(void *arg) * was last reset in the latest version (DDI0598D_b). */ if (ris->comp->class->type == MPAM_CLASS_MEMORY) { - if (is_midr_in_range_list(read_cpuid_id(), mbwu_flowrate_list)) + if (!resctrl_arch_would_mbm_overflow()) break; } diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c index 1ade368e2631..9776b4e2834c 100644 --- a/fs/resctrl/rdtgroup.c +++ b/fs/resctrl/rdtgroup.c @@ -2576,7 +2576,7 @@ static int rdt_get_tree(struct fs_context *fc) if (resctrl_arch_alloc_capable() || resctrl_arch_mon_capable()) resctrl_mounted = true; - if (resctrl_is_mbm_enabled()) { + if (resctrl_is_mbm_enabled() && resctrl_arch_would_mbm_overflow()) { list_for_each_entry(dom, &l3->domains, list) mbm_setup_overflow_handler(dom, MBM_OVERFLOW_INTERVAL, RESCTRL_PICK_ANY_CPU); @@ -3796,7 +3796,7 @@ void resctrl_offline_domain(struct rdt_resource *r, struct rdt_domain *d) if (resctrl_mounted && resctrl_arch_mon_capable()) rmdir_mondata_subdir_allrdtgrp(r, d->id); - if (resctrl_is_mbm_enabled()) + if (resctrl_is_mbm_enabled() && resctrl_arch_would_mbm_overflow()) cancel_delayed_work(&d->mbm_over); if (resctrl_arch_is_llc_occupancy_enabled() && has_busy_rmid(d)) { /* @@ -3867,7 +3867,7 @@ int resctrl_online_domain(struct rdt_resource *r, struct rdt_domain *d) if (err) goto out_unlock; - if (resctrl_is_mbm_enabled()) { + if (resctrl_is_mbm_enabled() && resctrl_arch_would_mbm_overflow()) { INIT_DELAYED_WORK(&d->mbm_over, mbm_handle_overflow); mbm_setup_overflow_handler(d, MBM_OVERFLOW_INTERVAL, RESCTRL_PICK_ANY_CPU); @@ -3928,7 +3928,8 @@ void resctrl_offline_cpu(unsigned int cpu) d = resctrl_get_domain_from_cpu(cpu, l3); if (d) { - if (resctrl_is_mbm_enabled() && cpu == d->mbm_work_cpu) { + if (resctrl_is_mbm_enabled() && cpu == d->mbm_work_cpu && + resctrl_arch_would_mbm_overflow()) { cancel_delayed_work(&d->mbm_over); mbm_setup_overflow_handler(d, 0, cpu); } diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h index d70e4e726fe6..c80f220d98d6 100644 --- a/include/linux/arm_mpam.h +++ b/include/linux/arm_mpam.h @@ -66,6 +66,7 @@ bool resctrl_arch_mon_capable(void); bool resctrl_arch_is_llc_occupancy_enabled(void); bool resctrl_arch_is_mbm_local_enabled(void); bool resctrl_arch_is_mbm_total_enabled(void); +bool resctrl_arch_would_mbm_overflow(void); /* reset cached configurations, then all devices */ void resctrl_arch_reset_resources(void); -- 2.25.1

hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IAJUN4 --------------------------------------------------- Be compatible with the hardware platform which has different CPBM bandwidth of cache MSCs within the same class, and prevent the CPBM feature from being cleared. Fixes: 931c09722546 ("arm_mpam: Merge supported features during mpam_enable() into mpam_class") Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/platform/mpam/mpam_devices.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/platform/mpam/mpam_devices.c b/drivers/platform/mpam/mpam_devices.c index c148ecd47613..6876aa5873e2 100644 --- a/drivers/platform/mpam/mpam_devices.c +++ b/drivers/platform/mpam/mpam_devices.c @@ -1858,9 +1858,10 @@ __resource_props_mismatch(struct mpam_msc_ris *ris, struct mpam_class *class) /* Clear missing features */ cprops->features &= rprops->features; - /* Clear incompatible features */ + /* Set cpbm_wd with the min cpbm_wd among all cache msc */ if (cprops->cpbm_wd != rprops->cpbm_wd) - mpam_clear_feature(mpam_feat_cpor_part, &cprops->features); + cprops->cpbm_wd = min(cprops->cpbm_wd, rprops->cpbm_wd); + if (cprops->mbw_pbm_bits != rprops->mbw_pbm_bits) mpam_clear_feature(mpam_feat_mbw_part, &cprops->features); -- 2.25.1

hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IAJUN4 --------------------------------------------------- To check whether hardware supports the CMAX feature or not, not only needs to check the CMAX_WD field of the MPAMF_CCAP_IDR register, but also needs to check the NO_CMAX field. Fixes: b1576ca4ed95 ("arm_mpam: Probe and reset the rest of the features") Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/platform/mpam/mpam_devices.c | 3 ++- drivers/platform/mpam/mpam_internal.h | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/platform/mpam/mpam_devices.c b/drivers/platform/mpam/mpam_devices.c index 6876aa5873e2..0bc8393541f1 100644 --- a/drivers/platform/mpam/mpam_devices.c +++ b/drivers/platform/mpam/mpam_devices.c @@ -577,7 +577,8 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris) u32 ccap_features = mpam_read_partsel_reg(msc, CCAP_IDR); props->cmax_wd = FIELD_GET(MPAMF_CCAP_IDR_CMAX_WD, ccap_features); - if (props->cmax_wd) + if (props->cmax_wd && + !FIELD_GET(MPAMF_CCAP_IDR_NO_CMAX, ccap_features)) mpam_set_feature(mpam_feat_ccap_part, props); } diff --git a/drivers/platform/mpam/mpam_internal.h b/drivers/platform/mpam/mpam_internal.h index a613e5a77a85..ea13c9e0725e 100644 --- a/drivers/platform/mpam/mpam_internal.h +++ b/drivers/platform/mpam/mpam_internal.h @@ -52,7 +52,7 @@ struct mpam_msc struct mpam_msc * __percpu *error_dev_id; atomic_t online_refs; - + struct mutex lock; bool probed; bool error_irq_requested; @@ -391,6 +391,9 @@ void mpam_resctrl_exit(void); /* MPAMF_CCAP_IDR - MPAM features cache capacity partitioning ID register */ #define MPAMF_CCAP_IDR_CMAX_WD GENMASK(5, 0) +#define MPAMF_CCAP_IDR_HAS_CMIN BIT(29) +#define MPAMF_CCAP_IDR_NO_CMAX BIT(30) +#define MPAMF_CCAP_IDR_HAS_CMAX_SOFTLIM BIT(31) /* MPAMF_MBW_IDR - MPAM features memory bandwidth partitioning ID register */ #define MPAMF_MBW_IDR_BWA_WD GENMASK(5, 0) -- 2.25.1

hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IAJUN4 -------------------------------- When the resctrl fs is mounted, closid_init() will allocate memory of closid_free_map, but when the fs is unmounted, it is never released, which will cause a memory leak. Add release of closid_free_map in rdt_kill_sb() to ensure no leaks when the fs is unmounted. Fixes: 1e7284b7981c ("fs/resctrl: Remove the limit on the number of CLOSID") Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- fs/resctrl/rdtgroup.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c index 9776b4e2834c..eca8f0866390 100644 --- a/fs/resctrl/rdtgroup.c +++ b/fs/resctrl/rdtgroup.c @@ -162,6 +162,11 @@ static void closid_init(void) closid_free_map_len = rdt_min_closid; } +static void closid_exit(void) +{ + bitmap_free(closid_free_map); +} + static int closid_alloc(void) { int cleanest_closid; @@ -2524,10 +2529,8 @@ static int rdt_get_tree(struct fs_context *fc) goto out_root; ret = schemata_list_create(); - if (ret) { - schemata_list_destroy(); - goto out_ctx; - } + if (ret) + goto out_schemata_free; closid_init(); @@ -2536,13 +2539,13 @@ static int rdt_get_tree(struct fs_context *fc) ret = rdtgroup_add_files(rdtgroup_default.kn, flags); if (ret) - goto out_schemata_free; + goto out_closid; kernfs_activate(rdtgroup_default.kn); ret = rdtgroup_create_info_dir(rdtgroup_default.kn); if (ret < 0) - goto out_schemata_free; + goto out_closid; if (resctrl_arch_mon_capable()) { ret = mongroup_create_dir(rdtgroup_default.kn, @@ -2595,9 +2598,10 @@ static int rdt_get_tree(struct fs_context *fc) kernfs_remove(kn_mongrp); out_info: kernfs_remove(kn_info); +out_closid: + closid_exit(); out_schemata_free: schemata_list_destroy(); -out_ctx: rdt_disable_ctx(); out_root: rdtgroup_destroy_root(); @@ -2806,6 +2810,7 @@ static void rdt_kill_sb(struct super_block *sb) if (IS_ENABLED(CONFIG_RESCTRL_FS_PSEUDO_LOCK)) rdt_pseudo_lock_release(); rdtgroup_default.mode = RDT_MODE_SHAREABLE; + closid_exit(); schemata_list_destroy(); rdtgroup_destroy_root(); if (resctrl_arch_alloc_capable()) -- 2.25.1

hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8T2RT -------------------------------- In order to expand the new features of MPAM in the following patches, enum resctrl_feat_type is newly added. When the configuration is updated, the CDP type and configuration feature will be traversed and updated, so the staged_config array used to deliver the configuration is expanded into a two-dimensional array. Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- arch/x86/include/asm/resctrl.h | 17 ++++ arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 39 ++++---- drivers/platform/mpam/mpam_resctrl.c | 75 ++++++++++----- fs/resctrl/ctrlmondata.c | 23 +++-- fs/resctrl/monitor.c | 5 +- fs/resctrl/rdtgroup.c | 106 ++++++++++++++-------- include/linux/arm_mpam.h | 3 + include/linux/resctrl.h | 15 +-- include/linux/resctrl_types.h | 6 ++ 9 files changed, 195 insertions(+), 94 deletions(-) diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h index c5f90edc3e20..1e398cc766b2 100644 --- a/arch/x86/include/asm/resctrl.h +++ b/arch/x86/include/asm/resctrl.h @@ -223,6 +223,23 @@ void resctrl_cpu_detect(struct cpuinfo_x86 *c); bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level l); int resctrl_arch_set_cdp_enabled(enum resctrl_res_level l, bool enable); +static inline bool resctrl_arch_feat_capable(enum resctrl_res_level level, + enum resctrl_feat_type feat) +{ + if (feat == FEAT_PBM) { + if (level == RDT_RESOURCE_L3 || + level == RDT_RESOURCE_L2) + return true; + + } else if (feat == FEAT_MAX) { + if (level == RDT_RESOURCE_MBA || + level == RDT_RESOURCE_SMBA) + return true; + } + + return false; +} + #else static inline void resctrl_sched_in(struct task_struct *tsk) {} diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c index c5c3eaea27b6..30b57c88e3bf 100644 --- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c +++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c @@ -40,7 +40,8 @@ static bool apply_config(struct rdt_hw_domain *hw_dom, } int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, - u32 closid, enum resctrl_conf_type t, u32 cfg_val) + u32 closid, enum resctrl_conf_type t, + enum resctrl_feat_type f, u32 cfg_val) { struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d); @@ -66,6 +67,7 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid) struct rdt_hw_domain *hw_dom; struct msr_param msr_param; enum resctrl_conf_type t; + enum resctrl_feat_type f; cpumask_var_t cpu_mask; struct rdt_domain *d; u32 idx; @@ -80,21 +82,23 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid) list_for_each_entry(d, &r->domains, list) { hw_dom = resctrl_to_arch_dom(d); for (t = 0; t < CDP_NUM_TYPES; t++) { - cfg = &hw_dom->d_resctrl.staged_config[t]; - if (!cfg->have_new_ctrl) - continue; - - idx = resctrl_get_config_index(closid, t); - if (!apply_config(hw_dom, cfg, idx, cpu_mask)) - continue; - - if (!msr_param.res) { - msr_param.low = idx; - msr_param.high = msr_param.low + 1; - msr_param.res = r; - } else { - msr_param.low = min(msr_param.low, idx); - msr_param.high = max(msr_param.high, idx + 1); + for (f = 0; f < FEAT_NUM_TYPES; f++) { + cfg = &hw_dom->d_resctrl.staged_config[t][f]; + if (!cfg->have_new_ctrl) + continue; + + idx = resctrl_get_config_index(closid, t); + if (!apply_config(hw_dom, cfg, idx, cpu_mask)) + continue; + + if (!msr_param.res) { + msr_param.low = idx; + msr_param.high = msr_param.low + 1; + msr_param.res = r; + } else { + msr_param.low = min(msr_param.low, idx); + msr_param.high = max(msr_param.high, idx + 1); + } } } } @@ -112,7 +116,8 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid) } u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, - u32 closid, enum resctrl_conf_type type) + u32 closid, enum resctrl_conf_type type, + enum resctrl_feat_type feat) { struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d); u32 idx = resctrl_get_config_index(closid, type); diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index 728f03a2a3f6..8f49d509ddd7 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -68,6 +68,21 @@ bool resctrl_arch_mon_capable(void) return exposed_mon_capable; } +bool resctrl_arch_feat_capable(enum resctrl_res_level level, + enum resctrl_feat_type feat) +{ + if (feat == FEAT_PBM) { + if (level == RDT_RESOURCE_L3) + return true; + + } else if (feat == FEAT_MAX) { + if (level == RDT_RESOURCE_MBA) + return true; + } + + return false; +} + bool resctrl_arch_is_mbm_local_enabled(void) { return mbm_local_class; @@ -890,7 +905,8 @@ void mpam_resctrl_exit(void) } u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, - u32 closid, enum resctrl_conf_type type) + u32 closid, enum resctrl_conf_type type, + enum resctrl_feat_type feat) { u32 partid; struct mpam_config *cfg; @@ -914,13 +930,20 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, switch (r->rid) { case RDT_RESOURCE_L2: case RDT_RESOURCE_L3: - configured_by = mpam_feat_cpor_part; - break; + if (mpam_has_feature(mpam_feat_cpor_part, cprops) && + (feat == FEAT_PBM)) { + configured_by = mpam_feat_cpor_part; + break; + } + return -EINVAL; + case RDT_RESOURCE_MBA: - if (mba_class_use_mbw_part(cprops)) { + if (mba_class_use_mbw_part(cprops) && + (feat == FEAT_PBM)) { configured_by = mpam_feat_mbw_part; break; - } else if (mpam_has_feature(mpam_feat_mbw_max, cprops)) { + } else if (mpam_has_feature(mpam_feat_mbw_max, cprops) && + (feat == FEAT_MAX)) { configured_by = mpam_feat_mbw_max; break; } @@ -947,8 +970,9 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, } } -int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, - u32 closid, enum resctrl_conf_type t, u32 cfg_val) +int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, u32 closid, + enum resctrl_conf_type t, enum resctrl_feat_type f, + u32 cfg_val) { int err; u32 partid; @@ -973,16 +997,22 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, switch (r->rid) { case RDT_RESOURCE_L2: case RDT_RESOURCE_L3: - /* TODO: Scaling is not yet supported */ - cfg.cpbm = cfg_val; - mpam_set_feature(mpam_feat_cpor_part, &cfg); - break; + if (mpam_has_feature(mpam_feat_cpor_part, cprops) && + (f == FEAT_PBM)) { + /* TODO: Scaling is not yet supported */ + cfg.cpbm = cfg_val; + mpam_set_feature(mpam_feat_cpor_part, &cfg); + break; + } + return -EINVAL; + case RDT_RESOURCE_MBA: - if (mba_class_use_mbw_part(cprops)) { + if (mba_class_use_mbw_part(cprops) && (f == FEAT_PBM)) { cfg.mbw_pbm = percent_to_mbw_pbm(cfg_val, cprops); mpam_set_feature(mpam_feat_mbw_part, &cfg); break; - } else if (mpam_has_feature(mpam_feat_mbw_max, cprops)) { + } else if (mpam_has_feature(mpam_feat_mbw_max, cprops) && + (f == FEAT_MAX)) { cfg.mbw_max = percent_to_mbw_max(cfg_val, cprops->bwa_wd); mpam_set_feature(mpam_feat_mbw_max, &cfg); break; @@ -1016,6 +1046,7 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid) int err = 0; struct rdt_domain *d; enum resctrl_conf_type t; + enum resctrl_feat_type f; struct resctrl_staged_config *cfg; lockdep_assert_cpus_held(); @@ -1023,14 +1054,16 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid) list_for_each_entry(d, &r->domains, list) { for (t = 0; t < CDP_NUM_TYPES; t++) { - cfg = &d->staged_config[t]; - if (!cfg->have_new_ctrl) - continue; - - err = resctrl_arch_update_one(r, d, closid, t, - cfg->new_ctrl); - if (err) - return err; + for (f = 0; f < FEAT_NUM_TYPES; f++) { + cfg = &d->staged_config[t][f]; + if (!cfg->have_new_ctrl) + continue; + + err = resctrl_arch_update_one( + r, d, closid, t, f, cfg->new_ctrl); + if (err) + return err; + } } } diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c index 62a6a67f1192..0cdedb7f3c3a 100644 --- a/fs/resctrl/ctrlmondata.c +++ b/fs/resctrl/ctrlmondata.c @@ -74,7 +74,7 @@ static int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s, struct rdt_resource *r = s->res; unsigned long bw_val; - cfg = &d->staged_config[s->conf_type]; + cfg = &d->staged_config[s->conf_type][s->feat_type]; if (cfg->have_new_ctrl) { rdt_last_cmd_printf("Duplicate domain %d\n", d->id); return -EINVAL; @@ -153,7 +153,7 @@ static int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s, struct rdt_resource *r = s->res; u32 cbm_val; - cfg = &d->staged_config[s->conf_type]; + cfg = &d->staged_config[s->conf_type][s->feat_type]; if (cfg->have_new_ctrl) { rdt_last_cmd_printf("Duplicate domain %d\n", d->id); return -EINVAL; @@ -203,9 +203,10 @@ static int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s, return 0; } -static ctrlval_parser_t *get_parser(struct rdt_resource *res) +static ctrlval_parser_t *get_parser(struct resctrl_schema *s) { - if (res->fflags & RFTYPE_RES_CACHE) + if ((s->res->fflags & RFTYPE_RES_CACHE) && + (s->feat_type == FEAT_PBM)) return &parse_cbm; else return &parse_bw; @@ -220,8 +221,9 @@ static ctrlval_parser_t *get_parser(struct rdt_resource *res) static int parse_line(char *line, struct resctrl_schema *s, struct rdtgroup *rdtgrp) { - ctrlval_parser_t *parse_ctrlval = get_parser(s->res); + ctrlval_parser_t *parse_ctrlval = get_parser(s); enum resctrl_conf_type t = s->conf_type; + enum resctrl_feat_type f = s->feat_type; struct resctrl_staged_config *cfg; struct rdt_resource *r = s->res; struct rdt_parse_data data; @@ -255,7 +257,7 @@ static int parse_line(char *line, struct resctrl_schema *s, if (parse_ctrlval(&data, s, d)) return -EINVAL; if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) { - cfg = &d->staged_config[t]; + cfg = &d->staged_config[t][f]; /* * In pseudo-locking setup mode and just * parsed a valid CBM that should be @@ -373,10 +375,14 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of, static void show_doms(struct seq_file *s, struct resctrl_schema *schema, int closid) { struct rdt_resource *r = schema->res; + const char *format_str; struct rdt_domain *dom; bool sep = false; u32 ctrl_val; + format_str = (schema->feat_type == FEAT_PBM) ? + "%d=%0*x" : "%d=%0*u"; + /* Walking r->domains, ensure it can't race with cpuhp */ lockdep_assert_cpus_held(); @@ -389,9 +395,10 @@ static void show_doms(struct seq_file *s, struct resctrl_schema *schema, int clo ctrl_val = dom->mbps_val[closid]; else ctrl_val = resctrl_arch_get_config(r, dom, closid, - schema->conf_type); + schema->conf_type, + schema->feat_type); - seq_printf(s, r->format_str, dom->id, max_data_width, + seq_printf(s, format_str, dom->id, max_data_width, ctrl_val); sep = true; } diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c index 7d824dc8fa90..77f4818e03af 100644 --- a/fs/resctrl/monitor.c +++ b/fs/resctrl/monitor.c @@ -494,7 +494,7 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm) delta_bw = pmbm_data->delta_bw; /* MBA resource doesn't support CDP */ - cur_msr_val = resctrl_arch_get_config(r_mba, dom_mba, closid, CDP_NONE); + cur_msr_val = resctrl_arch_get_config(r_mba, dom_mba, closid, CDP_NONE, FEAT_MAX); /* * For Ctrl groups read data from child monitor groups. @@ -529,7 +529,8 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm) return; } - resctrl_arch_update_one(r_mba, dom_mba, closid, CDP_NONE, new_msr_val); + resctrl_arch_update_one(r_mba, dom_mba, closid, CDP_NONE, + FEAT_MAX, new_msr_val); /* * Delta values are updated dynamically package wise for each diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c index eca8f0866390..f336668bf847 100644 --- a/fs/resctrl/rdtgroup.c +++ b/fs/resctrl/rdtgroup.c @@ -1044,7 +1044,8 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of, if (!closid_allocated(i)) continue; ctrl_val = resctrl_arch_get_config(r, dom, i, - s->conf_type); + s->conf_type, + s->feat_type); mode = rdtgroup_mode_by_closid(i); switch (mode) { case RDT_MODE_SHAREABLE: @@ -1273,7 +1274,7 @@ static bool __rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_domain *d /* Check for overlap with other resource groups */ for (i = 0; i < closids_supported(); i++) { - ctrl_b = resctrl_arch_get_config(r, d, i, type); + ctrl_b = resctrl_arch_get_config(r, d, i, type, FEAT_PBM); mode = rdtgroup_mode_by_closid(i); if (closid_allocated(i) && i != closid && mode != RDT_MODE_PSEUDO_LOCKSETUP) { @@ -1323,7 +1324,9 @@ bool rdtgroup_cbm_overlaps(struct resctrl_schema *s, struct rdt_domain *d, if (!resctrl_arch_get_cdp_enabled(r->rid)) return false; - return __rdtgroup_cbm_overlaps(r, d, cbm, closid, peer_type, exclusive); + + return __rdtgroup_cbm_overlaps(r, d, cbm, closid, peer_type, + exclusive); } /** @@ -1358,7 +1361,8 @@ static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp) has_cache = true; list_for_each_entry(d, &r->domains, list) { ctrl = resctrl_arch_get_config(r, d, closid, - s->conf_type); + s->conf_type, + s->feat_type); if (rdtgroup_cbm_overlaps(s, d, ctrl, closid, false)) { rdt_last_cmd_puts("Schemata overlaps\n"); return false; @@ -1491,6 +1495,7 @@ static int rdtgroup_size_show(struct kernfs_open_file *of, { struct resctrl_schema *schema; enum resctrl_conf_type type; + enum resctrl_feat_type feat; struct rdtgroup *rdtgrp; struct rdt_resource *r; struct rdt_domain *d; @@ -1527,6 +1532,7 @@ static int rdtgroup_size_show(struct kernfs_open_file *of, list_for_each_entry(schema, &resctrl_schema_all, list) { r = schema->res; type = schema->conf_type; + feat = schema->feat_type; sep = false; seq_printf(s, "%*s:", max_name_width, schema->name); list_for_each_entry(d, &r->domains, list) { @@ -1540,12 +1546,13 @@ static int rdtgroup_size_show(struct kernfs_open_file *of, else ctrl = resctrl_arch_get_config(r, d, closid, - type); - if (r->rid == RDT_RESOURCE_MBA || - r->rid == RDT_RESOURCE_SMBA) - size = ctrl; - else + type, + feat); + if ((r->fflags & RFTYPE_RES_CACHE) && + feat == FEAT_PBM) size = rdtgroup_cbm_to_size(r, d, ctrl); + else + size = ctrl; } seq_printf(s, "%d=%u", d->id, size); sep = true; @@ -2405,22 +2412,17 @@ static int rdt_enable_ctx(struct rdt_fs_context *ctx) return ret; } -static int schemata_list_add(struct rdt_resource *r, enum resctrl_conf_type type) +static int schemata_list_add(struct rdt_resource *r, + enum resctrl_conf_type type, + enum resctrl_feat_type feat) { struct resctrl_schema *s; - const char *suffix = ""; + const char *suffix; int ret, cl; - s = kzalloc(sizeof(*s), GFP_KERNEL); - if (!s) - return -ENOMEM; - - s->res = r; - s->num_closid = resctrl_arch_get_num_closid(r); - if (resctrl_arch_get_cdp_enabled(r->rid)) - s->num_closid /= 2; + if (!resctrl_arch_feat_capable(r->rid, feat)) + return 0; - s->conf_type = type; switch (type) { case CDP_CODE: suffix = "CODE"; @@ -2431,9 +2433,24 @@ static int schemata_list_add(struct rdt_resource *r, enum resctrl_conf_type type case CDP_NONE: suffix = ""; break; + default: + return -EINVAL; } - ret = snprintf(s->name, sizeof(s->name), "%s%s", r->name, suffix); + s = kzalloc(sizeof(*s), GFP_KERNEL); + if (!s) + return -ENOMEM; + + s->res = r; + s->num_closid = resctrl_arch_get_num_closid(r); + if (resctrl_arch_get_cdp_enabled(r->rid)) + s->num_closid /= 2; + + s->conf_type = type; + s->feat_type = feat; + + ret = snprintf(s->name, sizeof(s->name), "%s%s", + r->name, suffix); if (ret >= sizeof(s->name)) { kfree(s); return -EINVAL; @@ -2466,29 +2483,33 @@ static int schemata_list_add(struct rdt_resource *r, enum resctrl_conf_type type static int schemata_list_create(void) { + enum resctrl_feat_type feat; enum resctrl_res_level i; struct rdt_resource *r; int ret = 0; for (i = 0; i < RDT_NUM_RESOURCES; i++) { r = resctrl_arch_get_resource(i); - if (!r->alloc_capable) + if (!r || !r->alloc_capable) continue; - if (resctrl_arch_get_cdp_enabled(r->rid)) { - ret = schemata_list_add(r, CDP_CODE); - if (ret) - break; + for (feat = 0; feat < FEAT_NUM_TYPES; feat++) { + if (resctrl_arch_get_cdp_enabled(r->rid)) { + ret = schemata_list_add(r, CDP_CODE, feat); + if (ret) + goto out; - ret = schemata_list_add(r, CDP_DATA); - } else { - ret = schemata_list_add(r, CDP_NONE); + ret = schemata_list_add(r, CDP_DATA, feat); + if (ret) + goto out; + } else { + ret = schemata_list_add(r, CDP_NONE, feat); + if (ret) + goto out; + } } - - if (ret) - break; } - +out: return ret; } @@ -3057,6 +3078,7 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, { enum resctrl_conf_type peer_type = resctrl_peer_type(s->conf_type); enum resctrl_conf_type t = s->conf_type; + enum resctrl_feat_type feat = s->feat_type; struct resctrl_staged_config *cfg; struct rdt_resource *r = s->res; u32 used_b = 0, unused_b = 0; @@ -3065,7 +3087,7 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, u32 peer_ctl, ctrl_val; int i; - cfg = &d->staged_config[t]; + cfg = &d->staged_config[t][feat]; cfg->have_new_ctrl = false; cfg->new_ctrl = r->cache.shareable_bits; used_b = r->cache.shareable_bits; @@ -3086,11 +3108,13 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, */ if (resctrl_arch_get_cdp_enabled(r->rid)) peer_ctl = resctrl_arch_get_config(r, d, i, - peer_type); + peer_type, + feat); else peer_ctl = 0; ctrl_val = resctrl_arch_get_config(r, d, i, - s->conf_type); + s->conf_type, + feat); used_b |= ctrl_val | peer_ctl; if (mode == RDT_MODE_SHAREABLE) cfg->new_ctrl |= ctrl_val | peer_ctl; @@ -3156,7 +3180,7 @@ static void rdtgroup_init_mba(struct rdt_resource *r, u32 closid) continue; } - cfg = &d->staged_config[CDP_NONE]; + cfg = &d->staged_config[CDP_NONE][FEAT_MAX]; cfg->new_ctrl = r->default_ctrl; cfg->have_new_ctrl = true; } @@ -3179,9 +3203,11 @@ static int rdtgroup_init_alloc(struct rdtgroup *rdtgrp) if (is_mba_sc(r)) continue; } else { - ret = rdtgroup_init_cat(s, rdtgrp->closid); - if (ret < 0) - goto out; + if (s->feat_type == FEAT_PBM) { + ret = rdtgroup_init_cat(s, rdtgrp->closid); + if (ret < 0) + goto out; + } } ret = resctrl_arch_update_domains(r, rdtgrp->closid); diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h index c80f220d98d6..5390be8e2765 100644 --- a/include/linux/arm_mpam.h +++ b/include/linux/arm_mpam.h @@ -68,6 +68,9 @@ bool resctrl_arch_is_mbm_local_enabled(void); bool resctrl_arch_is_mbm_total_enabled(void); bool resctrl_arch_would_mbm_overflow(void); +bool resctrl_arch_feat_capable(enum resctrl_res_level level, + enum resctrl_feat_type feat); + /* reset cached configurations, then all devices */ void resctrl_arch_reset_resources(void); diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index edc7264a8369..ca2ad398b8b5 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -118,7 +118,7 @@ struct rdt_domain { int mbm_work_cpu; int cqm_work_cpu; struct pseudo_lock_region *plr; - struct resctrl_staged_config staged_config[CDP_NUM_TYPES]; + struct resctrl_staged_config staged_config[CDP_NUM_TYPES][FEAT_NUM_TYPES]; u32 *mbps_val; }; @@ -234,8 +234,9 @@ struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l); */ struct resctrl_schema { struct list_head list; - char name[8]; + char name[16]; enum resctrl_conf_type conf_type; + enum resctrl_feat_type feat_type; struct rdt_resource *res; u32 num_closid; }; @@ -293,9 +294,9 @@ static inline u32 resctrl_get_config_index(u32 closid, case CDP_NONE: return closid; case CDP_CODE: - return (closid * 2) + 1; + return (closid * 2) + 1; case CDP_DATA: - return (closid * 2); + return (closid * 2); } } @@ -331,10 +332,12 @@ resctrl_get_domain_from_cpu(int cpu, struct rdt_resource *r) * Must be called on one of the domain's CPUs. */ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, - u32 closid, enum resctrl_conf_type t, u32 cfg_val); + u32 closid, enum resctrl_conf_type t, + enum resctrl_feat_type f, u32 cfg_val); u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, - u32 closid, enum resctrl_conf_type type); + u32 closid, enum resctrl_conf_type type, + enum resctrl_feat_type feat); int resctrl_online_domain(struct rdt_resource *r, struct rdt_domain *d); void resctrl_offline_domain(struct rdt_resource *r, struct rdt_domain *d); void resctrl_online_cpu(unsigned int cpu); diff --git a/include/linux/resctrl_types.h b/include/linux/resctrl_types.h index 44f7a47f986b..c68ef46ea5df 100644 --- a/include/linux/resctrl_types.h +++ b/include/linux/resctrl_types.h @@ -73,6 +73,12 @@ enum resctrl_conf_type { CDP_DATA, }; +enum resctrl_feat_type { + FEAT_PBM, + FEAT_MAX, + FEAT_NUM_TYPES, +}; + enum resctrl_res_level { RDT_RESOURCE_L3, RDT_RESOURCE_L2, -- 2.25.1

hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8T2RT -------------------------------- Implement mbw_min/cmin feature for mata/cache msc, and provide MBMIN/LxMIN interface in schemata file for user. On some specific platforms, L3 implements the cmin feature, but L2 may not provide it, or vice versa. Therefore, it is necessary to separately determine whether the cache msc has implemented the corresponding feature. Before transmitting the cache MIN portion value to msc, need to check whether the CMIN setting from user space is validate or not. The same goes for MBMIN. It should be noted that the new configuration value is in decimal form instead of hexadecimal, so here reuse the parse_bw() to analysis input value for cache msc. Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- arch/x86/include/asm/resctrl.h | 6 +++ drivers/platform/mpam/mpam_devices.c | 25 ++++++++-- drivers/platform/mpam/mpam_internal.h | 7 ++- drivers/platform/mpam/mpam_resctrl.c | 67 +++++++++++++++++++++++++-- fs/resctrl/ctrlmondata.c | 37 +++++++++++++-- fs/resctrl/rdtgroup.c | 5 +- include/linux/arm_mpam.h | 2 + include/linux/resctrl_types.h | 1 + 8 files changed, 134 insertions(+), 16 deletions(-) diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h index 1e398cc766b2..2aa30e36b29a 100644 --- a/arch/x86/include/asm/resctrl.h +++ b/arch/x86/include/asm/resctrl.h @@ -240,6 +240,12 @@ static inline bool resctrl_arch_feat_capable(enum resctrl_res_level level, return false; } +static inline const char *resctrl_arch_set_feat_lab(enum resctrl_feat_type feat, + unsigned long fflags) +{ + return ""; +} + #else static inline void resctrl_sched_in(struct task_struct *tsk) {} diff --git a/drivers/platform/mpam/mpam_devices.c b/drivers/platform/mpam/mpam_devices.c index 0bc8393541f1..e4ee2cd73cc8 100644 --- a/drivers/platform/mpam/mpam_devices.c +++ b/drivers/platform/mpam/mpam_devices.c @@ -577,9 +577,13 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris) u32 ccap_features = mpam_read_partsel_reg(msc, CCAP_IDR); props->cmax_wd = FIELD_GET(MPAMF_CCAP_IDR_CMAX_WD, ccap_features); - if (props->cmax_wd && - !FIELD_GET(MPAMF_CCAP_IDR_NO_CMAX, ccap_features)) - mpam_set_feature(mpam_feat_ccap_part, props); + if (props->cmax_wd) { + if (!FIELD_GET(MPAMF_CCAP_IDR_NO_CMAX, ccap_features)) + mpam_set_feature(mpam_feat_ccap_part, props); + + if (FIELD_GET(MPAMF_CCAP_IDR_HAS_CMIN, ccap_features)) + mpam_set_feature(mpam_feat_cmin, props); + } } /* Cache Portion partitioning */ @@ -1211,6 +1215,13 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, rprops->cpbm_wd); } + if (mpam_has_feature(mpam_feat_cmin, rprops)) { + if (mpam_has_feature(mpam_feat_cmin, cfg)) + mpam_write_partsel_reg(msc, CMIN, cfg->ca_min); + else + mpam_write_partsel_reg(msc, CMIN, 0); + } + if (mpam_has_feature(mpam_feat_mbw_part, rprops)) { if (mpam_has_feature(mpam_feat_mbw_part, cfg)) mpam_write_partsel_reg(msc, MBW_PBM, cfg->mbw_pbm); @@ -1219,8 +1230,12 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, rprops->mbw_pbm_bits); } - if (mpam_has_feature(mpam_feat_mbw_min, rprops)) - mpam_write_partsel_reg(msc, MBW_MIN, 0); + if (mpam_has_feature(mpam_feat_mbw_min, rprops)) { + if (mpam_has_feature(mpam_feat_mbw_min, cfg)) + mpam_write_partsel_reg(msc, MBW_MIN, cfg->mbw_min); + else + mpam_write_partsel_reg(msc, MBW_MIN, 0); + } if (mpam_has_feature(mpam_feat_mbw_max, rprops)) { if (mpam_has_feature(mpam_feat_mbw_max, cfg)) diff --git a/drivers/platform/mpam/mpam_internal.h b/drivers/platform/mpam/mpam_internal.h index ea13c9e0725e..400afaba0ecd 100644 --- a/drivers/platform/mpam/mpam_internal.h +++ b/drivers/platform/mpam/mpam_internal.h @@ -86,6 +86,7 @@ typedef u32 mpam_features_t; enum mpam_device_features { mpam_feat_ccap_part = 0, mpam_feat_cpor_part, + mpam_feat_cmin, mpam_feat_mbw_part, mpam_feat_mbw_min, mpam_feat_mbw_max, @@ -160,8 +161,11 @@ struct mpam_config { mpam_features_t features; u32 cpbm; + u16 ca_min; + u32 mbw_pbm; u16 mbw_max; + u16 mbw_min; }; struct mpam_component @@ -340,7 +344,8 @@ void mpam_resctrl_exit(void); /* Configuration and Status Register offsets in the memory mapped page */ #define MPAMCFG_PART_SEL 0x0100 /* partid to configure: */ #define MPAMCFG_CPBM 0x1000 /* cache-portion config */ -#define MPAMCFG_CMAX 0x0108 /* cache-capacity config */ +#define MPAMCFG_CMAX 0x0108 /* cache-capacity max config */ +#define MPAMCFG_CMIN 0x0110 /* cache-capacity min config */ #define MPAMCFG_MBW_MIN 0x0200 /* min mem-bw config */ #define MPAMCFG_MBW_MAX 0x0208 /* max mem-bw config */ #define MPAMCFG_MBW_WINWD 0x0220 /* mem-bw accounting window config */ diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index 8f49d509ddd7..1b19d74dd75c 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -68,21 +68,45 @@ bool resctrl_arch_mon_capable(void) return exposed_mon_capable; } +static bool min_capable[RDT_NUM_RESOURCES]; bool resctrl_arch_feat_capable(enum resctrl_res_level level, enum resctrl_feat_type feat) { - if (feat == FEAT_PBM) { + switch (feat) { + case FEAT_PBM: if (level == RDT_RESOURCE_L3) return true; + break; - } else if (feat == FEAT_MAX) { + case FEAT_MAX: if (level == RDT_RESOURCE_MBA) return true; + break; + + case FEAT_MIN: + return min_capable[level]; + + default: + break; } return false; } +const char *resctrl_arch_set_feat_lab(enum resctrl_feat_type feat, + unsigned long fflags) +{ + switch (feat) { + case FEAT_MIN: + return "MIN"; + + default: + break; + } + + return ""; +} + bool resctrl_arch_is_mbm_local_enabled(void) { return mbm_local_class; @@ -779,6 +803,9 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) exposed_alloc_capable = true; } + if (mpam_has_feature(mpam_feat_cmin, &class->props)) + min_capable[r->rid] = true; + /* * MBWU counters may be 'local' or 'total' depending on where * they are in the topology. Counters on caches are assumed to @@ -820,6 +847,9 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) exposed_alloc_capable = true; } + if (mpam_has_feature(mpam_feat_mbw_min, cprops)) + min_capable[r->rid] = true; + if (has_mbwu && class->type == MPAM_CLASS_MEMORY) { mbm_total_class = class; r->mon_capable = true; @@ -934,6 +964,10 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, (feat == FEAT_PBM)) { configured_by = mpam_feat_cpor_part; break; + } else if (mpam_has_feature(mpam_feat_cmin, cprops) && + (feat == FEAT_MIN)) { + configured_by = mpam_feat_cmin; + break; } return -EINVAL; @@ -946,6 +980,10 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, (feat == FEAT_MAX)) { configured_by = mpam_feat_mbw_max; break; + } else if (mpam_has_feature(mpam_feat_mbw_min, cprops) && + (feat == FEAT_MIN)) { + configured_by = mpam_feat_mbw_min; + break; } fallthrough; default: @@ -953,18 +991,29 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, } if (!r->alloc_capable || partid >= resctrl_arch_get_num_closid(r) || - !mpam_has_feature(configured_by, cfg)) + !mpam_has_feature(configured_by, cfg)) { + if (configured_by == mpam_feat_cmin) + return 0; + + if (configured_by == mpam_feat_mbw_min) + return 0; + return r->default_ctrl; + } switch (configured_by) { case mpam_feat_cpor_part: /* TODO: Scaling is not yet supported */ return cfg->cpbm; + case mpam_feat_cmin: + return mbw_max_to_percent(cfg->ca_min, cprops->cmax_wd); case mpam_feat_mbw_part: /* TODO: Scaling is not yet supported */ return mbw_pbm_to_percent(cfg->mbw_pbm, cprops); case mpam_feat_mbw_max: return mbw_max_to_percent(cfg->mbw_max, cprops->bwa_wd); + case mpam_feat_mbw_min: + return mbw_max_to_percent(cfg->mbw_min, cprops->bwa_wd); default: return -EINVAL; } @@ -994,6 +1043,8 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, u32 cl if (!r->alloc_capable || partid >= resctrl_arch_get_num_closid(r)) return -EINVAL; + cfg = dom->comp->cfg[partid]; + switch (r->rid) { case RDT_RESOURCE_L2: case RDT_RESOURCE_L3: @@ -1003,6 +1054,11 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, u32 cl cfg.cpbm = cfg_val; mpam_set_feature(mpam_feat_cpor_part, &cfg); break; + } else if (mpam_has_feature(mpam_feat_cmin, cprops) && + (f == FEAT_MIN)) { + cfg.ca_min = percent_to_mbw_max(cfg_val, cprops->cmax_wd); + mpam_set_feature(mpam_feat_cmin, &cfg); + break; } return -EINVAL; @@ -1016,6 +1072,11 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, u32 cl cfg.mbw_max = percent_to_mbw_max(cfg_val, cprops->bwa_wd); mpam_set_feature(mpam_feat_mbw_max, &cfg); break; + } else if (mpam_has_feature(mpam_feat_mbw_min, cprops) && + (f == FEAT_MIN)) { + cfg.mbw_min = percent_to_mbw_max(cfg_val, cprops->bwa_wd); + mpam_set_feature(mpam_feat_mbw_min, &cfg); + break; } fallthrough; default: diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c index 0cdedb7f3c3a..787595f2cf7d 100644 --- a/fs/resctrl/ctrlmondata.c +++ b/fs/resctrl/ctrlmondata.c @@ -66,6 +66,26 @@ static bool bw_validate(char *buf, unsigned long *data, struct rdt_resource *r) return true; } +static bool deci_validate(char *buf, unsigned long *data, struct rdt_resource *r) +{ + unsigned long deci; + int ret; + + ret = kstrtoul(buf, 10, &deci); + if (ret) { + rdt_last_cmd_printf("Non-decimal digit in value %s\n", buf); + return false; + } + + if (deci > 100) { + rdt_last_cmd_printf("Value %ld out of range [0,100]\n", deci); + return false; + } + + *data = deci; + return true; +} + static int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s, struct rdt_domain *d) { @@ -80,12 +100,19 @@ static int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s, return -EINVAL; } - if (!bw_validate(data->buf, &bw_val, r)) - return -EINVAL; + if (r->rid == RDT_RESOURCE_MBA) { + if (!bw_validate(data->buf, &bw_val, r)) + return -EINVAL; - if (is_mba_sc(r)) { - d->mbps_val[closid] = bw_val; - return 0; + if (s->feat_type == FEAT_MAX && is_mba_sc(r)) { + d->mbps_val[closid] = bw_val; + return 0; + } + + } else { + /* For the RDT_RESOURCE_L3/L2 */ + if (!deci_validate(data->buf, &bw_val, r)) + return -EINVAL; } cfg->new_ctrl = bw_val; diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c index f336668bf847..2d0a349caadf 100644 --- a/fs/resctrl/rdtgroup.c +++ b/fs/resctrl/rdtgroup.c @@ -2449,8 +2449,9 @@ static int schemata_list_add(struct rdt_resource *r, s->conf_type = type; s->feat_type = feat; - ret = snprintf(s->name, sizeof(s->name), "%s%s", - r->name, suffix); + ret = snprintf(s->name, sizeof(s->name), "%s%s%s", + r->name, suffix, + resctrl_arch_set_feat_lab(feat, r->fflags)); if (ret >= sizeof(s->name)) { kfree(s); return -EINVAL; diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h index 5390be8e2765..8f68f0397e03 100644 --- a/include/linux/arm_mpam.h +++ b/include/linux/arm_mpam.h @@ -70,6 +70,8 @@ bool resctrl_arch_would_mbm_overflow(void); bool resctrl_arch_feat_capable(enum resctrl_res_level level, enum resctrl_feat_type feat); +const char *resctrl_arch_set_feat_lab(enum resctrl_feat_type feat, + unsigned long fflags); /* reset cached configurations, then all devices */ void resctrl_arch_reset_resources(void); diff --git a/include/linux/resctrl_types.h b/include/linux/resctrl_types.h index c68ef46ea5df..1ccfe08b118b 100644 --- a/include/linux/resctrl_types.h +++ b/include/linux/resctrl_types.h @@ -76,6 +76,7 @@ enum resctrl_conf_type { enum resctrl_feat_type { FEAT_PBM, FEAT_MAX, + FEAT_MIN, FEAT_NUM_TYPES, }; -- 2.25.1

hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8T2RT -------------------------------- The Priority Partition feature controls the priority of requests attributed to the target PARTID. In addition to the MATA msc implementing priority features, the L3 controller can also have the same features. Here the *MBPRI* and *L3PRI* interface are provided in the schemata file to allow users to configure and query QoS partition settings. Before transmitting the priority value to msc, it needs to check whether the setting from user is validate or not. Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/platform/mpam/mpam_devices.c | 35 ++++++++++++-------- drivers/platform/mpam/mpam_internal.h | 6 ++++ drivers/platform/mpam/mpam_resctrl.c | 47 +++++++++++++++++++++++++-- fs/resctrl/ctrlmondata.c | 33 ++++++++++++++++++- include/linux/resctrl.h | 2 ++ include/linux/resctrl_types.h | 1 + 6 files changed, 106 insertions(+), 18 deletions(-) diff --git a/drivers/platform/mpam/mpam_devices.c b/drivers/platform/mpam/mpam_devices.c index e4ee2cd73cc8..e9d03f2abdc3 100644 --- a/drivers/platform/mpam/mpam_devices.c +++ b/drivers/platform/mpam/mpam_devices.c @@ -1193,12 +1193,11 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, struct mpam_config *cfg) { u32 pri_val = 0; + u16 intpri, dspri; u16 cmax = MPAMCFG_CMAX_CMAX; struct mpam_msc *msc = ris->msc; u16 bwa_fract = MPAMCFG_MBW_MAX_MAX; struct mpam_props *rprops = &ris->props; - u16 dspri = GENMASK(rprops->dspri_wd, 0); - u16 intpri = GENMASK(rprops->intpri_wd, 0); spin_lock(&msc->part_sel_lock); __mpam_part_sel(ris->ris_idx, partid, msc); @@ -1250,21 +1249,29 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, if (mpam_has_feature(mpam_feat_ccap_part, rprops)) mpam_write_partsel_reg(msc, CMAX, cmax); - if (mpam_has_feature(mpam_feat_intpri_part, rprops) || - mpam_has_feature(mpam_feat_dspri_part, rprops)) { - /* aces high? */ - if (!mpam_has_feature(mpam_feat_intpri_part_0_low, rprops)) - intpri = 0; - if (!mpam_has_feature(mpam_feat_dspri_part_0_low, rprops)) - dspri = 0; - - if (mpam_has_feature(mpam_feat_intpri_part, rprops)) + if (mpam_has_feature(mpam_feat_intpri_part_0_low, rprops)) + intpri = GENMASK(rprops->intpri_wd - 1, 0); + else + intpri = 0; + + if (mpam_has_feature(mpam_feat_intpri_part, rprops)) { + if (mpam_has_feature(mpam_feat_intpri_part, cfg)) + pri_val |= FIELD_PREP(MPAMCFG_PRI_INTPRI, cfg->intpri); + else pri_val |= FIELD_PREP(MPAMCFG_PRI_INTPRI, intpri); - if (mpam_has_feature(mpam_feat_dspri_part, rprops)) - pri_val |= FIELD_PREP(MPAMCFG_PRI_DSPRI, dspri); + } + if (mpam_has_feature(mpam_feat_dspri_part_0_low, rprops)) + dspri = GENMASK(rprops->dspri_wd - 1, 0); + else + dspri = 0; + + if (mpam_has_feature(mpam_feat_dspri_part, rprops)) + pri_val |= FIELD_PREP(MPAMCFG_PRI_DSPRI, dspri); + + if (mpam_has_feature(mpam_feat_intpri_part, rprops) || + mpam_has_feature(mpam_feat_dspri_part, rprops)) mpam_write_partsel_reg(msc, PRI, pri_val); - } spin_unlock(&msc->part_sel_lock); } diff --git a/drivers/platform/mpam/mpam_internal.h b/drivers/platform/mpam/mpam_internal.h index 400afaba0ecd..533c891bc0c5 100644 --- a/drivers/platform/mpam/mpam_internal.h +++ b/drivers/platform/mpam/mpam_internal.h @@ -166,6 +166,12 @@ struct mpam_config { u32 mbw_pbm; u16 mbw_max; u16 mbw_min; + + /* + * dspri is downstream priority, intpri is internal priority. + */ + u16 dspri; + u16 intpri; }; struct mpam_component diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index 1b19d74dd75c..278da1e7836c 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -69,6 +69,7 @@ bool resctrl_arch_mon_capable(void) } static bool min_capable[RDT_NUM_RESOURCES]; +static bool intpri_capable[RDT_NUM_RESOURCES]; bool resctrl_arch_feat_capable(enum resctrl_res_level level, enum resctrl_feat_type feat) { @@ -86,6 +87,9 @@ bool resctrl_arch_feat_capable(enum resctrl_res_level level, case FEAT_MIN: return min_capable[level]; + case FEAT_INTPRI: + return intpri_capable[level]; + default: break; } @@ -100,6 +104,9 @@ const char *resctrl_arch_set_feat_lab(enum resctrl_feat_type feat, case FEAT_MIN: return "MIN"; + case FEAT_INTPRI: + return "PRI"; + default: break; } @@ -780,6 +787,7 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) /* TODO: Scaling is not yet supported */ r->cache.cbm_len = class->props.cpbm_wd; r->cache.arch_has_sparse_bitmasks = true; + r->cache.intpri_wd = class->props.intpri_wd; /* mpam_devices will reject empty bitmaps */ r->cache.min_cbm_bits = 1; @@ -806,6 +814,9 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) if (mpam_has_feature(mpam_feat_cmin, &class->props)) min_capable[r->rid] = true; + if (mpam_has_feature(mpam_feat_intpri_part, &class->props)) + intpri_capable[r->rid] = true; + /* * MBWU counters may be 'local' or 'total' depending on where * they are in the topology. Counters on caches are assumed to @@ -837,6 +848,7 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) r->membw.delay_linear = true; r->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED; r->membw.bw_gran = get_mba_granularity(cprops); + r->membw.intpri_wd = class->props.intpri_wd; /* Round up to at least 1% */ if (!r->membw.bw_gran) @@ -850,6 +862,9 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) if (mpam_has_feature(mpam_feat_mbw_min, cprops)) min_capable[r->rid] = true; + if (mpam_has_feature(mpam_feat_intpri_part, cprops)) + intpri_capable[r->rid] = true; + if (has_mbwu && class->type == MPAM_CLASS_MEMORY) { mbm_total_class = class; r->mon_capable = true; @@ -968,6 +983,10 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, (feat == FEAT_MIN)) { configured_by = mpam_feat_cmin; break; + } else if (mpam_has_feature(mpam_feat_intpri_part, cprops) && + (feat == FEAT_INTPRI)) { + configured_by = mpam_feat_intpri_part; + break; } return -EINVAL; @@ -984,6 +1003,10 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, (feat == FEAT_MIN)) { configured_by = mpam_feat_mbw_min; break; + } else if (mpam_has_feature(mpam_feat_intpri_part, cprops) && + (feat == FEAT_INTPRI)) { + configured_by = mpam_feat_intpri_part; + break; } fallthrough; default: @@ -992,11 +1015,16 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, if (!r->alloc_capable || partid >= resctrl_arch_get_num_closid(r) || !mpam_has_feature(configured_by, cfg)) { - if (configured_by == mpam_feat_cmin) + if ((configured_by == mpam_feat_cmin) || + (configured_by == mpam_feat_mbw_min)) return 0; - if (configured_by == mpam_feat_mbw_min) - return 0; + if (configured_by == mpam_feat_intpri_part) { + if (!mpam_has_feature(mpam_feat_intpri_part_0_low, cprops)) + return 0; + + return (u32)GENMASK(cprops->intpri_wd - 1, 0); + } return r->default_ctrl; } @@ -1014,6 +1042,8 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, return mbw_max_to_percent(cfg->mbw_max, cprops->bwa_wd); case mpam_feat_mbw_min: return mbw_max_to_percent(cfg->mbw_min, cprops->bwa_wd); + case mpam_feat_intpri_part: + return cfg->intpri; default: return -EINVAL; } @@ -1059,6 +1089,11 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, u32 cl cfg.ca_min = percent_to_mbw_max(cfg_val, cprops->cmax_wd); mpam_set_feature(mpam_feat_cmin, &cfg); break; + } else if (mpam_has_feature(mpam_feat_intpri_part, cprops) && + (f == FEAT_INTPRI)) { + cfg.intpri = cfg_val; + mpam_set_feature(mpam_feat_intpri_part, &cfg); + break; } return -EINVAL; @@ -1077,7 +1112,13 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, u32 cl cfg.mbw_min = percent_to_mbw_max(cfg_val, cprops->bwa_wd); mpam_set_feature(mpam_feat_mbw_min, &cfg); break; + } else if (mpam_has_feature(mpam_feat_intpri_part, cprops) && + (f == FEAT_INTPRI)) { + cfg.intpri = cfg_val; + mpam_set_feature(mpam_feat_intpri_part, &cfg); + break; } + fallthrough; default: return -EINVAL; diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c index 787595f2cf7d..61e498ce808a 100644 --- a/fs/resctrl/ctrlmondata.c +++ b/fs/resctrl/ctrlmondata.c @@ -86,6 +86,32 @@ static bool deci_validate(char *buf, unsigned long *data, struct rdt_resource *r return true; } +static bool prio_validate(char *buf, unsigned long *data, struct rdt_resource *r) +{ + unsigned long prio, prio_max; + int ret; + + ret = kstrtoul(buf, 10, &prio); + if (ret) { + rdt_last_cmd_printf("Non-decimal digit in PRIO value %s\n", buf); + return false; + } + + if (r->fflags & RFTYPE_RES_CACHE) + prio_max = GENMASK(r->cache.intpri_wd - 1, 0); + else + prio_max = GENMASK(r->membw.intpri_wd - 1, 0); + + if (prio > prio_max) { + rdt_last_cmd_printf("PRIO value %ld out of range [0,%ld]\n", + prio, prio_max); + return false; + } + + *data = prio; + return true; +} + static int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s, struct rdt_domain *d) { @@ -100,7 +126,12 @@ static int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s, return -EINVAL; } - if (r->rid == RDT_RESOURCE_MBA) { + if (s->feat_type == FEAT_INTPRI) { + if (!prio_validate(data->buf, &bw_val, r)) + return -EINVAL; + + } else if (r->rid == RDT_RESOURCE_MBA) { + /* For FEAT_MAX and FEAT_MIN */ if (!bw_validate(data->buf, &bw_val, r)) return -EINVAL; diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index ca2ad398b8b5..0dbee80f7211 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -140,6 +140,7 @@ struct resctrl_cache { unsigned int shareable_bits; bool arch_has_sparse_bitmasks; bool arch_has_per_cpu_cfg; + unsigned int intpri_wd; }; /** @@ -175,6 +176,7 @@ struct resctrl_membw { enum membw_throttle_mode throttle_mode; bool mba_sc; u32 *mb_map; + u32 intpri_wd; }; /** diff --git a/include/linux/resctrl_types.h b/include/linux/resctrl_types.h index 1ccfe08b118b..7a33a4c119c3 100644 --- a/include/linux/resctrl_types.h +++ b/include/linux/resctrl_types.h @@ -77,6 +77,7 @@ enum resctrl_feat_type { FEAT_PBM, FEAT_MAX, FEAT_MIN, + FEAT_INTPRI, FEAT_NUM_TYPES, }; -- 2.25.1

hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8T2RT -------------------------------- Implement the cmax feature, which controls the cache maximum capacity for the PARTID selected by the MPAMCFG_PART_SEL. User can update CMAX settings by the interface {L2,L3}MAX:$domain_id=$value in the schemata file. Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/platform/mpam/mpam_devices.c | 11 ++++++--- drivers/platform/mpam/mpam_internal.h | 1 + drivers/platform/mpam/mpam_resctrl.c | 34 ++++++++++++++++++++++++--- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/drivers/platform/mpam/mpam_devices.c b/drivers/platform/mpam/mpam_devices.c index e9d03f2abdc3..637cf13052a6 100644 --- a/drivers/platform/mpam/mpam_devices.c +++ b/drivers/platform/mpam/mpam_devices.c @@ -1214,6 +1214,14 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, rprops->cpbm_wd); } + if (mpam_has_feature(mpam_feat_ccap_part, rprops)) { + if (mpam_has_feature(mpam_feat_ccap_part, cfg)) + mpam_write_partsel_reg(msc, CMAX, cfg->ca_max); + else + mpam_write_partsel_reg(msc, CMAX, cmax); + + } + if (mpam_has_feature(mpam_feat_cmin, rprops)) { if (mpam_has_feature(mpam_feat_cmin, cfg)) mpam_write_partsel_reg(msc, CMIN, cfg->ca_min); @@ -1246,9 +1254,6 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, if (mpam_has_feature(mpam_feat_mbw_prop, rprops)) mpam_write_partsel_reg(msc, MBW_PROP, bwa_fract); - if (mpam_has_feature(mpam_feat_ccap_part, rprops)) - mpam_write_partsel_reg(msc, CMAX, cmax); - if (mpam_has_feature(mpam_feat_intpri_part_0_low, rprops)) intpri = GENMASK(rprops->intpri_wd - 1, 0); else diff --git a/drivers/platform/mpam/mpam_internal.h b/drivers/platform/mpam/mpam_internal.h index 533c891bc0c5..532f55795ad6 100644 --- a/drivers/platform/mpam/mpam_internal.h +++ b/drivers/platform/mpam/mpam_internal.h @@ -161,6 +161,7 @@ struct mpam_config { mpam_features_t features; u32 cpbm; + u16 ca_max; u16 ca_min; u32 mbw_pbm; diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index 278da1e7836c..d4c770389aee 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -68,6 +68,7 @@ bool resctrl_arch_mon_capable(void) return exposed_mon_capable; } +static bool max_capable[RDT_NUM_RESOURCES]; static bool min_capable[RDT_NUM_RESOURCES]; static bool intpri_capable[RDT_NUM_RESOURCES]; bool resctrl_arch_feat_capable(enum resctrl_res_level level, @@ -80,9 +81,7 @@ bool resctrl_arch_feat_capable(enum resctrl_res_level level, break; case FEAT_MAX: - if (level == RDT_RESOURCE_MBA) - return true; - break; + return max_capable[level]; case FEAT_MIN: return min_capable[level]; @@ -101,6 +100,11 @@ const char *resctrl_arch_set_feat_lab(enum resctrl_feat_type feat, unsigned long fflags) { switch (feat) { + case FEAT_MAX: + if (fflags & RFTYPE_RES_MB) + break; + return "MAX"; + case FEAT_MIN: return "MIN"; @@ -811,6 +815,9 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) exposed_alloc_capable = true; } + if (mpam_has_feature(mpam_feat_ccap_part, &class->props)) + max_capable[r->rid] = true; + if (mpam_has_feature(mpam_feat_cmin, &class->props)) min_capable[r->rid] = true; @@ -857,6 +864,9 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) if (class_has_usable_mba(cprops)) { r->alloc_capable = true; exposed_alloc_capable = true; + + if (mpam_has_feature(mpam_feat_mbw_max, cprops)) + max_capable[r->rid] = true; } if (mpam_has_feature(mpam_feat_mbw_min, cprops)) @@ -979,6 +989,12 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, (feat == FEAT_PBM)) { configured_by = mpam_feat_cpor_part; break; + + } else if (mpam_has_feature(mpam_feat_ccap_part, cprops) && + (feat == FEAT_MAX)) { + configured_by = mpam_feat_ccap_part; + break; + } else if (mpam_has_feature(mpam_feat_cmin, cprops) && (feat == FEAT_MIN)) { configured_by = mpam_feat_cmin; @@ -1015,6 +1031,11 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, if (!r->alloc_capable || partid >= resctrl_arch_get_num_closid(r) || !mpam_has_feature(configured_by, cfg)) { + + if ((configured_by == mpam_feat_ccap_part) || + (configured_by == mpam_feat_mbw_max)) + return MAX_MBA_BW; + if ((configured_by == mpam_feat_cmin) || (configured_by == mpam_feat_mbw_min)) return 0; @@ -1033,6 +1054,8 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, case mpam_feat_cpor_part: /* TODO: Scaling is not yet supported */ return cfg->cpbm; + case mpam_feat_ccap_part: + return mbw_max_to_percent(cfg->ca_max, cprops->cmax_wd); case mpam_feat_cmin: return mbw_max_to_percent(cfg->ca_min, cprops->cmax_wd); case mpam_feat_mbw_part: @@ -1084,6 +1107,11 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, u32 cl cfg.cpbm = cfg_val; mpam_set_feature(mpam_feat_cpor_part, &cfg); break; + } else if (mpam_has_feature(mpam_feat_ccap_part, cprops) && + (f == FEAT_MAX)) { + cfg.ca_max = percent_to_mbw_max(cfg_val, cprops->cmax_wd); + mpam_set_feature(mpam_feat_ccap_part, &cfg); + break; } else if (mpam_has_feature(mpam_feat_cmin, cprops) && (f == FEAT_MIN)) { cfg.ca_min = percent_to_mbw_max(cfg_val, cprops->cmax_wd); -- 2.25.1

hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8T2RT -------------------------------- Support both of CPBM and MBW_PBM features, which provides the cache and memory bandwidth portion bitmap. User can update PBM settings by the interface {L2,L3,MBPBM}:$domain_id=$value in the schemata file. Software would update the MPAMCFG_CPBM<n> register to configure which cache portions the PARTID is allowed to allocate. Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/platform/mpam/mpam_resctrl.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index d4c770389aee..994c1c6e06c4 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -68,6 +68,7 @@ bool resctrl_arch_mon_capable(void) return exposed_mon_capable; } +static bool pbm_capable[RDT_NUM_RESOURCES]; static bool max_capable[RDT_NUM_RESOURCES]; static bool min_capable[RDT_NUM_RESOURCES]; static bool intpri_capable[RDT_NUM_RESOURCES]; @@ -76,9 +77,7 @@ bool resctrl_arch_feat_capable(enum resctrl_res_level level, { switch (feat) { case FEAT_PBM: - if (level == RDT_RESOURCE_L3) - return true; - break; + return pbm_capable[level]; case FEAT_MAX: return max_capable[level]; @@ -100,6 +99,11 @@ const char *resctrl_arch_set_feat_lab(enum resctrl_feat_type feat, unsigned long fflags) { switch (feat) { + case FEAT_PBM: + if (fflags & RFTYPE_RES_CACHE) + break; + return "PBM"; + case FEAT_MAX: if (fflags & RFTYPE_RES_MB) break; @@ -813,6 +817,7 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) if (mpam_has_feature(mpam_feat_cpor_part, &class->props)) { r->alloc_capable = true; exposed_alloc_capable = true; + pbm_capable[r->rid] = true; } if (mpam_has_feature(mpam_feat_ccap_part, &class->props)) @@ -865,6 +870,9 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) r->alloc_capable = true; exposed_alloc_capable = true; + if (mpam_has_feature(mpam_feat_mbw_part, cprops)) + pbm_capable[r->rid] = true; + if (mpam_has_feature(mpam_feat_mbw_max, cprops)) max_capable[r->rid] = true; } @@ -1032,6 +1040,11 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, if (!r->alloc_capable || partid >= resctrl_arch_get_num_closid(r) || !mpam_has_feature(configured_by, cfg)) { + if (configured_by == mpam_feat_cpor_part) + return BIT_MASK(cprops->cpbm_wd) - 1; + if (configured_by == mpam_feat_mbw_part) + return BIT_MASK(cprops->mbw_pbm_bits) - 1; + if ((configured_by == mpam_feat_ccap_part) || (configured_by == mpam_feat_mbw_max)) return MAX_MBA_BW; -- 2.25.1

hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8T2RT -------------------------------- Allow users can configure the mata hard-limit feature and cache soft-limit feature by the schemata {MB,L3}HDL:$domain_id=$value interface under the resctrl fs. When MAX bandwidth is exceeded, the hard-limit feature not allows the partition use any more bandwidth until the memory bandwidth measurement for the partition falls below MAX. When CMAX cache capacity is exceeded, the soft-limit allows the partition to allocate capacity beyond CMAX, but only from invalid lines or lines belonging to disabled PARTIDs. Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/platform/mpam/mpam_devices.c | 32 +++++++++++++++++---- drivers/platform/mpam/mpam_internal.h | 4 +++ drivers/platform/mpam/mpam_resctrl.c | 41 ++++++++++++++++++++++++++- fs/resctrl/ctrlmondata.c | 24 ++++++++++++++++ include/linux/resctrl_types.h | 2 ++ 5 files changed, 97 insertions(+), 6 deletions(-) diff --git a/drivers/platform/mpam/mpam_devices.c b/drivers/platform/mpam/mpam_devices.c index 637cf13052a6..72f0f8c2db0d 100644 --- a/drivers/platform/mpam/mpam_devices.c +++ b/drivers/platform/mpam/mpam_devices.c @@ -578,9 +578,13 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris) props->cmax_wd = FIELD_GET(MPAMF_CCAP_IDR_CMAX_WD, ccap_features); if (props->cmax_wd) { - if (!FIELD_GET(MPAMF_CCAP_IDR_NO_CMAX, ccap_features)) + if (!FIELD_GET(MPAMF_CCAP_IDR_NO_CMAX, ccap_features)) { mpam_set_feature(mpam_feat_ccap_part, props); + if (FIELD_GET(MPAMF_CCAP_IDR_HAS_CMAX_SOFTLIM, ccap_features)) + mpam_set_feature(mpam_feat_max_limit, props); + } + if (FIELD_GET(MPAMF_CCAP_IDR_HAS_CMIN, ccap_features)) mpam_set_feature(mpam_feat_cmin, props); } @@ -606,8 +610,10 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris) mpam_set_feature(mpam_feat_mbw_part, props); props->bwa_wd = FIELD_GET(MPAMF_MBW_IDR_BWA_WD, mbw_features); - 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); + 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); @@ -1192,6 +1198,7 @@ static void mpam_reset_msc_bitmap(struct mpam_msc *msc, u16 reg, u16 wd) static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, struct mpam_config *cfg) { + bool limit; u32 pri_val = 0; u16 intpri, dspri; u16 cmax = MPAMCFG_CMAX_CMAX; @@ -1216,10 +1223,17 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, if (mpam_has_feature(mpam_feat_ccap_part, rprops)) { if (mpam_has_feature(mpam_feat_ccap_part, cfg)) - mpam_write_partsel_reg(msc, CMAX, cfg->ca_max); + cmax = cfg->ca_max; + + if (mpam_has_feature(mpam_feat_max_limit, cfg)) + limit = cfg->max_limit; else - mpam_write_partsel_reg(msc, CMAX, cmax); + limit = true; + if (limit) + mpam_write_partsel_reg(msc, CMAX, cmax); + else + mpam_write_partsel_reg(msc, CMAX, cmax | MPAMCFG_CMAX_CMAX_SOFTLIM); } if (mpam_has_feature(mpam_feat_cmin, rprops)) { @@ -1246,9 +1260,17 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, if (mpam_has_feature(mpam_feat_mbw_max, rprops)) { if (mpam_has_feature(mpam_feat_mbw_max, cfg)) - mpam_write_partsel_reg(msc, MBW_MAX, cfg->mbw_max | MPAMCFG_MBW_MAX_HARDLIM); + bwa_fract = cfg->mbw_max; + + if (mpam_has_feature(mpam_feat_max_limit, cfg)) + limit = cfg->max_limit; else + limit = false; + + if (!limit) mpam_write_partsel_reg(msc, MBW_MAX, bwa_fract); + else + mpam_write_partsel_reg(msc, MBW_MAX, bwa_fract | MPAMCFG_MBW_MAX_HARDLIM); } if (mpam_has_feature(mpam_feat_mbw_prop, rprops)) diff --git a/drivers/platform/mpam/mpam_internal.h b/drivers/platform/mpam/mpam_internal.h index 532f55795ad6..f5af8d240e59 100644 --- a/drivers/platform/mpam/mpam_internal.h +++ b/drivers/platform/mpam/mpam_internal.h @@ -110,6 +110,7 @@ enum mpam_device_features { mpam_feat_msmon_mbwu_rwbw, mpam_feat_msmon_capt, mpam_feat_partid_nrw, + mpam_feat_max_limit, MPAM_FEATURE_LAST, }; #define MPAM_ALL_FEATURES ((1<<MPAM_FEATURE_LAST) - 1) @@ -173,6 +174,8 @@ struct mpam_config { */ u16 dspri; u16 intpri; + + bool max_limit; }; struct mpam_component @@ -459,6 +462,7 @@ void mpam_resctrl_exit(void); /* MPAMCFG_CMAX - MPAM cache portion bitmap partition configuration register */ #define MPAMCFG_CMAX_CMAX GENMASK(15, 0) +#define MPAMCFG_CMAX_CMAX_SOFTLIM BIT(31) /* * MPAMCFG_MBW_MIN - MPAM memory minimum bandwidth partitioning configuration diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index 994c1c6e06c4..fac1af07c44c 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -70,6 +70,7 @@ bool resctrl_arch_mon_capable(void) static bool pbm_capable[RDT_NUM_RESOURCES]; static bool max_capable[RDT_NUM_RESOURCES]; +static bool lim_capable[RDT_NUM_RESOURCES]; static bool min_capable[RDT_NUM_RESOURCES]; static bool intpri_capable[RDT_NUM_RESOURCES]; bool resctrl_arch_feat_capable(enum resctrl_res_level level, @@ -82,6 +83,9 @@ bool resctrl_arch_feat_capable(enum resctrl_res_level level, case FEAT_MAX: return max_capable[level]; + case FEAT_LIMIT: + return lim_capable[level]; + case FEAT_MIN: return min_capable[level]; @@ -109,6 +113,9 @@ const char *resctrl_arch_set_feat_lab(enum resctrl_feat_type feat, break; return "MAX"; + case FEAT_LIMIT: + return "HDL"; + case FEAT_MIN: return "MIN"; @@ -829,6 +836,9 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) if (mpam_has_feature(mpam_feat_intpri_part, &class->props)) intpri_capable[r->rid] = true; + if (mpam_has_feature(mpam_feat_max_limit, &class->props)) + lim_capable[r->rid] = true; + /* * MBWU counters may be 'local' or 'total' depending on where * they are in the topology. Counters on caches are assumed to @@ -873,8 +883,10 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) if (mpam_has_feature(mpam_feat_mbw_part, cprops)) pbm_capable[r->rid] = true; - if (mpam_has_feature(mpam_feat_mbw_max, cprops)) + if (mpam_has_feature(mpam_feat_mbw_max, cprops)) { max_capable[r->rid] = true; + lim_capable[r->rid] = true; + } } if (mpam_has_feature(mpam_feat_mbw_min, cprops)) @@ -1003,6 +1015,10 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, configured_by = mpam_feat_ccap_part; break; + } else if (mpam_has_feature(mpam_feat_max_limit, cprops) && + (feat == FEAT_LIMIT)) { + configured_by = mpam_feat_max_limit; + break; } else if (mpam_has_feature(mpam_feat_cmin, cprops) && (feat == FEAT_MIN)) { configured_by = mpam_feat_cmin; @@ -1023,6 +1039,10 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, (feat == FEAT_MAX)) { configured_by = mpam_feat_mbw_max; break; + } else if (mpam_has_feature(mpam_feat_max_limit, cprops) && + (feat == FEAT_LIMIT)) { + configured_by = mpam_feat_max_limit; + break; } else if (mpam_has_feature(mpam_feat_mbw_min, cprops) && (feat == FEAT_MIN)) { configured_by = mpam_feat_mbw_min; @@ -1049,6 +1069,13 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, (configured_by == mpam_feat_mbw_max)) return MAX_MBA_BW; + if (configured_by == mpam_feat_max_limit) { + if (r->fflags & RFTYPE_RES_CACHE) + return true; + else + return false; + } + if ((configured_by == mpam_feat_cmin) || (configured_by == mpam_feat_mbw_min)) return 0; @@ -1076,6 +1103,8 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, return mbw_pbm_to_percent(cfg->mbw_pbm, cprops); case mpam_feat_mbw_max: return mbw_max_to_percent(cfg->mbw_max, cprops->bwa_wd); + case mpam_feat_max_limit: + return cfg->max_limit; case mpam_feat_mbw_min: return mbw_max_to_percent(cfg->mbw_min, cprops->bwa_wd); case mpam_feat_intpri_part: @@ -1125,6 +1154,11 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, u32 cl cfg.ca_max = percent_to_mbw_max(cfg_val, cprops->cmax_wd); mpam_set_feature(mpam_feat_ccap_part, &cfg); break; + } else if (mpam_has_feature(mpam_feat_max_limit, cprops) && + (f == FEAT_LIMIT)) { + cfg.max_limit = cfg_val; + mpam_set_feature(mpam_feat_max_limit, &cfg); + break; } else if (mpam_has_feature(mpam_feat_cmin, cprops) && (f == FEAT_MIN)) { cfg.ca_min = percent_to_mbw_max(cfg_val, cprops->cmax_wd); @@ -1148,6 +1182,11 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, u32 cl cfg.mbw_max = percent_to_mbw_max(cfg_val, cprops->bwa_wd); mpam_set_feature(mpam_feat_mbw_max, &cfg); break; + } else if (mpam_has_feature(mpam_feat_max_limit, cprops) && + (f == FEAT_LIMIT)) { + cfg.max_limit = cfg_val; + mpam_set_feature(mpam_feat_max_limit, &cfg); + break; } else if (mpam_has_feature(mpam_feat_mbw_min, cprops) && (f == FEAT_MIN)) { cfg.mbw_min = percent_to_mbw_max(cfg_val, cprops->bwa_wd); diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c index 61e498ce808a..7c728b4eaaa2 100644 --- a/fs/resctrl/ctrlmondata.c +++ b/fs/resctrl/ctrlmondata.c @@ -112,6 +112,26 @@ static bool prio_validate(char *buf, unsigned long *data, struct rdt_resource *r return true; } +static bool lim_validate(char *buf, unsigned long *data, struct rdt_resource *r) +{ + unsigned long cap; + int ret; + + ret = kstrtoul(buf, 10, &cap); + if (ret) { + rdt_last_cmd_printf("Non-decimal digit in limit value %s\n", buf); + return false; + } + + if (cap > 1) { + rdt_last_cmd_printf("Limit value %ld out of range [0,1]\n", cap); + return false; + } + + *data = !!cap; + return true; +} + static int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s, struct rdt_domain *d) { @@ -130,6 +150,10 @@ static int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s, if (!prio_validate(data->buf, &bw_val, r)) return -EINVAL; + } else if (s->feat_type == FEAT_LIMIT) { + if (!lim_validate(data->buf, &bw_val, r)) + return -EINVAL; + } else if (r->rid == RDT_RESOURCE_MBA) { /* For FEAT_MAX and FEAT_MIN */ if (!bw_validate(data->buf, &bw_val, r)) diff --git a/include/linux/resctrl_types.h b/include/linux/resctrl_types.h index 7a33a4c119c3..f6a0d8142fde 100644 --- a/include/linux/resctrl_types.h +++ b/include/linux/resctrl_types.h @@ -78,6 +78,8 @@ enum resctrl_feat_type { FEAT_MAX, FEAT_MIN, FEAT_INTPRI, + FEAT_LIMIT, + FEAT_NUM_TYPES, }; -- 2.25.1

hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IAFXTZ -------------------------------- Fix struct rdt_resource initialization about cache level in mpam_resctrl_resource_init(), otherwise when obtaining allocated cache size by size file under control group, it would be found that the cache level is uninitialized. Fixes: 1ca491c7bbcd ("arm_mpam: resctrl: Pick the caches we will use as resctrl resources") Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/platform/mpam/mpam_resctrl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index fac1af07c44c..bb826277d027 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -812,6 +812,7 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) r->fflags = RFTYPE_RES_CACHE; r->default_ctrl = BIT_MASK(class->props.cpbm_wd) - 1; r->data_width = (class->props.cpbm_wd + 3) / 4; + r->cache_level = class->level; /* * Which bits are shared with other ...things... -- 2.25.1

hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IAK8CS -------------------------------- When CDP is enabled, but the resource like MATA doesn't support it, we need to apply the same configuration to both of the CDP_CODE and CDP_DATA partids. In mpam_apply_config(), it will synchronize the configuration to the wrong comp->cfg[partid]. We will first update the staged_config with correct conf_type and then update the configuration to the comp->cfg corresponding to the partid by resctrl_arch_update_one(). In the same way, when get configuration from schemata interface by resctrl_arch_get_config(), we need to get the configuration of the CDP_CODE partid. Fixes: 58db5c68e84a ("untested: arm_mpam: resctrl: Add support for MB resource") Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- arch/x86/include/asm/resctrl.h | 4 ++++ drivers/platform/mpam/mpam_resctrl.c | 31 +++++++++++----------------- fs/resctrl/ctrlmondata.c | 28 ++++++++++++++++++++++--- include/linux/arm_mpam.h | 1 + 4 files changed, 42 insertions(+), 22 deletions(-) diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h index 2aa30e36b29a..b0cb9d283a2b 100644 --- a/arch/x86/include/asm/resctrl.h +++ b/arch/x86/include/asm/resctrl.h @@ -222,6 +222,10 @@ void resctrl_cpu_detect(struct cpuinfo_x86 *c); bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level l); int resctrl_arch_set_cdp_enabled(enum resctrl_res_level l, bool enable); +static inline bool resctrl_arch_hide_cdp(enum resctrl_res_level rid) +{ + return false; +}; static inline bool resctrl_arch_feat_capable(enum resctrl_res_level level, enum resctrl_feat_type feat) diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index bb826277d027..b20ab2c756f1 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -180,7 +180,7 @@ int resctrl_arch_set_cdp_enabled(enum resctrl_res_level ignored, bool enable) return 0; } -static bool mpam_resctrl_hide_cdp(enum resctrl_res_level rid) +bool resctrl_arch_hide_cdp(enum resctrl_res_level rid) { return cdp_enabled && !resctrl_arch_get_cdp_enabled(rid); } @@ -1000,7 +1000,16 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, dom = container_of(d, struct mpam_resctrl_dom, resctrl_dom); cprops = &res->class->props; - partid = resctrl_get_config_index(closid, type); + /* + * When CDP is enabled, but the resource doesn't support it, we + * need to get the configuration from the CDP_CODE resctrl_conf_type + * which is same as the CDP_DATA one. + */ + if (resctrl_arch_hide_cdp(r->rid)) + partid = resctrl_get_config_index(closid, CDP_CODE); + else + partid = resctrl_get_config_index(closid, type); + cfg = &dom->comp->cfg[partid]; switch (r->rid) { @@ -1119,7 +1128,6 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, u32 cl enum resctrl_conf_type t, enum resctrl_feat_type f, u32 cfg_val) { - int err; u32 partid; struct mpam_config cfg; struct mpam_props *cprops; @@ -1205,22 +1213,7 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, u32 cl return -EINVAL; } - /* - * When CDP is enabled, but the resource doesn't support it, we need to - * apply the same configuration to the other partid. - */ - if (mpam_resctrl_hide_cdp(r->rid)) { - partid = resctrl_get_config_index(closid, CDP_CODE); - err = mpam_apply_config(dom->comp, partid, &cfg); - if (err) - return err; - - partid = resctrl_get_config_index(closid, CDP_DATA); - return mpam_apply_config(dom->comp, partid, &cfg); - - } else { - return mpam_apply_config(dom->comp, partid, &cfg); - } + return mpam_apply_config(dom->comp, partid, &cfg); } /* TODO: this is IPI heavy */ diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c index 7c728b4eaaa2..ec27c7cc12e3 100644 --- a/fs/resctrl/ctrlmondata.c +++ b/fs/resctrl/ctrlmondata.c @@ -132,15 +132,15 @@ static bool lim_validate(char *buf, unsigned long *data, struct rdt_resource *r) return true; } -static int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s, - struct rdt_domain *d) +static int parse_bw_conf_type(struct rdt_parse_data *data, struct resctrl_schema *s, + struct rdt_domain *d, enum resctrl_conf_type conf_type) { struct resctrl_staged_config *cfg; u32 closid = data->rdtgrp->closid; struct rdt_resource *r = s->res; unsigned long bw_val; - cfg = &d->staged_config[s->conf_type][s->feat_type]; + cfg = &d->staged_config[conf_type][s->feat_type]; if (cfg->have_new_ctrl) { rdt_last_cmd_printf("Duplicate domain %d\n", d->id); return -EINVAL; @@ -176,6 +176,28 @@ static int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s, return 0; } +static int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s, + struct rdt_domain *d) +{ + struct rdt_resource *r = s->res; + int err; + + /* + * When CDP is enabled, but the resource doesn't support it, we + * need to apply the same configuration to both of the CDP_CODE + * and CDP_DATA resctrl_conf_type. + */ + if (resctrl_arch_hide_cdp(r->rid)) { + err = parse_bw_conf_type(data, s, d, CDP_CODE); + if (err) + return err; + + return parse_bw_conf_type(data, s, d, CDP_DATA); + } + + return parse_bw_conf_type(data, s, d, s->conf_type); +} + /* * Check whether a cache bit mask is valid. * On Intel CPUs, non-contiguous 1s value support is indicated by CPUID: diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h index 8f68f0397e03..afc7445f09e1 100644 --- a/include/linux/arm_mpam.h +++ b/include/linux/arm_mpam.h @@ -78,6 +78,7 @@ void resctrl_arch_reset_resources(void); bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level ignored); int resctrl_arch_set_cdp_enabled(enum resctrl_res_level ignored, bool enable); +bool resctrl_arch_hide_cdp(enum resctrl_res_level rid); bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid); bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid); void resctrl_arch_set_cpu_default_closid(int cpu, u32 closid); -- 2.25.1

hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAG93D -------------------------------- If the CDP mount option is enabled, allow users to configure separately code and data portion, but still provide one monitor for each MSC class instead of two. Based on the above reason, add debugging information about monitor value for code and data streams separately. Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/platform/mpam/mpam_resctrl.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index b20ab2c756f1..d3dc628f9fec 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -419,15 +419,19 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d, cfg.opts = resctrl_evt_config_to_mpam(dom->mbm_local_evt_cfg); if (cdp_enabled) { - cfg.partid = closid << 1; + cfg.partid = resctrl_get_config_index(closid, CDP_DATA); err = mpam_msmon_read(dom->comp, &cfg, type, val); if (err) return err; - cfg.partid += 1; + cfg.partid = resctrl_get_config_index(closid, CDP_CODE); err = mpam_msmon_read(dom->comp, &cfg, type, &cdp_val); - if (!err) + if (!err) { + pr_debug("read monitor rmid %u %s:%u CODE/DATA: %lld/%lld\n", + resctrl_arch_rmid_idx_encode(closid, rmid), + r->name, dom->comp->comp_id, cdp_val, *val); *val += cdp_val; + } } else { cfg.partid = closid; err = mpam_msmon_read(dom->comp, &cfg, type, val); -- 2.25.1
participants (2)
-
patchwork bot
-
Zeng Heng