diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c index 6a5a5b43af275a99932cfd4c7eb66b431b74dc5b..0d63f1a0eb72025a7da750545817ee48289236b3 100644 --- a/arch/x86/kernel/cpu/resctrl/core.c +++ b/arch/x86/kernel/cpu/resctrl/core.c @@ -61,7 +61,7 @@ mba_wrmsr_amd(struct rdt_domain *d, struct msr_param *m, #define domain_init(id) LIST_HEAD_INIT(rdt_resources_all[id].r_resctrl.domains) -struct rdt_hw_resource rdt_resources_all[] = { +struct rdt_hw_resource rdt_resources_all[RDT_NUM_RESOURCES] = { [RDT_RESOURCE_L3] = { .r_resctrl = { @@ -71,6 +71,7 @@ struct rdt_hw_resource rdt_resources_all[] = { .domains = domain_init(RDT_RESOURCE_L3), .format_str = "%d=%0*x", .fflags = RFTYPE_RES_CACHE, + .schema_fmt = RESCTRL_SCHEMA_BITMAP, }, .msr_base = MSR_IA32_L3_CBM_BASE, .msr_update = cat_wrmsr, @@ -84,6 +85,7 @@ struct rdt_hw_resource rdt_resources_all[] = { .domains = domain_init(RDT_RESOURCE_L2), .format_str = "%d=%0*x", .fflags = RFTYPE_RES_CACHE, + .schema_fmt = RESCTRL_SCHEMA_BITMAP, }, .msr_base = MSR_IA32_L2_CBM_BASE, .msr_update = cat_wrmsr, @@ -97,6 +99,7 @@ struct rdt_hw_resource rdt_resources_all[] = { .domains = domain_init(RDT_RESOURCE_MBA), .format_str = "%d=%*u", .fflags = RFTYPE_RES_MB, + .schema_fmt = RESCTRL_SCHEMA_RANGE, }, }, [RDT_RESOURCE_SMBA] = @@ -108,6 +111,7 @@ struct rdt_hw_resource rdt_resources_all[] = { .domains = domain_init(RDT_RESOURCE_SMBA), .format_str = "%d=%*u", .fflags = RFTYPE_RES_MB, + .schema_fmt = RESCTRL_SCHEMA_RANGE, }, }, }; diff --git a/drivers/platform/mpam/mpam_devices.c b/drivers/platform/mpam/mpam_devices.c index 0bc8393541f1daa441f7014908eb8e65879f4369..e0a16198a810d3567272d557686b951248e11d89 100644 --- a/drivers/platform/mpam/mpam_devices.c +++ b/drivers/platform/mpam/mpam_devices.c @@ -577,9 +577,14 @@ 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 */ @@ -602,8 +607,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); @@ -1188,13 +1195,13 @@ 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; 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); @@ -1211,6 +1218,20 @@ 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->cmax); + 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->cmin); + 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,12 +1240,25 @@ 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)) - 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 | + MPAMCFG_MBW_MAX_HARDLIM); else mpam_write_partsel_reg(msc, MBW_MAX, bwa_fract); } @@ -1232,24 +1266,29 @@ 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 + intpri = 0; - 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, 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 d8854cc6f78ee981e0d1169e1bdfe79326414eab..e9c52078edea4c04cbbe7fa7329d8c3d1a8ad126 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; @@ -86,9 +86,11 @@ 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, + mpam_feat_max_limit, mpam_feat_mbw_prop, mpam_feat_intpri_part, mpam_feat_intpri_part_0_low, @@ -162,6 +164,17 @@ struct mpam_config { u32 cpbm; u32 mbw_pbm; u16 mbw_max; + u16 mbw_min; + bool max_limit; + u16 cmax; + u16 cmin; + + /* + * dspri is downstream priority + * intpri is internal priority + */ + u16 dspri; + u16 intpri; }; struct mpam_component @@ -341,6 +354,7 @@ void mpam_resctrl_exit(void); #define MPAMCFG_PART_SEL 0x0100 /* partid to configure: */ #define MPAMCFG_CPBM 0x1000 /* cache-portion config */ #define MPAMCFG_CMAX 0x0108 /* cache-capacity 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 7586c8ffbb8803c82c3a197edaf3ab15bdacd2ff..67cdcfc9e693a85f7f4fbaeacfeaedeae2033e29 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -483,6 +483,20 @@ static bool cache_has_usable_cpor(struct mpam_class *class) return (class->props.cpbm_wd <= RESCTRL_MAX_CBM); } +static bool cache_has_usable_cmax(struct mpam_class *class) +{ + struct mpam_props *cprops = &class->props; + + return mpam_has_feature(mpam_feat_ccap_part, cprops); +} + +static bool cache_has_usable_cmin(struct mpam_class *class) +{ + struct mpam_props *cprops = &class->props; + + return mpam_has_feature(mpam_feat_cmin, cprops); +} + static bool cache_has_usable_csu(struct mpam_class *class) { struct mpam_props *cprops; @@ -536,6 +550,30 @@ static bool class_has_usable_mba(struct mpam_props *cprops) return false; } +static bool class_has_usable_mbw_min(struct mpam_props *cprops) +{ + if (mpam_has_feature(mpam_feat_mbw_min, cprops)) + return true; + + return false; +} + +static bool class_has_usable_intpri(struct mpam_props *cprops) +{ + if (mpam_has_feature(mpam_feat_intpri_part, cprops)) + return true; + + return false; +} + +static bool class_has_usable_max_limit(struct mpam_props *cprops) +{ + if (mpam_has_feature(mpam_feat_max_limit, cprops)) + return true; + + return false; +} + /* * Calculate the percentage change from each implemented bit in the control * This can return 0 when BWA_WD is greater than 6. (100 / (1<<7) == 0) @@ -581,6 +619,9 @@ static u32 mbw_max_to_percent(u16 mbw_max, u8 wd) u8 bit; u32 divisor = 2, value = 0, precision = get_wd_precision(wd); + if (mbw_max == GENMASK(15, 15 - wd + 1)) + return MAX_MBA_BW; + for (bit = 15; bit; bit--) { if (mbw_max & BIT(bit)) value += MAX_MBA_BW * precision / divisor; @@ -610,6 +651,9 @@ static u16 percent_to_mbw_max(u32 pc, u8 wd) if (WARN_ON_ONCE(wd > 15)) return MAX_MBA_BW; + if (pc == MAX_MBA_BW) + return GENMASK(15, 15 - wd + 1); + pc *= precision; for (bit = 15; bit; bit--) { @@ -635,13 +679,18 @@ static void mpam_resctrl_pick_caches(void) unsigned int cache_size; struct mpam_class *class; struct mpam_resctrl_res *res; + bool has_cpor, has_cmax, has_cmin, has_intpri; lockdep_assert_cpus_held(); idx = srcu_read_lock(&mpam_srcu); list_for_each_entry_rcu(class, &mpam_classes, classes_list) { struct mpam_props *cprops = &class->props; - bool has_cpor = cache_has_usable_cpor(class); + + has_cpor = cache_has_usable_cpor(class); + has_cmax = cache_has_usable_cmax(class); + has_cmin = cache_has_usable_cmin(class); + has_intpri = class_has_usable_intpri(cprops); if (class->type != MPAM_CLASS_CACHE) { pr_debug("pick_caches: Class is not a cache\n"); @@ -677,22 +726,58 @@ static void mpam_resctrl_pick_caches(void) if (mpam_has_feature(mpam_feat_msmon_csu, cprops)) update_rmid_limits(cache_size); - if (class->level == 2) { - res = &mpam_resctrl_exports[RDT_RESOURCE_L2]; - res->resctrl_res.name = "L2"; - } else { - res = &mpam_resctrl_exports[RDT_RESOURCE_L3]; - res->resctrl_res.name = "L3"; + if (has_cpor) { + if (class->level == 2) { + res = &mpam_resctrl_exports[RDT_RESOURCE_L2]; + res->resctrl_res.name = "L2"; + } else { + res = &mpam_resctrl_exports[RDT_RESOURCE_L3]; + res->resctrl_res.name = "L3"; + } + res->class = class; + } + + if (has_cmax) { + if (class->level == 2) { + res = &mpam_resctrl_exports[RDT_RESOURCE_L2_MAX]; + res->resctrl_res.name = "L2MAX"; + } else { + res = &mpam_resctrl_exports[RDT_RESOURCE_L3_MAX]; + res->resctrl_res.name = "L3MAX"; + } + res->class = class; + } + + if (has_cmin) { + if (class->level == 2) { + res = &mpam_resctrl_exports[RDT_RESOURCE_L2_MIN]; + res->resctrl_res.name = "L2MIN"; + } else { + res = &mpam_resctrl_exports[RDT_RESOURCE_L3_MIN]; + res->resctrl_res.name = "L3MIN"; + } + res->class = class; + } + + if (has_intpri) { + if (class->level == 2) { + res = &mpam_resctrl_exports[RDT_RESOURCE_L2_PRI]; + res->resctrl_res.name = "L2PRI"; + } else { + res = &mpam_resctrl_exports[RDT_RESOURCE_L3_PRI]; + res->resctrl_res.name = "L3PRI"; + } + res->class = class; } - res->class = class; } srcu_read_unlock(&mpam_srcu, idx); } static void mpam_resctrl_pick_mba(void) { - struct mpam_class *class, *candidate_class = NULL; + bool has_mba, has_mbw_min, has_intpri, has_limit; struct mpam_resctrl_res *res; + struct mpam_class *class; int idx; lockdep_assert_cpus_held(); @@ -701,30 +786,42 @@ static void mpam_resctrl_pick_mba(void) list_for_each_entry_rcu(class, &mpam_classes, classes_list) { struct mpam_props *cprops = &class->props; - if (class->level < 3) - continue; + has_mba = class_has_usable_mba(cprops); + has_mbw_min = class_has_usable_mbw_min(cprops); + has_intpri = class_has_usable_intpri(cprops); + has_limit = class_has_usable_max_limit(cprops); - if (!class_has_usable_mba(cprops)) + if (class->level < 3) continue; if (!cpumask_equal(&class->affinity, cpu_possible_mask)) continue; - /* - * mba_sc reads the mbm_local counter, and waggles the MBA controls. - * mbm_local is implicitly part of the L3, pick a resouce to be MBA - * that as close as possible to the L3. - */ - if (!candidate_class || class->level < candidate_class->level) - candidate_class = class; - } - srcu_read_unlock(&mpam_srcu, idx); + if (has_mba) { + res = &mpam_resctrl_exports[RDT_RESOURCE_MBA]; + res->class = class; + res->resctrl_res.name = "MB"; + } - if (candidate_class) { - res = &mpam_resctrl_exports[RDT_RESOURCE_MBA]; - res->class = candidate_class; - res->resctrl_res.name = "MB"; + if (has_mbw_min) { + res = &mpam_resctrl_exports[RDT_RESOURCE_MB_MIN]; + res->class = class; + res->resctrl_res.name = "MBMIN"; + } + + if (has_intpri) { + res = &mpam_resctrl_exports[RDT_RESOURCE_MB_PRI]; + res->class = class; + res->resctrl_res.name = "MBPRI"; + } + + if (has_limit) { + res = &mpam_resctrl_exports[RDT_RESOURCE_MB_HDL]; + res->class = class; + res->resctrl_res.name = "MBHDL"; + } } + srcu_read_unlock(&mpam_srcu, idx); } bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt) @@ -778,14 +875,15 @@ void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_domain *d) static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) { struct mpam_class *class = res->class; + struct mpam_props *cprops = &class->props; struct rdt_resource *r = &res->resctrl_res; bool has_mbwu = class_has_usable_mbwu(class); + bool has_csu = cache_has_usable_csu(class); /* Is this one of the two well-known caches? */ - if (res->resctrl_res.rid == RDT_RESOURCE_L2 || - res->resctrl_res.rid == RDT_RESOURCE_L3) { - bool has_csu = cache_has_usable_csu(class); - + switch (res->resctrl_res.rid) { + case RDT_RESOURCE_L2: + case RDT_RESOURCE_L3: /* TODO: Scaling is not yet supported */ r->cache.cbm_len = class->props.cpbm_wd; r->cache.arch_has_sparse_bitmasks = true; @@ -795,6 +893,7 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) /* TODO: kill these properties off as they are derivatives */ r->format_str = "%d=%0*x"; + r->schema_fmt = RESCTRL_SCHEMA_BITMAP; r->fflags = RFTYPE_RES_CACHE; r->default_ctrl = BIT_MASK(class->props.cpbm_wd) - 1; r->data_width = (class->props.cpbm_wd + 3) / 4; @@ -808,7 +907,7 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) */ r->cache.shareable_bits = r->default_ctrl; - if (mpam_has_feature(mpam_feat_cpor_part, &class->props)) { + if (mpam_has_feature(mpam_feat_cpor_part, cprops)) { r->alloc_capable = true; exposed_alloc_capable = true; } @@ -832,11 +931,12 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) class->level == 3) { r->mon_capable = true; } - } else if (res->resctrl_res.rid == RDT_RESOURCE_MBA) { - struct mpam_props *cprops = &class->props; + break; + case RDT_RESOURCE_MBA: /* TODO: kill these properties off as they are derivatives */ r->format_str = "%d=%0*u"; + r->schema_fmt = RESCTRL_SCHEMA_PERCENT; r->fflags = RFTYPE_RES_MB; r->default_ctrl = MAX_MBA_BW; r->data_width = 3; @@ -858,6 +958,103 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) mbm_total_class = class; r->mon_capable = true; } + break; + + case RDT_RESOURCE_L3_MAX: + case RDT_RESOURCE_L2_MAX: + r->format_str = "%d=%0*u"; + r->schema_fmt = RESCTRL_SCHEMA_PERCENT; + r->fflags = RFTYPE_RES_CACHE; + r->default_ctrl = MAX_MBA_BW; + r->data_width = 3; + r->cache_level = class->level; + + if (cache_has_usable_cmax(class)) + r->alloc_capable = true; + + r->membw.min_bw = 0; + r->membw.bw_gran = max(100 / (1 << cprops->cmax_wd), 1); + break; + + case RDT_RESOURCE_L3_MIN: + case RDT_RESOURCE_L2_MIN: + r->format_str = "%d=%0*u"; + r->schema_fmt = RESCTRL_SCHEMA_PERCENT; + r->fflags = RFTYPE_RES_CACHE; + r->default_ctrl = MAX_MBA_BW; + r->data_width = 3; + r->cache_level = class->level; + + if (cache_has_usable_cmin(class)) + r->alloc_capable = true; + + r->membw.min_bw = 0; + r->membw.bw_gran = max(100 / (1 << cprops->cmax_wd), 1); + break; + + case RDT_RESOURCE_MB_MIN: + r->format_str = "%d=%0*u"; + r->schema_fmt = RESCTRL_SCHEMA_PERCENT; + r->fflags = RFTYPE_RES_MB; + r->default_ctrl = MAX_MBA_BW; + r->data_width = 3; + + r->membw.delay_linear = true; + r->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED; + r->membw.bw_gran = get_mba_granularity(cprops); + + /* Round up to at least 1% */ + if (!r->membw.bw_gran) + r->membw.bw_gran = 1; + + if (class_has_usable_mbw_min(cprops)) + r->alloc_capable = true; + break; + + case RDT_RESOURCE_L3_PRI: + case RDT_RESOURCE_L2_PRI: + r->format_str = "%d=%0*u"; + r->schema_fmt = RESCTRL_SCHEMA_PERCENT; + r->fflags = RFTYPE_RES_CACHE; + r->default_ctrl = GENMASK(cprops->intpri_wd - 1, 0); + r->data_width = 3; + r->cache_level = class->level; + + if (class_has_usable_intpri(cprops)) + r->alloc_capable = true; + + r->membw.min_bw = 0; + r->membw.bw_gran = 1; + break; + + case RDT_RESOURCE_MB_PRI: + r->format_str = "%d=%0*u"; + r->schema_fmt = RESCTRL_SCHEMA_PERCENT; + r->fflags = RFTYPE_RES_MB; + r->default_ctrl = GENMASK(cprops->intpri_wd - 1, 0); + r->data_width = 3; + + r->membw.bw_gran = 1; + + if (class_has_usable_intpri(cprops)) + r->alloc_capable = true; + break; + + case RDT_RESOURCE_MB_HDL: + r->format_str = "%d=%0*u"; + r->schema_fmt = RESCTRL_SCHEMA_PERCENT; + r->fflags = RFTYPE_RES_MB; + r->default_ctrl = 1; + r->data_width = 1; + + r->membw.bw_gran = 1; + + if (class_has_usable_max_limit(cprops)) + r->alloc_capable = true; + break; + + default: + break; } if (r->mon_capable) { @@ -871,7 +1068,7 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) * For mpam, each control group has its own pmg/rmid * space. */ - r->num_rmid = 1; + r->num_rmid = mpam_partid_max * mpam_pmg_max; } return 0; @@ -974,6 +1171,20 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, case RDT_RESOURCE_L3: configured_by = mpam_feat_cpor_part; break; + case RDT_RESOURCE_L2_MAX: + case RDT_RESOURCE_L3_MAX: + configured_by = mpam_feat_ccap_part; + break; + case RDT_RESOURCE_L2_MIN: + case RDT_RESOURCE_L3_MIN: + configured_by = mpam_feat_cmin; + break; + case RDT_RESOURCE_L2_PRI: + case RDT_RESOURCE_L3_PRI: + case RDT_RESOURCE_MB_PRI: + configured_by = mpam_feat_intpri_part; + break; + case RDT_RESOURCE_MBA: if (mba_class_use_mbw_part(cprops)) { configured_by = mpam_feat_mbw_part; @@ -982,7 +1193,16 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, configured_by = mpam_feat_mbw_max; break; } - fallthrough; + return -EINVAL; + + case RDT_RESOURCE_MB_MIN: + configured_by = mpam_feat_mbw_min; + break; + + case RDT_RESOURCE_MB_HDL: + configured_by = mpam_feat_max_limit; + break; + default: return -EINVAL; } @@ -995,11 +1215,21 @@ 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->cmax, cprops->cmax_wd); + case mpam_feat_cmin: + return mbw_max_to_percent(cfg->cmin, cprops->cmax_wd); + case mpam_feat_intpri_part: + return cfg->intpri; 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); + case mpam_feat_max_limit: + return cfg->max_limit; default: return -EINVAL; } @@ -1027,6 +1257,8 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, 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: @@ -1034,6 +1266,22 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, cfg.cpbm = cfg_val; mpam_set_feature(mpam_feat_cpor_part, &cfg); break; + case RDT_RESOURCE_L2_MAX: + case RDT_RESOURCE_L3_MAX: + cfg.cmax = percent_to_mbw_max(cfg_val, cprops->cmax_wd); + mpam_set_feature(mpam_feat_ccap_part, &cfg); + break; + case RDT_RESOURCE_L2_MIN: + case RDT_RESOURCE_L3_MIN: + cfg.cmin = percent_to_mbw_max(cfg_val, cprops->cmax_wd); + mpam_set_feature(mpam_feat_cmin, &cfg); + break; + case RDT_RESOURCE_L2_PRI: + case RDT_RESOURCE_L3_PRI: + case RDT_RESOURCE_MB_PRI: + cfg.intpri = cfg_val; + mpam_set_feature(mpam_feat_intpri_part, &cfg); + break; case RDT_RESOURCE_MBA: if (mba_class_use_mbw_part(cprops)) { cfg.mbw_pbm = percent_to_mbw_pbm(cfg_val, cprops); @@ -1044,7 +1292,15 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, mpam_set_feature(mpam_feat_mbw_max, &cfg); break; } - fallthrough; + return -EINVAL; + case RDT_RESOURCE_MB_MIN: + cfg.mbw_min = percent_to_mbw_max(cfg_val, cprops->bwa_wd); + mpam_set_feature(mpam_feat_mbw_min, &cfg); + break; + case RDT_RESOURCE_MB_HDL: + cfg.max_limit = cfg_val; + mpam_set_feature(mpam_feat_max_limit, &cfg); + break; default: return -EINVAL; } diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c index 15df4334ff14e2210e3a55135210b3044e0c87cc..60b422eed2c81d97331e32c43adac06fd00de9b8 100644 --- a/fs/resctrl/ctrlmondata.c +++ b/fs/resctrl/ctrlmondata.c @@ -45,20 +45,23 @@ static bool bw_validate(char *buf, unsigned long *data, struct rdt_resource *r) * Only linear delay values is supported for current Intel SKUs. */ if (!r->membw.delay_linear && r->membw.arch_needs_linear) { - rdt_last_cmd_puts("No support for non-linear MB domains\n"); + rdt_last_cmd_printf("No support for non-linear %s domains\n", + r->name); return false; } ret = kstrtoul(buf, 10, &bw); if (ret) { - rdt_last_cmd_printf("Non-decimal digit in MB value %s\n", buf); + rdt_last_cmd_printf("Non-decimal digit in %s value %s\n", + r->name, buf); return false; } if ((bw < r->membw.min_bw || bw > r->default_ctrl) && !is_mba_sc(r)) { - rdt_last_cmd_printf("MB value %ld out of range [%d,%d]\n", bw, - r->membw.min_bw, r->default_ctrl); + rdt_last_cmd_printf("%s value %ld out of range [%d,%d]\n", + r->name, bw, r->membw.min_bw, + r->default_ctrl); return false; } @@ -227,7 +230,7 @@ static int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s, static ctrlval_parser_t *get_parser(struct rdt_resource *res) { - if (res->fflags & RFTYPE_RES_CACHE) + if (res->schema_fmt == RESCTRL_SCHEMA_BITMAP) return &parse_cbm; else return &parse_bw; diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c index 4b38a68cc0f3e7b92b12912467d1ec2aeaa0dcb4..ffb6b8930435f44e1a46105e606fe8269180cef5 100644 --- a/fs/resctrl/rdtgroup.c +++ b/fs/resctrl/rdtgroup.c @@ -1679,11 +1679,11 @@ static int rdtgroup_size_show(struct kernfs_open_file *of, ctrl = resctrl_arch_get_config(r, d, closid, type); - if (r->rid == RDT_RESOURCE_MBA || - r->rid == RDT_RESOURCE_SMBA) - size = ctrl; - else + if (r->rid == RDT_RESOURCE_L3 || + r->rid == RDT_RESOURCE_L2) size = rdtgroup_cbm_to_size(r, d, ctrl); + else + size = ctrl; } seq_printf(s, "%d=%u", d->id, size); sep = true; @@ -2293,6 +2293,11 @@ static int rdtgroup_create_info_dir(struct kernfs_node *parent_kn) /* loop over enabled controls, these are all alloc_capable */ list_for_each_entry(s, &resctrl_schema_all, list) { r = s->res; + + /* Not supported yet */ + if (r->rid > RDT_RESOURCE_SMBA) + continue; + fflags = r->fflags | RFTYPE_CTRL_INFO; ret = rdtgroup_mkdir_info_resdir(s, s->name, fflags); if (ret) diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index 61ff7dd5d74c96d216df4821a3ff4a011874b8e1..566a891f1e04baf01f1d4fe09fa8afc7c776b1d0 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -133,6 +133,8 @@ struct rdt_domain { * @arch_has_sparse_bitmasks: True if a bitmask like f00f is valid. * @arch_has_per_cpu_cfg: True if QOS_CFG register for this cache * level has CPU scope. + * @intpri_wd: Number of implemented bits in the priority + * partition. */ struct resctrl_cache { unsigned int cbm_len; @@ -140,6 +142,7 @@ struct resctrl_cache { unsigned int shareable_bits; bool arch_has_sparse_bitmasks; bool arch_has_per_cpu_cfg; + unsigned int intpri_wd; }; /** @@ -166,6 +169,8 @@ enum membw_throttle_mode { * different memory bandwidths * @mba_sc: True if MBA software controller(mba_sc) is enabled * @mb_map: Mapping of memory B/W percentage to memory B/W delay + * @intpri_wd: Number of implemented bits in the priority + * partition. */ struct resctrl_membw { u32 min_bw; @@ -175,6 +180,17 @@ struct resctrl_membw { enum membw_throttle_mode throttle_mode; bool mba_sc; u32 *mb_map; + u32 intpri_wd; +}; + +/** + * enum resctrl_schema_fmt - The format user-space provides for a schema. + * @RESCTRL_SCHEMA_BITMAP: The schema is a bitmap in hex. + * @RESCTRL_SCHEMA_RANGE: The schema is a decimal number. + */ +enum resctrl_schema_fmt { + RESCTRL_SCHEMA_BITMAP, + RESCTRL_SCHEMA_RANGE, }; /** @@ -211,6 +227,7 @@ struct rdt_resource { struct list_head evt_list; unsigned long fflags; bool cdp_capable; + enum resctrl_schema_fmt schema_fmt; }; /* @@ -234,7 +251,7 @@ 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; struct rdt_resource *res; u32 num_closid; diff --git a/include/linux/resctrl_types.h b/include/linux/resctrl_types.h index 44f7a47f986bae282d785998f91a5ebea8cd7c59..fd1704766c29db516d0b95a5cc721d332c7de758 100644 --- a/include/linux/resctrl_types.h +++ b/include/linux/resctrl_types.h @@ -78,6 +78,17 @@ enum resctrl_res_level { RDT_RESOURCE_L2, RDT_RESOURCE_MBA, RDT_RESOURCE_SMBA, +#ifdef CONFIG_ARM64_MPAM + RDT_RESOURCE_L3_MAX, + RDT_RESOURCE_L2_MAX, + RDT_RESOURCE_L3_MIN, + RDT_RESOURCE_L2_MIN, + RDT_RESOURCE_MB_MIN, + RDT_RESOURCE_L3_PRI, + RDT_RESOURCE_L2_PRI, + RDT_RESOURCE_MB_PRI, + RDT_RESOURCE_MB_HDL, +#endif /* Must be the last */ RDT_NUM_RESOURCES,