This patchset has some preparatory patches to cgroup to add a wrapper to
to cgroup_rmdir to destroy the cgroup directories recursively, new mount
and umount interfaces for ss. It then has patches to support Intel code
data prioritization which is an extension of cache allocation and lets
allocate code and data cache seperately.
Details of the feature can be found in the Intel SDM june 2015 volume 3,
section 17.16.
The preparatory patches and some part of enabling are tested but
otherwise this is mostly a *pre hardware* patch and I still need to test
it once i setup the hardware.
This patch is dependent on cache allocation patch series V11.
http://marc.info/?l=linux-kernel&m=143526051306160
Known issues:
- Need changes to the formating of the change logs
- Remove some RDT specific flags in cgroup.c
- Patch is for initial testing. Will add more documentation on the new
APIs if needed.
[PATCH 1/6] cgroup: Adds cgroup_destroy_children
[PATCH 2/6] cgroup: Add css_mount and css_umount
[PATCH 3/6] x86/intel_rdt: Intel Code Data Prioritization detection
[PATCH 4/6] x86/intel_rdt: Adds support to enable CDP
[PATCH 5/6] x86/intel_rdt: Class of service management for code data
[PATCH 6/6] x86/intel_rdt: Support dcache and icache mask for Code
cgroup currently does not support removing a cgroup directory if it has
children.
Adds a api cgroup_destroy_children which destroys all the children in
the cgroup hierarchy starting from the bottom. After each cgroup node is
destroyed we wait till the css is offlined and freed.
Signed-off-by: Vikas Shivappa <[email protected]>
---
include/linux/cgroup.h | 4 +++
kernel/cgroup.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 89 insertions(+)
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index b9cb94c..292ed97 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -609,6 +609,7 @@ char *task_cgroup_path(struct task_struct *task, char *buf, size_t buflen);
int cgroup_add_dfl_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);
int cgroup_add_legacy_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);
int cgroup_rm_cftypes(struct cftype *cfts);
+void cgroup_destroy_children(struct cgroup_subsys_state *css);
bool cgroup_is_descendant(struct cgroup *cgrp, struct cgroup *ancestor);
@@ -705,6 +706,9 @@ struct cgroup_subsys {
* specifies the mask of subsystems that this one depends on.
*/
unsigned int depends_on;
+
+ /* used to wait for freeing of csses */
+ wait_queue_head_t pending_css_free_waitq;
};
#define SUBSYS(_x) extern struct cgroup_subsys _x ## _cgrp_subsys;
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 469dd54..668f614 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1733,6 +1733,33 @@ out:
return ret;
}
+/*
+ * css_wait_free: Wait till css is freed.
+ * @css: The css that we need to wait for
+ *
+ * Wait for the release_css to call the ss->css_free and goto
+ * quiescent state for a while.
+ * This ensures that stage 4/last stage of css destruction is complete.
+ */
+static void css_wait_free(struct cgroup_subsys_state *css)
+{
+ struct cgroup_subsys *ss;
+ DEFINE_WAIT(wait);
+
+ lockdep_assert_held(&cgroup_mutex);
+
+ if (css && (css->flags & CSS_ONLINE)) {
+ ss = css->ss;
+ prepare_to_wait(&ss->pending_css_free_waitq, &wait,
+ TASK_UNINTERRUPTIBLE);
+ mutex_unlock(&cgroup_mutex);
+ schedule();
+ finish_wait(&ss->pending_css_free_waitq, &wait);
+ msleep(10);
+ mutex_lock(&cgroup_mutex);
+ }
+}
+
static struct dentry *cgroup_mount(struct file_system_type *fs_type,
int flags, const char *unused_dev_name,
void *data)
@@ -4387,6 +4414,7 @@ static void css_free_work_fn(struct work_struct *work)
ss->css_free(css);
cgroup_idr_remove(&ss->css_idr, id);
cgroup_put(cgrp);
+ wake_up_all(&ss->pending_css_free_waitq);
} else {
/* cgroup free path */
atomic_dec(&cgrp->root->nr_cgrps);
@@ -4870,6 +4898,62 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
return 0;
};
+/*
+ * cgroup_destroy_recursive - Destroy the cgroup hierarchy
+ *@css: The css we need to wait for to be freed
+ *
+ * Destroy the cgroup hierarchy bottom-up. After destroying
+ * each directory, and wait for css to be freed before
+ * proceeding to destroy its parent.
+ */
+static void cgroup_destroy_recursive(struct cgroup_subsys_state *css)
+{
+ struct cgroup_subsys_state *prev,*par = css,*tmp;
+
+ lockdep_assert_held(&cgroup_mutex);
+
+ if (!css_has_online_children(css))
+ cgroup_destroy_locked(css->cgroup);
+ else {
+ prev = css_next_child(NULL, par);
+ while(prev) {
+ tmp = css_next_child(prev, par);
+ cgroup_destroy_recursive(prev);
+ prev = tmp;
+ }
+
+ cgroup_destroy_locked(css->cgroup);
+ }
+ css_wait_free(css);
+}
+
+/*
+ * cgroup_destroy_children - Destroy all the children of the cgroup
+ * @css: the css which has the cgroup
+ */
+void cgroup_destroy_children(struct cgroup_subsys_state *css)
+{
+ struct cgroup_subsys_state *tmp,*prev, *par;
+
+ lockdep_assert_held(&cgroup_mutex);
+
+ par = css;
+
+ /*
+ * Since we want to give a chance for the css_release
+ * to call the rcu callback, dont hold a rcu lock here.
+ * We destroy the prev and when destroying prev,
+ * make sure the next one is accessible.
+ */
+ prev = css_next_child(NULL, par);
+
+ while(prev) {
+ tmp = css_next_child(prev, par);
+ cgroup_destroy_recursive(prev);
+ prev = tmp;
+ }
+}
+
static int cgroup_rmdir(struct kernfs_node *kn)
{
struct cgroup *cgrp;
@@ -4910,6 +4994,7 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early)
/* We don't handle early failures gracefully */
BUG_ON(IS_ERR(css));
init_and_link_css(css, ss, &cgrp_dfl_root.cgrp);
+ init_waitqueue_head(&ss->pending_css_free_waitq);
/*
* Root csses are never destroyed and we can't initialize
--
1.9.1
Add subsystem APIs css_mount and css_umount which will be called during
cgroup_mount and umount respectively. This will let the subsystem
perform any specific setup during mount/umount.
This will be used in code data prioritization code later.
Signed-off-by: Vikas Shivappa <[email protected]>
---
include/linux/cgroup.h | 2 ++
kernel/cgroup.c | 12 ++++++++++++
2 files changed, 14 insertions(+)
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 292ed97..3ded186 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -655,6 +655,8 @@ struct cgroup_subsys {
struct cgroup_subsys_state *old_css,
struct task_struct *task);
void (*bind)(struct cgroup_subsys_state *root_css);
+ void (*css_mount)(void *mount_info);
+ void (*css_umount)(void);
int disabled;
int early_init;
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 668f614..e139504 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1345,6 +1345,7 @@ struct cgroup_sb_opts {
char *name;
/* User explicitly requested empty subsystem */
bool none;
+ void *mount_info;
};
static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
@@ -1787,6 +1788,11 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
if (ret)
goto out_unlock;
+ for_each_subsys(ss, i) {
+ if ((opts.subsys_mask && (1U << i)) && ss->css_mount)
+ ss->css_mount(opts.mount_info);
+ }
+
/* look for a matching existing root */
if (opts.flags & CGRP_ROOT_SANE_BEHAVIOR) {
cgrp_dfl_root_visible = true;
@@ -1928,7 +1934,13 @@ static void cgroup_kill_sb(struct super_block *sb)
{
struct kernfs_root *kf_root = kernfs_root_from_sb(sb);
struct cgroup_root *root = cgroup_root_from_kf(kf_root);
+ struct cgroup_subsys *ss;
+ int i;
+ for_each_subsys(ss, i) {
+ if ((root->subsys_mask && (1U << i)) && ss->css_umount)
+ ss->css_umount();
+ }
/*
* If @root doesn't have any mounts or children, start killing it.
* This prevents new mounts by disabling percpu_ref_tryget_live().
--
1.9.1
This patch adds enumeration support for code data prioritization(CDP)
feature found in future Intel Xeon processors.
CDP is an extension to Cache Allocation and lets threads allocate subset
of L3 cache for code and data separately. The allocation is represented
by the code or data cache mask MSRs (IA32_L3_QOS_MASK_n). Each Class of
service would be associated with one dcache_mask and one icache_mask
MSR. The association for a CLOSid 'n' is shown below :
data_mask_address (n) = base + (n <<1)
code_mask_address (n) = base + (n <<1) +1.
During scheduling the kernel writes the CLOSid
of the thread to IA32_PQR_ASSOC_MSR.
This patch includes CPUID enumeration routines which includes CPUID
enumeration as well probing MSR_IA32_PQOS_CFG.
Signed-off-by: Vikas Shivappa <[email protected]>
---
arch/x86/include/asm/cpufeature.h | 5 +++-
arch/x86/include/asm/intel_rdt.h | 1 +
arch/x86/include/asm/rdt_common.h | 1 +
arch/x86/kernel/cpu/common.c | 1 +
arch/x86/kernel/cpu/intel_rdt.c | 58 ++++++++++++++++++++++++++-------------
5 files changed, 46 insertions(+), 20 deletions(-)
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index ae5ae9d..c0d435a 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -12,7 +12,7 @@
#include <asm/disabled-features.h>
#endif
-#define NCAPINTS 14 /* N 32-bit words worth of info */
+#define NCAPINTS 15 /* N 32-bit words worth of info */
#define NBUGINTS 1 /* N 32-bit bug flags */
/*
@@ -256,6 +256,9 @@
/* Intel-defined CPU features, CPUID level 0x00000010:0 (ebx), word 13 */
#define X86_FEATURE_CAT_L3 (13*32 + 1) /* Cache Allocation L3 */
+/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x00000010:1 (ecx), word 14 */
+#define X86_FEATURE_CDP_L3 (14*32 + 2) /* Code data prioritization L3 */
+
/*
* BUG word(s)
*/
diff --git a/arch/x86/include/asm/intel_rdt.h b/arch/x86/include/asm/intel_rdt.h
index 78df3d7..68f220e 100644
--- a/arch/x86/include/asm/intel_rdt.h
+++ b/arch/x86/include/asm/intel_rdt.h
@@ -16,6 +16,7 @@ extern void __intel_rdt_sched_in(void);
struct rdt_subsys_info {
unsigned long *closmap;
+ bool cdp_supported;
};
struct intel_rdt {
diff --git a/arch/x86/include/asm/rdt_common.h b/arch/x86/include/asm/rdt_common.h
index 01502c5..8b75128 100644
--- a/arch/x86/include/asm/rdt_common.h
+++ b/arch/x86/include/asm/rdt_common.h
@@ -2,6 +2,7 @@
#define _X86_RDT_H_
#define MSR_IA32_PQR_ASSOC 0x0c8f
+#define MSR_IA32_PQOS_CFG 0x0c81
/**
* struct intel_pqr_state - State cache for the PQR MSR
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index fd014f5..cf5f962 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -682,6 +682,7 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
cpuid_count(0x00000010, 1, &eax, &ebx, &ecx, &edx);
c->x86_cache_max_closid = edx + 1;
c->x86_cache_max_cbm_len = eax + 1;
+ c->x86_capability[14] = ecx;
}
}
diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c
index b2752cc..b8dcb30 100644
--- a/arch/x86/kernel/cpu/intel_rdt.c
+++ b/arch/x86/kernel/cpu/intel_rdt.c
@@ -50,8 +50,30 @@ static cpumask_t rdt_cpumask;
#define rdt_for_each_child(pos_css, parent_ir) \
css_for_each_child((pos_css), &(parent_ir)->css)
+static inline bool msr_probe_rdt(unsigned int msr,u32 l, u32 h)
+{
+ u32 h_old, h_new, h_tmp;
+ u32 l_old, l_new, l_tmp;
+
+ if (rdmsr_safe(msr, &l_old, &h_old))
+ return false;
+
+ l_tmp = l_old ^ l;
+ h_tmp = h_old ^ h;
+ if (wrmsr_safe(msr, l_tmp, h_tmp) ||
+ rdmsr_safe(msr, &l_new, &h_new))
+ return false;
+
+ if ((l_tmp != l_new) || (h_tmp != h_new))
+ return false;
+
+ wrmsr_safe(msr, l_old, h_old);
+
+ return true;
+}
+
/*
- * hsw_probetest() - Have to do probe test for Intel haswell CPUs as it
+ * cache_alloc_hswprobe() - Have to do probe test for Intel haswell CPUs as it
* does not have CPUID enumeration support for Cache allocation.
*
* Probes by writing to the high 32 bits(CLOSid) of the IA32_PQR_MSR and
@@ -59,26 +81,11 @@ static cpumask_t rdt_cpumask;
* bitmask length on hsw. The minimum cache bitmask length allowed for
* HSW is 2 bits.
*/
-static inline bool hsw_probetest(void)
+static inline bool cache_alloc_hswprobe(void)
{
- u32 l, h_old, h_new, h_tmp;
-
- if (rdmsr_safe(MSR_IA32_PQR_ASSOC, &l, &h_old))
+ if (!msr_probe_rdt(MSR_IA32_PQR_ASSOC, 0, 0x1U))
return false;
- /*
- * Default value is always 0 if feature is present.
- */
- h_tmp = h_old ^ 0x1U;
- if (wrmsr_safe(MSR_IA32_PQR_ASSOC, l, h_tmp) ||
- rdmsr_safe(MSR_IA32_PQR_ASSOC, &l, &h_new))
- return false;
-
- if (h_tmp != h_new)
- return false;
-
- wrmsr_safe(MSR_IA32_PQR_ASSOC, l, h_old);
-
boot_cpu_data.x86_cache_max_closid = 4;
boot_cpu_data.x86_cache_max_cbm_len = 20;
min_bitmask_len = 2;
@@ -95,7 +102,16 @@ static inline bool cache_alloc_supported(struct cpuinfo_x86 *c)
* Probe test for Haswell CPUs.
*/
if (c->x86 == 0x6 && c->x86_model == 0x3f)
- return hsw_probetest();
+ return cache_alloc_hswprobe();
+
+ return false;
+}
+
+static inline bool cdp_supported(struct cpuinfo_x86 *c)
+{
+ if (cpu_has(c, X86_FEATURE_CDP_L3) &&
+ msr_probe_rdt(MSR_IA32_PQOS_CFG, 0x1U, 0))
+ return true;
return false;
}
@@ -499,6 +515,10 @@ static int __init intel_rdt_late_init(void)
static_key_slow_inc(&rdt_enable_key);
pr_info("Intel cache allocation enabled\n");
+ if (cdp_supported(c)) {
+ rdtss_info.cdp_supported = true;
+ pr_info("Intel code data prioritization enabled\n");
+ }
out_err:
return err;
--
1.9.1
At any time the intel_rdt cgroup operates in 2 modes (legacy cache
allocation mode/default or code data prioritization mode).
When CDP is enabled the number of available CLOSids is halved and its
doubled when CDP is disabled. When CDP is enabled each CLOSid
maps to a data cache mask and instruction cache mask.
The enabling itself is done by writing to the IA32_PQOS_CFG MSR and can
dynamically be enabled or disabled.
On every mode change all the bit mask MSRs are reset to all 1s or fully
open. This implies that all the tasks also need to be now moved to the
root cgroup since root cgroup represents the cgroup with a mask of all
1s. Thereby we destroy all the child cgroups in the hierarchy.
The enabling and disabling is done during mount/umount and depending on
the mode we switched into , the corresponding files are only displayed
in the cgroup directory. Each cgroup would
expose its dcache(data cache) and icache(instruction cache) mask when
CDP is enabled and expose the cache_mask(common cache mask) when
operating in Cache allocation mode.
---
arch/x86/include/asm/intel_rdt.h | 11 +-
arch/x86/kernel/cpu/intel_rdt.c | 253 ++++++++++++++++++++++++++++++++-------
include/linux/cgroup.h | 1 +
kernel/cgroup.c | 32 ++++-
4 files changed, 247 insertions(+), 50 deletions(-)
diff --git a/arch/x86/include/asm/intel_rdt.h b/arch/x86/include/asm/intel_rdt.h
index 68f220e..55c496a 100644
--- a/arch/x86/include/asm/intel_rdt.h
+++ b/arch/x86/include/asm/intel_rdt.h
@@ -9,6 +9,8 @@
#define MAX_CBM_LENGTH 32
#define IA32_L3_CBM_BASE 0xc90
#define CBM_FROM_INDEX(x) (IA32_L3_CBM_BASE + x)
+#define DCACHE_MASK_INDEX(x) CBM_FROM_INDEX((x << 1))
+#define ICACHE_MASK_INDEX(x) CBM_FROM_INDEX((x << 1) + 1)
DECLARE_PER_CPU(struct intel_pqr_state, pqr_state);
extern struct static_key rdt_enable_key;
@@ -17,6 +19,7 @@ extern void __intel_rdt_sched_in(void);
struct rdt_subsys_info {
unsigned long *closmap;
bool cdp_supported;
+ bool cdp_enable;
};
struct intel_rdt {
@@ -24,11 +27,17 @@ struct intel_rdt {
u32 closid;
};
-struct clos_cbm_map {
+struct cat_clos_mask_map {
unsigned long cache_mask;
unsigned int clos_refcnt;
};
+struct cdp_clos_mask_map {
+ unsigned long icache_mask;
+ unsigned long dcache_mask;
+ unsigned int clos_refcnt;
+};
+
/*
* Return rdt group corresponding to this container.
*/
diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c
index b8dcb30..155ac51 100644
--- a/arch/x86/kernel/cpu/intel_rdt.c
+++ b/arch/x86/kernel/cpu/intel_rdt.c
@@ -29,9 +29,17 @@
#include <asm/intel_rdt.h>
/*
- * ccmap maintains 1:1 mapping between CLOSid and cache bitmask.
+ * cat_cm_map maintains 1:1 mapping between CLOSid and cache bitmask.
+ * Used for cache allocation.
*/
-static struct clos_cbm_map *ccmap;
+static struct cat_clos_mask_map *cat_cm_map;
+
+/*
+ * cdp_cm_map maintains 1:2 mapping between Closid and the icache,dcache mask.
+ */
+static struct cdp_clos_mask_map *cdp_cm_map;
+
+static struct cftype rdt_files[];
static struct rdt_subsys_info rdtss_info;
static DEFINE_MUTEX(rdt_group_mutex);
struct intel_rdt rdt_root_group;
@@ -47,6 +55,11 @@ static unsigned int min_bitmask_len = 1;
*/
static cpumask_t rdt_cpumask;
+struct rdt_remote_data {
+ int msr;
+ u64 val;
+};
+
#define rdt_for_each_child(pos_css, parent_ir) \
css_for_each_child((pos_css), &(parent_ir)->css)
@@ -116,9 +129,168 @@ static inline bool cdp_supported(struct cpuinfo_x86 *c)
return false;
}
+static void cbm_cpu_update(void *info)
+{
+ u32 closid = (u32) info;
+
+ wrmsrl(CBM_FROM_INDEX(closid), cat_cm_map[closid].cache_mask);
+}
+
+static void msr_cpu_update(void *arg)
+{
+ struct rdt_remote_data *info = arg;
+
+ wrmsrl(info->msr, info->val);
+}
+
+/*
+ * msr_update_all() - Update the msr for all packages.
+ */
+static inline void msr_update_all(int msr, u64 val)
+{
+ struct rdt_remote_data info;
+
+ info.msr = msr;
+ info.val = val;
+ on_each_cpu_mask(&rdt_cpumask, msr_cpu_update, &info, 1);
+}
+
+static void closcbm_map_dump(void)
+{
+ u32 i;
+
+ pr_debug("CBMMAP\n");
+ for (i = 0; i < boot_cpu_data.x86_cache_max_closid; i++) {
+ pr_debug("cache_mask: 0x%x,clos_refcnt: %u\n",
+ (unsigned int)cat_cm_map[i].cache_mask, cat_cm_map[i].clos_refcnt);
+ }
+}
+
+static void cdp_cm_map_reset(int maxid, unsigned long max_cbm_mask)
+{
+ size_t sizeb;
+
+ sizeb = (maxid - 1) * sizeof(struct cdp_clos_mask_map);
+ memset(&cdp_cm_map[1], 0, sizeb);
+
+ cdp_cm_map[0].clos_refcnt = 1;
+}
+
+static void cat_cm_map_reset(int maxid, unsigned long max_cbm_mask)
+{
+ size_t sizeb;
+
+ sizeb = (maxid - 1) * sizeof(struct cat_clos_mask_map);
+ memset(&cat_cm_map[1], 0, sizeb);
+
+ cat_cm_map[0].clos_refcnt = 1;
+}
+
+static void cdp_enable(void)
+{
+ int max_cbm_len = boot_cpu_data.x86_cache_max_cbm_len;
+ struct cpuinfo_x86 *c = &boot_cpu_data;
+ unsigned long max_cbm_mask;
+ unsigned int i;
+
+ max_cbm_mask = (1ULL << max_cbm_len) - 1;
+ c->x86_cache_max_closid = c->x86_cache_max_closid >> 1;
+
+ for (i = 0; i < c->x86_cache_max_closid; i++) {
+ msr_update_all(DCACHE_MASK_INDEX(i), max_cbm_mask);
+ msr_update_all(ICACHE_MASK_INDEX(i), max_cbm_mask);
+ }
+ cdp_cm_map_reset(c->x86_cache_max_closid, max_cbm_mask);
+ msr_update_all(MSR_IA32_PQOS_CFG, 0x1U);
+}
+
+static void cdp_disable(void)
+{
+ struct cpuinfo_x86 *c = &boot_cpu_data;
+ int max_cbm_len = boot_cpu_data.x86_cache_max_cbm_len;
+ unsigned int i;
+ unsigned long max_cbm_mask;
+
+ max_cbm_mask = (1ULL << max_cbm_len) - 1;
+ c->x86_cache_max_closid = c->x86_cache_max_closid << 1;
+
+ for (i = 0; i < c->x86_cache_max_closid; i++) {
+ msr_update_all(CBM_FROM_INDEX(i), max_cbm_mask);
+ }
+ cat_cm_map_reset(c->x86_cache_max_closid, max_cbm_mask);
+ msr_update_all(MSR_IA32_PQOS_CFG, 0x0U);
+}
+
+static void cdp_fileinfo_set(bool cdp_enable)
+{
+ unsigned tmp_flags = CFTYPE_ONLY_ON_ROOT | CFTYPE_NOT_ON_ROOT;
+
+ lockdep_assert_held(&rdt_group_mutex);
+
+ if (cdp_enable) {
+ rdt_files[0].flags |= tmp_flags;
+ rdt_files[1].flags &= ~tmp_flags;
+ rdt_files[2].flags &= ~tmp_flags;
+ } else {
+ rdt_files[0].flags &= ~tmp_flags;
+ rdt_files[1].flags |= tmp_flags;
+ rdt_files[2].flags |= tmp_flags;
+ }
+}
+
+static void rdt_css_umount(void)
+{
+ struct cgroup *cgrp = rdt_root_group.css.cgroup;
+
+ if (!rdtss_info.cdp_supported)
+ return;
+
+ if (css_has_online_children(&cgrp->self))
+ cgroup_destroy_children(&rdt_root_group.css);
+
+ return;
+}
+
+static void rdt_css_mount(void* info)
+{
+ bool enable_cdp = (bool) info;
+
+ if (!rdtss_info.cdp_supported || rdtss_info.cdp_enable == enable_cdp)
+ return;
+
+ mutex_lock(&rdt_group_mutex);
+ cdp_fileinfo_set(enable_cdp);
+
+ if (enable_cdp)
+ cdp_enable();
+ else
+ cdp_disable();
+
+ rdtss_info.cdp_enable = enable_cdp;
+ mutex_unlock(&rdt_group_mutex);
+}
+
+static inline void rdt_cdp_init(int cdp_maxid, unsigned long max_cbm_mask)
+{
+ size_t sizeb;
+
+ sizeb = cdp_maxid * sizeof(struct cdp_clos_mask_map);
+ cdp_cm_map = kzalloc(sizeb, GFP_KERNEL);
+ if (!cdp_cm_map) {
+ pr_err("cdp enable failure. No Memory\n");
+ return;
+ }
+
+ cdp_cm_map[0].icache_mask = max_cbm_mask;
+ cdp_cm_map[0].dcache_mask = max_cbm_mask;
+ cdp_cm_map[0].clos_refcnt = 1;
+
+ rdtss_info.cdp_supported = true;
+}
+
static inline void closid_get(u32 closid)
{
- struct clos_cbm_map *ccm = &ccmap[closid];
+ struct cat_clos_mask_map *ccm = &cat_cm_map[closid];
lockdep_assert_held(&rdt_group_mutex);
@@ -147,12 +319,12 @@ static int closid_alloc(struct intel_rdt *ir)
static inline void closid_free(u32 closid)
{
clear_bit(closid, rdtss_info.closmap);
- ccmap[closid].cache_mask = 0;
+ cat_cm_map[closid].cache_mask = 0;
}
static inline void closid_put(u32 closid)
{
- struct clos_cbm_map *ccm = &ccmap[closid];
+ struct cat_clos_mask_map *ccm = &cat_cm_map[closid];
lockdep_assert_held(&rdt_group_mutex);
if (WARN_ON(!ccm->clos_refcnt))
@@ -216,7 +388,7 @@ static int intel_cache_alloc_cbm_read(struct seq_file *m, void *v)
{
struct intel_rdt *ir = css_rdt(seq_css(m));
- seq_printf(m, "%08lx\n", ccmap[ir->closid].cache_mask);
+ seq_printf(m, "%08lx\n", cat_cm_map[ir->closid].cache_mask);
return 0;
}
@@ -253,7 +425,7 @@ static int cbm_validate(struct intel_rdt *ir, unsigned long cbmvalue)
}
par = parent_rdt(ir);
- cbm_tmp = &ccmap[par->closid].cache_mask;
+ cbm_tmp = &cat_cm_map[par->closid].cache_mask;
if (!bitmap_subset(&cbmvalue, cbm_tmp, MAX_CBM_LENGTH)) {
err = -EINVAL;
goto out_err;
@@ -262,7 +434,7 @@ static int cbm_validate(struct intel_rdt *ir, unsigned long cbmvalue)
rcu_read_lock();
rdt_for_each_child(css, ir) {
c = css_rdt(css);
- cbm_tmp = &ccmap[c->closid].cache_mask;
+ cbm_tmp = &cat_cm_map[c->closid].cache_mask;
if (!bitmap_subset(cbm_tmp, &cbmvalue, MAX_CBM_LENGTH)) {
rcu_read_unlock();
pr_err("Children's mask not a subset\n");
@@ -282,7 +454,7 @@ static bool cbm_search(unsigned long cbm, u32 *closid)
u32 i;
for (i = 0; i < maxid; i++) {
- if (bitmap_equal(&cbm, &ccmap[i].cache_mask, MAX_CBM_LENGTH)) {
+ if (bitmap_equal(&cbm, &cat_cm_map[i].cache_mask, MAX_CBM_LENGTH)) {
*closid = i;
return true;
}
@@ -291,36 +463,10 @@ static bool cbm_search(unsigned long cbm, u32 *closid)
return false;
}
-static void closcbm_map_dump(void)
-{
- u32 i;
-
- pr_debug("CBMMAP\n");
- for (i = 0; i < boot_cpu_data.x86_cache_max_closid; i++) {
- pr_debug("cache_mask: 0x%x,clos_refcnt: %u\n",
- (unsigned int)ccmap[i].cache_mask, ccmap[i].clos_refcnt);
- }
-}
-
-static void cbm_cpu_update(void *info)
-{
- u32 closid = (u32) info;
-
- wrmsrl(CBM_FROM_INDEX(closid), ccmap[closid].cache_mask);
-}
-
-/*
- * cbm_update_all() - Update the cache bit mask for all packages.
- */
-static inline void cbm_update_all(u32 closid)
-{
- on_each_cpu_mask(&rdt_cpumask, cbm_cpu_update, (void *)closid, 1);
-}
-
/*
* intel_cache_alloc_cbm_write() - Validates and writes the
* cache bit mask(cbm) to the IA32_L3_MASK_n
- * and also store the same in the ccmap.
+ * and also store the same in the cat_cm_map.
*
* CLOSids are reused for cgroups which have same bitmask.
* This helps to use the scant CLOSids optimally. This also
@@ -350,7 +496,7 @@ static int intel_cache_alloc_cbm_write(struct cgroup_subsys_state *css,
goto out;
}
- if (cbmvalue == ccmap[ir->closid].cache_mask)
+ if (cbmvalue == cat_cm_map[ir->closid].cache_mask)
goto out;
err = cbm_validate(ir, cbmvalue);
@@ -376,8 +522,8 @@ static int intel_cache_alloc_cbm_write(struct cgroup_subsys_state *css,
goto out;
}
- ccmap[ir->closid].cache_mask = cbmvalue;
- cbm_update_all(ir->closid);
+ cat_cm_map[ir->closid].cache_mask = cbmvalue;
+ msr_update_all(CBM_FROM_INDEX(ir->closid), cbmvalue);
}
closcbm_map_dump();
out:
@@ -415,7 +561,7 @@ static inline void cbm_update_msrs(void)
* whose cache mask is all 1s always.
*/
for (i = 1; i < maxid; i++) {
- if (ccmap[i].clos_refcnt)
+ if (cat_cm_map[i].clos_refcnt)
cbm_cpu_update((void *)i);
}
}
@@ -469,7 +615,7 @@ static int intel_rdt_cpu_notifier(struct notifier_block *nb,
static int __init intel_rdt_late_init(void)
{
struct cpuinfo_x86 *c = &boot_cpu_data;
- static struct clos_cbm_map *ccm;
+ static struct cat_clos_mask_map *ccm;
u32 maxid, max_cbm_len;
int err = 0, i;
size_t sizeb;
@@ -488,9 +634,9 @@ static int __init intel_rdt_late_init(void)
goto out_err;
}
- sizeb = maxid * sizeof(struct clos_cbm_map);
- ccmap = kzalloc(sizeb, GFP_KERNEL);
- if (!ccmap) {
+ sizeb = maxid * sizeof(struct cat_clos_mask_map);
+ cat_cm_map = kzalloc(sizeb, GFP_KERNEL);
+ if (!cat_cm_map) {
kfree(rdtss_info.closmap);
err = -ENOMEM;
goto out_err;
@@ -498,7 +644,7 @@ static int __init intel_rdt_late_init(void)
set_bit(0, rdtss_info.closmap);
rdt_root_group.closid = 0;
- ccm = &ccmap[0];
+ ccm = &cat_cm_map[0];
ccm->cache_mask = (1ULL << max_cbm_len) - 1;
ccm->clos_refcnt = 1;
@@ -515,8 +661,13 @@ static int __init intel_rdt_late_init(void)
static_key_slow_inc(&rdt_enable_key);
pr_info("Intel cache allocation enabled\n");
+
+ /*
+ * Test for Code data prioritization support.
+ * Failure is not fatal as CAT can still work.
+ */
if (cdp_supported(c)) {
- rdtss_info.cdp_supported = true;
+ rdt_cdp_init(maxid / 2, cat_cm_map[0].cache_mask);
pr_info("Intel code data prioritization enabled\n");
}
out_err:
@@ -533,12 +684,22 @@ static struct cftype rdt_files[] = {
.write_u64 = intel_cache_alloc_cbm_write,
.mode = 0666,
},
+ {
+ .name = "icache_mask",
+ .flags = CFTYPE_ONLY_ON_ROOT | CFTYPE_NOT_ON_ROOT,
+ },
+ {
+ .name = "dcache_mask",
+ .flags = CFTYPE_ONLY_ON_ROOT | CFTYPE_NOT_ON_ROOT,
+ },
{ } /* terminate */
};
struct cgroup_subsys intel_rdt_cgrp_subsys = {
.css_alloc = intel_rdt_css_alloc,
.css_free = intel_rdt_css_free,
+ .css_mount = rdt_css_mount,
+ .css_umount = rdt_css_umount,
.legacy_cftypes = rdt_files,
.early_init = 0,
};
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 3ded186..48f106c 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -195,6 +195,7 @@ enum {
* specified at mount time and thus is implemented here.
*/
CGRP_CPUSET_CLONE_CHILDREN,
+ CGRP_RDT_DESTROY_CHILDREN,
};
struct cgroup {
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index e139504..38b4de5 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1346,6 +1346,8 @@ struct cgroup_sb_opts {
/* User explicitly requested empty subsystem */
bool none;
void *mount_info;
+ bool rdt_cdp_enable;
+ bool rdt_mount;
};
static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
@@ -1392,6 +1394,13 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
opts->cpuset_clone_children = true;
continue;
}
+ if (!strcmp(token, "cdp_enable")) {
+ opts->rdt_cdp_enable = true;
+ continue;
+ }
+ if (!strcmp(token, "intel_rdt")) {
+ opts->rdt_mount = true;
+ }
if (!strcmp(token, "xattr")) {
opts->flags |= CGRP_ROOT_XATTR;
continue;
@@ -1640,6 +1649,8 @@ static void init_cgroup_root(struct cgroup_root *root,
strcpy(root->name, opts->name);
if (opts->cpuset_clone_children)
set_bit(CGRP_CPUSET_CLONE_CHILDREN, &root->cgrp.flags);
+ if (opts->rdt_mount)
+ set_bit(CGRP_RDT_DESTROY_CHILDREN, &root->cgrp.flags);
}
static int cgroup_setup_root(struct cgroup_root *root, unsigned int ss_mask)
@@ -1789,8 +1800,11 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
goto out_unlock;
for_each_subsys(ss, i) {
- if ((opts.subsys_mask && (1U << i)) && ss->css_mount)
+ if ((opts.subsys_mask && (1U << i)) && ss->css_mount) {
+ if (opts.rdt_mount)
+ opts.mount_info = (void *)opts.rdt_cdp_enable;
ss->css_mount(opts.mount_info);
+ }
}
/* look for a matching existing root */
@@ -1934,12 +1948,24 @@ static void cgroup_kill_sb(struct super_block *sb)
{
struct kernfs_root *kf_root = kernfs_root_from_sb(sb);
struct cgroup_root *root = cgroup_root_from_kf(kf_root);
+ bool root_has_no_children = false;
+ struct cgroup *cgrp = &root->cgrp;
struct cgroup_subsys *ss;
int i;
+ root_has_no_children = list_empty(&root->cgrp.self.children);
+
+ /*
+ * Call the subsystem specific umount API.
+ */
for_each_subsys(ss, i) {
- if ((root->subsys_mask && (1U << i)) && ss->css_umount)
+ if ((root->subsys_mask && (1U << i)) && ss->css_umount) {
+ mutex_lock(&cgroup_mutex);
ss->css_umount();
+ if (!css_has_online_children(&cgrp->self))
+ root_has_no_children = true;
+ mutex_unlock(&cgroup_mutex);
+ }
}
/*
* If @root doesn't have any mounts or children, start killing it.
@@ -1948,7 +1974,7 @@ static void cgroup_kill_sb(struct super_block *sb)
*
* And don't kill the default root.
*/
- if (!list_empty(&root->cgrp.self.children) ||
+ if (!root_has_no_children ||
root == &cgrp_dfl_root)
cgroup_put(&root->cgrp);
else
--
1.9.1
Add support to manage CLOSid(class of service id) for code data
prioritization(CDP). Includes allocating, freeing closid and closid_get
and closid_put.
During mount if the mode is changed between cdp and cache allocation
only, all the CLOSids are freed. When a new cgroup is created it
inherits its parents CLOSid in CDP just like in Cache allocation.
---
arch/x86/kernel/cpu/intel_rdt.c | 127 +++++++++++++++++++++++++---------------
1 file changed, 81 insertions(+), 46 deletions(-)
diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c
index 155ac51..285db1e 100644
--- a/arch/x86/kernel/cpu/intel_rdt.c
+++ b/arch/x86/kernel/cpu/intel_rdt.c
@@ -166,6 +166,85 @@ static void closcbm_map_dump(void)
}
}
+static void closid_map_init(void)
+{
+ u32 maxid = boot_cpu_data.x86_cache_max_closid;
+
+ bitmap_zero(rdtss_info.closmap, maxid);
+}
+
+static inline void closid_get(u32 closid)
+{
+ lockdep_assert_held(&rdt_group_mutex);
+
+ if (!rdtss_info.cdp_enable)
+ cat_cm_map[closid].clos_refcnt++;
+ else
+ cdp_cm_map[closid].clos_refcnt++;
+}
+
+static int closid_alloc(struct intel_rdt *ir)
+{
+ u32 maxid;
+ u32 id;
+
+ lockdep_assert_held(&rdt_group_mutex);
+
+ maxid = boot_cpu_data.x86_cache_max_closid;
+ id = find_next_zero_bit(rdtss_info.closmap, maxid, 0);
+ if (id == maxid)
+ return -ENOSPC;
+
+ set_bit(id, rdtss_info.closmap);
+ closid_get(id);
+ ir->closid = id;
+
+ return 0;
+}
+
+static inline void closid_free(u32 closid)
+{
+ clear_bit(closid, rdtss_info.closmap);
+ if (!rdtss_info.cdp_enable) {
+ cat_cm_map[closid].cache_mask = 0;
+ } else {
+ cdp_cm_map[closid].dcache_mask = 0;
+ cdp_cm_map[closid].icache_mask = 0;
+ }
+}
+
+static inline void closid_cat_put(u32 closid)
+{
+ struct cat_clos_mask_map *ccm = &cat_cm_map[closid];
+
+ lockdep_assert_held(&rdt_group_mutex);
+ if (WARN_ON(!ccm->clos_refcnt))
+ return;
+
+ if (!--ccm->clos_refcnt)
+ closid_free(closid);
+}
+
+static inline void closid_cdp_put(u32 closid)
+{
+ struct cdp_clos_mask_map *ccm = &cdp_cm_map[closid];
+
+ lockdep_assert_held(&rdt_group_mutex);
+ if (WARN_ON(!ccm->clos_refcnt))
+ return;
+
+ if (!--ccm->clos_refcnt)
+ closid_free(closid);
+}
+
+static inline void closid_put(u32 closid)
+{
+ if (!rdtss_info.cdp_enable)
+ closid_cat_put(closid);
+ else
+ closid_cdp_put(closid);
+}
+
static void cdp_cm_map_reset(int maxid, unsigned long max_cbm_mask)
{
size_t sizeb;
@@ -266,6 +345,8 @@ static void rdt_css_mount(void* info)
else
cdp_disable();
+ closid_map_init();
+
rdtss_info.cdp_enable = enable_cdp;
mutex_unlock(&rdt_group_mutex);
}
@@ -288,52 +369,6 @@ static inline void rdt_cdp_init(int cdp_maxid, unsigned long max_cbm_mask)
rdtss_info.cdp_supported = true;
}
-static inline void closid_get(u32 closid)
-{
- struct cat_clos_mask_map *ccm = &cat_cm_map[closid];
-
- lockdep_assert_held(&rdt_group_mutex);
-
- ccm->clos_refcnt++;
-}
-
-static int closid_alloc(struct intel_rdt *ir)
-{
- u32 maxid;
- u32 id;
-
- lockdep_assert_held(&rdt_group_mutex);
-
- maxid = boot_cpu_data.x86_cache_max_closid;
- id = find_next_zero_bit(rdtss_info.closmap, maxid, 0);
- if (id == maxid)
- return -ENOSPC;
-
- set_bit(id, rdtss_info.closmap);
- closid_get(id);
- ir->closid = id;
-
- return 0;
-}
-
-static inline void closid_free(u32 closid)
-{
- clear_bit(closid, rdtss_info.closmap);
- cat_cm_map[closid].cache_mask = 0;
-}
-
-static inline void closid_put(u32 closid)
-{
- struct cat_clos_mask_map *ccm = &cat_cm_map[closid];
-
- lockdep_assert_held(&rdt_group_mutex);
- if (WARN_ON(!ccm->clos_refcnt))
- return;
-
- if (!--ccm->clos_refcnt)
- closid_free(closid);
-}
-
void __intel_rdt_sched_in(void)
{
struct intel_pqr_state *state = this_cpu_ptr(&pqr_state);
--
1.9.1
Add support to read and write the per cgroup data and instruction cache
masks.
- When a new cgroup directory is created it inherits the parents dcache
and icache mask. So a mkdir never fails.
- When user changes the mask, we look to see if we can reuse an
existing CLOSid or else allocate a new one. When we run of CLOSids , we
simply return -ENOSPC.
---
arch/x86/kernel/cpu/intel_rdt.c | 177 ++++++++++++++++++++++++++++++++++++----
1 file changed, 163 insertions(+), 14 deletions(-)
diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c
index 285db1e..d0eaf04 100644
--- a/arch/x86/kernel/cpu/intel_rdt.c
+++ b/arch/x86/kernel/cpu/intel_rdt.c
@@ -428,6 +428,22 @@ static int intel_cache_alloc_cbm_read(struct seq_file *m, void *v)
return 0;
}
+static int cdp_dcache_read(struct seq_file *m, void *v)
+{
+ struct intel_rdt *ir = css_rdt(seq_css(m));
+
+ seq_printf(m, "%08lx\n", cdp_cm_map[ir->closid].dcache_mask);
+ return 0;
+}
+
+static int cdp_icache_read(struct seq_file *m, void *v)
+{
+ struct intel_rdt *ir = css_rdt(seq_css(m));
+
+ seq_printf(m, "%08lx\n", cdp_cm_map[ir->closid].icache_mask);
+ return 0;
+}
+
static inline bool cbm_is_contiguous(unsigned long var)
{
unsigned long maxcbm = MAX_CBM_LENGTH;
@@ -445,13 +461,24 @@ static inline bool cbm_is_contiguous(unsigned long var)
return true;
}
-static int cbm_validate(struct intel_rdt *ir, unsigned long cbmvalue)
+static int cache_mask_validate(struct intel_rdt *ir, unsigned long cbmvalue)
{
+ u32 max_cbm = boot_cpu_data.x86_cache_max_cbm_len;
struct cgroup_subsys_state *css;
struct intel_rdt *par, *c;
unsigned long *cbm_tmp;
+ u64 max_mask;
int err = 0;
+ if (ir == &rdt_root_group)
+ return -EPERM;
+
+ max_mask = (1ULL << max_cbm) - 1;
+ if (cbmvalue & ~max_mask) {
+ err = -EINVAL;
+ goto out_err;
+ }
+
if (!cbm_is_contiguous(cbmvalue)) {
pr_err("bitmask should have >=%d bits and be contiguous\n",
min_bitmask_len);
@@ -486,10 +513,12 @@ out_err:
static bool cbm_search(unsigned long cbm, u32 *closid)
{
u32 maxid = boot_cpu_data.x86_cache_max_closid;
+ unsigned long cache_mask;
u32 i;
for (i = 0; i < maxid; i++) {
- if (bitmap_equal(&cbm, &cat_cm_map[i].cache_mask, MAX_CBM_LENGTH)) {
+ cache_mask = cat_cm_map[i].cache_mask;
+ if (bitmap_equal(&cbm, &cache_mask, MAX_CBM_LENGTH)) {
*closid = i;
return true;
}
@@ -511,30 +540,19 @@ static bool cbm_search(unsigned long cbm, u32 *closid)
static int intel_cache_alloc_cbm_write(struct cgroup_subsys_state *css,
struct cftype *cft, u64 cbmvalue)
{
- u32 max_cbm = boot_cpu_data.x86_cache_max_cbm_len;
struct intel_rdt *ir = css_rdt(css);
ssize_t err = 0;
- u64 max_mask;
u32 closid;
- if (ir == &rdt_root_group)
- return -EPERM;
-
/*
* Need global mutex as cbm write may allocate a closid.
*/
mutex_lock(&rdt_group_mutex);
- max_mask = (1ULL << max_cbm) - 1;
- if (cbmvalue & ~max_mask) {
- err = -EINVAL;
- goto out;
- }
-
if (cbmvalue == cat_cm_map[ir->closid].cache_mask)
goto out;
- err = cbm_validate(ir, cbmvalue);
+ err = cache_mask_validate(ir, cbmvalue);
if (err)
goto out;
@@ -567,6 +585,133 @@ out:
return err;
}
+static void cdp_clos_map_dump(void)
+{
+ u32 i;
+
+ pr_debug("CBMMAP\n");
+ for (i = 0; i < boot_cpu_data.x86_cache_max_closid; i++) {
+ pr_debug("dcache_mask: 0x%x, icache_mask=0x%x,clos_refcnt:%u\n",
+ (unsigned int)cdp_cm_map[i].dcache_mask,
+ (unsigned int)cdp_cm_map[i].icache_mask,
+ cdp_cm_map[i].clos_refcnt);
+ }
+}
+
+static bool cdp_mask_search(unsigned long dcache_mask,
+ unsigned long icache_mask, u32 *closid)
+{
+ u32 maxid = boot_cpu_data.x86_cache_max_closid;
+ unsigned long dcm, icm;
+ u32 i;
+
+ for (i = 0; i < maxid; i++) {
+ dcm = cdp_cm_map[i].dcache_mask;
+ icm = cdp_cm_map[i].icache_mask;
+ if (bitmap_equal(&dcache_mask, &dcm, MAX_CBM_LENGTH)
+ && bitmap_equal(&icache_mask, &icm, MAX_CBM_LENGTH)) {
+ *closid = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int cdp_mask_write(struct intel_rdt *ir, u64 dcache_mask,
+ u64 icache_mask)
+{
+ int err = 0;
+ u32 closid;
+
+ /*
+ * Try to get a reference for a different CLOSid and release the
+ * reference to the current CLOSid.
+ * Need to put down the reference here and get it back in case we
+ * run out of closids. Otherwise we run into a problem when
+ * we could be using the last closid that could have been available.
+ */
+ closid_put(ir->closid);
+ if (cdp_mask_search(dcache_mask, icache_mask, &closid)) {
+ ir->closid = closid;
+ closid_get(closid);
+ } else {
+ err = closid_alloc(ir);
+ if (err) {
+ closid_get(ir->closid);
+ goto out;
+ }
+ closid = ir->closid;
+ cdp_cm_map[closid].dcache_mask = dcache_mask;
+ cdp_cm_map[closid].icache_mask = icache_mask;
+ msr_update_all(DCACHE_MASK_INDEX(closid), dcache_mask);
+ msr_update_all(ICACHE_MASK_INDEX(closid), icache_mask);
+ }
+out:
+
+ return err;
+}
+
+static int cdp_dcache_write(struct cgroup_subsys_state *css,
+ struct cftype *cft, u64 new_dcache_mask)
+{
+ unsigned long curr_icache_mask, curr_dcache_mask;
+ struct intel_rdt *ir = css_rdt(css);
+ int err = 0;
+
+ /*
+ * Need global mutex as cache mask write may allocate a closid.
+ */
+ mutex_lock(&rdt_group_mutex);
+
+ curr_dcache_mask = cdp_cm_map[ir->closid].dcache_mask;
+ curr_icache_mask = cdp_cm_map[ir->closid].icache_mask;
+
+ if (new_dcache_mask == curr_dcache_mask)
+ goto out;
+
+ err = cache_mask_validate(ir, new_dcache_mask);
+ if (err)
+ goto out;
+
+ err = cdp_mask_write(ir, new_dcache_mask, curr_icache_mask);
+ cdp_clos_map_dump();
+out:
+ mutex_unlock(&rdt_group_mutex);
+
+ return err;
+}
+
+static int cdp_icache_write(struct cgroup_subsys_state *css,
+ struct cftype *cft, u64 new_icache_mask)
+{
+ unsigned long curr_icache_mask, curr_dcache_mask;
+ struct intel_rdt *ir = css_rdt(css);
+ int err = 0;
+
+ /*
+ * Need global mutex as cache mask write may allocate a closid.
+ */
+ mutex_lock(&rdt_group_mutex);
+
+ curr_dcache_mask = cdp_cm_map[ir->closid].dcache_mask;
+ curr_icache_mask = cdp_cm_map[ir->closid].icache_mask;
+
+ if (new_icache_mask == curr_icache_mask)
+ goto out;
+
+ err = cache_mask_validate(ir, new_icache_mask);
+ if (err)
+ goto out;
+
+ err = cdp_mask_write(ir, curr_dcache_mask, new_icache_mask);
+ cdp_clos_map_dump();
+out:
+ mutex_unlock(&rdt_group_mutex);
+
+ return err;
+}
+
static inline bool rdt_cpumask_update(int cpu)
{
static cpumask_t tmp;
@@ -722,10 +867,14 @@ static struct cftype rdt_files[] = {
{
.name = "icache_mask",
.flags = CFTYPE_ONLY_ON_ROOT | CFTYPE_NOT_ON_ROOT,
+ .seq_show = cdp_icache_read,
+ .write_u64 = cdp_icache_write,
},
{
.name = "dcache_mask",
.flags = CFTYPE_ONLY_ON_ROOT | CFTYPE_NOT_ON_ROOT,
+ .seq_show = cdp_dcache_read,
+ .write_u64 = cdp_dcache_write,
},
{ } /* terminate */
};
--
1.9.1