
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC35SV -------------------------------- 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> --- drivers/platform/mpam/mpam_devices.c | 25 ++++++++--- drivers/platform/mpam/mpam_internal.h | 7 ++- drivers/platform/mpam/mpam_resctrl.c | 61 +++++++++++++++++++++++++-- fs/resctrl/ctrlmondata.c | 34 +++++++++++++-- include/linux/resctrl_types.h | 2 + 5 files changed, 117 insertions(+), 12 deletions(-) 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 d8854cc6f78e..b094095abe49 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 826acc6183bb..8c62e3b29f24 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -69,16 +69,26 @@ 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; @@ -87,6 +97,14 @@ bool resctrl_arch_feat_capable(enum resctrl_res_level level, const char *resctrl_arch_get_feat_lab(enum resctrl_feat_type feat, unsigned long fflags) { + switch (feat) { + case FEAT_MIN: + return "MIN"; + + default: + break; + } + return ""; } @@ -829,6 +847,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 @@ -870,6 +891,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; @@ -984,6 +1008,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; @@ -996,6 +1024,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: @@ -1003,18 +1035,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; } @@ -1044,6 +1087,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: @@ -1053,6 +1098,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; @@ -1066,6 +1116,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..4a74b71daed8 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,10 +100,18 @@ 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->fflags & RFTYPE_RES_MB) { + if (!bw_validate(data->buf, &bw_val, r)) + return -EINVAL; + + } else { + /* For the RDT_RESOURCE_L3/L2 */ + if (!deci_validate(data->buf, &bw_val, r)) + return -EINVAL; + } - if (is_mba_sc(r)) { + if ((r->fflags & RFTYPE_RES_MB) && (s->feat_type == FEAT_MAX) && + is_mba_sc(r)) { d->mbps_val[closid] = bw_val; return 0; } diff --git a/include/linux/resctrl_types.h b/include/linux/resctrl_types.h index 121f200c55ef..322839157983 100644 --- a/include/linux/resctrl_types.h +++ b/include/linux/resctrl_types.h @@ -78,10 +78,12 @@ enum resctrl_conf_type { * @FEAT_PBM: Portion Bit Map, allow the usage of bitmap method for * resource allocation. * @FEAT_MAX: Controls the maximum fraction of the resource capacity. + * @FEAT_MIN: Controls the minimum fraction of the resource capacity. */ enum resctrl_feat_type { FEAT_PBM, FEAT_MAX, + FEAT_MIN, FEAT_NUM_TYPES, }; -- 2.25.1