diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h index 37b8d7dfcfedeb091d51cf90154f234c68bd6007..829c87f928c4e39efb224db85e1c5974477899d7 100644 --- a/arch/x86/include/asm/resctrl.h +++ b/arch/x86/include/asm/resctrl.h @@ -9,6 +9,10 @@ #include #include +struct resctrl_arch_staged_config { + struct resctrl_staged_config config; +}; + /* * This value can never be a valid CLOSID, and is used when mapping a * (closid, rmid) pair to an index and back. On x86 only the RMID is @@ -94,6 +98,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)); @@ -220,6 +226,33 @@ 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) +{ + 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; +} + +static inline const char *resctrl_arch_set_feat_lab(enum resctrl_feat_type feat, + unsigned long fflags) +{ + return ""; +} #else diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c index c5c3eaea27b65be9f729863b9db4f5ecf933c940..f86c43fbacfbe5a56ec4f89a24d1303d35b37538 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); @@ -60,6 +61,14 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, return 0; } +struct resctrl_staged_config * +resctrl_arch_get_staged_config(struct rdt_domain *domain, + enum resctrl_conf_type conf_type, + enum resctrl_feat_type feat_type) +{ + return &domain->staged_config[conf_type].config; +} + int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid) { struct resctrl_staged_config *cfg; @@ -80,7 +89,7 @@ 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]; + cfg = resctrl_arch_get_staged_config(&hw_dom->d_resctrl, t, 0); if (!cfg->have_new_ctrl) continue; @@ -112,7 +121,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_devices.c b/drivers/platform/mpam/mpam_devices.c index 56bbd7290cd9001e87decff1088ec5b7e99bc089..72f0f8c2db0dade0af1c98c20f306b9534262e86 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; } @@ -577,8 +577,17 @@ 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) - 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_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); + } } /* Cache Portion partitioning */ @@ -601,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); @@ -921,6 +932,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 +1028,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; } @@ -1179,13 +1198,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); @@ -1202,6 +1221,28 @@ 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)) + cmax = cfg->ca_max; + + if (mpam_has_feature(mpam_feat_max_limit, cfg)) + limit = cfg->max_limit; + else + 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)) { + 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); @@ -1210,37 +1251,54 @@ 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); + else + mpam_write_partsel_reg(msc, MBW_MAX, bwa_fract | MPAMCFG_MBW_MAX_HARDLIM); } 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); } @@ -1850,9 +1908,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); diff --git a/drivers/platform/mpam/mpam_internal.h b/drivers/platform/mpam/mpam_internal.h index 119660a53e1631c809615961e20aa78bc69b9301..f5af8d240e592fc6effc34d6e7b9266f726d55ae 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,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, @@ -109,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<staged_config[conf_type].config[feat_type]; +} + 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) @@ -263,16 +330,15 @@ 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: - 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) @@ -297,25 +363,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; - - 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: - 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) @@ -336,7 +384,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; @@ -363,12 +411,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; @@ -376,15 +427,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); @@ -759,6 +814,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; @@ -768,6 +824,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... @@ -780,8 +837,21 @@ 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)) + max_capable[r->rid] = true; + + 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; + + 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 @@ -813,6 +883,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) @@ -821,8 +892,22 @@ 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_part, cprops)) + pbm_capable[r->rid] = true; + + 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)) + 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; @@ -908,7 +993,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; @@ -926,21 +1012,67 @@ 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) { 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; + + } 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_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; + break; + } else if (mpam_has_feature(mpam_feat_intpri_part, cprops) && + (feat == FEAT_INTPRI)) { + configured_by = mpam_feat_intpri_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; + } 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; + break; + } else if (mpam_has_feature(mpam_feat_intpri_part, cprops) && + (feat == FEAT_INTPRI)) { + configured_by = mpam_feat_intpri_part; + break; } fallthrough; default: @@ -948,27 +1080,66 @@ 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_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; + + 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; + + 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; + } switch (configured_by) { 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: /* 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_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: + return cfg->intpri; default: return -EINVAL; } } -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; struct mpam_config cfg; struct mpam_props *cprops; @@ -988,44 +1159,73 @@ 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: - /* 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; + } 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_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); + 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; + 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; + } 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); + 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; } - /* - * 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 */ @@ -1034,6 +1234,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(); @@ -1041,14 +1242,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 = resctrl_arch_get_staged_config(d, 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 62a6a67f11927f17371cad68cbbff40578faeb32..67e1faed70fdfbd49acfdcd9ae58c83cba23a13c 100644 --- a/fs/resctrl/ctrlmondata.c +++ b/fs/resctrl/ctrlmondata.c @@ -66,26 +66,108 @@ static bool bw_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 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 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 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_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]; + cfg = resctrl_arch_get_staged_config(d, conf_type, s->feat_type); if (cfg->have_new_ctrl) { rdt_last_cmd_printf("Duplicate domain %d\n", d->id); return -EINVAL; } - if (!bw_validate(data->buf, &bw_val, r)) - return -EINVAL; + if (s->feat_type == FEAT_INTPRI) { + if (!prio_validate(data->buf, &bw_val, r)) + return -EINVAL; - if (is_mba_sc(r)) { - d->mbps_val[closid] = bw_val; - return 0; + } 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)) + return -EINVAL; + + 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; @@ -94,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: @@ -153,7 +257,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 = resctrl_arch_get_staged_config(d, 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 +307,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 +325,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 +361,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 = resctrl_arch_get_staged_config(d, t, f); /* * In pseudo-locking setup mode and just * parsed a valid CBM that should be @@ -373,10 +479,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 +499,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 7d824dc8fa907078b7797bd4408527624fc35e1a..77f4818e03af7b29be6429fa3ef70cb89b02f072 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 1ade368e26315e335ad172579886e1ed2860743a..77d43846b31703a07f8789ed0d39bc94c0e7b9db 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; @@ -1039,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: @@ -1268,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) { @@ -1318,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); } /** @@ -1353,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; @@ -1486,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; @@ -1522,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) { @@ -1535,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; @@ -2150,6 +2162,20 @@ 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; + + /* + * Only CPBM and MB MAX are supported to create partition + * information folders under the resctrl/info. + */ + if (r->fflags & RFTYPE_RES_CACHE) { + if (s->feat_type != FEAT_PBM) + continue; + + } else if (r->fflags & RFTYPE_RES_MB) { + if (s->feat_type != FEAT_MAX) + continue; + } + fflags = r->fflags | RFTYPE_CTRL_INFO; ret = rdtgroup_mkdir_info_resdir(s, s->name, fflags); if (ret) @@ -2400,22 +2426,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"; @@ -2426,9 +2447,25 @@ 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%s", + r->name, suffix, + resctrl_arch_set_feat_lab(feat, r->fflags)); if (ret >= sizeof(s->name)) { kfree(s); return -EINVAL; @@ -2461,29 +2498,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; } @@ -2524,10 +2565,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 +2575,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, @@ -2576,7 +2615,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); @@ -2595,9 +2634,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 +2846,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()) @@ -3052,6 +3093,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; @@ -3060,7 +3102,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 = resctrl_arch_get_staged_config(d, t, feat); cfg->have_new_ctrl = false; cfg->new_ctrl = r->cache.shareable_bits; used_b = r->cache.shareable_bits; @@ -3081,11 +3123,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; @@ -3151,7 +3195,7 @@ static void rdtgroup_init_mba(struct rdt_resource *r, u32 closid) continue; } - cfg = &d->staged_config[CDP_NONE]; + cfg = resctrl_arch_get_staged_config(d, CDP_NONE, FEAT_MAX); cfg->new_ctrl = r->default_ctrl; cfg->have_new_ctrl = true; } @@ -3174,9 +3218,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); @@ -3796,7 +3842,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 +3913,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 +3974,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 d70e4e726fe65637ebc760297f4c19b076f48d59..d8782452a46fd31aae6050ec2243d38b904f02c1 100644 --- a/include/linux/arm_mpam.h +++ b/include/linux/arm_mpam.h @@ -31,6 +31,10 @@ enum mpam_class_types { MPAM_CLASS_UNKNOWN, /* Everything else, e.g. SMMU */ }; +struct resctrl_arch_staged_config { + struct resctrl_staged_config config[FEAT_NUM_TYPES]; +}; + #ifdef CONFIG_ACPI_MPAM /* Parse the ACPI description of resources entries for this MSC. */ int acpi_mpam_parse_resources(struct mpam_msc *msc, @@ -66,12 +70,19 @@ 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); + +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); 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); diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index edc7264a8369bdd525d86ded503aef2578c9f189..fb5d0da4168dbc01c2652c9d802dba73887cedc4 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -78,16 +78,6 @@ struct pseudo_lock_region { struct list_head pm_reqs; }; -/** - * struct resctrl_staged_config - parsed configuration to be applied - * @new_ctrl: new ctrl value to be loaded - * @have_new_ctrl: whether the user provided new_ctrl is valid - */ -struct resctrl_staged_config { - u32 new_ctrl; - bool have_new_ctrl; -}; - /** * struct rdt_domain - group of CPUs sharing a resctrl resource * @list: all instances of this resource @@ -118,7 +108,9 @@ 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]; +#ifdef CONFIG_ARCH_HAS_CPU_RESCTRL + struct resctrl_arch_staged_config staged_config[CDP_NUM_TYPES]; +#endif u32 *mbps_val; }; @@ -140,6 +132,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 +168,7 @@ struct resctrl_membw { enum membw_throttle_mode throttle_mode; bool mba_sc; u32 *mb_map; + u32 intpri_wd; }; /** @@ -220,6 +214,11 @@ struct rdt_resource { */ struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l); +struct resctrl_staged_config * +resctrl_arch_get_staged_config(struct rdt_domain *domain, + enum resctrl_conf_type conf_type, + enum resctrl_feat_type feat_type); + /** * struct resctrl_schema - configuration abilities of a resource presented to * user-space @@ -234,8 +233,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 +293,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 +331,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 44f7a47f986bae282d785998f91a5ebea8cd7c59..ed17e672690d2d2995cf7b6b1f9005749bbd7dd4 100644 --- a/include/linux/resctrl_types.h +++ b/include/linux/resctrl_types.h @@ -73,6 +73,16 @@ enum resctrl_conf_type { CDP_DATA, }; +enum resctrl_feat_type { + FEAT_PBM, + FEAT_MAX, + FEAT_MIN, + FEAT_INTPRI, + FEAT_LIMIT, + + FEAT_NUM_TYPES, +}; + enum resctrl_res_level { RDT_RESOURCE_L3, RDT_RESOURCE_L2, @@ -95,4 +105,14 @@ enum resctrl_event_id { QOS_L3_MBM_LOCAL_EVENT_ID = 0x03, }; +/** + * struct resctrl_staged_config - parsed configuration to be applied + * @new_ctrl: new ctrl value to be loaded + * @have_new_ctrl: whether the user provided new_ctrl is valid + */ +struct resctrl_staged_config { + u32 new_ctrl; + bool have_new_ctrl; +}; + #endif /* __LINUX_RESCTRL_TYPES_H */