Commit 5186ba33 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'x86_cache_for_v6.10_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 resource control updates from Borislav Petkov:

 - Add a tracepoint to read out LLC occupancy of resource monitor IDs
   with the goal of freeing them sooner rather than later

 - Other code improvements and cleanups

* tag 'x86_cache_for_v6.10_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/resctrl: Add tracepoint for llc_occupancy tracking
  x86/resctrl: Rename pseudo_lock_event.h to trace.h
  x86/resctrl: Simplify call convention for MSR update functions
  x86/resctrl: Pass domain to target CPU
parents 25c7cb05 931be446
...@@ -446,6 +446,12 @@ during mkdir. ...@@ -446,6 +446,12 @@ during mkdir.
max_threshold_occupancy is a user configurable value to determine the max_threshold_occupancy is a user configurable value to determine the
occupancy at which an RMID can be freed. occupancy at which an RMID can be freed.
The mon_llc_occupancy_limbo tracepoint gives the precise occupancy in bytes
for a subset of RMID that are not immediately available for allocation.
This can't be relied on to produce output every second, it may be necessary
to attempt to create an empty monitor group to force an update. Output may
only be produced if creation of a control or monitor group fails.
Schemata files - general concepts Schemata files - general concepts
--------------------------------- ---------------------------------
Each line in the file describes one resource. The line starts with Each line in the file describes one resource. The line starts with
......
...@@ -56,14 +56,9 @@ int max_name_width, max_data_width; ...@@ -56,14 +56,9 @@ int max_name_width, max_data_width;
*/ */
bool rdt_alloc_capable; bool rdt_alloc_capable;
static void static void mba_wrmsr_intel(struct msr_param *m);
mba_wrmsr_intel(struct rdt_domain *d, struct msr_param *m, static void cat_wrmsr(struct msr_param *m);
struct rdt_resource *r); static void mba_wrmsr_amd(struct msr_param *m);
static void
cat_wrmsr(struct rdt_domain *d, struct msr_param *m, struct rdt_resource *r);
static void
mba_wrmsr_amd(struct rdt_domain *d, struct msr_param *m,
struct rdt_resource *r);
#define domain_init(id) LIST_HEAD_INIT(rdt_resources_all[id].r_resctrl.domains) #define domain_init(id) LIST_HEAD_INIT(rdt_resources_all[id].r_resctrl.domains)
...@@ -309,12 +304,11 @@ static void rdt_get_cdp_l2_config(void) ...@@ -309,12 +304,11 @@ static void rdt_get_cdp_l2_config(void)
rdt_get_cdp_config(RDT_RESOURCE_L2); rdt_get_cdp_config(RDT_RESOURCE_L2);
} }
static void static void mba_wrmsr_amd(struct msr_param *m)
mba_wrmsr_amd(struct rdt_domain *d, struct msr_param *m, struct rdt_resource *r)
{ {
struct rdt_hw_resource *hw_res = resctrl_to_arch_res(m->res);
struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(m->dom);
unsigned int i; 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++) for (i = m->low; i < m->high; i++)
wrmsrl(hw_res->msr_base + i, hw_dom->ctrl_val[i]); wrmsrl(hw_res->msr_base + i, hw_dom->ctrl_val[i]);
...@@ -334,25 +328,22 @@ static u32 delay_bw_map(unsigned long bw, struct rdt_resource *r) ...@@ -334,25 +328,22 @@ static u32 delay_bw_map(unsigned long bw, struct rdt_resource *r)
return r->default_ctrl; return r->default_ctrl;
} }
static void static void mba_wrmsr_intel(struct msr_param *m)
mba_wrmsr_intel(struct rdt_domain *d, struct msr_param *m,
struct rdt_resource *r)
{ {
struct rdt_hw_resource *hw_res = resctrl_to_arch_res(m->res);
struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(m->dom);
unsigned int i; 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. */ /* Write the delay values for mba. */
for (i = m->low; i < m->high; i++) for (i = m->low; i < m->high; i++)
wrmsrl(hw_res->msr_base + i, delay_bw_map(hw_dom->ctrl_val[i], r)); wrmsrl(hw_res->msr_base + i, delay_bw_map(hw_dom->ctrl_val[i], m->res));
} }
static void static void cat_wrmsr(struct msr_param *m)
cat_wrmsr(struct rdt_domain *d, struct msr_param *m, struct rdt_resource *r)
{ {
struct rdt_hw_resource *hw_res = resctrl_to_arch_res(m->res);
struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(m->dom);
unsigned int i; 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++) for (i = m->low; i < m->high; i++)
wrmsrl(hw_res->msr_base + i, hw_dom->ctrl_val[i]); wrmsrl(hw_res->msr_base + i, hw_dom->ctrl_val[i]);
...@@ -362,6 +353,8 @@ struct rdt_domain *get_domain_from_cpu(int cpu, struct rdt_resource *r) ...@@ -362,6 +353,8 @@ struct rdt_domain *get_domain_from_cpu(int cpu, struct rdt_resource *r)
{ {
struct rdt_domain *d; struct rdt_domain *d;
lockdep_assert_cpus_held();
list_for_each_entry(d, &r->domains, list) { list_for_each_entry(d, &r->domains, list) {
/* Find the domain that contains this CPU */ /* Find the domain that contains this CPU */
if (cpumask_test_cpu(cpu, &d->cpu_mask)) if (cpumask_test_cpu(cpu, &d->cpu_mask))
...@@ -378,19 +371,11 @@ u32 resctrl_arch_get_num_closid(struct rdt_resource *r) ...@@ -378,19 +371,11 @@ u32 resctrl_arch_get_num_closid(struct rdt_resource *r)
void rdt_ctrl_update(void *arg) void rdt_ctrl_update(void *arg)
{ {
struct rdt_hw_resource *hw_res;
struct msr_param *m = arg; struct msr_param *m = arg;
struct rdt_hw_resource *hw_res = resctrl_to_arch_res(m->res);
struct rdt_resource *r = m->res;
int cpu = smp_processor_id();
struct rdt_domain *d;
d = get_domain_from_cpu(cpu, r); hw_res = resctrl_to_arch_res(m->res);
if (d) { hw_res->msr_update(m);
hw_res->msr_update(d, m, r);
return;
}
pr_warn_once("cpu %d not found in any domain for resource %s\n",
cpu, r->name);
} }
/* /*
...@@ -463,9 +448,11 @@ static int domain_setup_ctrlval(struct rdt_resource *r, struct rdt_domain *d) ...@@ -463,9 +448,11 @@ static int domain_setup_ctrlval(struct rdt_resource *r, struct rdt_domain *d)
hw_dom->ctrl_val = dc; hw_dom->ctrl_val = dc;
setup_default_ctrlval(r, dc); setup_default_ctrlval(r, dc);
m.res = r;
m.dom = d;
m.low = 0; m.low = 0;
m.high = hw_res->num_closid; m.high = hw_res->num_closid;
hw_res->msr_update(d, &m, r); hw_res->msr_update(&m);
return 0; return 0;
} }
......
...@@ -272,22 +272,6 @@ static u32 get_config_index(u32 closid, enum resctrl_conf_type type) ...@@ -272,22 +272,6 @@ static u32 get_config_index(u32 closid, enum resctrl_conf_type type)
} }
} }
static bool apply_config(struct rdt_hw_domain *hw_dom,
struct resctrl_staged_config *cfg, u32 idx,
cpumask_var_t cpu_mask)
{
struct rdt_domain *dom = &hw_dom->d_resctrl;
if (cfg->new_ctrl != hw_dom->ctrl_val[idx]) {
cpumask_set_cpu(cpumask_any(&dom->cpu_mask), cpu_mask);
hw_dom->ctrl_val[idx] = cfg->new_ctrl;
return true;
}
return false;
}
int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d,
u32 closid, enum resctrl_conf_type t, u32 cfg_val) u32 closid, enum resctrl_conf_type t, u32 cfg_val)
{ {
...@@ -302,9 +286,10 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, ...@@ -302,9 +286,10 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d,
hw_dom->ctrl_val[idx] = cfg_val; hw_dom->ctrl_val[idx] = cfg_val;
msr_param.res = r; msr_param.res = r;
msr_param.dom = d;
msr_param.low = idx; msr_param.low = idx;
msr_param.high = idx + 1; msr_param.high = idx + 1;
hw_res->msr_update(d, &msr_param, r); hw_res->msr_update(&msr_param);
return 0; return 0;
} }
...@@ -315,48 +300,39 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid) ...@@ -315,48 +300,39 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
struct rdt_hw_domain *hw_dom; struct rdt_hw_domain *hw_dom;
struct msr_param msr_param; struct msr_param msr_param;
enum resctrl_conf_type t; enum resctrl_conf_type t;
cpumask_var_t cpu_mask;
struct rdt_domain *d; struct rdt_domain *d;
u32 idx; u32 idx;
/* Walking r->domains, ensure it can't race with cpuhp */ /* Walking r->domains, ensure it can't race with cpuhp */
lockdep_assert_cpus_held(); lockdep_assert_cpus_held();
if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
return -ENOMEM;
msr_param.res = NULL;
list_for_each_entry(d, &r->domains, list) { list_for_each_entry(d, &r->domains, list) {
hw_dom = resctrl_to_arch_dom(d); hw_dom = resctrl_to_arch_dom(d);
msr_param.res = NULL;
for (t = 0; t < CDP_NUM_TYPES; t++) { for (t = 0; t < CDP_NUM_TYPES; t++) {
cfg = &hw_dom->d_resctrl.staged_config[t]; cfg = &hw_dom->d_resctrl.staged_config[t];
if (!cfg->have_new_ctrl) if (!cfg->have_new_ctrl)
continue; continue;
idx = get_config_index(closid, t); idx = get_config_index(closid, t);
if (!apply_config(hw_dom, cfg, idx, cpu_mask)) if (cfg->new_ctrl == hw_dom->ctrl_val[idx])
continue; continue;
hw_dom->ctrl_val[idx] = cfg->new_ctrl;
if (!msr_param.res) { if (!msr_param.res) {
msr_param.low = idx; msr_param.low = idx;
msr_param.high = msr_param.low + 1; msr_param.high = msr_param.low + 1;
msr_param.res = r; msr_param.res = r;
msr_param.dom = d;
} else { } else {
msr_param.low = min(msr_param.low, idx); msr_param.low = min(msr_param.low, idx);
msr_param.high = max(msr_param.high, idx + 1); msr_param.high = max(msr_param.high, idx + 1);
} }
} }
if (msr_param.res)
smp_call_function_any(&d->cpu_mask, rdt_ctrl_update, &msr_param, 1);
} }
if (cpumask_empty(cpu_mask))
goto done;
/* Update resource control msr on all the CPUs. */
on_each_cpu_mask(cpu_mask, rdt_ctrl_update, &msr_param, 1);
done:
free_cpumask_var(cpu_mask);
return 0; return 0;
} }
......
...@@ -379,11 +379,13 @@ static inline struct rdt_hw_domain *resctrl_to_arch_dom(struct rdt_domain *r) ...@@ -379,11 +379,13 @@ static inline struct rdt_hw_domain *resctrl_to_arch_dom(struct rdt_domain *r)
/** /**
* struct msr_param - set a range of MSRs from a domain * struct msr_param - set a range of MSRs from a domain
* @res: The resource to use * @res: The resource to use
* @dom: The domain to update
* @low: Beginning index from base MSR * @low: Beginning index from base MSR
* @high: End index * @high: End index
*/ */
struct msr_param { struct msr_param {
struct rdt_resource *res; struct rdt_resource *res;
struct rdt_domain *dom;
u32 low; u32 low;
u32 high; u32 high;
}; };
...@@ -443,8 +445,7 @@ struct rdt_hw_resource { ...@@ -443,8 +445,7 @@ struct rdt_hw_resource {
struct rdt_resource r_resctrl; struct rdt_resource r_resctrl;
u32 num_closid; u32 num_closid;
unsigned int msr_base; unsigned int msr_base;
void (*msr_update) (struct rdt_domain *d, struct msr_param *m, void (*msr_update)(struct msr_param *m);
struct rdt_resource *r);
unsigned int mon_scale; unsigned int mon_scale;
unsigned int mbm_width; unsigned int mbm_width;
unsigned int mbm_cfg_mask; unsigned int mbm_cfg_mask;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <asm/resctrl.h> #include <asm/resctrl.h>
#include "internal.h" #include "internal.h"
#include "trace.h"
/** /**
* struct rmid_entry - dirty tracking for all RMID. * struct rmid_entry - dirty tracking for all RMID.
...@@ -354,6 +355,16 @@ void __check_limbo(struct rdt_domain *d, bool force_free) ...@@ -354,6 +355,16 @@ void __check_limbo(struct rdt_domain *d, bool force_free)
rmid_dirty = true; rmid_dirty = true;
} else { } else {
rmid_dirty = (val >= resctrl_rmid_realloc_threshold); rmid_dirty = (val >= resctrl_rmid_realloc_threshold);
/*
* x86's CLOSID and RMID are independent numbers, so the entry's
* CLOSID is an empty CLOSID (X86_RESCTRL_EMPTY_CLOSID). On Arm the
* RMID (PMG) extends the CLOSID (PARTID) space with bits that aren't
* used to select the configuration. It is thus necessary to track both
* CLOSID and RMID because there may be dependencies between them
* on some architectures.
*/
trace_mon_llc_occupancy_limbo(entry->closid, entry->rmid, d->id, val);
} }
if (force_free || !rmid_dirty) { if (force_free || !rmid_dirty) {
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#include "internal.h" #include "internal.h"
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include "pseudo_lock_event.h" #include "trace.h"
/* /*
* The bits needed to disable hardware prefetching varies based on the * The bits needed to disable hardware prefetching varies based on the
......
...@@ -2813,16 +2813,12 @@ static int reset_all_ctrls(struct rdt_resource *r) ...@@ -2813,16 +2813,12 @@ static int reset_all_ctrls(struct rdt_resource *r)
struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
struct rdt_hw_domain *hw_dom; struct rdt_hw_domain *hw_dom;
struct msr_param msr_param; struct msr_param msr_param;
cpumask_var_t cpu_mask;
struct rdt_domain *d; struct rdt_domain *d;
int i; int i;
/* Walking r->domains, ensure it can't race with cpuhp */ /* Walking r->domains, ensure it can't race with cpuhp */
lockdep_assert_cpus_held(); lockdep_assert_cpus_held();
if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
return -ENOMEM;
msr_param.res = r; msr_param.res = r;
msr_param.low = 0; msr_param.low = 0;
msr_param.high = hw_res->num_closid; msr_param.high = hw_res->num_closid;
...@@ -2834,17 +2830,13 @@ static int reset_all_ctrls(struct rdt_resource *r) ...@@ -2834,17 +2830,13 @@ static int reset_all_ctrls(struct rdt_resource *r)
*/ */
list_for_each_entry(d, &r->domains, list) { list_for_each_entry(d, &r->domains, list) {
hw_dom = resctrl_to_arch_dom(d); 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++) for (i = 0; i < hw_res->num_closid; i++)
hw_dom->ctrl_val[i] = r->default_ctrl; hw_dom->ctrl_val[i] = r->default_ctrl;
msr_param.dom = d;
smp_call_function_any(&d->cpu_mask, rdt_ctrl_update, &msr_param, 1);
} }
/* Update CBM on all the CPUs in cpu_mask */
on_each_cpu_mask(cpu_mask, rdt_ctrl_update, &msr_param, 1);
free_cpumask_var(cpu_mask);
return 0; return 0;
} }
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
#undef TRACE_SYSTEM #undef TRACE_SYSTEM
#define TRACE_SYSTEM resctrl #define TRACE_SYSTEM resctrl
#if !defined(_TRACE_PSEUDO_LOCK_H) || defined(TRACE_HEADER_MULTI_READ) #if !defined(_TRACE_RESCTRL_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_PSEUDO_LOCK_H #define _TRACE_RESCTRL_H
#include <linux/tracepoint.h> #include <linux/tracepoint.h>
...@@ -35,9 +35,25 @@ TRACE_EVENT(pseudo_lock_l3, ...@@ -35,9 +35,25 @@ TRACE_EVENT(pseudo_lock_l3,
TP_printk("hits=%llu miss=%llu", TP_printk("hits=%llu miss=%llu",
__entry->l3_hits, __entry->l3_miss)); __entry->l3_hits, __entry->l3_miss));
#endif /* _TRACE_PSEUDO_LOCK_H */ TRACE_EVENT(mon_llc_occupancy_limbo,
TP_PROTO(u32 ctrl_hw_id, u32 mon_hw_id, int domain_id, u64 llc_occupancy_bytes),
TP_ARGS(ctrl_hw_id, mon_hw_id, domain_id, llc_occupancy_bytes),
TP_STRUCT__entry(__field(u32, ctrl_hw_id)
__field(u32, mon_hw_id)
__field(int, domain_id)
__field(u64, llc_occupancy_bytes)),
TP_fast_assign(__entry->ctrl_hw_id = ctrl_hw_id;
__entry->mon_hw_id = mon_hw_id;
__entry->domain_id = domain_id;
__entry->llc_occupancy_bytes = llc_occupancy_bytes;),
TP_printk("ctrl_hw_id=%u mon_hw_id=%u domain_id=%d llc_occupancy_bytes=%llu",
__entry->ctrl_hw_id, __entry->mon_hw_id, __entry->domain_id,
__entry->llc_occupancy_bytes)
);
#endif /* _TRACE_RESCTRL_H */
#undef TRACE_INCLUDE_PATH #undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH . #define TRACE_INCLUDE_PATH .
#define TRACE_INCLUDE_FILE pseudo_lock_event #define TRACE_INCLUDE_FILE trace
#include <trace/define_trace.h> #include <trace/define_trace.h>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment