
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