Commit b84b3381 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull x86 resource control updates from Borislav Petkov:

 - Enable Sub-NUMA clustering to work with resource control on Intel by
   teaching resctrl to handle scopes due to the clustering which
   partitions the L3 cache into sets. Modify and extend the subsystem to
   handle such scopes properly

* tag 'x86_cache_for_v6.11_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/resctrl: Update documentation with Sub-NUMA cluster changes
  x86/resctrl: Detect Sub-NUMA Cluster (SNC) mode
  x86/resctrl: Enable shared RMID mode on Sub-NUMA Cluster (SNC) systems
  x86/resctrl: Make __mon_event_count() handle sum domains
  x86/resctrl: Fill out rmid_read structure for smp_call*() to read a counter
  x86/resctrl: Handle removing directories in Sub-NUMA Cluster (SNC) mode
  x86/resctrl: Create Sub-NUMA Cluster (SNC) monitor files
  x86/resctrl: Allocate a new field in union mon_data_bits
  x86/resctrl: Refactor mkdir_mondata_subdir() with a helper function
  x86/resctrl: Initialize on-stack struct rmid_read instances
  x86/resctrl: Add a new field to struct rmid_read for summation of domains
  x86/resctrl: Prepare for new Sub-NUMA Cluster (SNC) monitor files
  x86/resctrl: Block use of mba_MBps mount option on Sub-NUMA Cluster (SNC) systems
  x86/resctrl: Introduce snc_nodes_per_l3_cache
  x86/resctrl: Add node-scope to the options for feature scope
  x86/resctrl: Split the rdt_domain and rdt_hw_domain structures
  x86/resctrl: Prepare for different scope for control/monitor operations
  x86/resctrl: Prepare to split rdt_domain structure
  x86/resctrl: Prepare for new domain scope
parents d6797831 ea34999f
...@@ -375,6 +375,10 @@ When monitoring is enabled all MON groups will also contain: ...@@ -375,6 +375,10 @@ When monitoring is enabled all MON groups will also contain:
all tasks in the group. In CTRL_MON groups these files provide all tasks in the group. In CTRL_MON groups these files provide
the sum for all tasks in the CTRL_MON group and all tasks in the sum for all tasks in the CTRL_MON group and all tasks in
MON groups. Please see example section for more details on usage. MON groups. Please see example section for more details on usage.
On systems with Sub-NUMA Cluster (SNC) enabled there are extra
directories for each node (located within the "mon_L3_XX" directory
for the L3 cache they occupy). These are named "mon_sub_L3_YY"
where "YY" is the node number.
"mon_hw_id": "mon_hw_id":
Available only with debug option. The identifier used by hardware Available only with debug option. The identifier used by hardware
...@@ -484,6 +488,29 @@ if non-contiguous 1s value is supported. On a system with a 20-bit mask ...@@ -484,6 +488,29 @@ if non-contiguous 1s value is supported. On a system with a 20-bit mask
each bit represents 5% of the capacity of the cache. You could partition each bit represents 5% of the capacity of the cache. You could partition
the cache into four equal parts with masks: 0x1f, 0x3e0, 0x7c00, 0xf8000. the cache into four equal parts with masks: 0x1f, 0x3e0, 0x7c00, 0xf8000.
Notes on Sub-NUMA Cluster mode
==============================
When SNC mode is enabled, Linux may load balance tasks between Sub-NUMA
nodes much more readily than between regular NUMA nodes since the CPUs
on Sub-NUMA nodes share the same L3 cache and the system may report
the NUMA distance between Sub-NUMA nodes with a lower value than used
for regular NUMA nodes.
The top-level monitoring files in each "mon_L3_XX" directory provide
the sum of data across all SNC nodes sharing an L3 cache instance.
Users who bind tasks to the CPUs of a specific Sub-NUMA node can read
the "llc_occupancy", "mbm_total_bytes", and "mbm_local_bytes" in the
"mon_sub_L3_YY" directories to get node local data.
Memory bandwidth allocation is still performed at the L3 cache
level. I.e. throttling controls are applied to all SNC nodes.
L3 cache allocation bitmaps also apply to all SNC nodes. But note that
the amount of L3 cache represented by each bit is divided by the number
of SNC nodes per L3 cache. E.g. with a 100MB cache on a system with 10-bit
allocation masks each bit normally represents 10MB. With SNC mode enabled
with two SNC nodes per L3 cache, each bit only represents 5MB.
Memory bandwidth Allocation and monitoring Memory bandwidth Allocation and monitoring
========================================== ==========================================
......
...@@ -1164,6 +1164,7 @@ ...@@ -1164,6 +1164,7 @@
#define MSR_IA32_QM_CTR 0xc8e #define MSR_IA32_QM_CTR 0xc8e
#define MSR_IA32_PQR_ASSOC 0xc8f #define MSR_IA32_PQR_ASSOC 0xc8f
#define MSR_IA32_L3_CBM_BASE 0xc90 #define MSR_IA32_L3_CBM_BASE 0xc90
#define MSR_RMID_SNC_CONFIG 0xca0
#define MSR_IA32_L2_CBM_BASE 0xd10 #define MSR_IA32_L2_CBM_BASE 0xd10
#define MSR_IA32_MBA_THRTL_BASE 0xd50 #define MSR_IA32_MBA_THRTL_BASE 0xd50
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/cacheinfo.h>
#include <linux/cpuhotplug.h> #include <linux/cpuhotplug.h>
#include <asm/cpu_device_id.h> #include <asm/cpu_device_id.h>
...@@ -60,7 +59,8 @@ static void mba_wrmsr_intel(struct msr_param *m); ...@@ -60,7 +59,8 @@ static void mba_wrmsr_intel(struct msr_param *m);
static void cat_wrmsr(struct msr_param *m); static void cat_wrmsr(struct msr_param *m);
static void mba_wrmsr_amd(struct msr_param *m); static void mba_wrmsr_amd(struct msr_param *m);
#define domain_init(id) LIST_HEAD_INIT(rdt_resources_all[id].r_resctrl.domains) #define ctrl_domain_init(id) LIST_HEAD_INIT(rdt_resources_all[id].r_resctrl.ctrl_domains)
#define mon_domain_init(id) LIST_HEAD_INIT(rdt_resources_all[id].r_resctrl.mon_domains)
struct rdt_hw_resource rdt_resources_all[] = { struct rdt_hw_resource rdt_resources_all[] = {
[RDT_RESOURCE_L3] = [RDT_RESOURCE_L3] =
...@@ -68,8 +68,10 @@ struct rdt_hw_resource rdt_resources_all[] = { ...@@ -68,8 +68,10 @@ struct rdt_hw_resource rdt_resources_all[] = {
.r_resctrl = { .r_resctrl = {
.rid = RDT_RESOURCE_L3, .rid = RDT_RESOURCE_L3,
.name = "L3", .name = "L3",
.cache_level = 3, .ctrl_scope = RESCTRL_L3_CACHE,
.domains = domain_init(RDT_RESOURCE_L3), .mon_scope = RESCTRL_L3_CACHE,
.ctrl_domains = ctrl_domain_init(RDT_RESOURCE_L3),
.mon_domains = mon_domain_init(RDT_RESOURCE_L3),
.parse_ctrlval = parse_cbm, .parse_ctrlval = parse_cbm,
.format_str = "%d=%0*x", .format_str = "%d=%0*x",
.fflags = RFTYPE_RES_CACHE, .fflags = RFTYPE_RES_CACHE,
...@@ -82,8 +84,8 @@ struct rdt_hw_resource rdt_resources_all[] = { ...@@ -82,8 +84,8 @@ struct rdt_hw_resource rdt_resources_all[] = {
.r_resctrl = { .r_resctrl = {
.rid = RDT_RESOURCE_L2, .rid = RDT_RESOURCE_L2,
.name = "L2", .name = "L2",
.cache_level = 2, .ctrl_scope = RESCTRL_L2_CACHE,
.domains = domain_init(RDT_RESOURCE_L2), .ctrl_domains = ctrl_domain_init(RDT_RESOURCE_L2),
.parse_ctrlval = parse_cbm, .parse_ctrlval = parse_cbm,
.format_str = "%d=%0*x", .format_str = "%d=%0*x",
.fflags = RFTYPE_RES_CACHE, .fflags = RFTYPE_RES_CACHE,
...@@ -96,8 +98,8 @@ struct rdt_hw_resource rdt_resources_all[] = { ...@@ -96,8 +98,8 @@ struct rdt_hw_resource rdt_resources_all[] = {
.r_resctrl = { .r_resctrl = {
.rid = RDT_RESOURCE_MBA, .rid = RDT_RESOURCE_MBA,
.name = "MB", .name = "MB",
.cache_level = 3, .ctrl_scope = RESCTRL_L3_CACHE,
.domains = domain_init(RDT_RESOURCE_MBA), .ctrl_domains = ctrl_domain_init(RDT_RESOURCE_MBA),
.parse_ctrlval = parse_bw, .parse_ctrlval = parse_bw,
.format_str = "%d=%*u", .format_str = "%d=%*u",
.fflags = RFTYPE_RES_MB, .fflags = RFTYPE_RES_MB,
...@@ -108,8 +110,8 @@ struct rdt_hw_resource rdt_resources_all[] = { ...@@ -108,8 +110,8 @@ struct rdt_hw_resource rdt_resources_all[] = {
.r_resctrl = { .r_resctrl = {
.rid = RDT_RESOURCE_SMBA, .rid = RDT_RESOURCE_SMBA,
.name = "SMBA", .name = "SMBA",
.cache_level = 3, .ctrl_scope = RESCTRL_L3_CACHE,
.domains = domain_init(RDT_RESOURCE_SMBA), .ctrl_domains = ctrl_domain_init(RDT_RESOURCE_SMBA),
.parse_ctrlval = parse_bw, .parse_ctrlval = parse_bw,
.format_str = "%d=%*u", .format_str = "%d=%*u",
.fflags = RFTYPE_RES_MB, .fflags = RFTYPE_RES_MB,
...@@ -306,8 +308,8 @@ static void rdt_get_cdp_l2_config(void) ...@@ -306,8 +308,8 @@ static void rdt_get_cdp_l2_config(void)
static void mba_wrmsr_amd(struct msr_param *m) static void mba_wrmsr_amd(struct msr_param *m)
{ {
struct rdt_hw_ctrl_domain *hw_dom = resctrl_to_arch_ctrl_dom(m->dom);
struct rdt_hw_resource *hw_res = resctrl_to_arch_res(m->res); 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;
for (i = m->low; i < m->high; i++) for (i = m->low; i < m->high; i++)
...@@ -330,8 +332,8 @@ static u32 delay_bw_map(unsigned long bw, struct rdt_resource *r) ...@@ -330,8 +332,8 @@ static u32 delay_bw_map(unsigned long bw, struct rdt_resource *r)
static void mba_wrmsr_intel(struct msr_param *m) static void mba_wrmsr_intel(struct msr_param *m)
{ {
struct rdt_hw_ctrl_domain *hw_dom = resctrl_to_arch_ctrl_dom(m->dom);
struct rdt_hw_resource *hw_res = resctrl_to_arch_res(m->res); 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;
/* Write the delay values for mba. */ /* Write the delay values for mba. */
...@@ -341,23 +343,38 @@ static void mba_wrmsr_intel(struct msr_param *m) ...@@ -341,23 +343,38 @@ static void mba_wrmsr_intel(struct msr_param *m)
static void cat_wrmsr(struct msr_param *m) static void cat_wrmsr(struct msr_param *m)
{ {
struct rdt_hw_ctrl_domain *hw_dom = resctrl_to_arch_ctrl_dom(m->dom);
struct rdt_hw_resource *hw_res = resctrl_to_arch_res(m->res); 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;
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]);
} }
struct rdt_domain *get_domain_from_cpu(int cpu, struct rdt_resource *r) struct rdt_ctrl_domain *get_ctrl_domain_from_cpu(int cpu, struct rdt_resource *r)
{ {
struct rdt_domain *d; struct rdt_ctrl_domain *d;
lockdep_assert_cpus_held(); lockdep_assert_cpus_held();
list_for_each_entry(d, &r->domains, list) { list_for_each_entry(d, &r->ctrl_domains, hdr.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->hdr.cpu_mask))
return d;
}
return NULL;
}
struct rdt_mon_domain *get_mon_domain_from_cpu(int cpu, struct rdt_resource *r)
{
struct rdt_mon_domain *d;
lockdep_assert_cpus_held();
list_for_each_entry(d, &r->mon_domains, hdr.list) {
/* Find the domain that contains this CPU */
if (cpumask_test_cpu(cpu, &d->hdr.cpu_mask))
return d; return d;
} }
...@@ -379,24 +396,21 @@ void rdt_ctrl_update(void *arg) ...@@ -379,24 +396,21 @@ void rdt_ctrl_update(void *arg)
} }
/* /*
* rdt_find_domain - Find a domain in a resource that matches input resource id * rdt_find_domain - Search for a domain id in a resource domain list.
* *
* Search resource r's domain list to find the resource id. If the resource * Search the domain list to find the domain id. If the domain id is
* id is found in a domain, return the domain. Otherwise, if requested by * found, return the domain. NULL otherwise. If the domain id is not
* caller, return the first domain whose id is bigger than the input id. * found (and NULL returned) then the first domain with id bigger than
* The domain list is sorted by id in ascending order. * the input id can be returned to the caller via @pos.
*/ */
struct rdt_domain *rdt_find_domain(struct rdt_resource *r, int id, struct rdt_domain_hdr *rdt_find_domain(struct list_head *h, int id,
struct list_head **pos) struct list_head **pos)
{ {
struct rdt_domain *d; struct rdt_domain_hdr *d;
struct list_head *l; struct list_head *l;
if (id < 0) list_for_each(l, h) {
return ERR_PTR(-ENODEV); d = list_entry(l, struct rdt_domain_hdr, list);
list_for_each(l, &r->domains) {
d = list_entry(l, struct rdt_domain, list);
/* When id is found, return its domain. */ /* When id is found, return its domain. */
if (id == d->id) if (id == d->id)
return d; return d;
...@@ -425,18 +439,23 @@ static void setup_default_ctrlval(struct rdt_resource *r, u32 *dc) ...@@ -425,18 +439,23 @@ static void setup_default_ctrlval(struct rdt_resource *r, u32 *dc)
*dc = r->default_ctrl; *dc = r->default_ctrl;
} }
static void domain_free(struct rdt_hw_domain *hw_dom) static void ctrl_domain_free(struct rdt_hw_ctrl_domain *hw_dom)
{
kfree(hw_dom->ctrl_val);
kfree(hw_dom);
}
static void mon_domain_free(struct rdt_hw_mon_domain *hw_dom)
{ {
kfree(hw_dom->arch_mbm_total); kfree(hw_dom->arch_mbm_total);
kfree(hw_dom->arch_mbm_local); kfree(hw_dom->arch_mbm_local);
kfree(hw_dom->ctrl_val);
kfree(hw_dom); kfree(hw_dom);
} }
static int domain_setup_ctrlval(struct rdt_resource *r, struct rdt_domain *d) static int domain_setup_ctrlval(struct rdt_resource *r, struct rdt_ctrl_domain *d)
{ {
struct rdt_hw_ctrl_domain *hw_dom = resctrl_to_arch_ctrl_dom(d);
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 = resctrl_to_arch_dom(d);
struct msr_param m; struct msr_param m;
u32 *dc; u32 *dc;
...@@ -461,7 +480,7 @@ static int domain_setup_ctrlval(struct rdt_resource *r, struct rdt_domain *d) ...@@ -461,7 +480,7 @@ static int domain_setup_ctrlval(struct rdt_resource *r, struct rdt_domain *d)
* @num_rmid: The size of the MBM counter array * @num_rmid: The size of the MBM counter array
* @hw_dom: The domain that owns the allocated arrays * @hw_dom: The domain that owns the allocated arrays
*/ */
static int arch_domain_mbm_alloc(u32 num_rmid, struct rdt_hw_domain *hw_dom) static int arch_domain_mbm_alloc(u32 num_rmid, struct rdt_hw_mon_domain *hw_dom)
{ {
size_t tsize; size_t tsize;
...@@ -484,37 +503,45 @@ static int arch_domain_mbm_alloc(u32 num_rmid, struct rdt_hw_domain *hw_dom) ...@@ -484,37 +503,45 @@ static int arch_domain_mbm_alloc(u32 num_rmid, struct rdt_hw_domain *hw_dom)
return 0; return 0;
} }
/* static int get_domain_id_from_scope(int cpu, enum resctrl_scope scope)
* domain_add_cpu - Add a cpu to a resource's domain list.
*
* If an existing domain in the resource r's domain list matches the cpu's
* resource id, add the cpu in the domain.
*
* Otherwise, a new domain is allocated and inserted into the right position
* in the domain list sorted by id in ascending order.
*
* The order in the domain list is visible to users when we print entries
* in the schemata file and schemata input is validated to have the same order
* as this list.
*/
static void domain_add_cpu(int cpu, struct rdt_resource *r)
{ {
int id = get_cpu_cacheinfo_id(cpu, r->cache_level); switch (scope) {
case RESCTRL_L2_CACHE:
case RESCTRL_L3_CACHE:
return get_cpu_cacheinfo_id(cpu, scope);
case RESCTRL_L3_NODE:
return cpu_to_node(cpu);
default:
break;
}
return -EINVAL;
}
static void domain_add_cpu_ctrl(int cpu, struct rdt_resource *r)
{
int id = get_domain_id_from_scope(cpu, r->ctrl_scope);
struct rdt_hw_ctrl_domain *hw_dom;
struct list_head *add_pos = NULL; struct list_head *add_pos = NULL;
struct rdt_hw_domain *hw_dom; struct rdt_domain_hdr *hdr;
struct rdt_domain *d; struct rdt_ctrl_domain *d;
int err; int err;
lockdep_assert_held(&domain_list_lock); lockdep_assert_held(&domain_list_lock);
d = rdt_find_domain(r, id, &add_pos); if (id < 0) {
if (IS_ERR(d)) { pr_warn_once("Can't find control domain id for CPU:%d scope:%d for resource %s\n",
pr_warn("Couldn't find cache id for CPU %d\n", cpu); cpu, r->ctrl_scope, r->name);
return; return;
} }
if (d) { hdr = rdt_find_domain(&r->ctrl_domains, id, &add_pos);
cpumask_set_cpu(cpu, &d->cpu_mask); if (hdr) {
if (WARN_ON_ONCE(hdr->type != RESCTRL_CTRL_DOMAIN))
return;
d = container_of(hdr, struct rdt_ctrl_domain, hdr);
cpumask_set_cpu(cpu, &d->hdr.cpu_mask);
if (r->cache.arch_has_per_cpu_cfg) if (r->cache.arch_has_per_cpu_cfg)
rdt_domain_reconfigure_cdp(r); rdt_domain_reconfigure_cdp(r);
return; return;
...@@ -525,64 +552,187 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r) ...@@ -525,64 +552,187 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r)
return; return;
d = &hw_dom->d_resctrl; d = &hw_dom->d_resctrl;
d->id = id; d->hdr.id = id;
cpumask_set_cpu(cpu, &d->cpu_mask); d->hdr.type = RESCTRL_CTRL_DOMAIN;
cpumask_set_cpu(cpu, &d->hdr.cpu_mask);
rdt_domain_reconfigure_cdp(r); rdt_domain_reconfigure_cdp(r);
if (r->alloc_capable && domain_setup_ctrlval(r, d)) { if (domain_setup_ctrlval(r, d)) {
domain_free(hw_dom); ctrl_domain_free(hw_dom);
return; return;
} }
if (r->mon_capable && arch_domain_mbm_alloc(r->num_rmid, hw_dom)) { list_add_tail_rcu(&d->hdr.list, add_pos);
domain_free(hw_dom);
err = resctrl_online_ctrl_domain(r, d);
if (err) {
list_del_rcu(&d->hdr.list);
synchronize_rcu();
ctrl_domain_free(hw_dom);
}
}
static void domain_add_cpu_mon(int cpu, struct rdt_resource *r)
{
int id = get_domain_id_from_scope(cpu, r->mon_scope);
struct list_head *add_pos = NULL;
struct rdt_hw_mon_domain *hw_dom;
struct rdt_domain_hdr *hdr;
struct rdt_mon_domain *d;
int err;
lockdep_assert_held(&domain_list_lock);
if (id < 0) {
pr_warn_once("Can't find monitor domain id for CPU:%d scope:%d for resource %s\n",
cpu, r->mon_scope, r->name);
return; return;
} }
list_add_tail_rcu(&d->list, add_pos); hdr = rdt_find_domain(&r->mon_domains, id, &add_pos);
if (hdr) {
if (WARN_ON_ONCE(hdr->type != RESCTRL_MON_DOMAIN))
return;
d = container_of(hdr, struct rdt_mon_domain, hdr);
cpumask_set_cpu(cpu, &d->hdr.cpu_mask);
return;
}
err = resctrl_online_domain(r, d); hw_dom = kzalloc_node(sizeof(*hw_dom), GFP_KERNEL, cpu_to_node(cpu));
if (!hw_dom)
return;
d = &hw_dom->d_resctrl;
d->hdr.id = id;
d->hdr.type = RESCTRL_MON_DOMAIN;
d->ci = get_cpu_cacheinfo_level(cpu, RESCTRL_L3_CACHE);
if (!d->ci) {
pr_warn_once("Can't find L3 cache for CPU:%d resource %s\n", cpu, r->name);
mon_domain_free(hw_dom);
return;
}
cpumask_set_cpu(cpu, &d->hdr.cpu_mask);
arch_mon_domain_online(r, d);
if (arch_domain_mbm_alloc(r->num_rmid, hw_dom)) {
mon_domain_free(hw_dom);
return;
}
list_add_tail_rcu(&d->hdr.list, add_pos);
err = resctrl_online_mon_domain(r, d);
if (err) { if (err) {
list_del_rcu(&d->list); list_del_rcu(&d->hdr.list);
synchronize_rcu(); synchronize_rcu();
domain_free(hw_dom); mon_domain_free(hw_dom);
} }
} }
static void domain_remove_cpu(int cpu, struct rdt_resource *r) static void domain_add_cpu(int cpu, struct rdt_resource *r)
{
if (r->alloc_capable)
domain_add_cpu_ctrl(cpu, r);
if (r->mon_capable)
domain_add_cpu_mon(cpu, r);
}
static void domain_remove_cpu_ctrl(int cpu, struct rdt_resource *r)
{ {
int id = get_cpu_cacheinfo_id(cpu, r->cache_level); int id = get_domain_id_from_scope(cpu, r->ctrl_scope);
struct rdt_hw_domain *hw_dom; struct rdt_hw_ctrl_domain *hw_dom;
struct rdt_domain *d; struct rdt_domain_hdr *hdr;
struct rdt_ctrl_domain *d;
lockdep_assert_held(&domain_list_lock); lockdep_assert_held(&domain_list_lock);
d = rdt_find_domain(r, id, NULL); if (id < 0) {
if (IS_ERR_OR_NULL(d)) { pr_warn_once("Can't find control domain id for CPU:%d scope:%d for resource %s\n",
pr_warn("Couldn't find cache id for CPU %d\n", cpu); cpu, r->ctrl_scope, r->name);
return; return;
} }
hw_dom = resctrl_to_arch_dom(d);
cpumask_clear_cpu(cpu, &d->cpu_mask); hdr = rdt_find_domain(&r->ctrl_domains, id, NULL);
if (cpumask_empty(&d->cpu_mask)) { if (!hdr) {
resctrl_offline_domain(r, d); pr_warn("Can't find control domain for id=%d for CPU %d for resource %s\n",
list_del_rcu(&d->list); id, cpu, r->name);
return;
}
if (WARN_ON_ONCE(hdr->type != RESCTRL_CTRL_DOMAIN))
return;
d = container_of(hdr, struct rdt_ctrl_domain, hdr);
hw_dom = resctrl_to_arch_ctrl_dom(d);
cpumask_clear_cpu(cpu, &d->hdr.cpu_mask);
if (cpumask_empty(&d->hdr.cpu_mask)) {
resctrl_offline_ctrl_domain(r, d);
list_del_rcu(&d->hdr.list);
synchronize_rcu(); synchronize_rcu();
/* /*
* rdt_domain "d" is going to be freed below, so clear * rdt_ctrl_domain "d" is going to be freed below, so clear
* its pointer from pseudo_lock_region struct. * its pointer from pseudo_lock_region struct.
*/ */
if (d->plr) if (d->plr)
d->plr->d = NULL; d->plr->d = NULL;
domain_free(hw_dom); ctrl_domain_free(hw_dom);
return; return;
} }
} }
static void domain_remove_cpu_mon(int cpu, struct rdt_resource *r)
{
int id = get_domain_id_from_scope(cpu, r->mon_scope);
struct rdt_hw_mon_domain *hw_dom;
struct rdt_domain_hdr *hdr;
struct rdt_mon_domain *d;
lockdep_assert_held(&domain_list_lock);
if (id < 0) {
pr_warn_once("Can't find monitor domain id for CPU:%d scope:%d for resource %s\n",
cpu, r->mon_scope, r->name);
return;
}
hdr = rdt_find_domain(&r->mon_domains, id, NULL);
if (!hdr) {
pr_warn("Can't find monitor domain for id=%d for CPU %d for resource %s\n",
id, cpu, r->name);
return;
}
if (WARN_ON_ONCE(hdr->type != RESCTRL_MON_DOMAIN))
return;
d = container_of(hdr, struct rdt_mon_domain, hdr);
hw_dom = resctrl_to_arch_mon_dom(d);
cpumask_clear_cpu(cpu, &d->hdr.cpu_mask);
if (cpumask_empty(&d->hdr.cpu_mask)) {
resctrl_offline_mon_domain(r, d);
list_del_rcu(&d->hdr.list);
synchronize_rcu();
mon_domain_free(hw_dom);
return;
}
}
static void domain_remove_cpu(int cpu, struct rdt_resource *r)
{
if (r->alloc_capable)
domain_remove_cpu_ctrl(cpu, r);
if (r->mon_capable)
domain_remove_cpu_mon(cpu, r);
}
static void clear_closid_rmid(int cpu) static void clear_closid_rmid(int cpu)
{ {
struct resctrl_pqr_state *state = this_cpu_ptr(&pqr_state); struct resctrl_pqr_state *state = this_cpu_ptr(&pqr_state);
......
...@@ -60,7 +60,7 @@ static bool bw_validate(char *buf, unsigned long *data, struct rdt_resource *r) ...@@ -60,7 +60,7 @@ 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, int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s,
struct rdt_domain *d) struct rdt_ctrl_domain *d)
{ {
struct resctrl_staged_config *cfg; struct resctrl_staged_config *cfg;
u32 closid = data->rdtgrp->closid; u32 closid = data->rdtgrp->closid;
...@@ -69,7 +69,7 @@ int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s, ...@@ -69,7 +69,7 @@ int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s,
cfg = &d->staged_config[s->conf_type]; cfg = &d->staged_config[s->conf_type];
if (cfg->have_new_ctrl) { if (cfg->have_new_ctrl) {
rdt_last_cmd_printf("Duplicate domain %d\n", d->id); rdt_last_cmd_printf("Duplicate domain %d\n", d->hdr.id);
return -EINVAL; return -EINVAL;
} }
...@@ -139,7 +139,7 @@ static bool cbm_validate(char *buf, u32 *data, struct rdt_resource *r) ...@@ -139,7 +139,7 @@ static bool cbm_validate(char *buf, u32 *data, struct rdt_resource *r)
* resource type. * resource type.
*/ */
int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s, int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s,
struct rdt_domain *d) struct rdt_ctrl_domain *d)
{ {
struct rdtgroup *rdtgrp = data->rdtgrp; struct rdtgroup *rdtgrp = data->rdtgrp;
struct resctrl_staged_config *cfg; struct resctrl_staged_config *cfg;
...@@ -148,7 +148,7 @@ int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s, ...@@ -148,7 +148,7 @@ int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s,
cfg = &d->staged_config[s->conf_type]; cfg = &d->staged_config[s->conf_type];
if (cfg->have_new_ctrl) { if (cfg->have_new_ctrl) {
rdt_last_cmd_printf("Duplicate domain %d\n", d->id); rdt_last_cmd_printf("Duplicate domain %d\n", d->hdr.id);
return -EINVAL; return -EINVAL;
} }
...@@ -208,8 +208,8 @@ static int parse_line(char *line, struct resctrl_schema *s, ...@@ -208,8 +208,8 @@ static int parse_line(char *line, struct resctrl_schema *s,
struct resctrl_staged_config *cfg; struct resctrl_staged_config *cfg;
struct rdt_resource *r = s->res; struct rdt_resource *r = s->res;
struct rdt_parse_data data; struct rdt_parse_data data;
struct rdt_ctrl_domain *d;
char *dom = NULL, *id; char *dom = NULL, *id;
struct rdt_domain *d;
unsigned long dom_id; unsigned long dom_id;
/* Walking r->domains, ensure it can't race with cpuhp */ /* Walking r->domains, ensure it can't race with cpuhp */
...@@ -231,8 +231,8 @@ static int parse_line(char *line, struct resctrl_schema *s, ...@@ -231,8 +231,8 @@ static int parse_line(char *line, struct resctrl_schema *s,
return -EINVAL; return -EINVAL;
} }
dom = strim(dom); dom = strim(dom);
list_for_each_entry(d, &r->domains, list) { list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
if (d->id == dom_id) { if (d->hdr.id == dom_id) {
data.buf = dom; data.buf = dom;
data.rdtgrp = rdtgrp; data.rdtgrp = rdtgrp;
if (r->parse_ctrlval(&data, s, d)) if (r->parse_ctrlval(&data, s, d))
...@@ -272,15 +272,15 @@ static u32 get_config_index(u32 closid, enum resctrl_conf_type type) ...@@ -272,15 +272,15 @@ static u32 get_config_index(u32 closid, enum resctrl_conf_type type)
} }
} }
int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
u32 closid, enum resctrl_conf_type t, u32 cfg_val) u32 closid, enum resctrl_conf_type t, u32 cfg_val)
{ {
struct rdt_hw_ctrl_domain *hw_dom = resctrl_to_arch_ctrl_dom(d);
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 = resctrl_to_arch_dom(d);
u32 idx = get_config_index(closid, t); u32 idx = get_config_index(closid, t);
struct msr_param msr_param; struct msr_param msr_param;
if (!cpumask_test_cpu(smp_processor_id(), &d->cpu_mask)) if (!cpumask_test_cpu(smp_processor_id(), &d->hdr.cpu_mask))
return -EINVAL; return -EINVAL;
hw_dom->ctrl_val[idx] = cfg_val; hw_dom->ctrl_val[idx] = cfg_val;
...@@ -297,17 +297,17 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, ...@@ -297,17 +297,17 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d,
int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid) int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
{ {
struct resctrl_staged_config *cfg; struct resctrl_staged_config *cfg;
struct rdt_hw_domain *hw_dom; struct rdt_hw_ctrl_domain *hw_dom;
struct msr_param msr_param; struct msr_param msr_param;
struct rdt_ctrl_domain *d;
enum resctrl_conf_type t; enum resctrl_conf_type t;
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();
list_for_each_entry(d, &r->domains, list) { list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
hw_dom = resctrl_to_arch_dom(d); hw_dom = resctrl_to_arch_ctrl_dom(d);
msr_param.res = NULL; 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];
...@@ -330,7 +330,7 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid) ...@@ -330,7 +330,7 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
} }
} }
if (msr_param.res) if (msr_param.res)
smp_call_function_any(&d->cpu_mask, rdt_ctrl_update, &msr_param, 1); smp_call_function_any(&d->hdr.cpu_mask, rdt_ctrl_update, &msr_param, 1);
} }
return 0; return 0;
...@@ -430,10 +430,10 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of, ...@@ -430,10 +430,10 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
return ret ?: nbytes; return ret ?: nbytes;
} }
u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
u32 closid, enum resctrl_conf_type type) u32 closid, enum resctrl_conf_type type)
{ {
struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d); struct rdt_hw_ctrl_domain *hw_dom = resctrl_to_arch_ctrl_dom(d);
u32 idx = get_config_index(closid, type); u32 idx = get_config_index(closid, type);
return hw_dom->ctrl_val[idx]; return hw_dom->ctrl_val[idx];
...@@ -442,7 +442,7 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, ...@@ -442,7 +442,7 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d,
static void show_doms(struct seq_file *s, struct resctrl_schema *schema, int closid) static void show_doms(struct seq_file *s, struct resctrl_schema *schema, int closid)
{ {
struct rdt_resource *r = schema->res; struct rdt_resource *r = schema->res;
struct rdt_domain *dom; struct rdt_ctrl_domain *dom;
bool sep = false; bool sep = false;
u32 ctrl_val; u32 ctrl_val;
...@@ -450,7 +450,7 @@ static void show_doms(struct seq_file *s, struct resctrl_schema *schema, int clo ...@@ -450,7 +450,7 @@ static void show_doms(struct seq_file *s, struct resctrl_schema *schema, int clo
lockdep_assert_cpus_held(); lockdep_assert_cpus_held();
seq_printf(s, "%*s:", max_name_width, schema->name); seq_printf(s, "%*s:", max_name_width, schema->name);
list_for_each_entry(dom, &r->domains, list) { list_for_each_entry(dom, &r->ctrl_domains, hdr.list) {
if (sep) if (sep)
seq_puts(s, ";"); seq_puts(s, ";");
...@@ -460,7 +460,7 @@ static void show_doms(struct seq_file *s, struct resctrl_schema *schema, int clo ...@@ -460,7 +460,7 @@ static void show_doms(struct seq_file *s, struct resctrl_schema *schema, int clo
ctrl_val = resctrl_arch_get_config(r, dom, closid, ctrl_val = resctrl_arch_get_config(r, dom, closid,
schema->conf_type); schema->conf_type);
seq_printf(s, r->format_str, dom->id, max_data_width, seq_printf(s, r->format_str, dom->hdr.id, max_data_width,
ctrl_val); ctrl_val);
sep = true; sep = true;
} }
...@@ -489,7 +489,7 @@ int rdtgroup_schemata_show(struct kernfs_open_file *of, ...@@ -489,7 +489,7 @@ int rdtgroup_schemata_show(struct kernfs_open_file *of,
} else { } else {
seq_printf(s, "%s:%d=%x\n", seq_printf(s, "%s:%d=%x\n",
rdtgrp->plr->s->res->name, rdtgrp->plr->s->res->name,
rdtgrp->plr->d->id, rdtgrp->plr->d->hdr.id,
rdtgrp->plr->cbm); rdtgrp->plr->cbm);
} }
} else { } else {
...@@ -514,8 +514,8 @@ static int smp_mon_event_count(void *arg) ...@@ -514,8 +514,8 @@ static int smp_mon_event_count(void *arg)
} }
void mon_event_read(struct rmid_read *rr, struct rdt_resource *r, void mon_event_read(struct rmid_read *rr, struct rdt_resource *r,
struct rdt_domain *d, struct rdtgroup *rdtgrp, struct rdt_mon_domain *d, struct rdtgroup *rdtgrp,
int evtid, int first) cpumask_t *cpumask, int evtid, int first)
{ {
int cpu; int cpu;
...@@ -529,7 +529,6 @@ void mon_event_read(struct rmid_read *rr, struct rdt_resource *r, ...@@ -529,7 +529,6 @@ void mon_event_read(struct rmid_read *rr, struct rdt_resource *r,
rr->evtid = evtid; rr->evtid = evtid;
rr->r = r; rr->r = r;
rr->d = d; rr->d = d;
rr->val = 0;
rr->first = first; rr->first = first;
rr->arch_mon_ctx = resctrl_arch_mon_ctx_alloc(r, evtid); rr->arch_mon_ctx = resctrl_arch_mon_ctx_alloc(r, evtid);
if (IS_ERR(rr->arch_mon_ctx)) { if (IS_ERR(rr->arch_mon_ctx)) {
...@@ -537,7 +536,7 @@ void mon_event_read(struct rmid_read *rr, struct rdt_resource *r, ...@@ -537,7 +536,7 @@ void mon_event_read(struct rmid_read *rr, struct rdt_resource *r,
return; return;
} }
cpu = cpumask_any_housekeeping(&d->cpu_mask, RESCTRL_PICK_ANY_CPU); cpu = cpumask_any_housekeeping(cpumask, RESCTRL_PICK_ANY_CPU);
/* /*
* cpumask_any_housekeeping() prefers housekeeping CPUs, but * cpumask_any_housekeeping() prefers housekeeping CPUs, but
...@@ -546,7 +545,7 @@ void mon_event_read(struct rmid_read *rr, struct rdt_resource *r, ...@@ -546,7 +545,7 @@ void mon_event_read(struct rmid_read *rr, struct rdt_resource *r,
* counters on some platforms if its called in IRQ context. * counters on some platforms if its called in IRQ context.
*/ */
if (tick_nohz_full_cpu(cpu)) if (tick_nohz_full_cpu(cpu))
smp_call_function_any(&d->cpu_mask, mon_event_count, rr, 1); smp_call_function_any(cpumask, mon_event_count, rr, 1);
else else
smp_call_on_cpu(cpu, smp_mon_event_count, rr, false); smp_call_on_cpu(cpu, smp_mon_event_count, rr, false);
...@@ -556,12 +555,13 @@ void mon_event_read(struct rmid_read *rr, struct rdt_resource *r, ...@@ -556,12 +555,13 @@ void mon_event_read(struct rmid_read *rr, struct rdt_resource *r,
int rdtgroup_mondata_show(struct seq_file *m, void *arg) int rdtgroup_mondata_show(struct seq_file *m, void *arg)
{ {
struct kernfs_open_file *of = m->private; struct kernfs_open_file *of = m->private;
struct rdt_domain_hdr *hdr;
struct rmid_read rr = {0};
struct rdt_mon_domain *d;
u32 resid, evtid, domid; u32 resid, evtid, domid;
struct rdtgroup *rdtgrp; struct rdtgroup *rdtgrp;
struct rdt_resource *r; struct rdt_resource *r;
union mon_data_bits md; union mon_data_bits md;
struct rdt_domain *d;
struct rmid_read rr;
int ret = 0; int ret = 0;
rdtgrp = rdtgroup_kn_lock_live(of->kn); rdtgrp = rdtgroup_kn_lock_live(of->kn);
...@@ -574,15 +574,40 @@ int rdtgroup_mondata_show(struct seq_file *m, void *arg) ...@@ -574,15 +574,40 @@ int rdtgroup_mondata_show(struct seq_file *m, void *arg)
resid = md.u.rid; resid = md.u.rid;
domid = md.u.domid; domid = md.u.domid;
evtid = md.u.evtid; evtid = md.u.evtid;
r = &rdt_resources_all[resid].r_resctrl; r = &rdt_resources_all[resid].r_resctrl;
d = rdt_find_domain(r, domid, NULL);
if (IS_ERR_OR_NULL(d)) { if (md.u.sum) {
/*
* This file requires summing across all domains that share
* the L3 cache id that was provided in the "domid" field of the
* mon_data_bits union. Search all domains in the resource for
* one that matches this cache id.
*/
list_for_each_entry(d, &r->mon_domains, hdr.list) {
if (d->ci->id == domid) {
rr.ci = d->ci;
mon_event_read(&rr, r, NULL, rdtgrp,
&d->ci->shared_cpu_map, evtid, false);
goto checkresult;
}
}
ret = -ENOENT; ret = -ENOENT;
goto out; goto out;
} else {
/*
* This file provides data from a single domain. Search
* the resource to find the domain with "domid".
*/
hdr = rdt_find_domain(&r->mon_domains, domid, NULL);
if (!hdr || WARN_ON_ONCE(hdr->type != RESCTRL_MON_DOMAIN)) {
ret = -ENOENT;
goto out;
}
d = container_of(hdr, struct rdt_mon_domain, hdr);
mon_event_read(&rr, r, d, rdtgrp, &d->hdr.cpu_mask, evtid, false);
} }
mon_event_read(&rr, r, d, rdtgrp, evtid, false); checkresult:
if (rr.err == -EIO) if (rr.err == -EIO)
seq_puts(m, "Error\n"); seq_puts(m, "Error\n");
......
...@@ -127,29 +127,54 @@ struct mon_evt { ...@@ -127,29 +127,54 @@ struct mon_evt {
}; };
/** /**
* union mon_data_bits - Monitoring details for each event file * union mon_data_bits - Monitoring details for each event file.
* @priv: Used to store monitoring event data in @u * @priv: Used to store monitoring event data in @u
* as kernfs private data * as kernfs private data.
* @rid: Resource id associated with the event file * @u.rid: Resource id associated with the event file.
* @evtid: Event id associated with the event file * @u.evtid: Event id associated with the event file.
* @domid: The domain to which the event file belongs * @u.sum: Set when event must be summed across multiple
* @u: Name of the bit fields struct * domains.
* @u.domid: When @u.sum is zero this is the domain to which
* the event file belongs. When @sum is one this
* is the id of the L3 cache that all domains to be
* summed share.
* @u: Name of the bit fields struct.
*/ */
union mon_data_bits { union mon_data_bits {
void *priv; void *priv;
struct { struct {
unsigned int rid : 10; unsigned int rid : 10;
enum resctrl_event_id evtid : 8; enum resctrl_event_id evtid : 7;
unsigned int sum : 1;
unsigned int domid : 14; unsigned int domid : 14;
} u; } u;
}; };
/**
* struct rmid_read - Data passed across smp_call*() to read event count.
* @rgrp: Resource group for which the counter is being read. If it is a parent
* resource group then its event count is summed with the count from all
* its child resource groups.
* @r: Resource describing the properties of the event being read.
* @d: Domain that the counter should be read from. If NULL then sum all
* domains in @r sharing L3 @ci.id
* @evtid: Which monitor event to read.
* @first: Initialize MBM counter when true.
* @ci: Cacheinfo for L3. Only set when @d is NULL. Used when summing domains.
* @err: Error encountered when reading counter.
* @val: Returned value of event counter. If @rgrp is a parent resource group,
* @val includes the sum of event counts from its child resource groups.
* If @d is NULL, @val includes the sum of all domains in @r sharing @ci.id,
* (summed across child resource groups if @rgrp is a parent resource group).
* @arch_mon_ctx: Hardware monitor allocated for this read request (MPAM only).
*/
struct rmid_read { struct rmid_read {
struct rdtgroup *rgrp; struct rdtgroup *rgrp;
struct rdt_resource *r; struct rdt_resource *r;
struct rdt_domain *d; struct rdt_mon_domain *d;
enum resctrl_event_id evtid; enum resctrl_event_id evtid;
bool first; bool first;
struct cacheinfo *ci;
int err; int err;
u64 val; u64 val;
void *arch_mon_ctx; void *arch_mon_ctx;
...@@ -232,7 +257,7 @@ struct mongroup { ...@@ -232,7 +257,7 @@ struct mongroup {
*/ */
struct pseudo_lock_region { struct pseudo_lock_region {
struct resctrl_schema *s; struct resctrl_schema *s;
struct rdt_domain *d; struct rdt_ctrl_domain *d;
u32 cbm; u32 cbm;
wait_queue_head_t lock_thread_wq; wait_queue_head_t lock_thread_wq;
int thread_done; int thread_done;
...@@ -355,25 +380,41 @@ struct arch_mbm_state { ...@@ -355,25 +380,41 @@ struct arch_mbm_state {
}; };
/** /**
* struct rdt_hw_domain - Arch private attributes of a set of CPUs that share * struct rdt_hw_ctrl_domain - Arch private attributes of a set of CPUs that share
* a resource * a resource for a control function
* @d_resctrl: Properties exposed to the resctrl file system * @d_resctrl: Properties exposed to the resctrl file system
* @ctrl_val: array of cache or mem ctrl values (indexed by CLOSID) * @ctrl_val: array of cache or mem ctrl values (indexed by CLOSID)
*
* Members of this structure are accessed via helpers that provide abstraction.
*/
struct rdt_hw_ctrl_domain {
struct rdt_ctrl_domain d_resctrl;
u32 *ctrl_val;
};
/**
* struct rdt_hw_mon_domain - Arch private attributes of a set of CPUs that share
* a resource for a monitor function
* @d_resctrl: Properties exposed to the resctrl file system
* @arch_mbm_total: arch private state for MBM total bandwidth * @arch_mbm_total: arch private state for MBM total bandwidth
* @arch_mbm_local: arch private state for MBM local bandwidth * @arch_mbm_local: arch private state for MBM local bandwidth
* *
* Members of this structure are accessed via helpers that provide abstraction. * Members of this structure are accessed via helpers that provide abstraction.
*/ */
struct rdt_hw_domain { struct rdt_hw_mon_domain {
struct rdt_domain d_resctrl; struct rdt_mon_domain d_resctrl;
u32 *ctrl_val;
struct arch_mbm_state *arch_mbm_total; struct arch_mbm_state *arch_mbm_total;
struct arch_mbm_state *arch_mbm_local; struct arch_mbm_state *arch_mbm_local;
}; };
static inline struct rdt_hw_domain *resctrl_to_arch_dom(struct rdt_domain *r) static inline struct rdt_hw_ctrl_domain *resctrl_to_arch_ctrl_dom(struct rdt_ctrl_domain *r)
{ {
return container_of(r, struct rdt_hw_domain, d_resctrl); return container_of(r, struct rdt_hw_ctrl_domain, d_resctrl);
}
static inline struct rdt_hw_mon_domain *resctrl_to_arch_mon_dom(struct rdt_mon_domain *r)
{
return container_of(r, struct rdt_hw_mon_domain, d_resctrl);
} }
/** /**
...@@ -385,7 +426,7 @@ static inline struct rdt_hw_domain *resctrl_to_arch_dom(struct rdt_domain *r) ...@@ -385,7 +426,7 @@ static inline struct rdt_hw_domain *resctrl_to_arch_dom(struct rdt_domain *r)
*/ */
struct msr_param { struct msr_param {
struct rdt_resource *res; struct rdt_resource *res;
struct rdt_domain *dom; struct rdt_ctrl_domain *dom;
u32 low; u32 low;
u32 high; u32 high;
}; };
...@@ -458,9 +499,9 @@ static inline struct rdt_hw_resource *resctrl_to_arch_res(struct rdt_resource *r ...@@ -458,9 +499,9 @@ static inline struct rdt_hw_resource *resctrl_to_arch_res(struct rdt_resource *r
} }
int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s, int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s,
struct rdt_domain *d); struct rdt_ctrl_domain *d);
int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s, int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s,
struct rdt_domain *d); struct rdt_ctrl_domain *d);
extern struct mutex rdtgroup_mutex; extern struct mutex rdtgroup_mutex;
...@@ -493,6 +534,8 @@ static inline bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level l) ...@@ -493,6 +534,8 @@ static inline bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level l)
int resctrl_arch_set_cdp_enabled(enum resctrl_res_level l, bool enable); int resctrl_arch_set_cdp_enabled(enum resctrl_res_level l, bool enable);
void arch_mon_domain_online(struct rdt_resource *r, struct rdt_mon_domain *d);
/* /*
* To return the common struct rdt_resource, which is contained in struct * To return the common struct rdt_resource, which is contained in struct
* rdt_hw_resource, walk the resctrl member of struct rdt_hw_resource. * rdt_hw_resource, walk the resctrl member of struct rdt_hw_resource.
...@@ -558,27 +601,28 @@ void rdtgroup_kn_unlock(struct kernfs_node *kn); ...@@ -558,27 +601,28 @@ void rdtgroup_kn_unlock(struct kernfs_node *kn);
int rdtgroup_kn_mode_restrict(struct rdtgroup *r, const char *name); int rdtgroup_kn_mode_restrict(struct rdtgroup *r, const char *name);
int rdtgroup_kn_mode_restore(struct rdtgroup *r, const char *name, int rdtgroup_kn_mode_restore(struct rdtgroup *r, const char *name,
umode_t mask); umode_t mask);
struct rdt_domain *rdt_find_domain(struct rdt_resource *r, int id, struct rdt_domain_hdr *rdt_find_domain(struct list_head *h, int id,
struct list_head **pos); struct list_head **pos);
ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of, ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
char *buf, size_t nbytes, loff_t off); char *buf, size_t nbytes, loff_t off);
int rdtgroup_schemata_show(struct kernfs_open_file *of, int rdtgroup_schemata_show(struct kernfs_open_file *of,
struct seq_file *s, void *v); struct seq_file *s, void *v);
bool rdtgroup_cbm_overlaps(struct resctrl_schema *s, struct rdt_domain *d, bool rdtgroup_cbm_overlaps(struct resctrl_schema *s, struct rdt_ctrl_domain *d,
unsigned long cbm, int closid, bool exclusive); unsigned long cbm, int closid, bool exclusive);
unsigned int rdtgroup_cbm_to_size(struct rdt_resource *r, struct rdt_domain *d, unsigned int rdtgroup_cbm_to_size(struct rdt_resource *r, struct rdt_ctrl_domain *d,
unsigned long cbm); unsigned long cbm);
enum rdtgrp_mode rdtgroup_mode_by_closid(int closid); enum rdtgrp_mode rdtgroup_mode_by_closid(int closid);
int rdtgroup_tasks_assigned(struct rdtgroup *r); int rdtgroup_tasks_assigned(struct rdtgroup *r);
int rdtgroup_locksetup_enter(struct rdtgroup *rdtgrp); int rdtgroup_locksetup_enter(struct rdtgroup *rdtgrp);
int rdtgroup_locksetup_exit(struct rdtgroup *rdtgrp); int rdtgroup_locksetup_exit(struct rdtgroup *rdtgrp);
bool rdtgroup_cbm_overlaps_pseudo_locked(struct rdt_domain *d, unsigned long cbm); bool rdtgroup_cbm_overlaps_pseudo_locked(struct rdt_ctrl_domain *d, unsigned long cbm);
bool rdtgroup_pseudo_locked_in_hierarchy(struct rdt_domain *d); bool rdtgroup_pseudo_locked_in_hierarchy(struct rdt_ctrl_domain *d);
int rdt_pseudo_lock_init(void); int rdt_pseudo_lock_init(void);
void rdt_pseudo_lock_release(void); void rdt_pseudo_lock_release(void);
int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp); int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp);
void rdtgroup_pseudo_lock_remove(struct rdtgroup *rdtgrp); void rdtgroup_pseudo_lock_remove(struct rdtgroup *rdtgrp);
struct rdt_domain *get_domain_from_cpu(int cpu, struct rdt_resource *r); struct rdt_ctrl_domain *get_ctrl_domain_from_cpu(int cpu, struct rdt_resource *r);
struct rdt_mon_domain *get_mon_domain_from_cpu(int cpu, struct rdt_resource *r);
int closids_supported(void); int closids_supported(void);
void closid_free(int closid); void closid_free(int closid);
int alloc_rmid(u32 closid); int alloc_rmid(u32 closid);
...@@ -589,19 +633,19 @@ bool __init rdt_cpu_has(int flag); ...@@ -589,19 +633,19 @@ bool __init rdt_cpu_has(int flag);
void mon_event_count(void *info); void mon_event_count(void *info);
int rdtgroup_mondata_show(struct seq_file *m, void *arg); int rdtgroup_mondata_show(struct seq_file *m, void *arg);
void mon_event_read(struct rmid_read *rr, struct rdt_resource *r, void mon_event_read(struct rmid_read *rr, struct rdt_resource *r,
struct rdt_domain *d, struct rdtgroup *rdtgrp, struct rdt_mon_domain *d, struct rdtgroup *rdtgrp,
int evtid, int first); cpumask_t *cpumask, int evtid, int first);
void mbm_setup_overflow_handler(struct rdt_domain *dom, void mbm_setup_overflow_handler(struct rdt_mon_domain *dom,
unsigned long delay_ms, unsigned long delay_ms,
int exclude_cpu); int exclude_cpu);
void mbm_handle_overflow(struct work_struct *work); void mbm_handle_overflow(struct work_struct *work);
void __init intel_rdt_mbm_apply_quirk(void); void __init intel_rdt_mbm_apply_quirk(void);
bool is_mba_sc(struct rdt_resource *r); bool is_mba_sc(struct rdt_resource *r);
void cqm_setup_limbo_handler(struct rdt_domain *dom, unsigned long delay_ms, void cqm_setup_limbo_handler(struct rdt_mon_domain *dom, unsigned long delay_ms,
int exclude_cpu); int exclude_cpu);
void cqm_handle_limbo(struct work_struct *work); void cqm_handle_limbo(struct work_struct *work);
bool has_busy_rmid(struct rdt_domain *d); bool has_busy_rmid(struct rdt_mon_domain *d);
void __check_limbo(struct rdt_domain *d, bool force_free); void __check_limbo(struct rdt_mon_domain *d, bool force_free);
void rdt_domain_reconfigure_cdp(struct rdt_resource *r); void rdt_domain_reconfigure_cdp(struct rdt_resource *r);
void __init thread_throttle_mode_init(void); void __init thread_throttle_mode_init(void);
void __init mbm_config_rftype_init(const char *config); void __init mbm_config_rftype_init(const char *config);
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
* Software Developer Manual June 2016, volume 3, section 17.17. * Software Developer Manual June 2016, volume 3, section 17.17.
*/ */
#define pr_fmt(fmt) "resctrl: " fmt
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/sizes.h> #include <linux/sizes.h>
...@@ -97,6 +99,8 @@ unsigned int resctrl_rmid_realloc_limit; ...@@ -97,6 +99,8 @@ unsigned int resctrl_rmid_realloc_limit;
#define CF(cf) ((unsigned long)(1048576 * (cf) + 0.5)) #define CF(cf) ((unsigned long)(1048576 * (cf) + 0.5))
static int snc_nodes_per_l3_cache = 1;
/* /*
* The correction factor table is documented in Documentation/arch/x86/resctrl.rst. * The correction factor table is documented in Documentation/arch/x86/resctrl.rst.
* If rmid > rmid threshold, MBM total and local values should be multiplied * If rmid > rmid threshold, MBM total and local values should be multiplied
...@@ -185,7 +189,43 @@ static inline struct rmid_entry *__rmid_entry(u32 idx) ...@@ -185,7 +189,43 @@ static inline struct rmid_entry *__rmid_entry(u32 idx)
return entry; return entry;
} }
static int __rmid_read(u32 rmid, enum resctrl_event_id eventid, u64 *val) /*
* When Sub-NUMA Cluster (SNC) mode is not enabled (as indicated by
* "snc_nodes_per_l3_cache == 1") no translation of the RMID value is
* needed. The physical RMID is the same as the logical RMID.
*
* On a platform with SNC mode enabled, Linux enables RMID sharing mode
* via MSR 0xCA0 (see the "RMID Sharing Mode" section in the "Intel
* Resource Director Technology Architecture Specification" for a full
* description of RMID sharing mode).
*
* In RMID sharing mode there are fewer "logical RMID" values available
* to accumulate data ("physical RMIDs" are divided evenly between SNC
* nodes that share an L3 cache). Linux creates an rdt_mon_domain for
* each SNC node.
*
* The value loaded into IA32_PQR_ASSOC is the "logical RMID".
*
* Data is collected independently on each SNC node and can be retrieved
* using the "physical RMID" value computed by this function and loaded
* into IA32_QM_EVTSEL. @cpu can be any CPU in the SNC node.
*
* The scope of the IA32_QM_EVTSEL and IA32_QM_CTR MSRs is at the L3
* cache. So a "physical RMID" may be read from any CPU that shares
* the L3 cache with the desired SNC node, not just from a CPU in
* the specific SNC node.
*/
static int logical_rmid_to_physical_rmid(int cpu, int lrmid)
{
struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
if (snc_nodes_per_l3_cache == 1)
return lrmid;
return lrmid + (cpu_to_node(cpu) % snc_nodes_per_l3_cache) * r->num_rmid;
}
static int __rmid_read_phys(u32 prmid, enum resctrl_event_id eventid, u64 *val)
{ {
u64 msr_val; u64 msr_val;
...@@ -197,7 +237,7 @@ static int __rmid_read(u32 rmid, enum resctrl_event_id eventid, u64 *val) ...@@ -197,7 +237,7 @@ static int __rmid_read(u32 rmid, enum resctrl_event_id eventid, u64 *val)
* IA32_QM_CTR.Error (bit 63) and IA32_QM_CTR.Unavailable (bit 62) * IA32_QM_CTR.Error (bit 63) and IA32_QM_CTR.Unavailable (bit 62)
* are error bits. * are error bits.
*/ */
wrmsr(MSR_IA32_QM_EVTSEL, eventid, rmid); wrmsr(MSR_IA32_QM_EVTSEL, eventid, prmid);
rdmsrl(MSR_IA32_QM_CTR, msr_val); rdmsrl(MSR_IA32_QM_CTR, msr_val);
if (msr_val & RMID_VAL_ERROR) if (msr_val & RMID_VAL_ERROR)
...@@ -209,7 +249,7 @@ static int __rmid_read(u32 rmid, enum resctrl_event_id eventid, u64 *val) ...@@ -209,7 +249,7 @@ static int __rmid_read(u32 rmid, enum resctrl_event_id eventid, u64 *val)
return 0; return 0;
} }
static struct arch_mbm_state *get_arch_mbm_state(struct rdt_hw_domain *hw_dom, static struct arch_mbm_state *get_arch_mbm_state(struct rdt_hw_mon_domain *hw_dom,
u32 rmid, u32 rmid,
enum resctrl_event_id eventid) enum resctrl_event_id eventid)
{ {
...@@ -228,19 +268,22 @@ static struct arch_mbm_state *get_arch_mbm_state(struct rdt_hw_domain *hw_dom, ...@@ -228,19 +268,22 @@ static struct arch_mbm_state *get_arch_mbm_state(struct rdt_hw_domain *hw_dom,
return NULL; return NULL;
} }
void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_domain *d, void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_mon_domain *d,
u32 unused, u32 rmid, u32 unused, u32 rmid,
enum resctrl_event_id eventid) enum resctrl_event_id eventid)
{ {
struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d); struct rdt_hw_mon_domain *hw_dom = resctrl_to_arch_mon_dom(d);
int cpu = cpumask_any(&d->hdr.cpu_mask);
struct arch_mbm_state *am; struct arch_mbm_state *am;
u32 prmid;
am = get_arch_mbm_state(hw_dom, rmid, eventid); am = get_arch_mbm_state(hw_dom, rmid, eventid);
if (am) { if (am) {
memset(am, 0, sizeof(*am)); memset(am, 0, sizeof(*am));
prmid = logical_rmid_to_physical_rmid(cpu, rmid);
/* Record any initial, non-zero count value. */ /* Record any initial, non-zero count value. */
__rmid_read(rmid, eventid, &am->prev_msr); __rmid_read_phys(prmid, eventid, &am->prev_msr);
} }
} }
...@@ -248,9 +291,9 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_domain *d, ...@@ -248,9 +291,9 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_domain *d,
* Assumes that hardware counters are also reset and thus that there is * Assumes that hardware counters are also reset and thus that there is
* no need to record initial non-zero counts. * no need to record initial non-zero counts.
*/ */
void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_domain *d) void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_mon_domain *d)
{ {
struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d); struct rdt_hw_mon_domain *hw_dom = resctrl_to_arch_mon_dom(d);
if (is_mbm_total_enabled()) if (is_mbm_total_enabled())
memset(hw_dom->arch_mbm_total, 0, memset(hw_dom->arch_mbm_total, 0,
...@@ -269,22 +312,22 @@ static u64 mbm_overflow_count(u64 prev_msr, u64 cur_msr, unsigned int width) ...@@ -269,22 +312,22 @@ static u64 mbm_overflow_count(u64 prev_msr, u64 cur_msr, unsigned int width)
return chunks >> shift; return chunks >> shift;
} }
int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d, int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_mon_domain *d,
u32 unused, u32 rmid, enum resctrl_event_id eventid, u32 unused, u32 rmid, enum resctrl_event_id eventid,
u64 *val, void *ignored) u64 *val, void *ignored)
{ {
struct rdt_hw_mon_domain *hw_dom = resctrl_to_arch_mon_dom(d);
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 = resctrl_to_arch_dom(d); int cpu = cpumask_any(&d->hdr.cpu_mask);
struct arch_mbm_state *am; struct arch_mbm_state *am;
u64 msr_val, chunks; u64 msr_val, chunks;
u32 prmid;
int ret; int ret;
resctrl_arch_rmid_read_context_check(); resctrl_arch_rmid_read_context_check();
if (!cpumask_test_cpu(smp_processor_id(), &d->cpu_mask)) prmid = logical_rmid_to_physical_rmid(cpu, rmid);
return -EINVAL; ret = __rmid_read_phys(prmid, eventid, &msr_val);
ret = __rmid_read(rmid, eventid, &msr_val);
if (ret) if (ret)
return ret; return ret;
...@@ -320,7 +363,7 @@ static void limbo_release_entry(struct rmid_entry *entry) ...@@ -320,7 +363,7 @@ static void limbo_release_entry(struct rmid_entry *entry)
* decrement the count. If the busy count gets to zero on an RMID, we * decrement the count. If the busy count gets to zero on an RMID, we
* free the RMID * free the RMID
*/ */
void __check_limbo(struct rdt_domain *d, bool force_free) void __check_limbo(struct rdt_mon_domain *d, bool force_free)
{ {
struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl; struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
u32 idx_limit = resctrl_arch_system_num_rmid_idx(); u32 idx_limit = resctrl_arch_system_num_rmid_idx();
...@@ -364,7 +407,7 @@ void __check_limbo(struct rdt_domain *d, bool force_free) ...@@ -364,7 +407,7 @@ void __check_limbo(struct rdt_domain *d, bool force_free)
* CLOSID and RMID because there may be dependencies between them * CLOSID and RMID because there may be dependencies between them
* on some architectures. * on some architectures.
*/ */
trace_mon_llc_occupancy_limbo(entry->closid, entry->rmid, d->id, val); trace_mon_llc_occupancy_limbo(entry->closid, entry->rmid, d->hdr.id, val);
} }
if (force_free || !rmid_dirty) { if (force_free || !rmid_dirty) {
...@@ -378,7 +421,7 @@ void __check_limbo(struct rdt_domain *d, bool force_free) ...@@ -378,7 +421,7 @@ void __check_limbo(struct rdt_domain *d, bool force_free)
resctrl_arch_mon_ctx_free(r, QOS_L3_OCCUP_EVENT_ID, arch_mon_ctx); resctrl_arch_mon_ctx_free(r, QOS_L3_OCCUP_EVENT_ID, arch_mon_ctx);
} }
bool has_busy_rmid(struct rdt_domain *d) bool has_busy_rmid(struct rdt_mon_domain *d)
{ {
u32 idx_limit = resctrl_arch_system_num_rmid_idx(); u32 idx_limit = resctrl_arch_system_num_rmid_idx();
...@@ -479,7 +522,7 @@ int alloc_rmid(u32 closid) ...@@ -479,7 +522,7 @@ int alloc_rmid(u32 closid)
static void add_rmid_to_limbo(struct rmid_entry *entry) static void add_rmid_to_limbo(struct rmid_entry *entry)
{ {
struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl; struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
struct rdt_domain *d; struct rdt_mon_domain *d;
u32 idx; u32 idx;
lockdep_assert_held(&rdtgroup_mutex); lockdep_assert_held(&rdtgroup_mutex);
...@@ -490,7 +533,7 @@ static void add_rmid_to_limbo(struct rmid_entry *entry) ...@@ -490,7 +533,7 @@ static void add_rmid_to_limbo(struct rmid_entry *entry)
idx = resctrl_arch_rmid_idx_encode(entry->closid, entry->rmid); idx = resctrl_arch_rmid_idx_encode(entry->closid, entry->rmid);
entry->busy = 0; entry->busy = 0;
list_for_each_entry(d, &r->domains, list) { list_for_each_entry(d, &r->mon_domains, hdr.list) {
/* /*
* For the first limbo RMID in the domain, * For the first limbo RMID in the domain,
* setup up the limbo worker. * setup up the limbo worker.
...@@ -532,7 +575,7 @@ void free_rmid(u32 closid, u32 rmid) ...@@ -532,7 +575,7 @@ void free_rmid(u32 closid, u32 rmid)
list_add_tail(&entry->list, &rmid_free_lru); list_add_tail(&entry->list, &rmid_free_lru);
} }
static struct mbm_state *get_mbm_state(struct rdt_domain *d, u32 closid, static struct mbm_state *get_mbm_state(struct rdt_mon_domain *d, u32 closid,
u32 rmid, enum resctrl_event_id evtid) u32 rmid, enum resctrl_event_id evtid)
{ {
u32 idx = resctrl_arch_rmid_idx_encode(closid, rmid); u32 idx = resctrl_arch_rmid_idx_encode(closid, rmid);
...@@ -549,7 +592,10 @@ static struct mbm_state *get_mbm_state(struct rdt_domain *d, u32 closid, ...@@ -549,7 +592,10 @@ static struct mbm_state *get_mbm_state(struct rdt_domain *d, u32 closid,
static int __mon_event_count(u32 closid, u32 rmid, struct rmid_read *rr) static int __mon_event_count(u32 closid, u32 rmid, struct rmid_read *rr)
{ {
int cpu = smp_processor_id();
struct rdt_mon_domain *d;
struct mbm_state *m; struct mbm_state *m;
int err, ret;
u64 tval = 0; u64 tval = 0;
if (rr->first) { if (rr->first) {
...@@ -560,14 +606,47 @@ static int __mon_event_count(u32 closid, u32 rmid, struct rmid_read *rr) ...@@ -560,14 +606,47 @@ static int __mon_event_count(u32 closid, u32 rmid, struct rmid_read *rr)
return 0; return 0;
} }
rr->err = resctrl_arch_rmid_read(rr->r, rr->d, closid, rmid, rr->evtid, if (rr->d) {
&tval, rr->arch_mon_ctx); /* Reading a single domain, must be on a CPU in that domain. */
if (!cpumask_test_cpu(cpu, &rr->d->hdr.cpu_mask))
return -EINVAL;
rr->err = resctrl_arch_rmid_read(rr->r, rr->d, closid, rmid,
rr->evtid, &tval, rr->arch_mon_ctx);
if (rr->err) if (rr->err)
return rr->err; return rr->err;
rr->val += tval; rr->val += tval;
return 0; return 0;
}
/* Summing domains that share a cache, must be on a CPU for that cache. */
if (!cpumask_test_cpu(cpu, &rr->ci->shared_cpu_map))
return -EINVAL;
/*
* Legacy files must report the sum of an event across all
* domains that share the same L3 cache instance.
* Report success if a read from any domain succeeds, -EINVAL
* (translated to "Unavailable" for user space) if reading from
* all domains fail for any reason.
*/
ret = -EINVAL;
list_for_each_entry(d, &rr->r->mon_domains, hdr.list) {
if (d->ci->id != rr->ci->id)
continue;
err = resctrl_arch_rmid_read(rr->r, d, closid, rmid,
rr->evtid, &tval, rr->arch_mon_ctx);
if (!err) {
rr->val += tval;
ret = 0;
}
}
if (ret)
rr->err = ret;
return ret;
} }
/* /*
...@@ -668,12 +747,12 @@ void mon_event_count(void *info) ...@@ -668,12 +747,12 @@ void mon_event_count(void *info)
* throttle MSRs already have low percentage values. To avoid * throttle MSRs already have low percentage values. To avoid
* unnecessarily restricting such rdtgroups, we also increase the bandwidth. * unnecessarily restricting such rdtgroups, we also increase the bandwidth.
*/ */
static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm) static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_mon_domain *dom_mbm)
{ {
u32 closid, rmid, cur_msr_val, new_msr_val; u32 closid, rmid, cur_msr_val, new_msr_val;
struct mbm_state *pmbm_data, *cmbm_data; struct mbm_state *pmbm_data, *cmbm_data;
struct rdt_ctrl_domain *dom_mba;
struct rdt_resource *r_mba; struct rdt_resource *r_mba;
struct rdt_domain *dom_mba;
u32 cur_bw, user_bw, idx; u32 cur_bw, user_bw, idx;
struct list_head *head; struct list_head *head;
struct rdtgroup *entry; struct rdtgroup *entry;
...@@ -688,7 +767,7 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm) ...@@ -688,7 +767,7 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm)
idx = resctrl_arch_rmid_idx_encode(closid, rmid); idx = resctrl_arch_rmid_idx_encode(closid, rmid);
pmbm_data = &dom_mbm->mbm_local[idx]; pmbm_data = &dom_mbm->mbm_local[idx];
dom_mba = get_domain_from_cpu(smp_processor_id(), r_mba); dom_mba = get_ctrl_domain_from_cpu(smp_processor_id(), r_mba);
if (!dom_mba) { if (!dom_mba) {
pr_warn_once("Failure to get domain for MBA update\n"); pr_warn_once("Failure to get domain for MBA update\n");
return; return;
...@@ -734,12 +813,11 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm) ...@@ -734,12 +813,11 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm)
resctrl_arch_update_one(r_mba, dom_mba, closid, CDP_NONE, new_msr_val); resctrl_arch_update_one(r_mba, dom_mba, closid, CDP_NONE, new_msr_val);
} }
static void mbm_update(struct rdt_resource *r, struct rdt_domain *d, static void mbm_update(struct rdt_resource *r, struct rdt_mon_domain *d,
u32 closid, u32 rmid) u32 closid, u32 rmid)
{ {
struct rmid_read rr; struct rmid_read rr = {0};
rr.first = false;
rr.r = r; rr.r = r;
rr.d = d; rr.d = d;
...@@ -792,17 +870,17 @@ static void mbm_update(struct rdt_resource *r, struct rdt_domain *d, ...@@ -792,17 +870,17 @@ static void mbm_update(struct rdt_resource *r, struct rdt_domain *d,
void cqm_handle_limbo(struct work_struct *work) void cqm_handle_limbo(struct work_struct *work)
{ {
unsigned long delay = msecs_to_jiffies(CQM_LIMBOCHECK_INTERVAL); unsigned long delay = msecs_to_jiffies(CQM_LIMBOCHECK_INTERVAL);
struct rdt_domain *d; struct rdt_mon_domain *d;
cpus_read_lock(); cpus_read_lock();
mutex_lock(&rdtgroup_mutex); mutex_lock(&rdtgroup_mutex);
d = container_of(work, struct rdt_domain, cqm_limbo.work); d = container_of(work, struct rdt_mon_domain, cqm_limbo.work);
__check_limbo(d, false); __check_limbo(d, false);
if (has_busy_rmid(d)) { if (has_busy_rmid(d)) {
d->cqm_work_cpu = cpumask_any_housekeeping(&d->cpu_mask, d->cqm_work_cpu = cpumask_any_housekeeping(&d->hdr.cpu_mask,
RESCTRL_PICK_ANY_CPU); RESCTRL_PICK_ANY_CPU);
schedule_delayed_work_on(d->cqm_work_cpu, &d->cqm_limbo, schedule_delayed_work_on(d->cqm_work_cpu, &d->cqm_limbo,
delay); delay);
...@@ -820,13 +898,13 @@ void cqm_handle_limbo(struct work_struct *work) ...@@ -820,13 +898,13 @@ void cqm_handle_limbo(struct work_struct *work)
* @exclude_cpu: Which CPU the handler should not run on, * @exclude_cpu: Which CPU the handler should not run on,
* RESCTRL_PICK_ANY_CPU to pick any CPU. * RESCTRL_PICK_ANY_CPU to pick any CPU.
*/ */
void cqm_setup_limbo_handler(struct rdt_domain *dom, unsigned long delay_ms, void cqm_setup_limbo_handler(struct rdt_mon_domain *dom, unsigned long delay_ms,
int exclude_cpu) int exclude_cpu)
{ {
unsigned long delay = msecs_to_jiffies(delay_ms); unsigned long delay = msecs_to_jiffies(delay_ms);
int cpu; int cpu;
cpu = cpumask_any_housekeeping(&dom->cpu_mask, exclude_cpu); cpu = cpumask_any_housekeeping(&dom->hdr.cpu_mask, exclude_cpu);
dom->cqm_work_cpu = cpu; dom->cqm_work_cpu = cpu;
if (cpu < nr_cpu_ids) if (cpu < nr_cpu_ids)
...@@ -837,9 +915,9 @@ void mbm_handle_overflow(struct work_struct *work) ...@@ -837,9 +915,9 @@ void mbm_handle_overflow(struct work_struct *work)
{ {
unsigned long delay = msecs_to_jiffies(MBM_OVERFLOW_INTERVAL); unsigned long delay = msecs_to_jiffies(MBM_OVERFLOW_INTERVAL);
struct rdtgroup *prgrp, *crgrp; struct rdtgroup *prgrp, *crgrp;
struct rdt_mon_domain *d;
struct list_head *head; struct list_head *head;
struct rdt_resource *r; struct rdt_resource *r;
struct rdt_domain *d;
cpus_read_lock(); cpus_read_lock();
mutex_lock(&rdtgroup_mutex); mutex_lock(&rdtgroup_mutex);
...@@ -852,7 +930,7 @@ void mbm_handle_overflow(struct work_struct *work) ...@@ -852,7 +930,7 @@ void mbm_handle_overflow(struct work_struct *work)
goto out_unlock; goto out_unlock;
r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl; r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
d = container_of(work, struct rdt_domain, mbm_over.work); d = container_of(work, struct rdt_mon_domain, mbm_over.work);
list_for_each_entry(prgrp, &rdt_all_groups, rdtgroup_list) { list_for_each_entry(prgrp, &rdt_all_groups, rdtgroup_list) {
mbm_update(r, d, prgrp->closid, prgrp->mon.rmid); mbm_update(r, d, prgrp->closid, prgrp->mon.rmid);
...@@ -869,7 +947,7 @@ void mbm_handle_overflow(struct work_struct *work) ...@@ -869,7 +947,7 @@ void mbm_handle_overflow(struct work_struct *work)
* Re-check for housekeeping CPUs. This allows the overflow handler to * Re-check for housekeeping CPUs. This allows the overflow handler to
* move off a nohz_full CPU quickly. * move off a nohz_full CPU quickly.
*/ */
d->mbm_work_cpu = cpumask_any_housekeeping(&d->cpu_mask, d->mbm_work_cpu = cpumask_any_housekeeping(&d->hdr.cpu_mask,
RESCTRL_PICK_ANY_CPU); RESCTRL_PICK_ANY_CPU);
schedule_delayed_work_on(d->mbm_work_cpu, &d->mbm_over, delay); schedule_delayed_work_on(d->mbm_work_cpu, &d->mbm_over, delay);
...@@ -886,7 +964,7 @@ void mbm_handle_overflow(struct work_struct *work) ...@@ -886,7 +964,7 @@ void mbm_handle_overflow(struct work_struct *work)
* @exclude_cpu: Which CPU the handler should not run on, * @exclude_cpu: Which CPU the handler should not run on,
* RESCTRL_PICK_ANY_CPU to pick any CPU. * RESCTRL_PICK_ANY_CPU to pick any CPU.
*/ */
void mbm_setup_overflow_handler(struct rdt_domain *dom, unsigned long delay_ms, void mbm_setup_overflow_handler(struct rdt_mon_domain *dom, unsigned long delay_ms,
int exclude_cpu) int exclude_cpu)
{ {
unsigned long delay = msecs_to_jiffies(delay_ms); unsigned long delay = msecs_to_jiffies(delay_ms);
...@@ -898,7 +976,7 @@ void mbm_setup_overflow_handler(struct rdt_domain *dom, unsigned long delay_ms, ...@@ -898,7 +976,7 @@ void mbm_setup_overflow_handler(struct rdt_domain *dom, unsigned long delay_ms,
*/ */
if (!resctrl_mounted || !resctrl_arch_mon_capable()) if (!resctrl_mounted || !resctrl_arch_mon_capable())
return; return;
cpu = cpumask_any_housekeeping(&dom->cpu_mask, exclude_cpu); cpu = cpumask_any_housekeeping(&dom->hdr.cpu_mask, exclude_cpu);
dom->mbm_work_cpu = cpu; dom->mbm_work_cpu = cpu;
if (cpu < nr_cpu_ids) if (cpu < nr_cpu_ids)
...@@ -1015,6 +1093,88 @@ static void l3_mon_evt_init(struct rdt_resource *r) ...@@ -1015,6 +1093,88 @@ static void l3_mon_evt_init(struct rdt_resource *r)
list_add_tail(&mbm_local_event.list, &r->evt_list); list_add_tail(&mbm_local_event.list, &r->evt_list);
} }
/*
* The power-on reset value of MSR_RMID_SNC_CONFIG is 0x1
* which indicates that RMIDs are configured in legacy mode.
* This mode is incompatible with Linux resctrl semantics
* as RMIDs are partitioned between SNC nodes, which requires
* a user to know which RMID is allocated to a task.
* Clearing bit 0 reconfigures the RMID counters for use
* in RMID sharing mode. This mode is better for Linux.
* The RMID space is divided between all SNC nodes with the
* RMIDs renumbered to start from zero in each node when
* counting operations from tasks. Code to read the counters
* must adjust RMID counter numbers based on SNC node. See
* logical_rmid_to_physical_rmid() for code that does this.
*/
void arch_mon_domain_online(struct rdt_resource *r, struct rdt_mon_domain *d)
{
if (snc_nodes_per_l3_cache > 1)
msr_clear_bit(MSR_RMID_SNC_CONFIG, 0);
}
/* CPU models that support MSR_RMID_SNC_CONFIG */
static const struct x86_cpu_id snc_cpu_ids[] __initconst = {
X86_MATCH_VFM(INTEL_ICELAKE_X, 0),
X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X, 0),
X86_MATCH_VFM(INTEL_EMERALDRAPIDS_X, 0),
X86_MATCH_VFM(INTEL_GRANITERAPIDS_X, 0),
X86_MATCH_VFM(INTEL_ATOM_CRESTMONT_X, 0),
{}
};
/*
* There isn't a simple hardware bit that indicates whether a CPU is running
* in Sub-NUMA Cluster (SNC) mode. Infer the state by comparing the
* number of CPUs sharing the L3 cache with CPU0 to the number of CPUs in
* the same NUMA node as CPU0.
* It is not possible to accurately determine SNC state if the system is
* booted with a maxcpus=N parameter. That distorts the ratio of SNC nodes
* to L3 caches. It will be OK if system is booted with hyperthreading
* disabled (since this doesn't affect the ratio).
*/
static __init int snc_get_config(void)
{
struct cacheinfo *ci = get_cpu_cacheinfo_level(0, RESCTRL_L3_CACHE);
const cpumask_t *node0_cpumask;
int cpus_per_node, cpus_per_l3;
int ret;
if (!x86_match_cpu(snc_cpu_ids) || !ci)
return 1;
cpus_read_lock();
if (num_online_cpus() != num_present_cpus())
pr_warn("Some CPUs offline, SNC detection may be incorrect\n");
cpus_read_unlock();
node0_cpumask = cpumask_of_node(cpu_to_node(0));
cpus_per_node = cpumask_weight(node0_cpumask);
cpus_per_l3 = cpumask_weight(&ci->shared_cpu_map);
if (!cpus_per_node || !cpus_per_l3)
return 1;
ret = cpus_per_l3 / cpus_per_node;
/* sanity check: Only valid results are 1, 2, 3, 4 */
switch (ret) {
case 1:
break;
case 2 ... 4:
pr_info("Sub-NUMA Cluster mode detected with %d nodes per L3 cache\n", ret);
rdt_resources_all[RDT_RESOURCE_L3].r_resctrl.mon_scope = RESCTRL_L3_NODE;
break;
default:
pr_warn("Ignore improbable SNC node count %d\n", ret);
ret = 1;
break;
}
return ret;
}
int __init rdt_get_mon_l3_config(struct rdt_resource *r) int __init rdt_get_mon_l3_config(struct rdt_resource *r)
{ {
unsigned int mbm_offset = boot_cpu_data.x86_cache_mbm_width_offset; unsigned int mbm_offset = boot_cpu_data.x86_cache_mbm_width_offset;
...@@ -1022,9 +1182,11 @@ int __init rdt_get_mon_l3_config(struct rdt_resource *r) ...@@ -1022,9 +1182,11 @@ int __init rdt_get_mon_l3_config(struct rdt_resource *r)
unsigned int threshold; unsigned int threshold;
int ret; int ret;
snc_nodes_per_l3_cache = snc_get_config();
resctrl_rmid_realloc_limit = boot_cpu_data.x86_cache_size * 1024; resctrl_rmid_realloc_limit = boot_cpu_data.x86_cache_size * 1024;
hw_res->mon_scale = boot_cpu_data.x86_cache_occ_scale; hw_res->mon_scale = boot_cpu_data.x86_cache_occ_scale / snc_nodes_per_l3_cache;
r->num_rmid = boot_cpu_data.x86_cache_max_rmid + 1; r->num_rmid = (boot_cpu_data.x86_cache_max_rmid + 1) / snc_nodes_per_l3_cache;
hw_res->mbm_width = MBM_CNTR_WIDTH_BASE; hw_res->mbm_width = MBM_CNTR_WIDTH_BASE;
if (mbm_offset > 0 && mbm_offset <= MBM_CNTR_WIDTH_OFFSET_MAX) if (mbm_offset > 0 && mbm_offset <= MBM_CNTR_WIDTH_OFFSET_MAX)
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/cacheinfo.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
...@@ -221,7 +220,7 @@ static int pseudo_lock_cstates_constrain(struct pseudo_lock_region *plr) ...@@ -221,7 +220,7 @@ static int pseudo_lock_cstates_constrain(struct pseudo_lock_region *plr)
int cpu; int cpu;
int ret; int ret;
for_each_cpu(cpu, &plr->d->cpu_mask) { for_each_cpu(cpu, &plr->d->hdr.cpu_mask) {
pm_req = kzalloc(sizeof(*pm_req), GFP_KERNEL); pm_req = kzalloc(sizeof(*pm_req), GFP_KERNEL);
if (!pm_req) { if (!pm_req) {
rdt_last_cmd_puts("Failure to allocate memory for PM QoS\n"); rdt_last_cmd_puts("Failure to allocate memory for PM QoS\n");
...@@ -292,11 +291,15 @@ static void pseudo_lock_region_clear(struct pseudo_lock_region *plr) ...@@ -292,11 +291,15 @@ static void pseudo_lock_region_clear(struct pseudo_lock_region *plr)
*/ */
static int pseudo_lock_region_init(struct pseudo_lock_region *plr) static int pseudo_lock_region_init(struct pseudo_lock_region *plr)
{ {
enum resctrl_scope scope = plr->s->res->ctrl_scope;
struct cacheinfo *ci; struct cacheinfo *ci;
int ret; int ret;
if (WARN_ON_ONCE(scope != RESCTRL_L2_CACHE && scope != RESCTRL_L3_CACHE))
return -ENODEV;
/* Pick the first cpu we find that is associated with the cache. */ /* Pick the first cpu we find that is associated with the cache. */
plr->cpu = cpumask_first(&plr->d->cpu_mask); plr->cpu = cpumask_first(&plr->d->hdr.cpu_mask);
if (!cpu_online(plr->cpu)) { if (!cpu_online(plr->cpu)) {
rdt_last_cmd_printf("CPU %u associated with cache not online\n", rdt_last_cmd_printf("CPU %u associated with cache not online\n",
...@@ -305,7 +308,7 @@ static int pseudo_lock_region_init(struct pseudo_lock_region *plr) ...@@ -305,7 +308,7 @@ static int pseudo_lock_region_init(struct pseudo_lock_region *plr)
goto out_region; goto out_region;
} }
ci = get_cpu_cacheinfo_level(plr->cpu, plr->s->res->cache_level); ci = get_cpu_cacheinfo_level(plr->cpu, scope);
if (ci) { if (ci) {
plr->line_size = ci->coherency_line_size; plr->line_size = ci->coherency_line_size;
plr->size = rdtgroup_cbm_to_size(plr->s->res, plr->d, plr->cbm); plr->size = rdtgroup_cbm_to_size(plr->s->res, plr->d, plr->cbm);
...@@ -805,7 +808,7 @@ int rdtgroup_locksetup_exit(struct rdtgroup *rdtgrp) ...@@ -805,7 +808,7 @@ int rdtgroup_locksetup_exit(struct rdtgroup *rdtgrp)
* Return: true if @cbm overlaps with pseudo-locked region on @d, false * Return: true if @cbm overlaps with pseudo-locked region on @d, false
* otherwise. * otherwise.
*/ */
bool rdtgroup_cbm_overlaps_pseudo_locked(struct rdt_domain *d, unsigned long cbm) bool rdtgroup_cbm_overlaps_pseudo_locked(struct rdt_ctrl_domain *d, unsigned long cbm)
{ {
unsigned int cbm_len; unsigned int cbm_len;
unsigned long cbm_b; unsigned long cbm_b;
...@@ -832,11 +835,11 @@ bool rdtgroup_cbm_overlaps_pseudo_locked(struct rdt_domain *d, unsigned long cbm ...@@ -832,11 +835,11 @@ bool rdtgroup_cbm_overlaps_pseudo_locked(struct rdt_domain *d, unsigned long cbm
* if it is not possible to test due to memory allocation issue, * if it is not possible to test due to memory allocation issue,
* false otherwise. * false otherwise.
*/ */
bool rdtgroup_pseudo_locked_in_hierarchy(struct rdt_domain *d) bool rdtgroup_pseudo_locked_in_hierarchy(struct rdt_ctrl_domain *d)
{ {
struct rdt_ctrl_domain *d_i;
cpumask_var_t cpu_with_psl; cpumask_var_t cpu_with_psl;
struct rdt_resource *r; struct rdt_resource *r;
struct rdt_domain *d_i;
bool ret = false; bool ret = false;
/* Walking r->domains, ensure it can't race with cpuhp */ /* Walking r->domains, ensure it can't race with cpuhp */
...@@ -850,10 +853,10 @@ bool rdtgroup_pseudo_locked_in_hierarchy(struct rdt_domain *d) ...@@ -850,10 +853,10 @@ bool rdtgroup_pseudo_locked_in_hierarchy(struct rdt_domain *d)
* associated with them. * associated with them.
*/ */
for_each_alloc_capable_rdt_resource(r) { for_each_alloc_capable_rdt_resource(r) {
list_for_each_entry(d_i, &r->domains, list) { list_for_each_entry(d_i, &r->ctrl_domains, hdr.list) {
if (d_i->plr) if (d_i->plr)
cpumask_or(cpu_with_psl, cpu_with_psl, cpumask_or(cpu_with_psl, cpu_with_psl,
&d_i->cpu_mask); &d_i->hdr.cpu_mask);
} }
} }
...@@ -861,7 +864,7 @@ bool rdtgroup_pseudo_locked_in_hierarchy(struct rdt_domain *d) ...@@ -861,7 +864,7 @@ bool rdtgroup_pseudo_locked_in_hierarchy(struct rdt_domain *d)
* Next test if new pseudo-locked region would intersect with * Next test if new pseudo-locked region would intersect with
* existing region. * existing region.
*/ */
if (cpumask_intersects(&d->cpu_mask, cpu_with_psl)) if (cpumask_intersects(&d->hdr.cpu_mask, cpu_with_psl))
ret = true; ret = true;
free_cpumask_var(cpu_with_psl); free_cpumask_var(cpu_with_psl);
...@@ -1193,7 +1196,7 @@ static int pseudo_lock_measure_cycles(struct rdtgroup *rdtgrp, int sel) ...@@ -1193,7 +1196,7 @@ static int pseudo_lock_measure_cycles(struct rdtgroup *rdtgrp, int sel)
} }
plr->thread_done = 0; plr->thread_done = 0;
cpu = cpumask_first(&plr->d->cpu_mask); cpu = cpumask_first(&plr->d->hdr.cpu_mask);
if (!cpu_online(cpu)) { if (!cpu_online(cpu)) {
ret = -ENODEV; ret = -ENODEV;
goto out; goto out;
...@@ -1523,7 +1526,7 @@ static int pseudo_lock_dev_mmap(struct file *filp, struct vm_area_struct *vma) ...@@ -1523,7 +1526,7 @@ static int pseudo_lock_dev_mmap(struct file *filp, struct vm_area_struct *vma)
* may be scheduled elsewhere and invalidate entries in the * may be scheduled elsewhere and invalidate entries in the
* pseudo-locked region. * pseudo-locked region.
*/ */
if (!cpumask_subset(current->cpus_ptr, &plr->d->cpu_mask)) { if (!cpumask_subset(current->cpus_ptr, &plr->d->hdr.cpu_mask)) {
mutex_unlock(&rdtgroup_mutex); mutex_unlock(&rdtgroup_mutex);
return -EINVAL; return -EINVAL;
} }
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/cacheinfo.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/fs.h> #include <linux/fs.h>
...@@ -92,13 +91,13 @@ void rdt_last_cmd_printf(const char *fmt, ...) ...@@ -92,13 +91,13 @@ void rdt_last_cmd_printf(const char *fmt, ...)
void rdt_staged_configs_clear(void) void rdt_staged_configs_clear(void)
{ {
struct rdt_ctrl_domain *dom;
struct rdt_resource *r; struct rdt_resource *r;
struct rdt_domain *dom;
lockdep_assert_held(&rdtgroup_mutex); lockdep_assert_held(&rdtgroup_mutex);
for_each_alloc_capable_rdt_resource(r) { for_each_alloc_capable_rdt_resource(r) {
list_for_each_entry(dom, &r->domains, list) list_for_each_entry(dom, &r->ctrl_domains, hdr.list)
memset(dom->staged_config, 0, sizeof(dom->staged_config)); memset(dom->staged_config, 0, sizeof(dom->staged_config));
} }
} }
...@@ -317,7 +316,7 @@ static int rdtgroup_cpus_show(struct kernfs_open_file *of, ...@@ -317,7 +316,7 @@ static int rdtgroup_cpus_show(struct kernfs_open_file *of,
rdt_last_cmd_puts("Cache domain offline\n"); rdt_last_cmd_puts("Cache domain offline\n");
ret = -ENODEV; ret = -ENODEV;
} else { } else {
mask = &rdtgrp->plr->d->cpu_mask; mask = &rdtgrp->plr->d->hdr.cpu_mask;
seq_printf(s, is_cpu_list(of) ? seq_printf(s, is_cpu_list(of) ?
"%*pbl\n" : "%*pb\n", "%*pbl\n" : "%*pb\n",
cpumask_pr_args(mask)); cpumask_pr_args(mask));
...@@ -1012,7 +1011,7 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of, ...@@ -1012,7 +1011,7 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of,
unsigned long sw_shareable = 0, hw_shareable = 0; unsigned long sw_shareable = 0, hw_shareable = 0;
unsigned long exclusive = 0, pseudo_locked = 0; unsigned long exclusive = 0, pseudo_locked = 0;
struct rdt_resource *r = s->res; struct rdt_resource *r = s->res;
struct rdt_domain *dom; struct rdt_ctrl_domain *dom;
int i, hwb, swb, excl, psl; int i, hwb, swb, excl, psl;
enum rdtgrp_mode mode; enum rdtgrp_mode mode;
bool sep = false; bool sep = false;
...@@ -1021,12 +1020,12 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of, ...@@ -1021,12 +1020,12 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of,
cpus_read_lock(); cpus_read_lock();
mutex_lock(&rdtgroup_mutex); mutex_lock(&rdtgroup_mutex);
hw_shareable = r->cache.shareable_bits; hw_shareable = r->cache.shareable_bits;
list_for_each_entry(dom, &r->domains, list) { list_for_each_entry(dom, &r->ctrl_domains, hdr.list) {
if (sep) if (sep)
seq_putc(seq, ';'); seq_putc(seq, ';');
sw_shareable = 0; sw_shareable = 0;
exclusive = 0; exclusive = 0;
seq_printf(seq, "%d=", dom->id); seq_printf(seq, "%d=", dom->hdr.id);
for (i = 0; i < closids_supported(); i++) { for (i = 0; i < closids_supported(); i++) {
if (!closid_allocated(i)) if (!closid_allocated(i))
continue; continue;
...@@ -1243,7 +1242,7 @@ static int rdt_has_sparse_bitmasks_show(struct kernfs_open_file *of, ...@@ -1243,7 +1242,7 @@ static int rdt_has_sparse_bitmasks_show(struct kernfs_open_file *of,
* *
* Return: false if CBM does not overlap, true if it does. * Return: false if CBM does not overlap, true if it does.
*/ */
static bool __rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_domain *d, static bool __rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_ctrl_domain *d,
unsigned long cbm, int closid, unsigned long cbm, int closid,
enum resctrl_conf_type type, bool exclusive) enum resctrl_conf_type type, bool exclusive)
{ {
...@@ -1298,7 +1297,7 @@ static bool __rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_domain *d ...@@ -1298,7 +1297,7 @@ 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 * Return: true if CBM overlap detected, false if there is no overlap
*/ */
bool rdtgroup_cbm_overlaps(struct resctrl_schema *s, struct rdt_domain *d, bool rdtgroup_cbm_overlaps(struct resctrl_schema *s, struct rdt_ctrl_domain *d,
unsigned long cbm, int closid, bool exclusive) unsigned long cbm, int closid, bool exclusive)
{ {
enum resctrl_conf_type peer_type = resctrl_peer_type(s->conf_type); enum resctrl_conf_type peer_type = resctrl_peer_type(s->conf_type);
...@@ -1329,10 +1328,10 @@ bool rdtgroup_cbm_overlaps(struct resctrl_schema *s, struct rdt_domain *d, ...@@ -1329,10 +1328,10 @@ bool rdtgroup_cbm_overlaps(struct resctrl_schema *s, struct rdt_domain *d,
static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp) static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp)
{ {
int closid = rdtgrp->closid; int closid = rdtgrp->closid;
struct rdt_ctrl_domain *d;
struct resctrl_schema *s; struct resctrl_schema *s;
struct rdt_resource *r; struct rdt_resource *r;
bool has_cache = false; bool has_cache = false;
struct rdt_domain *d;
u32 ctrl; u32 ctrl;
/* Walking r->domains, ensure it can't race with cpuhp */ /* Walking r->domains, ensure it can't race with cpuhp */
...@@ -1343,7 +1342,7 @@ static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp) ...@@ -1343,7 +1342,7 @@ static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp)
if (r->rid == RDT_RESOURCE_MBA || r->rid == RDT_RESOURCE_SMBA) if (r->rid == RDT_RESOURCE_MBA || r->rid == RDT_RESOURCE_SMBA)
continue; continue;
has_cache = true; has_cache = true;
list_for_each_entry(d, &r->domains, list) { list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
ctrl = resctrl_arch_get_config(r, d, closid, ctrl = resctrl_arch_get_config(r, d, closid,
s->conf_type); s->conf_type);
if (rdtgroup_cbm_overlaps(s, d, ctrl, closid, false)) { if (rdtgroup_cbm_overlaps(s, d, ctrl, closid, false)) {
...@@ -1448,14 +1447,17 @@ static ssize_t rdtgroup_mode_write(struct kernfs_open_file *of, ...@@ -1448,14 +1447,17 @@ static ssize_t rdtgroup_mode_write(struct kernfs_open_file *of,
* bitmap functions work correctly. * bitmap functions work correctly.
*/ */
unsigned int rdtgroup_cbm_to_size(struct rdt_resource *r, unsigned int rdtgroup_cbm_to_size(struct rdt_resource *r,
struct rdt_domain *d, unsigned long cbm) struct rdt_ctrl_domain *d, unsigned long cbm)
{ {
unsigned int size = 0; unsigned int size = 0;
struct cacheinfo *ci; struct cacheinfo *ci;
int num_b; int num_b;
if (WARN_ON_ONCE(r->ctrl_scope != RESCTRL_L2_CACHE && r->ctrl_scope != RESCTRL_L3_CACHE))
return size;
num_b = bitmap_weight(&cbm, r->cache.cbm_len); num_b = bitmap_weight(&cbm, r->cache.cbm_len);
ci = get_cpu_cacheinfo_level(cpumask_any(&d->cpu_mask), r->cache_level); ci = get_cpu_cacheinfo_level(cpumask_any(&d->hdr.cpu_mask), r->ctrl_scope);
if (ci) if (ci)
size = ci->size / r->cache.cbm_len * num_b; size = ci->size / r->cache.cbm_len * num_b;
...@@ -1473,9 +1475,9 @@ static int rdtgroup_size_show(struct kernfs_open_file *of, ...@@ -1473,9 +1475,9 @@ static int rdtgroup_size_show(struct kernfs_open_file *of,
{ {
struct resctrl_schema *schema; struct resctrl_schema *schema;
enum resctrl_conf_type type; enum resctrl_conf_type type;
struct rdt_ctrl_domain *d;
struct rdtgroup *rdtgrp; struct rdtgroup *rdtgrp;
struct rdt_resource *r; struct rdt_resource *r;
struct rdt_domain *d;
unsigned int size; unsigned int size;
int ret = 0; int ret = 0;
u32 closid; u32 closid;
...@@ -1499,7 +1501,7 @@ static int rdtgroup_size_show(struct kernfs_open_file *of, ...@@ -1499,7 +1501,7 @@ static int rdtgroup_size_show(struct kernfs_open_file *of,
size = rdtgroup_cbm_to_size(rdtgrp->plr->s->res, size = rdtgroup_cbm_to_size(rdtgrp->plr->s->res,
rdtgrp->plr->d, rdtgrp->plr->d,
rdtgrp->plr->cbm); rdtgrp->plr->cbm);
seq_printf(s, "%d=%u\n", rdtgrp->plr->d->id, size); seq_printf(s, "%d=%u\n", rdtgrp->plr->d->hdr.id, size);
} }
goto out; goto out;
} }
...@@ -1511,7 +1513,7 @@ static int rdtgroup_size_show(struct kernfs_open_file *of, ...@@ -1511,7 +1513,7 @@ static int rdtgroup_size_show(struct kernfs_open_file *of,
type = schema->conf_type; type = schema->conf_type;
sep = false; sep = false;
seq_printf(s, "%*s:", max_name_width, schema->name); seq_printf(s, "%*s:", max_name_width, schema->name);
list_for_each_entry(d, &r->domains, list) { list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
if (sep) if (sep)
seq_putc(s, ';'); seq_putc(s, ';');
if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) { if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
...@@ -1529,7 +1531,7 @@ static int rdtgroup_size_show(struct kernfs_open_file *of, ...@@ -1529,7 +1531,7 @@ static int rdtgroup_size_show(struct kernfs_open_file *of,
else else
size = rdtgroup_cbm_to_size(r, d, ctrl); size = rdtgroup_cbm_to_size(r, d, ctrl);
} }
seq_printf(s, "%d=%u", d->id, size); seq_printf(s, "%d=%u", d->hdr.id, size);
sep = true; sep = true;
} }
seq_putc(s, '\n'); seq_putc(s, '\n');
...@@ -1587,21 +1589,21 @@ static void mon_event_config_read(void *info) ...@@ -1587,21 +1589,21 @@ static void mon_event_config_read(void *info)
mon_info->mon_config = msrval & MAX_EVT_CONFIG_BITS; mon_info->mon_config = msrval & MAX_EVT_CONFIG_BITS;
} }
static void mondata_config_read(struct rdt_domain *d, struct mon_config_info *mon_info) static void mondata_config_read(struct rdt_mon_domain *d, struct mon_config_info *mon_info)
{ {
smp_call_function_any(&d->cpu_mask, mon_event_config_read, mon_info, 1); smp_call_function_any(&d->hdr.cpu_mask, mon_event_config_read, mon_info, 1);
} }
static int mbm_config_show(struct seq_file *s, struct rdt_resource *r, u32 evtid) static int mbm_config_show(struct seq_file *s, struct rdt_resource *r, u32 evtid)
{ {
struct mon_config_info mon_info = {0}; struct mon_config_info mon_info = {0};
struct rdt_domain *dom; struct rdt_mon_domain *dom;
bool sep = false; bool sep = false;
cpus_read_lock(); cpus_read_lock();
mutex_lock(&rdtgroup_mutex); mutex_lock(&rdtgroup_mutex);
list_for_each_entry(dom, &r->domains, list) { list_for_each_entry(dom, &r->mon_domains, hdr.list) {
if (sep) if (sep)
seq_puts(s, ";"); seq_puts(s, ";");
...@@ -1609,7 +1611,7 @@ static int mbm_config_show(struct seq_file *s, struct rdt_resource *r, u32 evtid ...@@ -1609,7 +1611,7 @@ static int mbm_config_show(struct seq_file *s, struct rdt_resource *r, u32 evtid
mon_info.evtid = evtid; mon_info.evtid = evtid;
mondata_config_read(dom, &mon_info); mondata_config_read(dom, &mon_info);
seq_printf(s, "%d=0x%02x", dom->id, mon_info.mon_config); seq_printf(s, "%d=0x%02x", dom->hdr.id, mon_info.mon_config);
sep = true; sep = true;
} }
seq_puts(s, "\n"); seq_puts(s, "\n");
...@@ -1654,7 +1656,7 @@ static void mon_event_config_write(void *info) ...@@ -1654,7 +1656,7 @@ static void mon_event_config_write(void *info)
} }
static void mbm_config_write_domain(struct rdt_resource *r, static void mbm_config_write_domain(struct rdt_resource *r,
struct rdt_domain *d, u32 evtid, u32 val) struct rdt_mon_domain *d, u32 evtid, u32 val)
{ {
struct mon_config_info mon_info = {0}; struct mon_config_info mon_info = {0};
...@@ -1675,7 +1677,7 @@ static void mbm_config_write_domain(struct rdt_resource *r, ...@@ -1675,7 +1677,7 @@ static void mbm_config_write_domain(struct rdt_resource *r,
* are scoped at the domain level. Writing any of these MSRs * are scoped at the domain level. Writing any of these MSRs
* on one CPU is observed by all the CPUs in the domain. * on one CPU is observed by all the CPUs in the domain.
*/ */
smp_call_function_any(&d->cpu_mask, mon_event_config_write, smp_call_function_any(&d->hdr.cpu_mask, mon_event_config_write,
&mon_info, 1); &mon_info, 1);
/* /*
...@@ -1695,7 +1697,7 @@ static int mon_config_write(struct rdt_resource *r, char *tok, u32 evtid) ...@@ -1695,7 +1697,7 @@ static int mon_config_write(struct rdt_resource *r, char *tok, u32 evtid)
struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
char *dom_str = NULL, *id_str; char *dom_str = NULL, *id_str;
unsigned long dom_id, val; unsigned long dom_id, val;
struct rdt_domain *d; struct rdt_mon_domain *d;
/* 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();
...@@ -1725,8 +1727,8 @@ static int mon_config_write(struct rdt_resource *r, char *tok, u32 evtid) ...@@ -1725,8 +1727,8 @@ static int mon_config_write(struct rdt_resource *r, char *tok, u32 evtid)
return -EINVAL; return -EINVAL;
} }
list_for_each_entry(d, &r->domains, list) { list_for_each_entry(d, &r->mon_domains, hdr.list) {
if (d->id == dom_id) { if (d->hdr.id == dom_id) {
mbm_config_write_domain(r, d, evtid, val); mbm_config_write_domain(r, d, evtid, val);
goto next; goto next;
} }
...@@ -2254,9 +2256,9 @@ static inline bool is_mba_linear(void) ...@@ -2254,9 +2256,9 @@ static inline bool is_mba_linear(void)
static int set_cache_qos_cfg(int level, bool enable) static int set_cache_qos_cfg(int level, bool enable)
{ {
void (*update)(void *arg); void (*update)(void *arg);
struct rdt_ctrl_domain *d;
struct rdt_resource *r_l; struct rdt_resource *r_l;
cpumask_var_t cpu_mask; cpumask_var_t cpu_mask;
struct rdt_domain *d;
int cpu; int cpu;
/* Walking r->domains, ensure it can't race with cpuhp */ /* Walking r->domains, ensure it can't race with cpuhp */
...@@ -2273,14 +2275,14 @@ static int set_cache_qos_cfg(int level, bool enable) ...@@ -2273,14 +2275,14 @@ static int set_cache_qos_cfg(int level, bool enable)
return -ENOMEM; return -ENOMEM;
r_l = &rdt_resources_all[level].r_resctrl; r_l = &rdt_resources_all[level].r_resctrl;
list_for_each_entry(d, &r_l->domains, list) { list_for_each_entry(d, &r_l->ctrl_domains, hdr.list) {
if (r_l->cache.arch_has_per_cpu_cfg) if (r_l->cache.arch_has_per_cpu_cfg)
/* Pick all the CPUs in the domain instance */ /* Pick all the CPUs in the domain instance */
for_each_cpu(cpu, &d->cpu_mask) for_each_cpu(cpu, &d->hdr.cpu_mask)
cpumask_set_cpu(cpu, cpu_mask); cpumask_set_cpu(cpu, cpu_mask);
else else
/* Pick one CPU from each domain instance to update MSR */ /* Pick one CPU from each domain instance to update MSR */
cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask); cpumask_set_cpu(cpumask_any(&d->hdr.cpu_mask), cpu_mask);
} }
/* Update QOS_CFG MSR on all the CPUs in cpu_mask */ /* Update QOS_CFG MSR on all the CPUs in cpu_mask */
...@@ -2306,10 +2308,10 @@ void rdt_domain_reconfigure_cdp(struct rdt_resource *r) ...@@ -2306,10 +2308,10 @@ void rdt_domain_reconfigure_cdp(struct rdt_resource *r)
l3_qos_cfg_update(&hw_res->cdp_enabled); l3_qos_cfg_update(&hw_res->cdp_enabled);
} }
static int mba_sc_domain_allocate(struct rdt_resource *r, struct rdt_domain *d) static int mba_sc_domain_allocate(struct rdt_resource *r, struct rdt_ctrl_domain *d)
{ {
u32 num_closid = resctrl_arch_get_num_closid(r); u32 num_closid = resctrl_arch_get_num_closid(r);
int cpu = cpumask_any(&d->cpu_mask); int cpu = cpumask_any(&d->hdr.cpu_mask);
int i; int i;
d->mbps_val = kcalloc_node(num_closid, sizeof(*d->mbps_val), d->mbps_val = kcalloc_node(num_closid, sizeof(*d->mbps_val),
...@@ -2324,7 +2326,7 @@ static int mba_sc_domain_allocate(struct rdt_resource *r, struct rdt_domain *d) ...@@ -2324,7 +2326,7 @@ static int mba_sc_domain_allocate(struct rdt_resource *r, struct rdt_domain *d)
} }
static void mba_sc_domain_destroy(struct rdt_resource *r, static void mba_sc_domain_destroy(struct rdt_resource *r,
struct rdt_domain *d) struct rdt_ctrl_domain *d)
{ {
kfree(d->mbps_val); kfree(d->mbps_val);
d->mbps_val = NULL; d->mbps_val = NULL;
...@@ -2332,14 +2334,18 @@ static void mba_sc_domain_destroy(struct rdt_resource *r, ...@@ -2332,14 +2334,18 @@ static void mba_sc_domain_destroy(struct rdt_resource *r,
/* /*
* MBA software controller is supported only if * MBA software controller is supported only if
* MBM is supported and MBA is in linear scale. * MBM is supported and MBA is in linear scale,
* and the MBM monitor scope is the same as MBA
* control scope.
*/ */
static bool supports_mba_mbps(void) static bool supports_mba_mbps(void)
{ {
struct rdt_resource *rmbm = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_MBA].r_resctrl; struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_MBA].r_resctrl;
return (is_mbm_local_enabled() && return (is_mbm_local_enabled() &&
r->alloc_capable && is_mba_linear()); r->alloc_capable && is_mba_linear() &&
r->ctrl_scope == rmbm->mon_scope);
} }
/* /*
...@@ -2350,7 +2356,7 @@ static int set_mba_sc(bool mba_sc) ...@@ -2350,7 +2356,7 @@ static int set_mba_sc(bool mba_sc)
{ {
struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_MBA].r_resctrl; struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_MBA].r_resctrl;
u32 num_closid = resctrl_arch_get_num_closid(r); u32 num_closid = resctrl_arch_get_num_closid(r);
struct rdt_domain *d; struct rdt_ctrl_domain *d;
int i; int i;
if (!supports_mba_mbps() || mba_sc == is_mba_sc(r)) if (!supports_mba_mbps() || mba_sc == is_mba_sc(r))
...@@ -2358,7 +2364,7 @@ static int set_mba_sc(bool mba_sc) ...@@ -2358,7 +2364,7 @@ static int set_mba_sc(bool mba_sc)
r->membw.mba_sc = mba_sc; r->membw.mba_sc = mba_sc;
list_for_each_entry(d, &r->domains, list) { list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
for (i = 0; i < num_closid; i++) for (i = 0; i < num_closid; i++)
d->mbps_val[i] = MBA_MAX_MBPS; d->mbps_val[i] = MBA_MAX_MBPS;
} }
...@@ -2622,7 +2628,7 @@ static int rdt_get_tree(struct fs_context *fc) ...@@ -2622,7 +2628,7 @@ static int rdt_get_tree(struct fs_context *fc)
{ {
struct rdt_fs_context *ctx = rdt_fc2context(fc); struct rdt_fs_context *ctx = rdt_fc2context(fc);
unsigned long flags = RFTYPE_CTRL_BASE; unsigned long flags = RFTYPE_CTRL_BASE;
struct rdt_domain *dom; struct rdt_mon_domain *dom;
struct rdt_resource *r; struct rdt_resource *r;
int ret; int ret;
...@@ -2697,7 +2703,7 @@ static int rdt_get_tree(struct fs_context *fc) ...@@ -2697,7 +2703,7 @@ static int rdt_get_tree(struct fs_context *fc)
if (is_mbm_enabled()) { if (is_mbm_enabled()) {
r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl; r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
list_for_each_entry(dom, &r->domains, list) list_for_each_entry(dom, &r->mon_domains, hdr.list)
mbm_setup_overflow_handler(dom, MBM_OVERFLOW_INTERVAL, mbm_setup_overflow_handler(dom, MBM_OVERFLOW_INTERVAL,
RESCTRL_PICK_ANY_CPU); RESCTRL_PICK_ANY_CPU);
} }
...@@ -2747,6 +2753,7 @@ static int rdt_parse_param(struct fs_context *fc, struct fs_parameter *param) ...@@ -2747,6 +2753,7 @@ static int rdt_parse_param(struct fs_context *fc, struct fs_parameter *param)
{ {
struct rdt_fs_context *ctx = rdt_fc2context(fc); struct rdt_fs_context *ctx = rdt_fc2context(fc);
struct fs_parse_result result; struct fs_parse_result result;
const char *msg;
int opt; int opt;
opt = fs_parse(fc, rdt_fs_parameters, param, &result); opt = fs_parse(fc, rdt_fs_parameters, param, &result);
...@@ -2761,8 +2768,9 @@ static int rdt_parse_param(struct fs_context *fc, struct fs_parameter *param) ...@@ -2761,8 +2768,9 @@ static int rdt_parse_param(struct fs_context *fc, struct fs_parameter *param)
ctx->enable_cdpl2 = true; ctx->enable_cdpl2 = true;
return 0; return 0;
case Opt_mba_mbps: case Opt_mba_mbps:
msg = "mba_MBps requires local MBM and linear scale MBA at L3 scope";
if (!supports_mba_mbps()) if (!supports_mba_mbps())
return -EINVAL; return invalfc(fc, msg);
ctx->enable_mba_mbps = true; ctx->enable_mba_mbps = true;
return 0; return 0;
case Opt_debug: case Opt_debug:
...@@ -2807,9 +2815,9 @@ static int rdt_init_fs_context(struct fs_context *fc) ...@@ -2807,9 +2815,9 @@ static int rdt_init_fs_context(struct fs_context *fc)
static int reset_all_ctrls(struct rdt_resource *r) 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_ctrl_domain *hw_dom;
struct msr_param msr_param; struct msr_param msr_param;
struct rdt_domain *d; struct rdt_ctrl_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 */
...@@ -2821,16 +2829,16 @@ static int reset_all_ctrls(struct rdt_resource *r) ...@@ -2821,16 +2829,16 @@ static int reset_all_ctrls(struct rdt_resource *r)
/* /*
* Disable resource control for this resource by setting all * Disable resource control for this resource by setting all
* CBMs in all domains to the maximum mask value. Pick one CPU * CBMs in all ctrl_domains to the maximum mask value. Pick one CPU
* from each domain to update the MSRs below. * from each domain to update the MSRs below.
*/ */
list_for_each_entry(d, &r->domains, list) { list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
hw_dom = resctrl_to_arch_dom(d); hw_dom = resctrl_to_arch_ctrl_dom(d);
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; msr_param.dom = d;
smp_call_function_any(&d->cpu_mask, rdt_ctrl_update, &msr_param, 1); smp_call_function_any(&d->hdr.cpu_mask, rdt_ctrl_update, &msr_param, 1);
} }
return 0; return 0;
...@@ -2998,38 +3006,97 @@ static int mon_addfile(struct kernfs_node *parent_kn, const char *name, ...@@ -2998,38 +3006,97 @@ static int mon_addfile(struct kernfs_node *parent_kn, const char *name,
return ret; return ret;
} }
static void mon_rmdir_one_subdir(struct kernfs_node *pkn, char *name, char *subname)
{
struct kernfs_node *kn;
kn = kernfs_find_and_get(pkn, name);
if (!kn)
return;
kernfs_put(kn);
if (kn->dir.subdirs <= 1)
kernfs_remove(kn);
else
kernfs_remove_by_name(kn, subname);
}
/* /*
* Remove all subdirectories of mon_data of ctrl_mon groups * Remove all subdirectories of mon_data of ctrl_mon groups
* and monitor groups with given domain id. * and monitor groups for the given domain.
* Remove files and directories containing "sum" of domain data
* when last domain being summed is removed.
*/ */
static void rmdir_mondata_subdir_allrdtgrp(struct rdt_resource *r, static void rmdir_mondata_subdir_allrdtgrp(struct rdt_resource *r,
unsigned int dom_id) struct rdt_mon_domain *d)
{ {
struct rdtgroup *prgrp, *crgrp; struct rdtgroup *prgrp, *crgrp;
char subname[32];
bool snc_mode;
char name[32]; char name[32];
snc_mode = r->mon_scope == RESCTRL_L3_NODE;
sprintf(name, "mon_%s_%02d", r->name, snc_mode ? d->ci->id : d->hdr.id);
if (snc_mode)
sprintf(subname, "mon_sub_%s_%02d", r->name, d->hdr.id);
list_for_each_entry(prgrp, &rdt_all_groups, rdtgroup_list) { list_for_each_entry(prgrp, &rdt_all_groups, rdtgroup_list) {
sprintf(name, "mon_%s_%02d", r->name, dom_id); mon_rmdir_one_subdir(prgrp->mon.mon_data_kn, name, subname);
kernfs_remove_by_name(prgrp->mon.mon_data_kn, name);
list_for_each_entry(crgrp, &prgrp->mon.crdtgrp_list, mon.crdtgrp_list) list_for_each_entry(crgrp, &prgrp->mon.crdtgrp_list, mon.crdtgrp_list)
kernfs_remove_by_name(crgrp->mon.mon_data_kn, name); mon_rmdir_one_subdir(crgrp->mon.mon_data_kn, name, subname);
} }
} }
static int mkdir_mondata_subdir(struct kernfs_node *parent_kn, static int mon_add_all_files(struct kernfs_node *kn, struct rdt_mon_domain *d,
struct rdt_domain *d, struct rdt_resource *r, struct rdtgroup *prgrp,
struct rdt_resource *r, struct rdtgroup *prgrp) bool do_sum)
{ {
struct rmid_read rr = {0};
union mon_data_bits priv; union mon_data_bits priv;
struct kernfs_node *kn;
struct mon_evt *mevt; struct mon_evt *mevt;
struct rmid_read rr;
char name[32];
int ret; int ret;
sprintf(name, "mon_%s_%02d", r->name, d->id); if (WARN_ON(list_empty(&r->evt_list)))
/* create the directory */ return -EPERM;
priv.u.rid = r->rid;
priv.u.domid = do_sum ? d->ci->id : d->hdr.id;
priv.u.sum = do_sum;
list_for_each_entry(mevt, &r->evt_list, list) {
priv.u.evtid = mevt->evtid;
ret = mon_addfile(kn, mevt->name, priv.priv);
if (ret)
return ret;
if (!do_sum && is_mbm_event(mevt->evtid))
mon_event_read(&rr, r, d, prgrp, &d->hdr.cpu_mask, mevt->evtid, true);
}
return 0;
}
static int mkdir_mondata_subdir(struct kernfs_node *parent_kn,
struct rdt_mon_domain *d,
struct rdt_resource *r, struct rdtgroup *prgrp)
{
struct kernfs_node *kn, *ckn;
char name[32];
bool snc_mode;
int ret = 0;
lockdep_assert_held(&rdtgroup_mutex);
snc_mode = r->mon_scope == RESCTRL_L3_NODE;
sprintf(name, "mon_%s_%02d", r->name, snc_mode ? d->ci->id : d->hdr.id);
kn = kernfs_find_and_get(parent_kn, name);
if (kn) {
/*
* rdtgroup_mutex will prevent this directory from being
* removed. No need to keep this hold.
*/
kernfs_put(kn);
} else {
kn = kernfs_create_dir(parent_kn, name, parent_kn->mode, prgrp); kn = kernfs_create_dir(parent_kn, name, parent_kn->mode, prgrp);
if (IS_ERR(kn)) if (IS_ERR(kn))
return PTR_ERR(kn); return PTR_ERR(kn);
...@@ -3037,23 +3104,28 @@ static int mkdir_mondata_subdir(struct kernfs_node *parent_kn, ...@@ -3037,23 +3104,28 @@ static int mkdir_mondata_subdir(struct kernfs_node *parent_kn,
ret = rdtgroup_kn_set_ugid(kn); ret = rdtgroup_kn_set_ugid(kn);
if (ret) if (ret)
goto out_destroy; goto out_destroy;
ret = mon_add_all_files(kn, d, r, prgrp, snc_mode);
if (ret)
goto out_destroy;
}
if (WARN_ON(list_empty(&r->evt_list))) { if (snc_mode) {
ret = -EPERM; sprintf(name, "mon_sub_%s_%02d", r->name, d->hdr.id);
ckn = kernfs_create_dir(kn, name, parent_kn->mode, prgrp);
if (IS_ERR(ckn)) {
ret = -EINVAL;
goto out_destroy; goto out_destroy;
} }
priv.u.rid = r->rid; ret = rdtgroup_kn_set_ugid(ckn);
priv.u.domid = d->id;
list_for_each_entry(mevt, &r->evt_list, list) {
priv.u.evtid = mevt->evtid;
ret = mon_addfile(kn, mevt->name, priv.priv);
if (ret) if (ret)
goto out_destroy; goto out_destroy;
if (is_mbm_event(mevt->evtid)) ret = mon_add_all_files(ckn, d, r, prgrp, false);
mon_event_read(&rr, r, d, prgrp, mevt->evtid, true); if (ret)
goto out_destroy;
} }
kernfs_activate(kn); kernfs_activate(kn);
return 0; return 0;
...@@ -3067,7 +3139,7 @@ static int mkdir_mondata_subdir(struct kernfs_node *parent_kn, ...@@ -3067,7 +3139,7 @@ static int mkdir_mondata_subdir(struct kernfs_node *parent_kn,
* and "monitor" groups with given domain id. * and "monitor" groups with given domain id.
*/ */
static void mkdir_mondata_subdir_allrdtgrp(struct rdt_resource *r, static void mkdir_mondata_subdir_allrdtgrp(struct rdt_resource *r,
struct rdt_domain *d) struct rdt_mon_domain *d)
{ {
struct kernfs_node *parent_kn; struct kernfs_node *parent_kn;
struct rdtgroup *prgrp, *crgrp; struct rdtgroup *prgrp, *crgrp;
...@@ -3089,13 +3161,13 @@ static int mkdir_mondata_subdir_alldom(struct kernfs_node *parent_kn, ...@@ -3089,13 +3161,13 @@ static int mkdir_mondata_subdir_alldom(struct kernfs_node *parent_kn,
struct rdt_resource *r, struct rdt_resource *r,
struct rdtgroup *prgrp) struct rdtgroup *prgrp)
{ {
struct rdt_domain *dom; struct rdt_mon_domain *dom;
int ret; int ret;
/* 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();
list_for_each_entry(dom, &r->domains, list) { list_for_each_entry(dom, &r->mon_domains, hdr.list) {
ret = mkdir_mondata_subdir(parent_kn, dom, r, prgrp); ret = mkdir_mondata_subdir(parent_kn, dom, r, prgrp);
if (ret) if (ret)
return ret; return ret;
...@@ -3194,7 +3266,7 @@ static u32 cbm_ensure_valid(u32 _val, struct rdt_resource *r) ...@@ -3194,7 +3266,7 @@ 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, * Set the RDT domain up to start off with all usable allocations. That is,
* all shareable and unused bits. All-zero CBM is invalid. * all shareable and unused bits. All-zero CBM is invalid.
*/ */
static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, static int __init_one_rdt_domain(struct rdt_ctrl_domain *d, struct resctrl_schema *s,
u32 closid) u32 closid)
{ {
enum resctrl_conf_type peer_type = resctrl_peer_type(s->conf_type); enum resctrl_conf_type peer_type = resctrl_peer_type(s->conf_type);
...@@ -3254,7 +3326,7 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, ...@@ -3254,7 +3326,7 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s,
*/ */
tmp_cbm = cfg->new_ctrl; tmp_cbm = cfg->new_ctrl;
if (bitmap_weight(&tmp_cbm, r->cache.cbm_len) < r->cache.min_cbm_bits) { 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); rdt_last_cmd_printf("No space on %s:%d\n", s->name, d->hdr.id);
return -ENOSPC; return -ENOSPC;
} }
cfg->have_new_ctrl = true; cfg->have_new_ctrl = true;
...@@ -3274,10 +3346,10 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s, ...@@ -3274,10 +3346,10 @@ static int __init_one_rdt_domain(struct rdt_domain *d, struct resctrl_schema *s,
*/ */
static int rdtgroup_init_cat(struct resctrl_schema *s, u32 closid) static int rdtgroup_init_cat(struct resctrl_schema *s, u32 closid)
{ {
struct rdt_domain *d; struct rdt_ctrl_domain *d;
int ret; int ret;
list_for_each_entry(d, &s->res->domains, list) { list_for_each_entry(d, &s->res->ctrl_domains, hdr.list) {
ret = __init_one_rdt_domain(d, s, closid); ret = __init_one_rdt_domain(d, s, closid);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -3290,9 +3362,9 @@ static int rdtgroup_init_cat(struct resctrl_schema *s, u32 closid) ...@@ -3290,9 +3362,9 @@ static int rdtgroup_init_cat(struct resctrl_schema *s, u32 closid)
static void rdtgroup_init_mba(struct rdt_resource *r, u32 closid) static void rdtgroup_init_mba(struct rdt_resource *r, u32 closid)
{ {
struct resctrl_staged_config *cfg; struct resctrl_staged_config *cfg;
struct rdt_domain *d; struct rdt_ctrl_domain *d;
list_for_each_entry(d, &r->domains, list) { list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
if (is_mba_sc(r)) { if (is_mba_sc(r)) {
d->mbps_val[closid] = MBA_MAX_MBPS; d->mbps_val[closid] = MBA_MAX_MBPS;
continue; continue;
...@@ -3916,29 +3988,33 @@ static void __init rdtgroup_setup_default(void) ...@@ -3916,29 +3988,33 @@ static void __init rdtgroup_setup_default(void)
mutex_unlock(&rdtgroup_mutex); mutex_unlock(&rdtgroup_mutex);
} }
static void domain_destroy_mon_state(struct rdt_domain *d) static void domain_destroy_mon_state(struct rdt_mon_domain *d)
{ {
bitmap_free(d->rmid_busy_llc); bitmap_free(d->rmid_busy_llc);
kfree(d->mbm_total); kfree(d->mbm_total);
kfree(d->mbm_local); kfree(d->mbm_local);
} }
void resctrl_offline_domain(struct rdt_resource *r, struct rdt_domain *d) void resctrl_offline_ctrl_domain(struct rdt_resource *r, struct rdt_ctrl_domain *d)
{ {
mutex_lock(&rdtgroup_mutex); mutex_lock(&rdtgroup_mutex);
if (supports_mba_mbps() && r->rid == RDT_RESOURCE_MBA) if (supports_mba_mbps() && r->rid == RDT_RESOURCE_MBA)
mba_sc_domain_destroy(r, d); mba_sc_domain_destroy(r, d);
if (!r->mon_capable) mutex_unlock(&rdtgroup_mutex);
goto out_unlock; }
void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_mon_domain *d)
{
mutex_lock(&rdtgroup_mutex);
/* /*
* If resctrl is mounted, remove all the * If resctrl is mounted, remove all the
* per domain monitor data directories. * per domain monitor data directories.
*/ */
if (resctrl_mounted && resctrl_arch_mon_capable()) if (resctrl_mounted && resctrl_arch_mon_capable())
rmdir_mondata_subdir_allrdtgrp(r, d->id); rmdir_mondata_subdir_allrdtgrp(r, d);
if (is_mbm_enabled()) if (is_mbm_enabled())
cancel_delayed_work(&d->mbm_over); cancel_delayed_work(&d->mbm_over);
...@@ -3957,11 +4033,10 @@ void resctrl_offline_domain(struct rdt_resource *r, struct rdt_domain *d) ...@@ -3957,11 +4033,10 @@ void resctrl_offline_domain(struct rdt_resource *r, struct rdt_domain *d)
domain_destroy_mon_state(d); domain_destroy_mon_state(d);
out_unlock:
mutex_unlock(&rdtgroup_mutex); mutex_unlock(&rdtgroup_mutex);
} }
static int domain_setup_mon_state(struct rdt_resource *r, struct rdt_domain *d) static int domain_setup_mon_state(struct rdt_resource *r, struct rdt_mon_domain *d)
{ {
u32 idx_limit = resctrl_arch_system_num_rmid_idx(); u32 idx_limit = resctrl_arch_system_num_rmid_idx();
size_t tsize; size_t tsize;
...@@ -3992,7 +4067,7 @@ static int domain_setup_mon_state(struct rdt_resource *r, struct rdt_domain *d) ...@@ -3992,7 +4067,7 @@ static int domain_setup_mon_state(struct rdt_resource *r, struct rdt_domain *d)
return 0; return 0;
} }
int resctrl_online_domain(struct rdt_resource *r, struct rdt_domain *d) int resctrl_online_ctrl_domain(struct rdt_resource *r, struct rdt_ctrl_domain *d)
{ {
int err = 0; int err = 0;
...@@ -4001,11 +4076,18 @@ int resctrl_online_domain(struct rdt_resource *r, struct rdt_domain *d) ...@@ -4001,11 +4076,18 @@ int resctrl_online_domain(struct rdt_resource *r, struct rdt_domain *d)
if (supports_mba_mbps() && r->rid == RDT_RESOURCE_MBA) { if (supports_mba_mbps() && r->rid == RDT_RESOURCE_MBA) {
/* RDT_RESOURCE_MBA is never mon_capable */ /* RDT_RESOURCE_MBA is never mon_capable */
err = mba_sc_domain_allocate(r, d); err = mba_sc_domain_allocate(r, d);
goto out_unlock;
} }
if (!r->mon_capable) mutex_unlock(&rdtgroup_mutex);
goto out_unlock;
return err;
}
int resctrl_online_mon_domain(struct rdt_resource *r, struct rdt_mon_domain *d)
{
int err;
mutex_lock(&rdtgroup_mutex);
err = domain_setup_mon_state(r, d); err = domain_setup_mon_state(r, d);
if (err) if (err)
...@@ -4056,8 +4138,8 @@ static void clear_childcpus(struct rdtgroup *r, unsigned int cpu) ...@@ -4056,8 +4138,8 @@ static void clear_childcpus(struct rdtgroup *r, unsigned int cpu)
void resctrl_offline_cpu(unsigned int cpu) void resctrl_offline_cpu(unsigned int cpu)
{ {
struct rdt_resource *l3 = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl; struct rdt_resource *l3 = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
struct rdt_mon_domain *d;
struct rdtgroup *rdtgrp; struct rdtgroup *rdtgrp;
struct rdt_domain *d;
mutex_lock(&rdtgroup_mutex); mutex_lock(&rdtgroup_mutex);
list_for_each_entry(rdtgrp, &rdt_all_groups, rdtgroup_list) { list_for_each_entry(rdtgrp, &rdt_all_groups, rdtgroup_list) {
...@@ -4070,7 +4152,7 @@ void resctrl_offline_cpu(unsigned int cpu) ...@@ -4070,7 +4152,7 @@ void resctrl_offline_cpu(unsigned int cpu)
if (!l3->mon_capable) if (!l3->mon_capable)
goto out_unlock; goto out_unlock;
d = get_domain_from_cpu(cpu, l3); d = get_mon_domain_from_cpu(cpu, l3);
if (d) { if (d) {
if (is_mbm_enabled() && cpu == d->mbm_work_cpu) { if (is_mbm_enabled() && cpu == d->mbm_work_cpu) {
cancel_delayed_work(&d->mbm_over); cancel_delayed_work(&d->mbm_over);
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#ifndef _RESCTRL_H #ifndef _RESCTRL_H
#define _RESCTRL_H #define _RESCTRL_H
#include <linux/cacheinfo.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/pid.h> #include <linux/pid.h>
...@@ -58,11 +59,45 @@ struct resctrl_staged_config { ...@@ -58,11 +59,45 @@ struct resctrl_staged_config {
bool have_new_ctrl; bool have_new_ctrl;
}; };
enum resctrl_domain_type {
RESCTRL_CTRL_DOMAIN,
RESCTRL_MON_DOMAIN,
};
/** /**
* struct rdt_domain - group of CPUs sharing a resctrl resource * struct rdt_domain_hdr - common header for different domain types
* @list: all instances of this resource * @list: all instances of this resource
* @id: unique id for this instance * @id: unique id for this instance
* @type: type of this instance
* @cpu_mask: which CPUs share this resource * @cpu_mask: which CPUs share this resource
*/
struct rdt_domain_hdr {
struct list_head list;
int id;
enum resctrl_domain_type type;
struct cpumask cpu_mask;
};
/**
* struct rdt_ctrl_domain - group of CPUs sharing a resctrl control resource
* @hdr: common header for different domain types
* @plr: pseudo-locked region (if any) associated with domain
* @staged_config: parsed configuration to be applied
* @mbps_val: When mba_sc is enabled, this holds the array of user
* specified control values for mba_sc in MBps, indexed
* by closid
*/
struct rdt_ctrl_domain {
struct rdt_domain_hdr hdr;
struct pseudo_lock_region *plr;
struct resctrl_staged_config staged_config[CDP_NUM_TYPES];
u32 *mbps_val;
};
/**
* struct rdt_mon_domain - group of CPUs sharing a resctrl monitor resource
* @hdr: common header for different domain types
* @ci: cache info for this domain
* @rmid_busy_llc: bitmap of which limbo RMIDs are above threshold * @rmid_busy_llc: bitmap of which limbo RMIDs are above threshold
* @mbm_total: saved state for MBM total bandwidth * @mbm_total: saved state for MBM total bandwidth
* @mbm_local: saved state for MBM local bandwidth * @mbm_local: saved state for MBM local bandwidth
...@@ -70,16 +105,10 @@ struct resctrl_staged_config { ...@@ -70,16 +105,10 @@ struct resctrl_staged_config {
* @cqm_limbo: worker to periodically read CQM h/w counters * @cqm_limbo: worker to periodically read CQM h/w counters
* @mbm_work_cpu: worker CPU for MBM h/w counters * @mbm_work_cpu: worker CPU for MBM h/w counters
* @cqm_work_cpu: worker CPU for CQM 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
* @mbps_val: When mba_sc is enabled, this holds the array of user
* specified control values for mba_sc in MBps, indexed
* by closid
*/ */
struct rdt_domain { struct rdt_mon_domain {
struct list_head list; struct rdt_domain_hdr hdr;
int id; struct cacheinfo *ci;
struct cpumask cpu_mask;
unsigned long *rmid_busy_llc; unsigned long *rmid_busy_llc;
struct mbm_state *mbm_total; struct mbm_state *mbm_total;
struct mbm_state *mbm_local; struct mbm_state *mbm_local;
...@@ -87,9 +116,6 @@ struct rdt_domain { ...@@ -87,9 +116,6 @@ struct rdt_domain {
struct delayed_work cqm_limbo; struct delayed_work cqm_limbo;
int mbm_work_cpu; int mbm_work_cpu;
int cqm_work_cpu; int cqm_work_cpu;
struct pseudo_lock_region *plr;
struct resctrl_staged_config staged_config[CDP_NUM_TYPES];
u32 *mbps_val;
}; };
/** /**
...@@ -150,16 +176,24 @@ struct resctrl_membw { ...@@ -150,16 +176,24 @@ struct resctrl_membw {
struct rdt_parse_data; struct rdt_parse_data;
struct resctrl_schema; struct resctrl_schema;
enum resctrl_scope {
RESCTRL_L2_CACHE = 2,
RESCTRL_L3_CACHE = 3,
RESCTRL_L3_NODE,
};
/** /**
* struct rdt_resource - attributes of a resctrl resource * struct rdt_resource - attributes of a resctrl resource
* @rid: The index of the resource * @rid: The index of the resource
* @alloc_capable: Is allocation available on this machine * @alloc_capable: Is allocation available on this machine
* @mon_capable: Is monitor feature available on this machine * @mon_capable: Is monitor feature available on this machine
* @num_rmid: Number of RMIDs available * @num_rmid: Number of RMIDs available
* @cache_level: Which cache level defines scope of this resource * @ctrl_scope: Scope of this resource for control functions
* @mon_scope: Scope of this resource for monitor functions
* @cache: Cache allocation related data * @cache: Cache allocation related data
* @membw: If the component has bandwidth controls, their properties. * @membw: If the component has bandwidth controls, their properties.
* @domains: RCU list of all domains for this resource * @ctrl_domains: RCU list of all control domains for this resource
* @mon_domains: RCU list of all monitor domains for this resource
* @name: Name to use in "schemata" file. * @name: Name to use in "schemata" file.
* @data_width: Character width of data when displaying * @data_width: Character width of data when displaying
* @default_ctrl: Specifies default cache cbm or memory B/W percent. * @default_ctrl: Specifies default cache cbm or memory B/W percent.
...@@ -174,17 +208,19 @@ struct rdt_resource { ...@@ -174,17 +208,19 @@ struct rdt_resource {
bool alloc_capable; bool alloc_capable;
bool mon_capable; bool mon_capable;
int num_rmid; int num_rmid;
int cache_level; enum resctrl_scope ctrl_scope;
enum resctrl_scope mon_scope;
struct resctrl_cache cache; struct resctrl_cache cache;
struct resctrl_membw membw; struct resctrl_membw membw;
struct list_head domains; struct list_head ctrl_domains;
struct list_head mon_domains;
char *name; char *name;
int data_width; int data_width;
u32 default_ctrl; u32 default_ctrl;
const char *format_str; const char *format_str;
int (*parse_ctrlval)(struct rdt_parse_data *data, int (*parse_ctrlval)(struct rdt_parse_data *data,
struct resctrl_schema *s, struct resctrl_schema *s,
struct rdt_domain *d); struct rdt_ctrl_domain *d);
struct list_head evt_list; struct list_head evt_list;
unsigned long fflags; unsigned long fflags;
bool cdp_capable; bool cdp_capable;
...@@ -218,13 +254,15 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid); ...@@ -218,13 +254,15 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid);
* Update the ctrl_val and apply this config right now. * Update the ctrl_val and apply this config right now.
* Must be called on one of the domain's CPUs. * Must be called on one of the domain's CPUs.
*/ */
int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
u32 closid, enum resctrl_conf_type t, u32 cfg_val); u32 closid, enum resctrl_conf_type t, u32 cfg_val);
u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
u32 closid, enum resctrl_conf_type type); u32 closid, enum resctrl_conf_type type);
int resctrl_online_domain(struct rdt_resource *r, struct rdt_domain *d); int resctrl_online_ctrl_domain(struct rdt_resource *r, struct rdt_ctrl_domain *d);
void resctrl_offline_domain(struct rdt_resource *r, struct rdt_domain *d); int resctrl_online_mon_domain(struct rdt_resource *r, struct rdt_mon_domain *d);
void resctrl_offline_ctrl_domain(struct rdt_resource *r, struct rdt_ctrl_domain *d);
void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_mon_domain *d);
void resctrl_online_cpu(unsigned int cpu); void resctrl_online_cpu(unsigned int cpu);
void resctrl_offline_cpu(unsigned int cpu); void resctrl_offline_cpu(unsigned int cpu);
...@@ -253,7 +291,7 @@ void resctrl_offline_cpu(unsigned int cpu); ...@@ -253,7 +291,7 @@ void resctrl_offline_cpu(unsigned int cpu);
* Return: * Return:
* 0 on success, or -EIO, -EINVAL etc on error. * 0 on success, or -EIO, -EINVAL etc on error.
*/ */
int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d, int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_mon_domain *d,
u32 closid, u32 rmid, enum resctrl_event_id eventid, u32 closid, u32 rmid, enum resctrl_event_id eventid,
u64 *val, void *arch_mon_ctx); u64 *val, void *arch_mon_ctx);
...@@ -286,7 +324,7 @@ static inline void resctrl_arch_rmid_read_context_check(void) ...@@ -286,7 +324,7 @@ static inline void resctrl_arch_rmid_read_context_check(void)
* *
* This can be called from any CPU. * This can be called from any CPU.
*/ */
void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_domain *d, void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_mon_domain *d,
u32 closid, u32 rmid, u32 closid, u32 rmid,
enum resctrl_event_id eventid); enum resctrl_event_id eventid);
...@@ -299,7 +337,7 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_domain *d, ...@@ -299,7 +337,7 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_domain *d,
* *
* This can be called from any CPU. * This can be called from any CPU.
*/ */
void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_domain *d); void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_mon_domain *d);
extern unsigned int resctrl_rmid_realloc_threshold; extern unsigned int resctrl_rmid_realloc_threshold;
extern unsigned int resctrl_rmid_realloc_limit; extern unsigned int resctrl_rmid_realloc_limit;
......
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