From 63c8b1231929b8aa80abc753c1c91b6b49e2c0b0 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 28 Jul 2021 17:06:14 +0000 Subject: x86/resctrl: Split struct rdt_resource resctrl is the defacto Linux ABI for SoC resource partitioning features. To support it on another architecture, it needs to be abstracted from the features provided by Intel RDT and AMD PQoS, and moved to /fs/. struct rdt_resource contains a mix of architecture private details and properties of the filesystem interface user-space uses. Start by splitting struct rdt_resource, into an architecture private 'hw' struct, which contains the common resctrl structure that would be used by any architecture. The foreach helpers are most commonly used by the filesystem code, and should return the common resctrl structure. for_each_rdt_resource() is changed to walk the common structure in its parent arch private structure. Move as much of the structure as possible into the common structure in the core code's header file. The x86 hardware accessors remain part of the architecture private code, as do num_closid, mon_scale and mbm_width. mon_scale and mbm_width are used to detect overflow of the hardware counters, and convert them from their native size to bytes. Any cross-architecture abstraction should be in terms of bytes, making these properties private. The hardware's num_closid is kept in the private structure to force the filesystem code to use a helper to access it. MPAM would return a single value for the system, regardless of the resource. Using the helper prevents this field from being confused with the version of num_closid that is being exposed to user-space (added in a later patch). After this split, filesystem code touching a 'hw' struct indicates where an abstraction is needed. Splitting this structure only moves types around, and should not lead to any change in behaviour. Signed-off-by: James Morse Signed-off-by: Borislav Petkov Reviewed-by: Jamie Iles Reviewed-by: Reinette Chatre Tested-by: Babu Moger Link: https://lkml.kernel.org/r/20210728170637.25610-2-james.morse@arm.com --- include/linux/resctrl.h | 110 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) (limited to 'include/linux/resctrl.h') diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index 9b05af9b3e28..5ccf36b7dbbf 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -2,6 +2,8 @@ #ifndef _RESCTRL_H #define _RESCTRL_H +#include +#include #include #ifdef CONFIG_PROC_CPU_RESCTRL @@ -13,4 +15,112 @@ int proc_resctrl_show(struct seq_file *m, #endif +struct rdt_domain; + +/** + * struct resctrl_cache - Cache allocation related data + * @cbm_len: Length of the cache bit mask + * @min_cbm_bits: Minimum number of consecutive bits to be set + * @cbm_idx_mult: Multiplier of CBM index + * @cbm_idx_offset: Offset of CBM index. CBM index is computed by: + * closid * cbm_idx_multi + cbm_idx_offset + * in a cache bit mask + * @shareable_bits: Bitmask of shareable resource with other + * executing entities + * @arch_has_sparse_bitmaps: True if a bitmap like f00f is valid. + * @arch_has_empty_bitmaps: True if the '0' bitmap is valid. + * @arch_has_per_cpu_cfg: True if QOS_CFG register for this cache + * level has CPU scope. + */ +struct resctrl_cache { + unsigned int cbm_len; + unsigned int min_cbm_bits; + unsigned int cbm_idx_mult; // TODO remove this + unsigned int cbm_idx_offset; // TODO remove this + unsigned int shareable_bits; + bool arch_has_sparse_bitmaps; + bool arch_has_empty_bitmaps; + bool arch_has_per_cpu_cfg; +}; + +/** + * enum membw_throttle_mode - System's memory bandwidth throttling mode + * @THREAD_THROTTLE_UNDEFINED: Not relevant to the system + * @THREAD_THROTTLE_MAX: Memory bandwidth is throttled at the core + * always using smallest bandwidth percentage + * assigned to threads, aka "max throttling" + * @THREAD_THROTTLE_PER_THREAD: Memory bandwidth is throttled at the thread + */ +enum membw_throttle_mode { + THREAD_THROTTLE_UNDEFINED = 0, + THREAD_THROTTLE_MAX, + THREAD_THROTTLE_PER_THREAD, +}; + +/** + * struct resctrl_membw - Memory bandwidth allocation related data + * @min_bw: Minimum memory bandwidth percentage user can request + * @bw_gran: Granularity at which the memory bandwidth is allocated + * @delay_linear: True if memory B/W delay is in linear scale + * @arch_needs_linear: True if we can't configure non-linear resources + * @throttle_mode: Bandwidth throttling mode when threads request + * 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 + */ +struct resctrl_membw { + u32 min_bw; + u32 bw_gran; + u32 delay_linear; + bool arch_needs_linear; + enum membw_throttle_mode throttle_mode; + bool mba_sc; + u32 *mb_map; +}; + +struct rdt_parse_data; + +/** + * struct rdt_resource - attributes of a resctrl resource + * @rid: The index of the resource + * @alloc_enabled: Is allocation enabled on this machine + * @mon_enabled: Is monitoring enabled for this feature + * @alloc_capable: Is allocation available on this machine + * @mon_capable: Is monitor feature available on this machine + * @num_rmid: Number of RMIDs available + * @cache_level: Which cache level defines scope of this resource + * @cache: Cache allocation related data + * @membw: If the component has bandwidth controls, their properties. + * @domains: All domains for this resource + * @name: Name to use in "schemata" file. + * @data_width: Character width of data when displaying + * @default_ctrl: Specifies default cache cbm or memory B/W percent. + * @format_str: Per resource format string to show domain value + * @parse_ctrlval: Per resource function pointer to parse control values + * @evt_list: List of monitoring events + * @fflags: flags to choose base and info files + */ +struct rdt_resource { + int rid; + bool alloc_enabled; + bool mon_enabled; + bool alloc_capable; + bool mon_capable; + int num_rmid; + int cache_level; + struct resctrl_cache cache; + struct resctrl_membw membw; + struct list_head domains; + char *name; + int data_width; + u32 default_ctrl; + const char *format_str; + int (*parse_ctrlval)(struct rdt_parse_data *data, + struct rdt_resource *r, + struct rdt_domain *d); + struct list_head evt_list; + unsigned long fflags; + +}; + #endif /* _RESCTRL_H */ -- cgit v1.2.3-71-gd317 From 792e0f6f789bda5e31b1dbcfcc84068da36a79b1 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 28 Jul 2021 17:06:15 +0000 Subject: x86/resctrl: Split struct rdt_domain resctrl is the defacto Linux ABI for SoC resource partitioning features. To support it on another architecture, it needs to be abstracted from the features provided by Intel RDT and AMD PQoS, and moved to /fs/. struct rdt_domain contains a mix of architecture private details and properties of the filesystem interface user-space uses. Continue by splitting struct rdt_domain, into an architecture private 'hw' struct, which contains the common resctrl structure that would be used by any architecture. The hardware values in ctrl_val and mbps_val need to be accessed via helpers to allow another architecture to convert these into a different format if necessary. After this split, filesystem code paths touching a 'hw' struct indicates where an abstraction is needed. Splitting this structure only moves types around, and should not lead to any change in behaviour. Signed-off-by: James Morse Signed-off-by: Borislav Petkov Reviewed-by: Jamie Iles Reviewed-by: Reinette Chatre Tested-by: Babu Moger Link: https://lkml.kernel.org/r/20210728170637.25610-3-james.morse@arm.com --- arch/x86/kernel/cpu/resctrl/core.c | 32 ++++++++++++++--------- arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 10 ++++--- arch/x86/kernel/cpu/resctrl/internal.h | 43 +++++++++---------------------- arch/x86/kernel/cpu/resctrl/monitor.c | 8 +++--- arch/x86/kernel/cpu/resctrl/rdtgroup.c | 29 ++++++++++++++------- include/linux/resctrl.h | 32 ++++++++++++++++++++++- 6 files changed, 94 insertions(+), 60 deletions(-) (limited to 'include/linux/resctrl.h') diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c index 942d070aa92c..10fbbc3cf40a 100644 --- a/arch/x86/kernel/cpu/resctrl/core.c +++ b/arch/x86/kernel/cpu/resctrl/core.c @@ -385,10 +385,11 @@ static void mba_wrmsr_amd(struct rdt_domain *d, struct msr_param *m, struct rdt_resource *r) { unsigned int i; + struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d); struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); for (i = m->low; i < m->high; i++) - wrmsrl(hw_res->msr_base + i, d->ctrl_val[i]); + wrmsrl(hw_res->msr_base + i, hw_dom->ctrl_val[i]); } /* @@ -410,21 +411,23 @@ mba_wrmsr_intel(struct rdt_domain *d, struct msr_param *m, struct rdt_resource *r) { unsigned int i; + struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d); struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); /* Write the delay values for mba. */ for (i = m->low; i < m->high; i++) - wrmsrl(hw_res->msr_base + i, delay_bw_map(d->ctrl_val[i], r)); + wrmsrl(hw_res->msr_base + i, delay_bw_map(hw_dom->ctrl_val[i], r)); } static void cat_wrmsr(struct rdt_domain *d, struct msr_param *m, struct rdt_resource *r) { unsigned int i; + struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d); struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); for (i = m->low; i < m->high; i++) - wrmsrl(hw_res->msr_base + cbm_idx(r, i), d->ctrl_val[i]); + wrmsrl(hw_res->msr_base + cbm_idx(r, i), hw_dom->ctrl_val[i]); } struct rdt_domain *get_domain_from_cpu(int cpu, struct rdt_resource *r) @@ -510,21 +513,22 @@ void setup_default_ctrlval(struct rdt_resource *r, u32 *dc, u32 *dm) static int domain_setup_ctrlval(struct rdt_resource *r, struct rdt_domain *d) { struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); + struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d); struct msr_param m; u32 *dc, *dm; - dc = kmalloc_array(hw_res->num_closid, sizeof(*d->ctrl_val), GFP_KERNEL); + dc = kmalloc_array(hw_res->num_closid, sizeof(*hw_dom->ctrl_val), GFP_KERNEL); if (!dc) return -ENOMEM; - dm = kmalloc_array(hw_res->num_closid, sizeof(*d->mbps_val), GFP_KERNEL); + dm = kmalloc_array(hw_res->num_closid, sizeof(*hw_dom->mbps_val), GFP_KERNEL); if (!dm) { kfree(dc); return -ENOMEM; } - d->ctrl_val = dc; - d->mbps_val = dm; + hw_dom->ctrl_val = dc; + hw_dom->mbps_val = dm; setup_default_ctrlval(r, dc, dm); m.low = 0; @@ -586,6 +590,7 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r) { int id = get_cpu_cacheinfo_id(cpu, r->cache_level); struct list_head *add_pos = NULL; + struct rdt_hw_domain *hw_dom; struct rdt_domain *d; d = rdt_find_domain(r, id, &add_pos); @@ -601,10 +606,11 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r) return; } - d = kzalloc_node(sizeof(*d), GFP_KERNEL, cpu_to_node(cpu)); - if (!d) + hw_dom = kzalloc_node(sizeof(*hw_dom), GFP_KERNEL, cpu_to_node(cpu)); + if (!hw_dom) return; + d = &hw_dom->d_resctrl; d->id = id; cpumask_set_cpu(cpu, &d->cpu_mask); @@ -633,6 +639,7 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r) static void domain_remove_cpu(int cpu, struct rdt_resource *r) { int id = get_cpu_cacheinfo_id(cpu, r->cache_level); + struct rdt_hw_domain *hw_dom; struct rdt_domain *d; d = rdt_find_domain(r, id, NULL); @@ -640,6 +647,7 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r) pr_warn("Couldn't find cache id for CPU %d\n", cpu); return; } + hw_dom = resctrl_to_arch_dom(d); cpumask_clear_cpu(cpu, &d->cpu_mask); if (cpumask_empty(&d->cpu_mask)) { @@ -672,12 +680,12 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r) if (d->plr) d->plr->d = NULL; - kfree(d->ctrl_val); - kfree(d->mbps_val); + kfree(hw_dom->ctrl_val); + kfree(hw_dom->mbps_val); bitmap_free(d->rmid_busy_llc); kfree(d->mbm_total); kfree(d->mbm_local); - kfree(d); + kfree(hw_dom); return; } diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c index 3f0c33d5b658..08eef539cb6c 100644 --- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c +++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c @@ -238,6 +238,7 @@ next: int update_domains(struct rdt_resource *r, int closid) { + struct rdt_hw_domain *hw_dom; struct msr_param msr_param; cpumask_var_t cpu_mask; struct rdt_domain *d; @@ -254,7 +255,8 @@ int update_domains(struct rdt_resource *r, int closid) mba_sc = is_mba_sc(r); list_for_each_entry(d, &r->domains, list) { - dc = !mba_sc ? d->ctrl_val : d->mbps_val; + hw_dom = resctrl_to_arch_dom(d); + dc = !mba_sc ? hw_dom->ctrl_val : hw_dom->mbps_val; if (d->have_new_ctrl && d->new_ctrl != dc[closid]) { cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask); dc[closid] = d->new_ctrl; @@ -375,17 +377,19 @@ out: static void show_doms(struct seq_file *s, struct rdt_resource *r, int closid) { + struct rdt_hw_domain *hw_dom; struct rdt_domain *dom; bool sep = false; u32 ctrl_val; seq_printf(s, "%*s:", max_name_width, r->name); list_for_each_entry(dom, &r->domains, list) { + hw_dom = resctrl_to_arch_dom(dom); if (sep) seq_puts(s, ";"); - ctrl_val = (!is_mba_sc(r) ? dom->ctrl_val[closid] : - dom->mbps_val[closid]); + ctrl_val = (!is_mba_sc(r) ? hw_dom->ctrl_val[closid] : + hw_dom->mbps_val[closid]); seq_printf(s, r->format_str, dom->id, max_data_width, ctrl_val); sep = true; diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h index caf9248339d5..02c85c795113 100644 --- a/arch/x86/kernel/cpu/resctrl/internal.h +++ b/arch/x86/kernel/cpu/resctrl/internal.h @@ -304,44 +304,25 @@ struct mbm_state { }; /** - * struct rdt_domain - group of cpus sharing an RDT resource - * @list: all instances of this resource - * @id: unique id for this instance - * @cpu_mask: which cpus share this resource - * @rmid_busy_llc: - * bitmap of which limbo RMIDs are above threshold - * @mbm_total: saved state for MBM total bandwidth - * @mbm_local: saved state for MBM local bandwidth - * @mbm_over: worker to periodically read MBM h/w counters - * @cqm_limbo: worker to periodically read CQM h/w counters - * @mbm_work_cpu: - * worker cpu for MBM h/w counters - * @cqm_work_cpu: - * worker cpu for CQM h/w counters + * struct rdt_hw_domain - Arch private attributes of a set of CPUs that share + * a resource + * @d_resctrl: Properties exposed to the resctrl file system * @ctrl_val: array of cache or mem ctrl values (indexed by CLOSID) * @mbps_val: When mba_sc is enabled, this holds the bandwidth in MBps - * @new_ctrl: new ctrl value to be loaded - * @have_new_ctrl: did user provide new_ctrl for this domain - * @plr: pseudo-locked region (if any) associated with domain + * + * Members of this structure are accessed via helpers that provide abstraction. */ -struct rdt_domain { - struct list_head list; - int id; - struct cpumask cpu_mask; - unsigned long *rmid_busy_llc; - struct mbm_state *mbm_total; - struct mbm_state *mbm_local; - struct delayed_work mbm_over; - struct delayed_work cqm_limbo; - int mbm_work_cpu; - int cqm_work_cpu; +struct rdt_hw_domain { + struct rdt_domain d_resctrl; u32 *ctrl_val; u32 *mbps_val; - u32 new_ctrl; - bool have_new_ctrl; - struct pseudo_lock_region *plr; }; +static inline struct rdt_hw_domain *resctrl_to_arch_dom(struct rdt_domain *r) +{ + return container_of(r, struct rdt_hw_domain, d_resctrl); +} + /** * struct msr_param - set a range of MSRs from a domain * @res: The resource to use diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c index 5daf5847ff4c..26a094870c16 100644 --- a/arch/x86/kernel/cpu/resctrl/monitor.c +++ b/arch/x86/kernel/cpu/resctrl/monitor.c @@ -418,6 +418,7 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm) u32 closid, rmid, cur_msr, cur_msr_val, new_msr_val; struct mbm_state *pmbm_data, *cmbm_data; struct rdt_hw_resource *hw_r_mba; + struct rdt_hw_domain *hw_dom_mba; u32 cur_bw, delta_bw, user_bw; struct rdt_resource *r_mba; struct rdt_domain *dom_mba; @@ -438,11 +439,12 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm) pr_warn_once("Failure to get domain for MBA update\n"); return; } + hw_dom_mba = resctrl_to_arch_dom(dom_mba); cur_bw = pmbm_data->prev_bw; - user_bw = dom_mba->mbps_val[closid]; + user_bw = hw_dom_mba->mbps_val[closid]; delta_bw = pmbm_data->delta_bw; - cur_msr_val = dom_mba->ctrl_val[closid]; + cur_msr_val = hw_dom_mba->ctrl_val[closid]; /* * For Ctrl groups read data from child monitor groups. @@ -479,7 +481,7 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm) cur_msr = hw_r_mba->msr_base + closid; wrmsrl(cur_msr, delay_bw_map(new_msr_val, r_mba)); - dom_mba->ctrl_val[closid] = new_msr_val; + hw_dom_mba->ctrl_val[closid] = new_msr_val; /* * Delta values are updated dynamically package wise for each diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index d49a00754d98..d190a21845ce 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -915,7 +915,7 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of, list_for_each_entry(dom, &r->domains, list) { if (sep) seq_putc(seq, ';'); - ctrl = dom->ctrl_val; + ctrl = resctrl_to_arch_dom(dom)->ctrl_val; sw_shareable = 0; exclusive = 0; seq_printf(seq, "%d=", dom->id); @@ -1193,7 +1193,7 @@ static bool __rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_domain *d } /* Check for overlap with other resource groups */ - ctrl = d->ctrl_val; + ctrl = resctrl_to_arch_dom(d)->ctrl_val; for (i = 0; i < closids_supported(); i++, ctrl++) { ctrl_b = *ctrl; mode = rdtgroup_mode_by_closid(i); @@ -1262,6 +1262,7 @@ bool rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_domain *d, */ static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp) { + struct rdt_hw_domain *hw_dom; int closid = rdtgrp->closid; struct rdt_resource *r; bool has_cache = false; @@ -1272,7 +1273,8 @@ static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp) continue; has_cache = true; list_for_each_entry(d, &r->domains, list) { - if (rdtgroup_cbm_overlaps(r, d, d->ctrl_val[closid], + hw_dom = resctrl_to_arch_dom(d); + if (rdtgroup_cbm_overlaps(r, d, hw_dom->ctrl_val[closid], rdtgrp->closid, false)) { rdt_last_cmd_puts("Schemata overlaps\n"); return false; @@ -1404,6 +1406,7 @@ unsigned int rdtgroup_cbm_to_size(struct rdt_resource *r, static int rdtgroup_size_show(struct kernfs_open_file *of, struct seq_file *s, void *v) { + struct rdt_hw_domain *hw_dom; struct rdtgroup *rdtgrp; struct rdt_resource *r; struct rdt_domain *d; @@ -1438,14 +1441,15 @@ static int rdtgroup_size_show(struct kernfs_open_file *of, sep = false; seq_printf(s, "%*s:", max_name_width, r->name); list_for_each_entry(d, &r->domains, list) { + hw_dom = resctrl_to_arch_dom(d); if (sep) seq_putc(s, ';'); if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) { size = 0; } else { ctrl = (!is_mba_sc(r) ? - d->ctrl_val[rdtgrp->closid] : - d->mbps_val[rdtgrp->closid]); + hw_dom->ctrl_val[rdtgrp->closid] : + hw_dom->mbps_val[rdtgrp->closid]); if (r->rid == RDT_RESOURCE_MBA) size = ctrl; else @@ -1940,6 +1944,7 @@ void rdt_domain_reconfigure_cdp(struct rdt_resource *r) static int set_mba_sc(bool mba_sc) { struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_MBA].r_resctrl; + struct rdt_hw_domain *hw_dom; struct rdt_domain *d; if (!is_mbm_enabled() || !is_mba_linear() || @@ -1947,8 +1952,10 @@ static int set_mba_sc(bool mba_sc) return -EINVAL; r->membw.mba_sc = mba_sc; - list_for_each_entry(d, &r->domains, list) - setup_default_ctrlval(r, d->ctrl_val, d->mbps_val); + list_for_each_entry(d, &r->domains, list) { + hw_dom = resctrl_to_arch_dom(d); + setup_default_ctrlval(r, hw_dom->ctrl_val, hw_dom->mbps_val); + } return 0; } @@ -2265,6 +2272,7 @@ static int rdt_init_fs_context(struct fs_context *fc) static int reset_all_ctrls(struct rdt_resource *r) { struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); + struct rdt_hw_domain *hw_dom; struct msr_param msr_param; cpumask_var_t cpu_mask; struct rdt_domain *d; @@ -2283,10 +2291,11 @@ static int reset_all_ctrls(struct rdt_resource *r) * from each domain to update the MSRs below. */ list_for_each_entry(d, &r->domains, list) { + hw_dom = resctrl_to_arch_dom(d); cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask); for (i = 0; i < hw_res->num_closid; i++) - d->ctrl_val[i] = r->default_ctrl; + hw_dom->ctrl_val[i] = r->default_ctrl; } cpu = get_cpu(); /* Update CBM on this cpu if it's in cpu_mask. */ @@ -2665,7 +2674,7 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct rdt_resource *r, d->have_new_ctrl = false; d->new_ctrl = r->cache.shareable_bits; used_b = r->cache.shareable_bits; - ctrl = d->ctrl_val; + ctrl = resctrl_to_arch_dom(d)->ctrl_val; for (i = 0; i < closids_supported(); i++, ctrl++) { if (closid_allocated(i) && i != closid) { mode = rdtgroup_mode_by_closid(i); @@ -2682,7 +2691,7 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct rdt_resource *r, * with an exclusive group. */ if (d_cdp) - peer_ctl = d_cdp->ctrl_val[i]; + peer_ctl = resctrl_to_arch_dom(d_cdp)->ctrl_val[i]; else peer_ctl = 0; used_b |= *ctrl | peer_ctl; diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index 5ccf36b7dbbf..a4c89dafd7fa 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -15,7 +15,37 @@ int proc_resctrl_show(struct seq_file *m, #endif -struct rdt_domain; +/** + * struct rdt_domain - group of CPUs sharing a resctrl resource + * @list: all instances of this resource + * @id: unique id for this instance + * @cpu_mask: which CPUs share this resource + * @new_ctrl: new ctrl value to be loaded + * @have_new_ctrl: did user provide new_ctrl for this domain + * @rmid_busy_llc: bitmap of which limbo RMIDs are above threshold + * @mbm_total: saved state for MBM total bandwidth + * @mbm_local: saved state for MBM local bandwidth + * @mbm_over: worker to periodically read MBM h/w counters + * @cqm_limbo: worker to periodically read CQM h/w counters + * @mbm_work_cpu: worker CPU for MBM h/w counters + * @cqm_work_cpu: worker CPU for CQM h/w counters + * @plr: pseudo-locked region (if any) associated with domain + */ +struct rdt_domain { + struct list_head list; + int id; + struct cpumask cpu_mask; + u32 new_ctrl; + bool have_new_ctrl; + unsigned long *rmid_busy_llc; + struct mbm_state *mbm_total; + struct mbm_state *mbm_local; + struct delayed_work mbm_over; + struct delayed_work cqm_limbo; + int mbm_work_cpu; + int cqm_work_cpu; + struct pseudo_lock_region *plr; +}; /** * struct resctrl_cache - Cache allocation related data -- cgit v1.2.3-71-gd317 From cdb9ebc9178461c27d618bb1238e851da17271de Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 28 Jul 2021 17:06:16 +0000 Subject: x86/resctrl: Add a separate schema list for resctrl Resctrl exposes schemata to user-space, which allow the control values to be specified for a group of tasks. User-visible properties of the interface, (such as the schemata names and how the values are parsed) are rooted in a struct provided by the architecture code. (struct rdt_hw_resource). Once a second architecture uses resctrl, this would allow user-visible properties to diverge between architectures. These properties should come from the resctrl code that will be common to all architectures. Resctrl has no per-schema structure, only struct rdt_{hw_,}resource. Create a struct resctrl_schema to hold the rdt_resource. Before a second architecture can be supported, this structure will also need to hold the schema name visible to user-space and the type of configuration values for resctrl. Signed-off-by: James Morse Signed-off-by: Borislav Petkov Reviewed-by: Jamie Iles Reviewed-by: Reinette Chatre Tested-by: Babu Moger Link: https://lkml.kernel.org/r/20210728170637.25610-4-james.morse@arm.com --- arch/x86/kernel/cpu/resctrl/internal.h | 1 + arch/x86/kernel/cpu/resctrl/rdtgroup.c | 43 +++++++++++++++++++++++++++++++++- include/linux/resctrl.h | 11 +++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) (limited to 'include/linux/resctrl.h') diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h index 02c85c795113..2cc4b37bc128 100644 --- a/arch/x86/kernel/cpu/resctrl/internal.h +++ b/arch/x86/kernel/cpu/resctrl/internal.h @@ -110,6 +110,7 @@ extern unsigned int resctrl_cqm_threshold; extern bool rdt_alloc_capable; extern bool rdt_mon_capable; extern unsigned int rdt_mon_features; +extern struct list_head resctrl_schema_all; enum rdt_group_type { RDTCTRL_GROUP = 0, diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index d190a21845ce..3e0b6aa94571 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -39,6 +39,9 @@ static struct kernfs_root *rdt_root; struct rdtgroup rdtgroup_default; LIST_HEAD(rdt_all_groups); +/* list of entries for the schemata file */ +LIST_HEAD(resctrl_schema_all); + /* Kernel fs node for "info" directory under root */ static struct kernfs_node *kn_info; @@ -2109,6 +2112,35 @@ static int rdt_enable_ctx(struct rdt_fs_context *ctx) return ret; } +static int schemata_list_create(void) +{ + struct resctrl_schema *s; + struct rdt_resource *r; + + for_each_alloc_enabled_rdt_resource(r) { + s = kzalloc(sizeof(*s), GFP_KERNEL); + if (!s) + return -ENOMEM; + + s->res = r; + + INIT_LIST_HEAD(&s->list); + list_add(&s->list, &resctrl_schema_all); + } + + return 0; +} + +static void schemata_list_destroy(void) +{ + struct resctrl_schema *s, *tmp; + + list_for_each_entry_safe(s, tmp, &resctrl_schema_all, list) { + list_del(&s->list); + kfree(s); + } +} + static int rdt_get_tree(struct fs_context *fc) { struct rdt_fs_context *ctx = rdt_fc2context(fc); @@ -2130,11 +2162,17 @@ static int rdt_get_tree(struct fs_context *fc) if (ret < 0) goto out_cdp; + ret = schemata_list_create(); + if (ret) { + schemata_list_destroy(); + goto out_mba; + } + closid_init(); ret = rdtgroup_create_info_dir(rdtgroup_default.kn); if (ret < 0) - goto out_mba; + goto out_schemata_free; if (rdt_mon_capable) { ret = mongroup_create_dir(rdtgroup_default.kn, @@ -2184,6 +2222,8 @@ out_mongrp: kernfs_remove(kn_mongrp); out_info: kernfs_remove(kn_info); +out_schemata_free: + schemata_list_destroy(); out_mba: if (ctx->enable_mba_mbps) set_mba_sc(false); @@ -2425,6 +2465,7 @@ static void rdt_kill_sb(struct super_block *sb) rmdir_all_sub(); rdt_pseudo_lock_release(); rdtgroup_default.mode = RDT_MODE_SHAREABLE; + schemata_list_destroy(); static_branch_disable_cpuslocked(&rdt_alloc_enable_key); static_branch_disable_cpuslocked(&rdt_mon_enable_key); static_branch_disable_cpuslocked(&rdt_enable_key); diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index a4c89dafd7fa..5a21d483da6a 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -153,4 +153,15 @@ struct rdt_resource { }; +/** + * struct resctrl_schema - configuration abilities of a resource presented to + * user-space + * @list: Member of resctrl_schema_all. + * @res: The resource structure exported by the architecture to describe + * the hardware that is configured by this schema. + */ +struct resctrl_schema { + struct list_head list; + struct rdt_resource *res; +}; #endif /* _RESCTRL_H */ -- cgit v1.2.3-71-gd317 From 208ab16847c562c0d53a0266b6628ef6cb5ab5c2 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 28 Jul 2021 17:06:18 +0000 Subject: x86/resctrl: Label the resources with their configuration type The names of resources are used for the schema name presented to user-space. The name used is rooted in a structure provided by the architecture code because the names are different when CDP is enabled. x86 implements this by swapping between two sets of resource structures based on their alloc_enabled flag. The type of configuration in-use is encoded in the name (and cbm_idx_offset). Once the CDP behaviour is moved into the parts of resctrl that will move to /fs/, there will be two struct resctrl_schema for one struct rdt_resource. The schema describes the type of configuration being applied to the resource. The name of the schema should be generated by resctrl, base on the type of configuration. To do this struct resctrl_schema needs to store the type of configuration in use for a schema. Create an enum resctrl_conf_type describing the options, and add it to struct resctrl_schema. The underlying resources are still separate, as cbm_idx_offset is still in use. Temporarily label all the entries in rdt_resources_all[] and copy that value to struct resctrl_schema. Copying the value ensures there is no mismatch while the filesystem parts of resctrl are modified to use the schema. Once the resources are merged, the filesystem code can assign this value based on the schema being created. Signed-off-by: James Morse Signed-off-by: Borislav Petkov Reviewed-by: Jamie Iles Reviewed-by: Reinette Chatre Tested-by: Babu Moger Link: https://lkml.kernel.org/r/20210728170637.25610-6-james.morse@arm.com --- arch/x86/kernel/cpu/resctrl/core.c | 7 +++++++ arch/x86/kernel/cpu/resctrl/internal.h | 2 ++ arch/x86/kernel/cpu/resctrl/rdtgroup.c | 1 + include/linux/resctrl.h | 14 ++++++++++++++ 4 files changed, 24 insertions(+) (limited to 'include/linux/resctrl.h') diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c index 10fbbc3cf40a..c5b5c7227837 100644 --- a/arch/x86/kernel/cpu/resctrl/core.c +++ b/arch/x86/kernel/cpu/resctrl/core.c @@ -62,6 +62,7 @@ mba_wrmsr_amd(struct rdt_domain *d, struct msr_param *m, struct rdt_hw_resource rdt_resources_all[] = { [RDT_RESOURCE_L3] = { + .conf_type = CDP_NONE, .r_resctrl = { .rid = RDT_RESOURCE_L3, .name = "L3", @@ -81,6 +82,7 @@ struct rdt_hw_resource rdt_resources_all[] = { }, [RDT_RESOURCE_L3DATA] = { + .conf_type = CDP_DATA, .r_resctrl = { .rid = RDT_RESOURCE_L3DATA, .name = "L3DATA", @@ -100,6 +102,7 @@ struct rdt_hw_resource rdt_resources_all[] = { }, [RDT_RESOURCE_L3CODE] = { + .conf_type = CDP_CODE, .r_resctrl = { .rid = RDT_RESOURCE_L3CODE, .name = "L3CODE", @@ -119,6 +122,7 @@ struct rdt_hw_resource rdt_resources_all[] = { }, [RDT_RESOURCE_L2] = { + .conf_type = CDP_NONE, .r_resctrl = { .rid = RDT_RESOURCE_L2, .name = "L2", @@ -138,6 +142,7 @@ struct rdt_hw_resource rdt_resources_all[] = { }, [RDT_RESOURCE_L2DATA] = { + .conf_type = CDP_DATA, .r_resctrl = { .rid = RDT_RESOURCE_L2DATA, .name = "L2DATA", @@ -157,6 +162,7 @@ struct rdt_hw_resource rdt_resources_all[] = { }, [RDT_RESOURCE_L2CODE] = { + .conf_type = CDP_CODE, .r_resctrl = { .rid = RDT_RESOURCE_L2CODE, .name = "L2CODE", @@ -176,6 +182,7 @@ struct rdt_hw_resource rdt_resources_all[] = { }, [RDT_RESOURCE_MBA] = { + .conf_type = CDP_NONE, .r_resctrl = { .rid = RDT_RESOURCE_MBA, .name = "MB", diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h index 2cc4b37bc128..5e4a0a8d743c 100644 --- a/arch/x86/kernel/cpu/resctrl/internal.h +++ b/arch/x86/kernel/cpu/resctrl/internal.h @@ -369,6 +369,7 @@ struct rdt_parse_data { /** * struct rdt_hw_resource - arch private attributes of a resctrl resource + * @conf_type: The type that should be used when configuring. temporary * @r_resctrl: Attributes of the resource used directly by resctrl. * @num_closid: Maximum number of closid this hardware can support. * @msr_base: Base MSR address for CBMs @@ -381,6 +382,7 @@ struct rdt_parse_data { * msr_update and msr_base. */ struct rdt_hw_resource { + enum resctrl_conf_type conf_type; struct rdt_resource r_resctrl; int num_closid; unsigned int msr_base; diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index 1fc40dbce85d..d7fd0712e76c 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -2135,6 +2135,7 @@ static int schemata_list_create(void) return -ENOMEM; s->res = r; + s->conf_type = resctrl_to_arch_res(r)->conf_type; INIT_LIST_HEAD(&s->list); list_add(&s->list, &resctrl_schema_all); diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index 5a21d483da6a..095ed48168d7 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -15,6 +15,18 @@ int proc_resctrl_show(struct seq_file *m, #endif +/** + * enum resctrl_conf_type - The type of configuration. + * @CDP_NONE: No prioritisation, both code and data are controlled or monitored. + * @CDP_CODE: Configuration applies to instruction fetches. + * @CDP_DATA: Configuration applies to reads and writes. + */ +enum resctrl_conf_type { + CDP_NONE, + CDP_CODE, + CDP_DATA, +}; + /** * struct rdt_domain - group of CPUs sharing a resctrl resource * @list: all instances of this resource @@ -157,11 +169,13 @@ struct rdt_resource { * struct resctrl_schema - configuration abilities of a resource presented to * user-space * @list: Member of resctrl_schema_all. + * @conf_type: Whether this schema is specific to code/data. * @res: The resource structure exported by the architecture to describe * the hardware that is configured by this schema. */ struct resctrl_schema { struct list_head list; + enum resctrl_conf_type conf_type; struct rdt_resource *res; }; #endif /* _RESCTRL_H */ -- cgit v1.2.3-71-gd317 From 3183e87c1b797caaeb208b01c99bea8140273a16 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 28 Jul 2021 17:06:20 +0000 Subject: x86/resctrl: Store the effective num_closid in the schema Struct resctrl_schema holds properties that vary with the style of configuration that resctrl applies to a resource. There are already two values for the hardware's num_closid, depending on whether the architecture presents the L3 or L3CODE/L3DATA resources. As the way CDP changes the number of control groups that resctrl can create is part of the user-space interface, it should be managed by the filesystem parts of resctrl. This allows the architecture code to only describe the value the hardware supports. Add num_closid to resctrl_schema. This is the value seen by the filesystem, which may be different to the maximum value described by the arch code when CDP is enabled. These functions operate on the num_closid value that is exposed to user-space: * rdtgroup_parse_resource() * rdtgroup_schemata_show() * rdt_num_closids_show() * closid_init() Change them to use the schema value instead. schemata_list_create() sets this value, and reaches into the architecture-specific structure to get the value. This will eventually be replaced with a helper. Signed-off-by: James Morse Signed-off-by: Borislav Petkov Reviewed-by: Jamie Iles Reviewed-by: Reinette Chatre Tested-by: Babu Moger Link: https://lkml.kernel.org/r/20210728170637.25610-8-james.morse@arm.com --- arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 9 +++------ arch/x86/kernel/cpu/resctrl/rdtgroup.c | 13 ++++--------- include/linux/resctrl.h | 4 ++++ 3 files changed, 11 insertions(+), 15 deletions(-) (limited to 'include/linux/resctrl.h') diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c index 405b99d31ef9..d10fddaef5f4 100644 --- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c +++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c @@ -286,14 +286,12 @@ done: static int rdtgroup_parse_resource(char *resname, char *tok, struct rdtgroup *rdtgrp) { - struct rdt_hw_resource *hw_res; struct resctrl_schema *s; struct rdt_resource *r; list_for_each_entry(s, &resctrl_schema_all, list) { r = s->res; - hw_res = resctrl_to_arch_res(s->res); - if (!strcmp(resname, r->name) && rdtgrp->closid < hw_res->num_closid) + if (!strcmp(resname, r->name) && rdtgrp->closid < s->num_closid) return parse_line(tok, r, rdtgrp); } rdt_last_cmd_printf("Unknown or unsupported resource name '%s'\n", resname); @@ -404,7 +402,6 @@ static void show_doms(struct seq_file *s, struct rdt_resource *r, int closid) int rdtgroup_schemata_show(struct kernfs_open_file *of, struct seq_file *s, void *v) { - struct rdt_hw_resource *hw_res; struct resctrl_schema *schema; struct rdtgroup *rdtgrp; struct rdt_resource *r; @@ -432,8 +429,8 @@ int rdtgroup_schemata_show(struct kernfs_open_file *of, } else { closid = rdtgrp->closid; list_for_each_entry(schema, &resctrl_schema_all, list) { - hw_res = resctrl_to_arch_res(schema->res); - if (closid < hw_res->num_closid) + r = schema->res; + if (closid < schema->num_closid) show_doms(s, r, closid); } } diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index 7502b7de3916..2f29b7d7d602 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -103,15 +103,12 @@ int closids_supported(void) static void closid_init(void) { - struct rdt_hw_resource *hw_res; struct resctrl_schema *s; int rdt_min_closid = 32; /* Compute rdt_min_closid across all resources */ - list_for_each_entry(s, &resctrl_schema_all, list) { - hw_res = resctrl_to_arch_res(s->res); - rdt_min_closid = min(rdt_min_closid, hw_res->num_closid); - } + list_for_each_entry(s, &resctrl_schema_all, list) + rdt_min_closid = min(rdt_min_closid, s->num_closid); closid_free_map = BIT_MASK(rdt_min_closid) - 1; @@ -849,11 +846,8 @@ static int rdt_num_closids_show(struct kernfs_open_file *of, struct seq_file *seq, void *v) { struct resctrl_schema *s = of->kn->parent->priv; - struct rdt_resource *r = s->res; - struct rdt_hw_resource *hw_res; - hw_res = resctrl_to_arch_res(r); - seq_printf(seq, "%d\n", hw_res->num_closid); + seq_printf(seq, "%u\n", s->num_closid); return 0; } @@ -2140,6 +2134,7 @@ static int schemata_list_create(void) s->res = r; s->conf_type = resctrl_to_arch_res(r)->conf_type; + s->num_closid = resctrl_to_arch_res(r)->num_closid; INIT_LIST_HEAD(&s->list); list_add(&s->list, &resctrl_schema_all); diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index 095ed48168d7..59d0fa78bb69 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -172,10 +172,14 @@ struct rdt_resource { * @conf_type: Whether this schema is specific to code/data. * @res: The resource structure exported by the architecture to describe * the hardware that is configured by this schema. + * @num_closid: The number of closid that can be used with this schema. When + * features like CDP are enabled, this will be lower than the + * hardware supports for the resource. */ struct resctrl_schema { struct list_head list; enum resctrl_conf_type conf_type; struct rdt_resource *res; + int num_closid; }; #endif /* _RESCTRL_H */ -- cgit v1.2.3-71-gd317 From eb6f3187694158ca36e50083e861531488d5c1b1 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 28 Jul 2021 17:06:21 +0000 Subject: x86/resctrl: Add resctrl_arch_get_num_closid() To initialise struct resctrl_schema's num_closid, schemata_list_create() reaches into the architectures private structure to retrieve num_closid from the struct rdt_hw_resource. The 'half the closids' behaviour should be part of the filesystem parts of resctrl that are the same on any architecture. struct resctrl_schema's num_closid should include any correction for CDP. Having two properties called num_closid is likely to be confusing when they have different values. Add a helper to read the resource's num_closid from the arch code. This should return the number of closid that the resource supports, regardless of whether CDP is in use. Once the CDP resources are merged, schemata_list_create() can apply the correction itself. Using a type with an obvious size for the arch helper means changing the type of num_closid to u32, which matches the type already used by struct rdtgroup. reset_all_ctrls() does not use resctrl_arch_get_num_closid(), even though it sets up a structure for modifying the hardware. This function will be part of the architecture code, the maximum closid should be the maximum value the hardware has, regardless of the way resctrl is using it. All the uses of num_closid in core.c are naturally part of the architecture specific code. Signed-off-by: James Morse Signed-off-by: Borislav Petkov Reviewed-by: Jamie Iles Reviewed-by: Reinette Chatre Tested-by: Babu Moger Link: https://lkml.kernel.org/r/20210728170637.25610-9-james.morse@arm.com --- arch/x86/kernel/cpu/resctrl/core.c | 5 +++++ arch/x86/kernel/cpu/resctrl/internal.h | 8 ++++++-- arch/x86/kernel/cpu/resctrl/rdtgroup.c | 4 ++-- include/linux/resctrl.h | 6 +++++- 4 files changed, 18 insertions(+), 5 deletions(-) (limited to 'include/linux/resctrl.h') diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c index c5b5c7227837..26e8d20cd072 100644 --- a/arch/x86/kernel/cpu/resctrl/core.c +++ b/arch/x86/kernel/cpu/resctrl/core.c @@ -450,6 +450,11 @@ struct rdt_domain *get_domain_from_cpu(int cpu, struct rdt_resource *r) return NULL; } +u32 resctrl_arch_get_num_closid(struct rdt_resource *r) +{ + return resctrl_to_arch_res(r)->num_closid; +} + void rdt_ctrl_update(void *arg) { struct msr_param *m = arg; diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h index 5e4a0a8d743c..c4bc5fae5a29 100644 --- a/arch/x86/kernel/cpu/resctrl/internal.h +++ b/arch/x86/kernel/cpu/resctrl/internal.h @@ -371,7 +371,11 @@ struct rdt_parse_data { * struct rdt_hw_resource - arch private attributes of a resctrl resource * @conf_type: The type that should be used when configuring. temporary * @r_resctrl: Attributes of the resource used directly by resctrl. - * @num_closid: Maximum number of closid this hardware can support. + * @num_closid: Maximum number of closid this hardware can support, + * regardless of CDP. This is exposed via + * resctrl_arch_get_num_closid() to avoid confusion + * with struct resctrl_schema's property of the same name, + * which has been corrected for features like CDP. * @msr_base: Base MSR address for CBMs * @msr_update: Function pointer to update QOS MSRs * @mon_scale: cqm counter * mon_scale = occupancy in bytes @@ -384,7 +388,7 @@ struct rdt_parse_data { struct rdt_hw_resource { enum resctrl_conf_type conf_type; struct rdt_resource r_resctrl; - int num_closid; + u32 num_closid; unsigned int msr_base; void (*msr_update) (struct rdt_domain *d, struct msr_param *m, struct rdt_resource *r); diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index 2f29b7d7d602..09ffe9a4a32b 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -104,7 +104,7 @@ int closids_supported(void) static void closid_init(void) { struct resctrl_schema *s; - int rdt_min_closid = 32; + u32 rdt_min_closid = 32; /* Compute rdt_min_closid across all resources */ list_for_each_entry(s, &resctrl_schema_all, list) @@ -2134,7 +2134,7 @@ static int schemata_list_create(void) s->res = r; s->conf_type = resctrl_to_arch_res(r)->conf_type; - s->num_closid = resctrl_to_arch_res(r)->num_closid; + s->num_closid = resctrl_arch_get_num_closid(r); INIT_LIST_HEAD(&s->list); list_add(&s->list, &resctrl_schema_all); diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index 59d0fa78bb69..b9d200592e54 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -180,6 +180,10 @@ struct resctrl_schema { struct list_head list; enum resctrl_conf_type conf_type; struct rdt_resource *res; - int num_closid; + u32 num_closid; }; + +/* The number of closid supported by this resource regardless of CDP */ +u32 resctrl_arch_get_num_closid(struct rdt_resource *r); + #endif /* _RESCTRL_H */ -- cgit v1.2.3-71-gd317 From 1c290682c0c9c47aa7594ffc83b9cedd20c1ec87 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 28 Jul 2021 17:06:22 +0000 Subject: x86/resctrl: Pass the schema to resctrl filesystem functions Once the CDP resources are merged, there will be two struct resctrl_schema for one struct rdt_resource. CDP becomes a type of configuration that belongs to the schema. Helpers like rdtgroup_cbm_overlaps() need access to the schema to query the configuration (or configurations) based on schema properties. Change these functions to take a struct schema instead of the struct rdt_resource. All the modified functions are part of the filesystem code that will move to /fs/resctrl once it is possible to support a second architecture. Signed-off-by: James Morse Signed-off-by: Borislav Petkov Reviewed-by: Jamie Iles Reviewed-by: Reinette Chatre Tested-by: Babu Moger Link: https://lkml.kernel.org/r/20210728170637.25610-10-james.morse@arm.com --- arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 23 +++++++++++++---------- arch/x86/kernel/cpu/resctrl/internal.h | 6 +++--- arch/x86/kernel/cpu/resctrl/rdtgroup.c | 19 +++++++++++-------- include/linux/resctrl.h | 3 ++- 4 files changed, 29 insertions(+), 22 deletions(-) (limited to 'include/linux/resctrl.h') diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c index d10fddaef5f4..219b057e65b0 100644 --- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c +++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c @@ -57,9 +57,10 @@ static bool bw_validate(char *buf, unsigned long *data, struct rdt_resource *r) return true; } -int parse_bw(struct rdt_parse_data *data, struct rdt_resource *r, +int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s, struct rdt_domain *d) { + struct rdt_resource *r = s->res; unsigned long bw_val; if (d->have_new_ctrl) { @@ -125,10 +126,11 @@ static bool cbm_validate(char *buf, u32 *data, struct rdt_resource *r) * Read one cache bit mask (hex). Check that it is valid for the current * resource type. */ -int parse_cbm(struct rdt_parse_data *data, struct rdt_resource *r, +int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s, struct rdt_domain *d) { struct rdtgroup *rdtgrp = data->rdtgrp; + struct rdt_resource *r = s->res; u32 cbm_val; if (d->have_new_ctrl) { @@ -160,12 +162,12 @@ int parse_cbm(struct rdt_parse_data *data, struct rdt_resource *r, * The CBM may not overlap with the CBM of another closid if * either is exclusive. */ - if (rdtgroup_cbm_overlaps(r, d, cbm_val, rdtgrp->closid, true)) { + if (rdtgroup_cbm_overlaps(s, d, cbm_val, rdtgrp->closid, true)) { rdt_last_cmd_puts("Overlaps with exclusive group\n"); return -EINVAL; } - if (rdtgroup_cbm_overlaps(r, d, cbm_val, rdtgrp->closid, false)) { + if (rdtgroup_cbm_overlaps(s, d, cbm_val, rdtgrp->closid, false)) { if (rdtgrp->mode == RDT_MODE_EXCLUSIVE || rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) { rdt_last_cmd_puts("Overlaps with other group\n"); @@ -185,9 +187,10 @@ int parse_cbm(struct rdt_parse_data *data, struct rdt_resource *r, * separated by ";". The "id" is in decimal, and must match one of * the "id"s for this resource. */ -static int parse_line(char *line, struct rdt_resource *r, +static int parse_line(char *line, struct resctrl_schema *s, struct rdtgroup *rdtgrp) { + struct rdt_resource *r = s->res; struct rdt_parse_data data; char *dom = NULL, *id; struct rdt_domain *d; @@ -213,7 +216,7 @@ next: if (d->id == dom_id) { data.buf = dom; data.rdtgrp = rdtgrp; - if (r->parse_ctrlval(&data, r, d)) + if (r->parse_ctrlval(&data, s, d)) return -EINVAL; if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) { /* @@ -292,7 +295,7 @@ static int rdtgroup_parse_resource(char *resname, char *tok, list_for_each_entry(s, &resctrl_schema_all, list) { r = s->res; if (!strcmp(resname, r->name) && rdtgrp->closid < s->num_closid) - return parse_line(tok, r, rdtgrp); + return parse_line(tok, s, rdtgrp); } rdt_last_cmd_printf("Unknown or unsupported resource name '%s'\n", resname); return -EINVAL; @@ -377,8 +380,9 @@ out: return ret ?: nbytes; } -static void show_doms(struct seq_file *s, struct rdt_resource *r, int closid) +static void show_doms(struct seq_file *s, struct resctrl_schema *schema, int closid) { + struct rdt_resource *r = schema->res; struct rdt_hw_domain *hw_dom; struct rdt_domain *dom; bool sep = false; @@ -429,9 +433,8 @@ int rdtgroup_schemata_show(struct kernfs_open_file *of, } else { closid = rdtgrp->closid; list_for_each_entry(schema, &resctrl_schema_all, list) { - r = schema->res; if (closid < schema->num_closid) - show_doms(s, r, closid); + show_doms(s, schema, closid); } } } else { diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h index c4bc5fae5a29..5d5debe6e8d2 100644 --- a/arch/x86/kernel/cpu/resctrl/internal.h +++ b/arch/x86/kernel/cpu/resctrl/internal.h @@ -401,9 +401,9 @@ static inline struct rdt_hw_resource *resctrl_to_arch_res(struct rdt_resource *r return container_of(r, struct rdt_hw_resource, r_resctrl); } -int parse_cbm(struct rdt_parse_data *data, struct rdt_resource *r, +int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s, struct rdt_domain *d); -int parse_bw(struct rdt_parse_data *data, struct rdt_resource *r, +int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s, struct rdt_domain *d); extern struct mutex rdtgroup_mutex; @@ -505,7 +505,7 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off); int rdtgroup_schemata_show(struct kernfs_open_file *of, struct seq_file *s, void *v); -bool rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_domain *d, +bool rdtgroup_cbm_overlaps(struct resctrl_schema *s, struct rdt_domain *d, unsigned long cbm, int closid, bool exclusive); unsigned int rdtgroup_cbm_to_size(struct rdt_resource *r, struct rdt_domain *d, unsigned long cbm); diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index 09ffe9a4a32b..53d281a9f54f 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -1221,7 +1221,7 @@ static bool __rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_domain *d /** * rdtgroup_cbm_overlaps - Does CBM overlap with other use of hardware - * @r: Resource to which domain instance @d belongs. + * @s: Schema for the resource to which domain instance @d belongs. * @d: The domain instance for which @closid is being tested. * @cbm: Capacity bitmask being tested. * @closid: Intended closid for @cbm. @@ -1239,9 +1239,10 @@ static bool __rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_domain *d * * Return: true if CBM overlap detected, false if there is no overlap */ -bool rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_domain *d, +bool rdtgroup_cbm_overlaps(struct resctrl_schema *s, struct rdt_domain *d, unsigned long cbm, int closid, bool exclusive) { + struct rdt_resource *r = s->res; struct rdt_resource *r_cdp; struct rdt_domain *d_cdp; @@ -1282,7 +1283,8 @@ static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp) has_cache = true; list_for_each_entry(d, &r->domains, list) { hw_dom = resctrl_to_arch_dom(d); - if (rdtgroup_cbm_overlaps(r, d, hw_dom->ctrl_val[closid], + if (rdtgroup_cbm_overlaps(s, d, + hw_dom->ctrl_val[closid], rdtgrp->closid, false)) { rdt_last_cmd_puts("Schemata overlaps\n"); return false; @@ -2712,11 +2714,12 @@ static u32 cbm_ensure_valid(u32 _val, struct rdt_resource *r) * Set the RDT domain up to start off with all usable allocations. That is, * all shareable and unused bits. All-zero CBM is invalid. */ -static int __init_one_rdt_domain(struct rdt_domain *d, struct rdt_resource *r, +static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, u32 closid) { struct rdt_resource *r_cdp = NULL; struct rdt_domain *d_cdp = NULL; + struct rdt_resource *r = s->res; u32 used_b = 0, unused_b = 0; unsigned long tmp_cbm; enum rdtgrp_mode mode; @@ -2786,13 +2789,13 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct rdt_resource *r, * If there are no more shareable bits available on any domain then * the entire allocation will fail. */ -static int rdtgroup_init_cat(struct rdt_resource *r, u32 closid) +static int rdtgroup_init_cat(struct resctrl_schema *s, u32 closid) { struct rdt_domain *d; int ret; - list_for_each_entry(d, &r->domains, list) { - ret = __init_one_rdt_domain(d, r, closid); + list_for_each_entry(d, &s->res->domains, list) { + ret = __init_one_rdt_domain(d, s, closid); if (ret < 0) return ret; } @@ -2823,7 +2826,7 @@ static int rdtgroup_init_alloc(struct rdtgroup *rdtgrp) if (r->rid == RDT_RESOURCE_MBA) { rdtgroup_init_mba(r); } else { - ret = rdtgroup_init_cat(r, rdtgrp->closid); + ret = rdtgroup_init_cat(s, rdtgrp->closid); if (ret < 0) return ret; } diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index b9d200592e54..979592c869e6 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -121,6 +121,7 @@ struct resctrl_membw { }; struct rdt_parse_data; +struct resctrl_schema; /** * struct rdt_resource - attributes of a resctrl resource @@ -158,7 +159,7 @@ struct rdt_resource { u32 default_ctrl; const char *format_str; int (*parse_ctrlval)(struct rdt_parse_data *data, - struct rdt_resource *r, + struct resctrl_schema *s, struct rdt_domain *d); struct list_head evt_list; unsigned long fflags; -- cgit v1.2.3-71-gd317 From c091e90721b836c2367fa3017636d92427f3f8f7 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 28 Jul 2021 17:06:24 +0000 Subject: x86/resctrl: Add a helper to read/set the CDP configuration Whether CDP is enabled for a hardware resource like the L3 cache can be found by inspecting the alloc_enabled flags of the L3CODE/L3DATA struct rdt_hw_resources, even if they aren't in use. Once these resources are merged, the flags can't be compared. Whether CDP is enabled needs tracking explicitly. If another architecture is emulating CDP the behaviour may not be per-resource. 'cdp_capable' needs to be visible to resctrl, even if its not in use, as this affects the padding of the schemata table visible to user-space. Add cdp_enabled to struct rdt_hw_resource and cdp_capable to struct rdt_resource. Add resctrl_arch_set_cdp_enabled() to let resctrl enable or disable CDP on a resource. resctrl_arch_get_cdp_enabled() lets it read the current state. Signed-off-by: James Morse Signed-off-by: Borislav Petkov Reviewed-by: Jamie Iles Reviewed-by: Reinette Chatre Tested-by: Babu Moger Link: https://lkml.kernel.org/r/20210728170637.25610-12-james.morse@arm.com --- arch/x86/kernel/cpu/resctrl/core.c | 4 ++ arch/x86/kernel/cpu/resctrl/internal.h | 11 ++++- arch/x86/kernel/cpu/resctrl/pseudo_lock.c | 4 +- arch/x86/kernel/cpu/resctrl/rdtgroup.c | 75 ++++++++++++++++++------------- include/linux/resctrl.h | 3 +- 5 files changed, 62 insertions(+), 35 deletions(-) (limited to 'include/linux/resctrl.h') diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c index 26e8d20cd072..87b5aa7683ee 100644 --- a/arch/x86/kernel/cpu/resctrl/core.c +++ b/arch/x86/kernel/cpu/resctrl/core.c @@ -374,6 +374,10 @@ static void rdt_get_cdp_config(int level, int type) * "cdp" during resctrl file system mount time. */ r->alloc_enabled = false; + rdt_resources_all[level].cdp_enabled = false; + rdt_resources_all[type].cdp_enabled = false; + r_l->cdp_capable = true; + r->cdp_capable = true; } static void rdt_get_cdp_l3_config(void) diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h index c8521efe90e7..4e15667b88a8 100644 --- a/arch/x86/kernel/cpu/resctrl/internal.h +++ b/arch/x86/kernel/cpu/resctrl/internal.h @@ -380,6 +380,7 @@ struct rdt_parse_data { * @msr_update: Function pointer to update QOS MSRs * @mon_scale: cqm counter * mon_scale = occupancy in bytes * @mbm_width: Monitor width, to detect and correct for overflow. + * @cdp_enabled: CDP state of this resource * * Members of this structure are either private to the architecture * e.g. mbm_width, or accessed via helpers that provide abstraction. e.g. @@ -394,6 +395,7 @@ struct rdt_hw_resource { struct rdt_resource *r); unsigned int mon_scale; unsigned int mbm_width; + bool cdp_enabled; }; static inline struct rdt_hw_resource *resctrl_to_arch_res(struct rdt_resource *r) @@ -414,7 +416,7 @@ DECLARE_STATIC_KEY_FALSE(rdt_alloc_enable_key); extern struct dentry *debugfs_resctrl; -enum { +enum resctrl_res_level { RDT_RESOURCE_L3, RDT_RESOURCE_L3DATA, RDT_RESOURCE_L3CODE, @@ -435,6 +437,13 @@ static inline struct rdt_resource *resctrl_inc(struct rdt_resource *res) return &hw_res->r_resctrl; } +static inline bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level l) +{ + return rdt_resources_all[l].cdp_enabled; +} + +int resctrl_arch_set_cdp_enabled(enum resctrl_res_level l, bool enable); + /* * To return the common struct rdt_resource, which is contained in struct * rdt_hw_resource, walk the resctrl member of struct rdt_hw_resource. diff --git a/arch/x86/kernel/cpu/resctrl/pseudo_lock.c b/arch/x86/kernel/cpu/resctrl/pseudo_lock.c index 3c035a7fa61d..db813f819ad6 100644 --- a/arch/x86/kernel/cpu/resctrl/pseudo_lock.c +++ b/arch/x86/kernel/cpu/resctrl/pseudo_lock.c @@ -688,8 +688,8 @@ int rdtgroup_locksetup_enter(struct rdtgroup *rdtgrp) * resource, the portion of cache used by it should be made * unavailable to all future allocations from both resources. */ - if (rdt_resources_all[RDT_RESOURCE_L3DATA].r_resctrl.alloc_enabled || - rdt_resources_all[RDT_RESOURCE_L2DATA].r_resctrl.alloc_enabled) { + if (resctrl_arch_get_cdp_enabled(RDT_RESOURCE_L3) || + resctrl_arch_get_cdp_enabled(RDT_RESOURCE_L2)) { rdt_last_cmd_puts("CDP enabled\n"); return -EINVAL; } diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index 305dcf8850a0..cc9dacd73438 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -1940,14 +1940,16 @@ static int set_cache_qos_cfg(int level, bool enable) /* Restore the qos cfg state when a domain comes online */ void rdt_domain_reconfigure_cdp(struct rdt_resource *r) { - if (!r->alloc_capable) + struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); + + if (!r->cdp_capable) return; if (r == &rdt_resources_all[RDT_RESOURCE_L2DATA].r_resctrl) - l2_qos_cfg_update(&r->alloc_enabled); + l2_qos_cfg_update(&hw_res->cdp_enabled); if (r == &rdt_resources_all[RDT_RESOURCE_L3DATA].r_resctrl) - l3_qos_cfg_update(&r->alloc_enabled); + l3_qos_cfg_update(&hw_res->cdp_enabled); } /* @@ -1991,51 +1993,62 @@ static int cdp_enable(int level, int data_type, int code_type) r_l->alloc_enabled = false; r_ldata->alloc_enabled = true; r_lcode->alloc_enabled = true; + rdt_resources_all[level].cdp_enabled = true; + rdt_resources_all[data_type].cdp_enabled = true; + rdt_resources_all[code_type].cdp_enabled = true; } return ret; } -static int cdpl3_enable(void) -{ - return cdp_enable(RDT_RESOURCE_L3, RDT_RESOURCE_L3DATA, - RDT_RESOURCE_L3CODE); -} - -static int cdpl2_enable(void) -{ - return cdp_enable(RDT_RESOURCE_L2, RDT_RESOURCE_L2DATA, - RDT_RESOURCE_L2CODE); -} - static void cdp_disable(int level, int data_type, int code_type) { - struct rdt_resource *r = &rdt_resources_all[level].r_resctrl; + struct rdt_hw_resource *r_hw = &rdt_resources_all[level]; + struct rdt_resource *r = &r_hw->r_resctrl; r->alloc_enabled = r->alloc_capable; - if (rdt_resources_all[data_type].r_resctrl.alloc_enabled) { + if (r_hw->cdp_enabled) { rdt_resources_all[data_type].r_resctrl.alloc_enabled = false; rdt_resources_all[code_type].r_resctrl.alloc_enabled = false; set_cache_qos_cfg(level, false); + r_hw->cdp_enabled = false; + rdt_resources_all[data_type].cdp_enabled = false; + rdt_resources_all[code_type].cdp_enabled = false; } } -static void cdpl3_disable(void) +int resctrl_arch_set_cdp_enabled(enum resctrl_res_level l, bool enable) { - cdp_disable(RDT_RESOURCE_L3, RDT_RESOURCE_L3DATA, RDT_RESOURCE_L3CODE); -} + struct rdt_hw_resource *hw_res = &rdt_resources_all[l]; + enum resctrl_res_level code_type, data_type; -static void cdpl2_disable(void) -{ - cdp_disable(RDT_RESOURCE_L2, RDT_RESOURCE_L2DATA, RDT_RESOURCE_L2CODE); + if (!hw_res->r_resctrl.cdp_capable) + return -EINVAL; + + if (l == RDT_RESOURCE_L3) { + code_type = RDT_RESOURCE_L3CODE; + data_type = RDT_RESOURCE_L3DATA; + } else if (l == RDT_RESOURCE_L2) { + code_type = RDT_RESOURCE_L2CODE; + data_type = RDT_RESOURCE_L2DATA; + } else { + return -EINVAL; + } + + if (enable) + return cdp_enable(l, data_type, code_type); + + cdp_disable(l, data_type, code_type); + + return 0; } static void cdp_disable_all(void) { - if (rdt_resources_all[RDT_RESOURCE_L3DATA].r_resctrl.alloc_enabled) - cdpl3_disable(); - if (rdt_resources_all[RDT_RESOURCE_L2DATA].r_resctrl.alloc_enabled) - cdpl2_disable(); + if (resctrl_arch_get_cdp_enabled(RDT_RESOURCE_L3)) + resctrl_arch_set_cdp_enabled(RDT_RESOURCE_L3, false); + if (resctrl_arch_get_cdp_enabled(RDT_RESOURCE_L2)) + resctrl_arch_set_cdp_enabled(RDT_RESOURCE_L2, false); } /* @@ -2113,10 +2126,10 @@ static int rdt_enable_ctx(struct rdt_fs_context *ctx) int ret = 0; if (ctx->enable_cdpl2) - ret = cdpl2_enable(); + ret = resctrl_arch_set_cdp_enabled(RDT_RESOURCE_L2, true); if (!ret && ctx->enable_cdpl3) - ret = cdpl3_enable(); + ret = resctrl_arch_set_cdp_enabled(RDT_RESOURCE_L3, true); if (!ret && ctx->enable_mba_mbps) ret = set_mba_sc(true); @@ -3199,10 +3212,10 @@ out: static int rdtgroup_show_options(struct seq_file *seq, struct kernfs_root *kf) { - if (rdt_resources_all[RDT_RESOURCE_L3DATA].r_resctrl.alloc_enabled) + if (resctrl_arch_get_cdp_enabled(RDT_RESOURCE_L3)) seq_puts(seq, ",cdp"); - if (rdt_resources_all[RDT_RESOURCE_L2DATA].r_resctrl.alloc_enabled) + if (resctrl_arch_get_cdp_enabled(RDT_RESOURCE_L2)) seq_puts(seq, ",cdpl2"); if (is_mba_sc(&rdt_resources_all[RDT_RESOURCE_MBA].r_resctrl)) diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index 979592c869e6..4b30571fbc8e 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -142,6 +142,7 @@ struct resctrl_schema; * @parse_ctrlval: Per resource function pointer to parse control values * @evt_list: List of monitoring events * @fflags: flags to choose base and info files + * @cdp_capable: Is the CDP feature available on this resource */ struct rdt_resource { int rid; @@ -163,7 +164,7 @@ struct rdt_resource { struct rdt_domain *d); struct list_head evt_list; unsigned long fflags; - + bool cdp_capable; }; /** -- cgit v1.2.3-71-gd317 From e198fde3fe0892a5d1e28c0e29f1eebfb6f8c1cd Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 28 Jul 2021 17:06:25 +0000 Subject: x86/resctrl: Move the schemata names into struct resctrl_schema resctrl 'info' directories and schema parsing use the schema name. This lives in the struct rdt_resource, and is specified by the architecture code. Once the CDP resources are merged, there will only be one resource (and one name) in use by two schemata. To allow the CDP CODE/DATA property to be the type of configuration the schema uses, the name should also be per-schema. Add a name field to struct resctrl_schema, and use this wherever the schema name is exposed (or read from) user-space. Calculating max_name_width for padding the schemata file also moves as this is visible to user-space. As the names in struct rdt_resource already include the CDP information, schemata_list_create() copies them. schemata_list_create() includes the length of the CDP suffix when calculating max_name_width in preparation for CDP resources being merged. Signed-off-by: James Morse Signed-off-by: Borislav Petkov Reviewed-by: Jamie Iles Reviewed-by: Reinette Chatre Tested-by: Babu Moger Link: https://lkml.kernel.org/r/20210728170637.25610-13-james.morse@arm.com --- arch/x86/kernel/cpu/resctrl/core.c | 5 ----- arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 10 +++------- arch/x86/kernel/cpu/resctrl/rdtgroup.c | 29 +++++++++++++++++++++++++---- include/linux/resctrl.h | 2 ++ 4 files changed, 30 insertions(+), 16 deletions(-) (limited to 'include/linux/resctrl.h') diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c index 87b5aa7683ee..755118a9ef38 100644 --- a/arch/x86/kernel/cpu/resctrl/core.c +++ b/arch/x86/kernel/cpu/resctrl/core.c @@ -782,13 +782,8 @@ static int resctrl_offline_cpu(unsigned int cpu) static __init void rdt_init_padding(void) { struct rdt_resource *r; - int cl; for_each_alloc_capable_rdt_resource(r) { - cl = strlen(r->name); - if (cl > max_name_width) - max_name_width = cl; - if (r->data_width > max_data_width) max_data_width = r->data_width; } diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c index 0ee1ded5b8ff..104b285f8a60 100644 --- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c +++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c @@ -290,11 +290,9 @@ static int rdtgroup_parse_resource(char *resname, char *tok, struct rdtgroup *rdtgrp) { struct resctrl_schema *s; - struct rdt_resource *r; list_for_each_entry(s, &resctrl_schema_all, list) { - r = s->res; - if (!strcmp(resname, r->name) && rdtgrp->closid < s->num_closid) + if (!strcmp(resname, s->name) && rdtgrp->closid < s->num_closid) return parse_line(tok, s, rdtgrp); } rdt_last_cmd_printf("Unknown or unsupported resource name '%s'\n", resname); @@ -388,7 +386,7 @@ static void show_doms(struct seq_file *s, struct resctrl_schema *schema, int clo bool sep = false; u32 ctrl_val; - seq_printf(s, "%*s:", max_name_width, r->name); + seq_printf(s, "%*s:", max_name_width, schema->name); list_for_each_entry(dom, &r->domains, list) { hw_dom = resctrl_to_arch_dom(dom); if (sep) @@ -408,7 +406,6 @@ int rdtgroup_schemata_show(struct kernfs_open_file *of, { struct resctrl_schema *schema; struct rdtgroup *rdtgrp; - struct rdt_resource *r; int ret = 0; u32 closid; @@ -416,8 +413,7 @@ int rdtgroup_schemata_show(struct kernfs_open_file *of, if (rdtgrp) { if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) { list_for_each_entry(schema, &resctrl_schema_all, list) { - r = schema->res; - seq_printf(s, "%s:uninitialized\n", r->name); + seq_printf(s, "%s:uninitialized\n", schema->name); } } else if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) { if (!rdtgrp->plr->d) { diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index cc9dacd73438..1f8c8d79d00b 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -1439,7 +1439,7 @@ static int rdtgroup_size_show(struct kernfs_open_file *of, ret = -ENODEV; } else { seq_printf(s, "%*s:", max_name_width, - rdtgrp->plr->s->res->name); + rdtgrp->plr->s->name); size = rdtgroup_cbm_to_size(rdtgrp->plr->s->res, rdtgrp->plr->d, rdtgrp->plr->cbm); @@ -1451,7 +1451,7 @@ static int rdtgroup_size_show(struct kernfs_open_file *of, list_for_each_entry(schema, &resctrl_schema_all, list) { r = schema->res; sep = false; - seq_printf(s, "%*s:", max_name_width, r->name); + seq_printf(s, "%*s:", max_name_width, schema->name); list_for_each_entry(d, &r->domains, list) { hw_dom = resctrl_to_arch_dom(d); if (sep) @@ -1823,7 +1823,7 @@ static int rdtgroup_create_info_dir(struct kernfs_node *parent_kn) list_for_each_entry(s, &resctrl_schema_all, list) { r = s->res; fflags = r->fflags | RF_CTRL_INFO; - ret = rdtgroup_mkdir_info_resdir(s, r->name, fflags); + ret = rdtgroup_mkdir_info_resdir(s, s->name, fflags); if (ret) goto out_destroy; } @@ -2141,6 +2141,7 @@ static int schemata_list_create(void) { struct resctrl_schema *s; struct rdt_resource *r; + int ret, cl; for_each_alloc_enabled_rdt_resource(r) { s = kzalloc(sizeof(*s), GFP_KERNEL); @@ -2151,6 +2152,26 @@ static int schemata_list_create(void) s->conf_type = resctrl_to_arch_res(r)->conf_type; s->num_closid = resctrl_arch_get_num_closid(r); + ret = snprintf(s->name, sizeof(s->name), r->name); + if (ret >= sizeof(s->name)) { + kfree(s); + return -EINVAL; + } + + cl = strlen(s->name); + + /* + * If CDP is supported by this resource, but not enabled, + * include the suffix. This ensures the tabular format of the + * schemata file does not change between mounts of the + * filesystem. + */ + if (r->cdp_capable && !resctrl_arch_get_cdp_enabled(r->rid)) + cl += 4; + + if (cl > max_name_width) + max_name_width = cl; + INIT_LIST_HEAD(&s->list); list_add(&s->list, &resctrl_schema_all); } @@ -2784,7 +2805,7 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, */ tmp_cbm = d->new_ctrl; if (bitmap_weight(&tmp_cbm, r->cache.cbm_len) < r->cache.min_cbm_bits) { - rdt_last_cmd_printf("No space on %s:%d\n", r->name, d->id); + rdt_last_cmd_printf("No space on %s:%d\n", s->name, d->id); return -ENOSPC; } d->have_new_ctrl = true; diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index 4b30571fbc8e..e482ce790ce2 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -171,6 +171,7 @@ struct rdt_resource { * struct resctrl_schema - configuration abilities of a resource presented to * user-space * @list: Member of resctrl_schema_all. + * @name: The name to use in the "schemata" file. * @conf_type: Whether this schema is specific to code/data. * @res: The resource structure exported by the architecture to describe * the hardware that is configured by this schema. @@ -180,6 +181,7 @@ struct rdt_resource { */ struct resctrl_schema { struct list_head list; + char name[8]; enum resctrl_conf_type conf_type; struct rdt_resource *res; u32 num_closid; -- cgit v1.2.3-71-gd317 From e8f7282552b902af3bd1f07a87d657b7f5f12ab8 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 28 Jul 2021 17:06:26 +0000 Subject: x86/resctrl: Group staged configuration into a separate struct When configuration changes are made, the new value is written to struct rdt_domain's new_ctrl field and the have_new_ctrl flag is set. Later new_ctrl is copied to hardware by a call to update_domains(). Once the CDP resources are merged, there will be one new_ctrl field in use by two struct resctrl_schema requiring a per-schema IPI to copy the value to hardware. Move new_ctrl and have_new_ctrl into a new struct resctrl_staged_config. Before the CDP resources can be merged, struct rdt_domain will need an array of these, one per type of configuration. Using the type as an index to the array will ensure that a schema configuration string can't specify the same domain twice. Signed-off-by: James Morse Signed-off-by: Borislav Petkov Reviewed-by: Jamie Iles Reviewed-by: Reinette Chatre Tested-by: Babu Moger Link: https://lkml.kernel.org/r/20210728170637.25610-14-james.morse@arm.com --- arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 43 +++++++++++++++++++++---------- arch/x86/kernel/cpu/resctrl/rdtgroup.c | 22 +++++++++------- include/linux/resctrl.h | 16 +++++++++--- 3 files changed, 54 insertions(+), 27 deletions(-) (limited to 'include/linux/resctrl.h') diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c index 104b285f8a60..9ddfa7607234 100644 --- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c +++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c @@ -62,16 +62,17 @@ int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s, { struct rdt_resource *r = s->res; unsigned long bw_val; + struct resctrl_staged_config *cfg = &d->staged_config; - if (d->have_new_ctrl) { + 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; - d->new_ctrl = bw_val; - d->have_new_ctrl = true; + cfg->new_ctrl = bw_val; + cfg->have_new_ctrl = true; return 0; } @@ -129,11 +130,12 @@ static bool cbm_validate(char *buf, u32 *data, struct rdt_resource *r) int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s, struct rdt_domain *d) { + struct resctrl_staged_config *cfg = &d->staged_config; struct rdtgroup *rdtgrp = data->rdtgrp; struct rdt_resource *r = s->res; u32 cbm_val; - if (d->have_new_ctrl) { + if (cfg->have_new_ctrl) { rdt_last_cmd_printf("Duplicate domain %d\n", d->id); return -EINVAL; } @@ -175,8 +177,8 @@ int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s, } } - d->new_ctrl = cbm_val; - d->have_new_ctrl = true; + cfg->new_ctrl = cbm_val; + cfg->have_new_ctrl = true; return 0; } @@ -190,6 +192,7 @@ int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s, static int parse_line(char *line, struct resctrl_schema *s, struct rdtgroup *rdtgrp) { + struct resctrl_staged_config *cfg; struct rdt_resource *r = s->res; struct rdt_parse_data data; char *dom = NULL, *id; @@ -219,6 +222,7 @@ next: if (r->parse_ctrlval(&data, s, d)) return -EINVAL; if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) { + cfg = &d->staged_config; /* * In pseudo-locking setup mode and just * parsed a valid CBM that should be @@ -229,7 +233,7 @@ next: */ rdtgrp->plr->s = s; rdtgrp->plr->d = d; - rdtgrp->plr->cbm = d->new_ctrl; + rdtgrp->plr->cbm = cfg->new_ctrl; d->plr = rdtgrp->plr; return 0; } @@ -239,14 +243,27 @@ next: return -EINVAL; } +static void apply_config(struct rdt_hw_domain *hw_dom, + struct resctrl_staged_config *cfg, int closid, + cpumask_var_t cpu_mask, bool mba_sc) +{ + struct rdt_domain *dom = &hw_dom->d_resctrl; + u32 *dc = !mba_sc ? hw_dom->ctrl_val : hw_dom->mbps_val; + + if (cfg->new_ctrl != dc[closid]) { + cpumask_set_cpu(cpumask_any(&dom->cpu_mask), cpu_mask); + dc[closid] = cfg->new_ctrl; + } +} + int update_domains(struct rdt_resource *r, int closid) { + struct resctrl_staged_config *cfg; struct rdt_hw_domain *hw_dom; struct msr_param msr_param; cpumask_var_t cpu_mask; struct rdt_domain *d; bool mba_sc; - u32 *dc; int cpu; if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL)) @@ -259,11 +276,9 @@ int update_domains(struct rdt_resource *r, int closid) mba_sc = is_mba_sc(r); list_for_each_entry(d, &r->domains, list) { hw_dom = resctrl_to_arch_dom(d); - dc = !mba_sc ? hw_dom->ctrl_val : hw_dom->mbps_val; - if (d->have_new_ctrl && d->new_ctrl != dc[closid]) { - cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask); - dc[closid] = d->new_ctrl; - } + cfg = &hw_dom->d_resctrl.staged_config; + if (cfg->have_new_ctrl) + apply_config(hw_dom, cfg, closid, cpu_mask, mba_sc); } /* @@ -335,7 +350,7 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of, list_for_each_entry(s, &resctrl_schema_all, list) { list_for_each_entry(dom, &s->res->domains, list) - dom->have_new_ctrl = false; + memset(&dom->staged_config, 0, sizeof(dom->staged_config)); } while ((tok = strsep(&buf, "\n")) != NULL) { diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index 1f8c8d79d00b..62cc82d7b06e 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -2752,6 +2752,7 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, u32 closid) { struct rdt_resource *r_cdp = NULL; + struct resctrl_staged_config *cfg; struct rdt_domain *d_cdp = NULL; struct rdt_resource *r = s->res; u32 used_b = 0, unused_b = 0; @@ -2761,8 +2762,9 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, int i; rdt_cdp_peer_get(r, d, &r_cdp, &d_cdp); - d->have_new_ctrl = false; - d->new_ctrl = r->cache.shareable_bits; + cfg = &d->staged_config; + cfg->have_new_ctrl = false; + cfg->new_ctrl = r->cache.shareable_bits; used_b = r->cache.shareable_bits; ctrl = resctrl_to_arch_dom(d)->ctrl_val; for (i = 0; i < closids_supported(); i++, ctrl++) { @@ -2786,29 +2788,29 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, peer_ctl = 0; used_b |= *ctrl | peer_ctl; if (mode == RDT_MODE_SHAREABLE) - d->new_ctrl |= *ctrl | peer_ctl; + cfg->new_ctrl |= *ctrl | peer_ctl; } } if (d->plr && d->plr->cbm > 0) used_b |= d->plr->cbm; unused_b = used_b ^ (BIT_MASK(r->cache.cbm_len) - 1); unused_b &= BIT_MASK(r->cache.cbm_len) - 1; - d->new_ctrl |= unused_b; + cfg->new_ctrl |= unused_b; /* * Force the initial CBM to be valid, user can * modify the CBM based on system availability. */ - d->new_ctrl = cbm_ensure_valid(d->new_ctrl, r); + cfg->new_ctrl = cbm_ensure_valid(cfg->new_ctrl, r); /* * Assign the u32 CBM to an unsigned long to ensure that * bitmap_weight() does not access out-of-bound memory. */ - tmp_cbm = d->new_ctrl; + tmp_cbm = cfg->new_ctrl; if (bitmap_weight(&tmp_cbm, r->cache.cbm_len) < r->cache.min_cbm_bits) { rdt_last_cmd_printf("No space on %s:%d\n", s->name, d->id); return -ENOSPC; } - d->have_new_ctrl = true; + cfg->have_new_ctrl = true; return 0; } @@ -2840,11 +2842,13 @@ static int rdtgroup_init_cat(struct resctrl_schema *s, u32 closid) /* Initialize MBA resource with default values. */ static void rdtgroup_init_mba(struct rdt_resource *r) { + struct resctrl_staged_config *cfg; struct rdt_domain *d; list_for_each_entry(d, &r->domains, list) { - d->new_ctrl = is_mba_sc(r) ? MBA_MAX_MBPS : r->default_ctrl; - d->have_new_ctrl = true; + cfg = &d->staged_config; + cfg->new_ctrl = is_mba_sc(r) ? MBA_MAX_MBPS : r->default_ctrl; + cfg->have_new_ctrl = true; } } diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index e482ce790ce2..ff7f7d7e1348 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -27,13 +27,21 @@ enum resctrl_conf_type { CDP_DATA, }; +/** + * 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 * @id: unique id for this instance * @cpu_mask: which CPUs share this resource - * @new_ctrl: new ctrl value to be loaded - * @have_new_ctrl: did user provide new_ctrl for this domain * @rmid_busy_llc: bitmap of which limbo RMIDs are above threshold * @mbm_total: saved state for MBM total bandwidth * @mbm_local: saved state for MBM local bandwidth @@ -42,13 +50,12 @@ enum resctrl_conf_type { * @mbm_work_cpu: worker CPU for MBM h/w counters * @cqm_work_cpu: worker CPU for CQM h/w counters * @plr: pseudo-locked region (if any) associated with domain + * @staged_config: parsed configuration to be applied */ struct rdt_domain { struct list_head list; int id; struct cpumask cpu_mask; - u32 new_ctrl; - bool have_new_ctrl; unsigned long *rmid_busy_llc; struct mbm_state *mbm_total; struct mbm_state *mbm_local; @@ -57,6 +64,7 @@ struct rdt_domain { int mbm_work_cpu; int cqm_work_cpu; struct pseudo_lock_region *plr; + struct resctrl_staged_config staged_config; }; /** -- cgit v1.2.3-71-gd317 From 75408e43509ed6207870c0e7e28656acbbc1f7fd Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 28 Jul 2021 17:06:27 +0000 Subject: x86/resctrl: Allow different CODE/DATA configurations to be staged Before the CDP resources can be merged, struct rdt_domain will need an array of struct resctrl_staged_config, one per type of configuration. Use the type as an index to the array to ensure that a schema configuration string can't specify the same domain twice. This will allow two schemata to apply configuration changes to one resource. Signed-off-by: James Morse Signed-off-by: Borislav Petkov Reviewed-by: Jamie Iles Reviewed-by: Reinette Chatre Tested-by: Babu Moger Link: https://lkml.kernel.org/r/20210728170637.25610-15-james.morse@arm.com --- arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 20 ++++++++++++++------ arch/x86/kernel/cpu/resctrl/rdtgroup.c | 5 +++-- include/linux/resctrl.h | 4 +++- 3 files changed, 20 insertions(+), 9 deletions(-) (limited to 'include/linux/resctrl.h') diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c index 9ddfa7607234..f29848f98846 100644 --- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c +++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c @@ -60,10 +60,11 @@ static bool bw_validate(char *buf, unsigned long *data, struct rdt_resource *r) int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s, struct rdt_domain *d) { + struct resctrl_staged_config *cfg; struct rdt_resource *r = s->res; unsigned long bw_val; - struct resctrl_staged_config *cfg = &d->staged_config; + cfg = &d->staged_config[s->conf_type]; if (cfg->have_new_ctrl) { rdt_last_cmd_printf("Duplicate domain %d\n", d->id); return -EINVAL; @@ -130,11 +131,12 @@ static bool cbm_validate(char *buf, u32 *data, struct rdt_resource *r) int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s, struct rdt_domain *d) { - struct resctrl_staged_config *cfg = &d->staged_config; struct rdtgroup *rdtgrp = data->rdtgrp; + struct resctrl_staged_config *cfg; struct rdt_resource *r = s->res; u32 cbm_val; + cfg = &d->staged_config[s->conf_type]; if (cfg->have_new_ctrl) { rdt_last_cmd_printf("Duplicate domain %d\n", d->id); return -EINVAL; @@ -192,6 +194,7 @@ int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s, static int parse_line(char *line, struct resctrl_schema *s, struct rdtgroup *rdtgrp) { + enum resctrl_conf_type t = s->conf_type; struct resctrl_staged_config *cfg; struct rdt_resource *r = s->res; struct rdt_parse_data data; @@ -222,7 +225,7 @@ next: if (r->parse_ctrlval(&data, s, d)) return -EINVAL; if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) { - cfg = &d->staged_config; + cfg = &d->staged_config[t]; /* * In pseudo-locking setup mode and just * parsed a valid CBM that should be @@ -261,6 +264,7 @@ int update_domains(struct rdt_resource *r, int closid) struct resctrl_staged_config *cfg; struct rdt_hw_domain *hw_dom; struct msr_param msr_param; + enum resctrl_conf_type t; cpumask_var_t cpu_mask; struct rdt_domain *d; bool mba_sc; @@ -276,9 +280,13 @@ int update_domains(struct rdt_resource *r, int closid) mba_sc = is_mba_sc(r); list_for_each_entry(d, &r->domains, list) { hw_dom = resctrl_to_arch_dom(d); - cfg = &hw_dom->d_resctrl.staged_config; - if (cfg->have_new_ctrl) + for (t = 0; t < CDP_NUM_TYPES; t++) { + cfg = &hw_dom->d_resctrl.staged_config[t]; + if (!cfg->have_new_ctrl) + continue; + apply_config(hw_dom, cfg, closid, cpu_mask, mba_sc); + } } /* @@ -350,7 +358,7 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of, list_for_each_entry(s, &resctrl_schema_all, list) { list_for_each_entry(dom, &s->res->domains, list) - memset(&dom->staged_config, 0, sizeof(dom->staged_config)); + memset(dom->staged_config, 0, sizeof(dom->staged_config)); } while ((tok = strsep(&buf, "\n")) != NULL) { diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index 62cc82d7b06e..9f1354cb94e9 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -2751,6 +2751,7 @@ static u32 cbm_ensure_valid(u32 _val, struct rdt_resource *r) static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, u32 closid) { + enum resctrl_conf_type t = s->conf_type; struct rdt_resource *r_cdp = NULL; struct resctrl_staged_config *cfg; struct rdt_domain *d_cdp = NULL; @@ -2762,7 +2763,7 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, int i; rdt_cdp_peer_get(r, d, &r_cdp, &d_cdp); - cfg = &d->staged_config; + cfg = &d->staged_config[t]; cfg->have_new_ctrl = false; cfg->new_ctrl = r->cache.shareable_bits; used_b = r->cache.shareable_bits; @@ -2846,7 +2847,7 @@ static void rdtgroup_init_mba(struct rdt_resource *r) struct rdt_domain *d; list_for_each_entry(d, &r->domains, list) { - cfg = &d->staged_config; + cfg = &d->staged_config[CDP_NONE]; cfg->new_ctrl = is_mba_sc(r) ? MBA_MAX_MBPS : r->default_ctrl; cfg->have_new_ctrl = true; } diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index ff7f7d7e1348..51ba372f96cd 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -27,6 +27,8 @@ enum resctrl_conf_type { CDP_DATA, }; +#define CDP_NUM_TYPES (CDP_DATA + 1) + /** * struct resctrl_staged_config - parsed configuration to be applied * @new_ctrl: new ctrl value to be loaded @@ -64,7 +66,7 @@ struct rdt_domain { int mbm_work_cpu; int cqm_work_cpu; struct pseudo_lock_region *plr; - struct resctrl_staged_config staged_config; + struct resctrl_staged_config staged_config[CDP_NUM_TYPES]; }; /** -- cgit v1.2.3-71-gd317 From 2e6678195d59c51b6ca234169ad3de01134d3dec Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 28 Jul 2021 17:06:28 +0000 Subject: x86/resctrl: Rename update_domains() to resctrl_arch_update_domains() update_domains() merges the staged configuration changes into the arch codes configuration array. Rename to make it clear it is part of the arch code interface to resctrl. Signed-off-by: James Morse Signed-off-by: Borislav Petkov Reviewed-by: Jamie Iles Reviewed-by: Reinette Chatre Tested-by: Babu Moger Link: https://lkml.kernel.org/r/20210728170637.25610-16-james.morse@arm.com --- arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 4 ++-- arch/x86/kernel/cpu/resctrl/internal.h | 1 - arch/x86/kernel/cpu/resctrl/rdtgroup.c | 2 +- include/linux/resctrl.h | 1 + 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include/linux/resctrl.h') diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c index f29848f98846..8cde76df888a 100644 --- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c +++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c @@ -259,7 +259,7 @@ static void apply_config(struct rdt_hw_domain *hw_dom, } } -int update_domains(struct rdt_resource *r, int closid) +int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid) { struct resctrl_staged_config *cfg; struct rdt_hw_domain *hw_dom; @@ -380,7 +380,7 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of, list_for_each_entry(s, &resctrl_schema_all, list) { r = s->res; - ret = update_domains(r, rdtgrp->closid); + ret = resctrl_arch_update_domains(r, rdtgrp->closid); if (ret) goto out; } diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h index 4e15667b88a8..a95893ed3795 100644 --- a/arch/x86/kernel/cpu/resctrl/internal.h +++ b/arch/x86/kernel/cpu/resctrl/internal.h @@ -529,7 +529,6 @@ void rdt_pseudo_lock_release(void); int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp); void rdtgroup_pseudo_lock_remove(struct rdtgroup *rdtgrp); struct rdt_domain *get_domain_from_cpu(int cpu, struct rdt_resource *r); -int update_domains(struct rdt_resource *r, int closid); int closids_supported(void); void closid_free(int closid); int alloc_rmid(void); diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index 9f1354cb94e9..4b6de76493d6 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -2870,7 +2870,7 @@ static int rdtgroup_init_alloc(struct rdtgroup *rdtgrp) return ret; } - ret = update_domains(r, rdtgrp->closid); + ret = resctrl_arch_update_domains(r, rdtgrp->closid); if (ret < 0) { rdt_last_cmd_puts("Failed to initialize allocations\n"); return ret; diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index 51ba372f96cd..be5881171576 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -199,5 +199,6 @@ struct resctrl_schema { /* The number of closid supported by this resource regardless of CDP */ u32 resctrl_arch_get_num_closid(struct rdt_resource *r); +int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid); #endif /* _RESCTRL_H */ -- cgit v1.2.3-71-gd317 From f07e9d0250577a23eb06d4334798291616c01f2d Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 28 Jul 2021 17:06:29 +0000 Subject: x86/resctrl: Add a helper to read a closid's configuration Functions like show_doms() reach into the architecture's private structure to retrieve the configuration from the struct rdt_hw_resource. The hardware configuration may look completely different to the values resctrl gets from user-space. The staged configuration and resctrl_arch_update_domains() allow the architecture to convert or translate these values. Resctrl shouldn't read or write the ctrl_val[] values directly. Add a helper to read the current configuration. This will allow another architecture to scale the bitmaps if necessary, and possibly use controls that don't take the user-space control format at all. Of the remaining functions that access ctrl_val[] directly, apply_config() is part of the architecture-specific code, and is called via resctrl_arch_update_domains(). reset_all_ctrls() will be an architecture specific helper. update_mba_bw() manipulates both ctrl_val[], mbps_val[] and the hardware. The mbps_val[] that matches the mba_sc state of the resource is changed, but the other is left unchanged. Abstracting this is the subject of later patches that affect set_mba_sc() too. Signed-off-by: James Morse Signed-off-by: Borislav Petkov Reviewed-by: Jamie Iles Reviewed-by: Reinette Chatre Tested-by: Babu Moger Link: https://lkml.kernel.org/r/20210728170637.25610-17-james.morse@arm.com --- arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 16 +++++++++--- arch/x86/kernel/cpu/resctrl/monitor.c | 6 ++++- arch/x86/kernel/cpu/resctrl/rdtgroup.c | 43 +++++++++++++------------------ include/linux/resctrl.h | 2 ++ 4 files changed, 37 insertions(+), 30 deletions(-) (limited to 'include/linux/resctrl.h') diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c index 8cde76df888a..4da08ba0deda 100644 --- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c +++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c @@ -401,22 +401,30 @@ out: return ret ?: nbytes; } +void resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, + u32 closid, u32 *value) +{ + struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d); + + if (!is_mba_sc(r)) + *value = hw_dom->ctrl_val[closid]; + else + *value = hw_dom->mbps_val[closid]; +} + static void show_doms(struct seq_file *s, struct resctrl_schema *schema, int closid) { struct rdt_resource *r = schema->res; - struct rdt_hw_domain *hw_dom; struct rdt_domain *dom; bool sep = false; u32 ctrl_val; seq_printf(s, "%*s:", max_name_width, schema->name); list_for_each_entry(dom, &r->domains, list) { - hw_dom = resctrl_to_arch_dom(dom); if (sep) seq_puts(s, ";"); - ctrl_val = (!is_mba_sc(r) ? hw_dom->ctrl_val[closid] : - hw_dom->mbps_val[closid]); + resctrl_arch_get_config(r, dom, closid, &ctrl_val); seq_printf(s, r->format_str, dom->id, max_data_width, ctrl_val); sep = true; diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c index 26a094870c16..e45e7150eb81 100644 --- a/arch/x86/kernel/cpu/resctrl/monitor.c +++ b/arch/x86/kernel/cpu/resctrl/monitor.c @@ -442,8 +442,12 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm) hw_dom_mba = resctrl_to_arch_dom(dom_mba); cur_bw = pmbm_data->prev_bw; - user_bw = hw_dom_mba->mbps_val[closid]; + resctrl_arch_get_config(r_mba, dom_mba, closid, &user_bw); delta_bw = pmbm_data->delta_bw; + /* + * resctrl_arch_get_config() chooses the mbps/ctrl value to return + * based on is_mba_sc(). For now, reach into the hw_dom. + */ cur_msr_val = hw_dom_mba->ctrl_val[closid]; /* diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index 4b6de76493d6..6b2be5633536 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -910,27 +910,27 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of, int i, hwb, swb, excl, psl; enum rdtgrp_mode mode; bool sep = false; - u32 *ctrl; + u32 ctrl_val; mutex_lock(&rdtgroup_mutex); hw_shareable = r->cache.shareable_bits; list_for_each_entry(dom, &r->domains, list) { if (sep) seq_putc(seq, ';'); - ctrl = resctrl_to_arch_dom(dom)->ctrl_val; sw_shareable = 0; exclusive = 0; seq_printf(seq, "%d=", dom->id); - for (i = 0; i < closids_supported(); i++, ctrl++) { + for (i = 0; i < closids_supported(); i++) { if (!closid_allocated(i)) continue; + resctrl_arch_get_config(r, dom, i, &ctrl_val); mode = rdtgroup_mode_by_closid(i); switch (mode) { case RDT_MODE_SHAREABLE: - sw_shareable |= *ctrl; + sw_shareable |= ctrl_val; break; case RDT_MODE_EXCLUSIVE: - exclusive |= *ctrl; + exclusive |= ctrl_val; break; case RDT_MODE_PSEUDO_LOCKSETUP: /* @@ -1188,7 +1188,6 @@ static bool __rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_domain *d { enum rdtgrp_mode mode; unsigned long ctrl_b; - u32 *ctrl; int i; /* Check for any overlap with regions used by hardware directly */ @@ -1199,9 +1198,8 @@ static bool __rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_domain *d } /* Check for overlap with other resource groups */ - ctrl = resctrl_to_arch_dom(d)->ctrl_val; - for (i = 0; i < closids_supported(); i++, ctrl++) { - ctrl_b = *ctrl; + for (i = 0; i < closids_supported(); i++) { + resctrl_arch_get_config(r, d, i, (u32 *)&ctrl_b); mode = rdtgroup_mode_by_closid(i); if (closid_allocated(i) && i != closid && mode != RDT_MODE_PSEUDO_LOCKSETUP) { @@ -1269,12 +1267,12 @@ bool rdtgroup_cbm_overlaps(struct resctrl_schema *s, struct rdt_domain *d, */ static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp) { - struct rdt_hw_domain *hw_dom; int closid = rdtgrp->closid; struct resctrl_schema *s; struct rdt_resource *r; bool has_cache = false; struct rdt_domain *d; + u32 ctrl; list_for_each_entry(s, &resctrl_schema_all, list) { r = s->res; @@ -1282,10 +1280,8 @@ static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp) continue; has_cache = true; list_for_each_entry(d, &r->domains, list) { - hw_dom = resctrl_to_arch_dom(d); - if (rdtgroup_cbm_overlaps(s, d, - hw_dom->ctrl_val[closid], - rdtgrp->closid, false)) { + resctrl_arch_get_config(r, d, closid, &ctrl); + if (rdtgroup_cbm_overlaps(s, d, ctrl, closid, false)) { rdt_last_cmd_puts("Schemata overlaps\n"); return false; } @@ -1417,7 +1413,6 @@ static int rdtgroup_size_show(struct kernfs_open_file *of, struct seq_file *s, void *v) { struct resctrl_schema *schema; - struct rdt_hw_domain *hw_dom; struct rdtgroup *rdtgrp; struct rdt_resource *r; struct rdt_domain *d; @@ -1453,15 +1448,13 @@ static int rdtgroup_size_show(struct kernfs_open_file *of, sep = false; seq_printf(s, "%*s:", max_name_width, schema->name); list_for_each_entry(d, &r->domains, list) { - hw_dom = resctrl_to_arch_dom(d); if (sep) seq_putc(s, ';'); if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) { size = 0; } else { - ctrl = (!is_mba_sc(r) ? - hw_dom->ctrl_val[rdtgrp->closid] : - hw_dom->mbps_val[rdtgrp->closid]); + resctrl_arch_get_config(r, d, rdtgrp->closid, + &ctrl); if (r->rid == RDT_RESOURCE_MBA) size = ctrl; else @@ -2759,7 +2752,7 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, u32 used_b = 0, unused_b = 0; unsigned long tmp_cbm; enum rdtgrp_mode mode; - u32 peer_ctl, *ctrl; + u32 peer_ctl, ctrl_val; int i; rdt_cdp_peer_get(r, d, &r_cdp, &d_cdp); @@ -2767,8 +2760,7 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, cfg->have_new_ctrl = false; cfg->new_ctrl = r->cache.shareable_bits; used_b = r->cache.shareable_bits; - ctrl = resctrl_to_arch_dom(d)->ctrl_val; - for (i = 0; i < closids_supported(); i++, ctrl++) { + for (i = 0; i < closids_supported(); i++) { if (closid_allocated(i) && i != closid) { mode = rdtgroup_mode_by_closid(i); if (mode == RDT_MODE_PSEUDO_LOCKSETUP) @@ -2784,12 +2776,13 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, * with an exclusive group. */ if (d_cdp) - peer_ctl = resctrl_to_arch_dom(d_cdp)->ctrl_val[i]; + resctrl_arch_get_config(r_cdp, d_cdp, i, &peer_ctl); else peer_ctl = 0; - used_b |= *ctrl | peer_ctl; + resctrl_arch_get_config(r, d, i, &ctrl_val); + used_b |= ctrl_val | peer_ctl; if (mode == RDT_MODE_SHAREABLE) - cfg->new_ctrl |= *ctrl | peer_ctl; + cfg->new_ctrl |= ctrl_val | peer_ctl; } } if (d->plr && d->plr->cbm > 0) diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index be5881171576..3a2309403094 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -200,5 +200,7 @@ struct resctrl_schema { /* The number of closid supported by this resource regardless of CDP */ u32 resctrl_arch_get_num_closid(struct rdt_resource *r); int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid); +void resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, + u32 closid, u32 *value); #endif /* _RESCTRL_H */ -- cgit v1.2.3-71-gd317 From fa8f711d2f14381d1a47420b6da94b62e6484c56 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 28 Jul 2021 17:06:30 +0000 Subject: x86/resctrl: Pass configuration type to resctrl_arch_get_config() The ctrl_val[] array for a struct rdt_hw_resource only holds configurations of one type. The type is implicit. Once the CDP resources are merged, the ctrl_val[] array will hold all the configurations for the hardware resource. When a particular type of configuration is needed, it must be specified explicitly. Pass the expected type from the schema into resctrl_arch_get_config(). Nothing uses this yet, but once a single ctrl_val[] array is used for the three struct rdt_hw_resources that share hardware, the type will be used to return the correct configuration value from the shared array. Signed-off-by: James Morse Signed-off-by: Borislav Petkov Reviewed-by: Jamie Iles Reviewed-by: Reinette Chatre Tested-by: Babu Moger Link: https://lkml.kernel.org/r/20210728170637.25610-18-james.morse@arm.com --- arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 5 +++-- arch/x86/kernel/cpu/resctrl/monitor.c | 2 +- arch/x86/kernel/cpu/resctrl/rdtgroup.c | 35 ++++++++++++++++++++----------- include/linux/resctrl.h | 3 ++- 4 files changed, 29 insertions(+), 16 deletions(-) (limited to 'include/linux/resctrl.h') diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c index 4da08ba0deda..9ead0c0bf6ee 100644 --- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c +++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c @@ -402,7 +402,7 @@ out: } void resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, - u32 closid, u32 *value) + u32 closid, enum resctrl_conf_type type, u32 *value) { struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d); @@ -424,7 +424,8 @@ static void show_doms(struct seq_file *s, struct resctrl_schema *schema, int clo if (sep) seq_puts(s, ";"); - resctrl_arch_get_config(r, dom, closid, &ctrl_val); + resctrl_arch_get_config(r, dom, closid, schema->conf_type, + &ctrl_val); seq_printf(s, r->format_str, dom->id, max_data_width, ctrl_val); sep = true; diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c index e45e7150eb81..eb227298487f 100644 --- a/arch/x86/kernel/cpu/resctrl/monitor.c +++ b/arch/x86/kernel/cpu/resctrl/monitor.c @@ -442,7 +442,7 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm) hw_dom_mba = resctrl_to_arch_dom(dom_mba); cur_bw = pmbm_data->prev_bw; - resctrl_arch_get_config(r_mba, dom_mba, closid, &user_bw); + resctrl_arch_get_config(r_mba, dom_mba, closid, CDP_NONE, &user_bw); delta_bw = pmbm_data->delta_bw; /* * resctrl_arch_get_config() chooses the mbps/ctrl value to return diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index 6b2be5633536..61037b239327 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -923,7 +923,8 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of, for (i = 0; i < closids_supported(); i++) { if (!closid_allocated(i)) continue; - resctrl_arch_get_config(r, dom, i, &ctrl_val); + resctrl_arch_get_config(r, dom, i, s->conf_type, + &ctrl_val); mode = rdtgroup_mode_by_closid(i); switch (mode) { case RDT_MODE_SHAREABLE: @@ -1099,6 +1100,7 @@ static int rdtgroup_mode_show(struct kernfs_open_file *of, * Used to return the result. * @d_cdp: RDT domain that shares hardware with @d (RDT domain peer) * Used to return the result. + * @peer_type: The CDP configuration type of the peer resource. * * RDT resources are managed independently and by extension the RDT domains * (RDT resource instances) are managed independently also. The Code and @@ -1116,7 +1118,8 @@ static int rdtgroup_mode_show(struct kernfs_open_file *of, */ static int rdt_cdp_peer_get(struct rdt_resource *r, struct rdt_domain *d, struct rdt_resource **r_cdp, - struct rdt_domain **d_cdp) + struct rdt_domain **d_cdp, + enum resctrl_conf_type *peer_type) { struct rdt_resource *_r_cdp = NULL; struct rdt_domain *_d_cdp = NULL; @@ -1125,15 +1128,19 @@ static int rdt_cdp_peer_get(struct rdt_resource *r, struct rdt_domain *d, switch (r->rid) { case RDT_RESOURCE_L3DATA: _r_cdp = &rdt_resources_all[RDT_RESOURCE_L3CODE].r_resctrl; + *peer_type = CDP_CODE; break; case RDT_RESOURCE_L3CODE: _r_cdp = &rdt_resources_all[RDT_RESOURCE_L3DATA].r_resctrl; + *peer_type = CDP_DATA; break; case RDT_RESOURCE_L2DATA: _r_cdp = &rdt_resources_all[RDT_RESOURCE_L2CODE].r_resctrl; + *peer_type = CDP_CODE; break; case RDT_RESOURCE_L2CODE: _r_cdp = &rdt_resources_all[RDT_RESOURCE_L2DATA].r_resctrl; + *peer_type = CDP_DATA; break; default: ret = -ENOENT; @@ -1184,7 +1191,8 @@ out: * Return: false if CBM does not overlap, true if it does. */ static bool __rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_domain *d, - unsigned long cbm, int closid, bool exclusive) + unsigned long cbm, int closid, + enum resctrl_conf_type type, bool exclusive) { enum rdtgrp_mode mode; unsigned long ctrl_b; @@ -1199,7 +1207,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++) { - resctrl_arch_get_config(r, d, i, (u32 *)&ctrl_b); + resctrl_arch_get_config(r, d, i, type, (u32 *)&ctrl_b); mode = rdtgroup_mode_by_closid(i); if (closid_allocated(i) && i != closid && mode != RDT_MODE_PSEUDO_LOCKSETUP) { @@ -1240,17 +1248,19 @@ static bool __rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_domain *d bool rdtgroup_cbm_overlaps(struct resctrl_schema *s, struct rdt_domain *d, unsigned long cbm, int closid, bool exclusive) { + enum resctrl_conf_type peer_type; struct rdt_resource *r = s->res; struct rdt_resource *r_cdp; struct rdt_domain *d_cdp; - if (__rdtgroup_cbm_overlaps(r, d, cbm, closid, exclusive)) + if (__rdtgroup_cbm_overlaps(r, d, cbm, closid, s->conf_type, + exclusive)) return true; - if (rdt_cdp_peer_get(r, d, &r_cdp, &d_cdp) < 0) + if (rdt_cdp_peer_get(r, d, &r_cdp, &d_cdp, &peer_type) < 0) return false; - return __rdtgroup_cbm_overlaps(r_cdp, d_cdp, cbm, closid, exclusive); + return __rdtgroup_cbm_overlaps(r_cdp, d_cdp, cbm, closid, peer_type, exclusive); } /** @@ -1280,7 +1290,7 @@ static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp) continue; has_cache = true; list_for_each_entry(d, &r->domains, list) { - resctrl_arch_get_config(r, d, closid, &ctrl); + resctrl_arch_get_config(r, d, closid, s->conf_type, &ctrl); if (rdtgroup_cbm_overlaps(s, d, ctrl, closid, false)) { rdt_last_cmd_puts("Schemata overlaps\n"); return false; @@ -1454,7 +1464,7 @@ static int rdtgroup_size_show(struct kernfs_open_file *of, size = 0; } else { resctrl_arch_get_config(r, d, rdtgrp->closid, - &ctrl); + schema->conf_type, &ctrl); if (r->rid == RDT_RESOURCE_MBA) size = ctrl; else @@ -2747,6 +2757,7 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, enum resctrl_conf_type t = s->conf_type; struct rdt_resource *r_cdp = NULL; struct resctrl_staged_config *cfg; + enum resctrl_conf_type peer_type; struct rdt_domain *d_cdp = NULL; struct rdt_resource *r = s->res; u32 used_b = 0, unused_b = 0; @@ -2755,7 +2766,7 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, u32 peer_ctl, ctrl_val; int i; - rdt_cdp_peer_get(r, d, &r_cdp, &d_cdp); + rdt_cdp_peer_get(r, d, &r_cdp, &d_cdp, &peer_type); cfg = &d->staged_config[t]; cfg->have_new_ctrl = false; cfg->new_ctrl = r->cache.shareable_bits; @@ -2776,10 +2787,10 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, * with an exclusive group. */ if (d_cdp) - resctrl_arch_get_config(r_cdp, d_cdp, i, &peer_ctl); + resctrl_arch_get_config(r_cdp, d_cdp, i, peer_type, &peer_ctl); else peer_ctl = 0; - resctrl_arch_get_config(r, d, i, &ctrl_val); + resctrl_arch_get_config(r, d, i, s->conf_type, &ctrl_val); used_b |= ctrl_val | peer_ctl; if (mode == RDT_MODE_SHAREABLE) cfg->new_ctrl |= ctrl_val | peer_ctl; diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index 3a2309403094..69d7387b7f22 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -201,6 +201,7 @@ struct resctrl_schema { u32 resctrl_arch_get_num_closid(struct rdt_resource *r); int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid); void resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, - u32 closid, u32 *value); + u32 closid, enum resctrl_conf_type type, + u32 *value); #endif /* _RESCTRL_H */ -- cgit v1.2.3-71-gd317 From 2b8dd4ab65dad1251822fbf74fb0d5623e4eaee0 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 28 Jul 2021 17:06:33 +0000 Subject: x86/resctrl: Calculate the index from the configuration type resctrl uses cbm_idx() to map a closid to an index in the configuration array. This is based on a multiplier and offset that are held in the resource. To merge the resources, the resctrl arch code needs to calculate the index from something else, as there will only be one resource. Decide based on the staged configuration type. This makes the static mult and offset parameters redundant. [ bp: Remove superfluous brackets in get_config_index() ] Signed-off-by: James Morse Signed-off-by: Borislav Petkov Reviewed-by: Jamie Iles Reviewed-by: Reinette Chatre Tested-by: Babu Moger Link: https://lkml.kernel.org/r/20210728170637.25610-21-james.morse@arm.com --- arch/x86/kernel/cpu/resctrl/core.c | 12 ------------ arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 25 +++++++++++++++---------- include/linux/resctrl.h | 6 ------ 3 files changed, 15 insertions(+), 28 deletions(-) (limited to 'include/linux/resctrl.h') diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c index 990e41661b4a..c6b953fe7fdf 100644 --- a/arch/x86/kernel/cpu/resctrl/core.c +++ b/arch/x86/kernel/cpu/resctrl/core.c @@ -69,8 +69,6 @@ struct rdt_hw_resource rdt_resources_all[] = { .cache_level = 3, .cache = { .min_cbm_bits = 1, - .cbm_idx_mult = 1, - .cbm_idx_offset = 0, }, .domains = domain_init(RDT_RESOURCE_L3), .parse_ctrlval = parse_cbm, @@ -89,8 +87,6 @@ struct rdt_hw_resource rdt_resources_all[] = { .cache_level = 3, .cache = { .min_cbm_bits = 1, - .cbm_idx_mult = 2, - .cbm_idx_offset = 0, }, .domains = domain_init(RDT_RESOURCE_L3DATA), .parse_ctrlval = parse_cbm, @@ -109,8 +105,6 @@ struct rdt_hw_resource rdt_resources_all[] = { .cache_level = 3, .cache = { .min_cbm_bits = 1, - .cbm_idx_mult = 2, - .cbm_idx_offset = 1, }, .domains = domain_init(RDT_RESOURCE_L3CODE), .parse_ctrlval = parse_cbm, @@ -129,8 +123,6 @@ struct rdt_hw_resource rdt_resources_all[] = { .cache_level = 2, .cache = { .min_cbm_bits = 1, - .cbm_idx_mult = 1, - .cbm_idx_offset = 0, }, .domains = domain_init(RDT_RESOURCE_L2), .parse_ctrlval = parse_cbm, @@ -149,8 +141,6 @@ struct rdt_hw_resource rdt_resources_all[] = { .cache_level = 2, .cache = { .min_cbm_bits = 1, - .cbm_idx_mult = 2, - .cbm_idx_offset = 0, }, .domains = domain_init(RDT_RESOURCE_L2DATA), .parse_ctrlval = parse_cbm, @@ -169,8 +159,6 @@ struct rdt_hw_resource rdt_resources_all[] = { .cache_level = 2, .cache = { .min_cbm_bits = 1, - .cbm_idx_mult = 2, - .cbm_idx_offset = 1, }, .domains = domain_init(RDT_RESOURCE_L2CODE), .parse_ctrlval = parse_cbm, diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c index fdb0e11a78dc..92d79c88b965 100644 --- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c +++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c @@ -246,12 +246,17 @@ next: return -EINVAL; } -static u32 cbm_idx(struct rdt_resource *r, unsigned int closid) +static u32 get_config_index(u32 closid, enum resctrl_conf_type type) { - if (r->rid == RDT_RESOURCE_MBA) + switch (type) { + default: + case CDP_NONE: return closid; - - return closid * r->cache.cbm_idx_mult + r->cache.cbm_idx_offset; + case CDP_CODE: + return closid * 2 + 1; + case CDP_DATA: + return closid * 2; + } } static bool apply_config(struct rdt_hw_domain *hw_dom, @@ -286,10 +291,6 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid) if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL)) return -ENOMEM; - msr_param.low = cbm_idx(r, closid); - msr_param.high = msr_param.low + 1; - msr_param.res = r; - mba_sc = is_mba_sc(r); list_for_each_entry(d, &r->domains, list) { hw_dom = resctrl_to_arch_dom(d); @@ -298,9 +299,13 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid) if (!cfg->have_new_ctrl) continue; - idx = cbm_idx(r, closid); + idx = get_config_index(closid, t); if (!apply_config(hw_dom, cfg, idx, cpu_mask, mba_sc)) continue; + + msr_param.low = idx; + msr_param.high = msr_param.low + 1; + msr_param.res = r; } } @@ -420,7 +425,7 @@ void resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, u32 closid, enum resctrl_conf_type type, u32 *value) { struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d); - u32 idx = cbm_idx(r, closid); + u32 idx = get_config_index(closid, type); if (!is_mba_sc(r)) *value = hw_dom->ctrl_val[idx]; diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index 69d7387b7f22..18dd764af0dd 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -73,10 +73,6 @@ struct rdt_domain { * struct resctrl_cache - Cache allocation related data * @cbm_len: Length of the cache bit mask * @min_cbm_bits: Minimum number of consecutive bits to be set - * @cbm_idx_mult: Multiplier of CBM index - * @cbm_idx_offset: Offset of CBM index. CBM index is computed by: - * closid * cbm_idx_multi + cbm_idx_offset - * in a cache bit mask * @shareable_bits: Bitmask of shareable resource with other * executing entities * @arch_has_sparse_bitmaps: True if a bitmap like f00f is valid. @@ -87,8 +83,6 @@ struct rdt_domain { struct resctrl_cache { unsigned int cbm_len; unsigned int min_cbm_bits; - unsigned int cbm_idx_mult; // TODO remove this - unsigned int cbm_idx_offset; // TODO remove this unsigned int shareable_bits; bool arch_has_sparse_bitmaps; bool arch_has_empty_bitmaps; -- cgit v1.2.3-71-gd317 From 111136e69c9df50c3ca7d4e3977344b8a2d0d947 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 11 Aug 2021 16:38:31 +0000 Subject: x86/resctrl: Make resctrl_arch_get_config() return its value resctrl_arch_get_config() has no return, but does pass a single value back via one of its arguments. Return the value instead. Suggested-by: Borislav Petkov Signed-off-by: James Morse Signed-off-by: Borislav Petkov Link: https://lkml.kernel.org/r/20210811163831.14917-1-james.morse@arm.com --- arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 13 ++++++------- arch/x86/kernel/cpu/resctrl/monitor.c | 2 +- arch/x86/kernel/cpu/resctrl/rdtgroup.c | 20 ++++++++++++-------- include/linux/resctrl.h | 5 ++--- 4 files changed, 21 insertions(+), 19 deletions(-) (limited to 'include/linux/resctrl.h') diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c index a487cf7ff04e..87666275eed9 100644 --- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c +++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c @@ -427,16 +427,15 @@ out: return ret ?: nbytes; } -void resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, - u32 closid, enum resctrl_conf_type type, u32 *value) +u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, + u32 closid, enum resctrl_conf_type type) { struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d); u32 idx = get_config_index(closid, type); if (!is_mba_sc(r)) - *value = hw_dom->ctrl_val[idx]; - else - *value = hw_dom->mbps_val[idx]; + return hw_dom->ctrl_val[idx]; + return hw_dom->mbps_val[idx]; } static void show_doms(struct seq_file *s, struct resctrl_schema *schema, int closid) @@ -451,8 +450,8 @@ static void show_doms(struct seq_file *s, struct resctrl_schema *schema, int clo if (sep) seq_puts(s, ";"); - resctrl_arch_get_config(r, dom, closid, schema->conf_type, - &ctrl_val); + ctrl_val = resctrl_arch_get_config(r, dom, closid, + schema->conf_type); seq_printf(s, r->format_str, dom->id, max_data_width, ctrl_val); sep = true; diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c index eb227298487f..b0741bee79fc 100644 --- a/arch/x86/kernel/cpu/resctrl/monitor.c +++ b/arch/x86/kernel/cpu/resctrl/monitor.c @@ -442,7 +442,7 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm) hw_dom_mba = resctrl_to_arch_dom(dom_mba); cur_bw = pmbm_data->prev_bw; - resctrl_arch_get_config(r_mba, dom_mba, closid, CDP_NONE, &user_bw); + user_bw = resctrl_arch_get_config(r_mba, dom_mba, closid, CDP_NONE); delta_bw = pmbm_data->delta_bw; /* * resctrl_arch_get_config() chooses the mbps/ctrl value to return diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index 89123a4977cf..b57b3db9a6a7 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -923,8 +923,8 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of, for (i = 0; i < closids_supported(); i++) { if (!closid_allocated(i)) continue; - resctrl_arch_get_config(r, dom, i, s->conf_type, - &ctrl_val); + ctrl_val = resctrl_arch_get_config(r, dom, i, + s->conf_type); mode = rdtgroup_mode_by_closid(i); switch (mode) { case RDT_MODE_SHAREABLE: @@ -1142,7 +1142,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++) { - resctrl_arch_get_config(r, d, i, type, (u32 *)&ctrl_b); + ctrl_b = resctrl_arch_get_config(r, d, i, type); mode = rdtgroup_mode_by_closid(i); if (closid_allocated(i) && i != closid && mode != RDT_MODE_PSEUDO_LOCKSETUP) { @@ -1222,7 +1222,8 @@ static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp) continue; has_cache = true; list_for_each_entry(d, &r->domains, list) { - resctrl_arch_get_config(r, d, closid, s->conf_type, &ctrl); + ctrl = resctrl_arch_get_config(r, d, closid, + s->conf_type); if (rdtgroup_cbm_overlaps(s, d, ctrl, closid, false)) { rdt_last_cmd_puts("Schemata overlaps\n"); return false; @@ -1395,8 +1396,9 @@ static int rdtgroup_size_show(struct kernfs_open_file *of, if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) { size = 0; } else { - resctrl_arch_get_config(r, d, rdtgrp->closid, - schema->conf_type, &ctrl); + ctrl = resctrl_arch_get_config(r, d, + rdtgrp->closid, + schema->conf_type); if (r->rid == RDT_RESOURCE_MBA) size = ctrl; else @@ -2724,10 +2726,12 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, * with an exclusive group. */ if (resctrl_arch_get_cdp_enabled(r->rid)) - resctrl_arch_get_config(r, d, i, peer_type, &peer_ctl); + peer_ctl = resctrl_arch_get_config(r, d, i, + peer_type); else peer_ctl = 0; - resctrl_arch_get_config(r, d, i, s->conf_type, &ctrl_val); + ctrl_val = resctrl_arch_get_config(r, d, i, + s->conf_type); used_b |= ctrl_val | peer_ctl; if (mode == RDT_MODE_SHAREABLE) cfg->new_ctrl |= ctrl_val | peer_ctl; diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index 18dd764af0dd..21deb5212bbd 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -194,8 +194,7 @@ struct resctrl_schema { /* The number of closid supported by this resource regardless of CDP */ u32 resctrl_arch_get_num_closid(struct rdt_resource *r); int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid); -void resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, - u32 closid, enum resctrl_conf_type type, - u32 *value); +u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, + u32 closid, enum resctrl_conf_type type); #endif /* _RESCTRL_H */ -- cgit v1.2.3-71-gd317