Hi Tony, > There isn't a simple hardware enumeration to indicate to software that a > system is running with Sub-NUMA Cluster enabled. > > Compare the number of NUMA nodes with the number of L3 caches to calculate > the number of Sub-NUMA nodes per L3 cache. > > When Sub-NUMA cluster mode is enabled in BIOS setup the RMID counters are > distributed equally between the SNC nodes within each socket. > > E.g. if there are 400 RMID counters, and the system is configured with two SNC > nodes per socket, then RMID counter 0..199 are used on SNC node > 0 on the socket, and RMID counter 200..399 on SNC node 1. > > A model specific MSR (0xca0) can change the configuration of the RMIDs when > SNC mode is enabled. > > The MSR controls the interpretation of the RMID field in the IA32_PQR_ASSOC > MSR so that the appropriate hardware counters within the SNC node are > updated. > > Also initialize a per-cpu RMID offset value. Use this to calculate the value to > write to the IA32_QM_EVTSEL MSR when reading RMID event values. > > N.B. this works well for well-behaved NUMA applications that access memory > predominantly from the local memory node. For applications that access > memory across multiple nodes it may be necessary for the user to read counters > for all SNC nodes on a socket and add the values to get the actual LLC > occupancy or memory bandwidth. Perhaps this isn't all that different from > applications that span across multiple sockets in a legacy system. > > Signed-off-by: Tony Luck <tony.luck@xxxxxxxxx> > --- > arch/x86/include/asm/resctrl.h | 2 + > arch/x86/kernel/cpu/resctrl/core.c | 99 > ++++++++++++++++++++++++++- > arch/x86/kernel/cpu/resctrl/monitor.c | 2 +- > 3 files changed, 99 insertions(+), 4 deletions(-) > > diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h > index 255a78d9d906..f95e69bacc65 100644 > --- a/arch/x86/include/asm/resctrl.h > +++ b/arch/x86/include/asm/resctrl.h > @@ -35,6 +35,8 @@ DECLARE_STATIC_KEY_FALSE(rdt_enable_key); > DECLARE_STATIC_KEY_FALSE(rdt_alloc_enable_key); > DECLARE_STATIC_KEY_FALSE(rdt_mon_enable_key); > > +DECLARE_PER_CPU(int, rmid_offset); > + > /* > * __resctrl_sched_in() - Writes the task's CLOSid/RMID to IA32_PQR_MSR > * > diff --git a/arch/x86/kernel/cpu/resctrl/core.c > b/arch/x86/kernel/cpu/resctrl/core.c > index af3be3c2db96..869cfb46e8e4 100644 > --- a/arch/x86/kernel/cpu/resctrl/core.c > +++ b/arch/x86/kernel/cpu/resctrl/core.c > @@ -16,11 +16,14 @@ > > #define pr_fmt(fmt) "resctrl: " fmt > > +#include <linux/cpu.h> > #include <linux/slab.h> > #include <linux/err.h> > #include <linux/cacheinfo.h> > #include <linux/cpuhotplug.h> > +#include <linux/mod_devicetable.h> > > +#include <asm/cpu_device_id.h> > #include <asm/intel-family.h> > #include <asm/resctrl.h> > #include "internal.h" > @@ -524,6 +527,39 @@ static int get_domain_id(int cpu, enum resctrl_scope > scope) > } > } > > +DEFINE_PER_CPU(int, rmid_offset); > + > +static void set_per_cpu_rmid_offset(int cpu, struct rdt_resource *r) { > + this_cpu_write(rmid_offset, (cpu_to_node(cpu) % snc_ways) * > +r->num_rmid); } > + > +/* > + * This MSR provides for configuration of RMIDs on Sub-NUMA Cluster > + * systems. > + * Bit0 = 1 (default) For legacy configuration > + * Bit0 = 0 RMIDs are divided evenly between SNC nodes. > + */ > +#define MSR_RMID_SNC_CONFIG 0xCA0 > + > +static void snc_add_pkg(void) > +{ > + u64 msrval; > + > + rdmsrl(MSR_RMID_SNC_CONFIG, msrval); > + msrval |= BIT_ULL(0); > + wrmsrl(MSR_RMID_SNC_CONFIG, msrval); > +} > + > +static void snc_remove_pkg(void) > +{ > + u64 msrval; > + > + rdmsrl(MSR_RMID_SNC_CONFIG, msrval); > + msrval &= ~BIT_ULL(0); > + wrmsrl(MSR_RMID_SNC_CONFIG, msrval); > +} > + > /* > * domain_add_cpu - Add a cpu to a resource's domain list. > * > @@ -555,6 +591,8 @@ static void domain_add_cpu(int cpu, struct rdt_resource > *r) > cpumask_set_cpu(cpu, &d->cpu_mask); > if (r->cache.arch_has_per_cpu_cfg) > rdt_domain_reconfigure_cdp(r); > + if (r->mon_capable) > + set_per_cpu_rmid_offset(cpu, r); > return; > } > > @@ -573,11 +611,17 @@ static void domain_add_cpu(int cpu, struct > rdt_resource *r) > return; > } > > - if (r->mon_capable && arch_domain_mbm_alloc(r->num_rmid, > hw_dom)) { > - domain_free(hw_dom); > - return; > + if (r->mon_capable) { > + if (arch_domain_mbm_alloc(r->num_rmid, hw_dom)) { > + domain_free(hw_dom); > + return; > + } > + set_per_cpu_rmid_offset(cpu, r); > } > > + if (r->pkg_actions) > + snc_add_pkg(); > + > list_add_tail(&d->list, add_pos); > > err = resctrl_online_domain(r, d); > @@ -613,6 +657,9 @@ static void domain_remove_cpu(int cpu, struct > rdt_resource *r) > d->plr->d = NULL; > domain_free(hw_dom); > > + if (r->pkg_actions) > + snc_remove_pkg(); > + > return; > } > > @@ -899,11 +946,57 @@ static __init bool get_rdt_resources(void) > return (rdt_mon_capable || rdt_alloc_capable); } > > +static const struct x86_cpu_id snc_cpu_ids[] __initconst = { > + X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, 0), > + X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, 0), > + X86_MATCH_INTEL_FAM6_MODEL(EMERALDRAPIDS_X, 0), > + {} > +}; Cascade Lake and Skylake also seem to support Sub-NUMA cluster. At least in my environment(Intel(R) Xeon(R) Gold 6254 CPU @ 3.10GHz), Sub-NUMA cluster is supported. Best regards, Shaopeng TAN