From 6dde5e69c77d9e834fdb207f037cee1f1ce39782 Mon Sep 17 00:00:00 2001
From: Xie XiuQi <xiexiuqi@huawei.com>
Date: Tue, 29 Jan 2019 17:38:15 +0800
Subject: [PATCH 2810/2944] openEuler: arm64/mpam: use
 mpam_{read/write}_sysreg_s for debug

commit 19cab98fba25040817f1a6b9b6b70c6b458a169a openEuler-1.0

hulk inclusion
category: feature
bugzilla: 5510
CVE: NA

Signed-off-by: Xie XiuQi <xiexiuqi@huawei.com>
Reviewed-by: Hanjun Guo <guohanjun@huawei.com>
Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
Signed-off-by: Xin Hao <haoxing990@gmail.com>
Reviewed-by: Baolin Wang <baolin.wang@openanolis.org>
---
 arch/arm64/include/asm/mpam.h          | 100 +++++++++--
 arch/arm64/include/asm/mpam_resource.h |  82 +++++++++
 arch/arm64/include/asm/mpam_sched.h    |  12 +-
 arch/arm64/kernel/Makefile             |   1 +
 arch/arm64/kernel/mpam.c               | 309 ++++++++++++++++++++++++++++-----
 arch/arm64/kernel/mpam_ctrlmon.c       | 171 +++++++++++++++++-
 arch/arm64/kernel/mpam_resource.c      |  14 ++
 fs/resctrlfs.c                         |   4 +-
 8 files changed, 619 insertions(+), 74 deletions(-)
 create mode 100644 arch/arm64/include/asm/mpam_resource.h
 create mode 100644 arch/arm64/kernel/mpam_resource.c

diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
index 6f051f3..61bca63 100644
--- a/arch/arm64/include/asm/mpam.h
+++ b/arch/arm64/include/asm/mpam.h
@@ -165,11 +165,15 @@ struct rdt_domain {
 	struct list_head	list;
 	int			id;
 	struct cpumask		cpu_mask;
+	void __iomem		*base;
 
 	/* arch specific fields */
 	u32			*ctrl_val;
 	u32			new_ctrl;
 	bool			have_new_ctrl;
+
+	/* for debug */
+	char			*cpus_list;
 };
 
 extern struct mutex resctrl_group_mutex;
@@ -179,12 +183,9 @@ struct rdt_domain {
 int __init resctrl_group_init(void);
 
 enum {
-	MPAM_RESOURCE_L3,
-	MPAM_RESOURCE_L3DATA,
-	MPAM_RESOURCE_L3CODE,
-	MPAM_RESOURCE_L2,
-	MPAM_RESOURCE_L2DATA,
-	MPAM_RESOURCE_L2CODE,
+	MPAM_RESOURCE_SMMU,
+	MPAM_RESOURCE_CACHE,
+	MPAM_RESOURCE_MC,
 
 	/* Must be the last */
 	MPAM_NUM_RESOURCES,
@@ -213,8 +214,6 @@ void mkdir_mondata_subdir_allrdtgrp(struct resctrl_resource *r,
 
 static inline int __resctrl_group_show_options(struct seq_file *seq)
 {
-	if (resctrl_resources_all[MPAM_RESOURCE_L3DATA].alloc_enabled)
-		seq_puts(seq, ",cdp");
 	return 0;
 }
 
@@ -222,24 +221,89 @@ static inline int __resctrl_group_show_options(struct seq_file *seq)
 
 #define MPAM_SYS_REG_DEBUG
 
-static inline u32 mpam_read_sysreg_s(void *reg, char *name)
-{
 #ifdef MPAM_SYS_REG_DEBUG
-       pr_info("read_sysreg_s: %s (addr %p)\n", name, reg);
-       return 0;
+static inline u64 mpam_read_sysreg_s(u64 reg, char *name)
+{
+	pr_info("cpu %2d: read_sysreg_s: %s (addr %016llx)\n", smp_processor_id(), name, reg);
+	return 0;
+}
 #else
-       return read_sysreg_s(reg);
+#define mpam_read_sysreg_s(reg, name) read_sysreg_s(reg)
 #endif
-}
 
-static inline u32 mpam_write_sysreg_s(u32 v, void *reg, char *name)
+#ifdef MPAM_SYS_REG_DEBUG
+static inline u64 mpam_write_sysreg_s(u64 v, u64 reg, char *name)
 {
+	pr_info("cpu %2d: write_sysreg_s: %s (addr %016llx), value %016llx\n", smp_processor_id(), name, reg, v);
+	return 0;
+}
+#else
+#define mpam_write_sysreg_s(v, r, n) write_sysreg_s(v, r)
+#endif
+
 #ifdef MPAM_SYS_REG_DEBUG
-       pr_info("write_sysreg_s: %s (addr %p), value %x\n", name, reg, v);
-       return 0;
+static inline u32 mpam_readl(const volatile void __iomem *addr)
+{
+	return pr_info("readl: %p\n", addr);
+}
 #else
-       return write_sysreg_s(v, reg);
+#define mpam_readl(addr) readl(addr)
 #endif
+
+#ifdef MPAM_SYS_REG_DEBUG
+static inline u32 mpam_writel(u64 v, const volatile void __iomem *addr)
+{
+	return pr_info("writel: %016llx to %p\n", v, addr);
 }
+#else
+#define mpam_writel(v, addr) writel(v, addr)
+#endif
+
+/**
+ * struct msr_param - set a range of MSRs from a domain
+ * @res:	The resource to use
+ * @value:	value
+ */
+struct msr_param {
+	struct resctrl_resource	*res;
+	u64			value;
+};
+
+/**
+ * struct resctrl_resource - attributes of an RDT resource
+ * @rid:		The index of the resource
+ * @alloc_enabled:	Is allocation enabled on this machine
+ * @mon_enabled:		Is monitoring enabled for this feature
+ * @alloc_capable:	Is allocation available on this machine
+ * @mon_capable:		Is monitor feature available on this machine
+ * @name:		Name to use in "schemata" file
+ * @num_closid:		Number of CLOSIDs available
+ * @cache_level:	Which cache level defines scope of this resource
+ * @default_ctrl:	Specifies default cache cbm or memory B/W percent.
+ * @msr_base:		Base MSR address for CBMs
+ * @msr_update:		Function pointer to update QOS MSRs
+ * @data_width:		Character width of data when displaying
+ * @domains:		All domains for this resource
+ * @cache:		Cache allocation related data
+ * @format_str:		Per resource format string to show domain value
+ * @parse_ctrlval:	Per resource function pointer to parse control values
+ * @evt_list:			List of monitoring events
+ * @num_rmid:			Number of RMIDs available
+ * @mon_scale:			cqm counter * mon_scale = occupancy in bytes
+ * @fflags:			flags to choose base and info files
+ */
+
+struct raw_resctrl_resource {
+	int			num_partid;
+	u32			default_ctrl;
+	void (*msr_update)	(struct rdt_domain *d, int partid);
+	int			data_width;
+	const char		*format_str;
+	int (*parse_ctrlval)	(char *buf, struct raw_resctrl_resource *r,
+				 struct rdt_domain *d);
+	int			num_pmg;
+};
+
+int parse_cbm(char *buf, struct raw_resctrl_resource *r, struct rdt_domain *d);
 
 #endif /* _ASM_ARM64_MPAM_H */
diff --git a/arch/arm64/include/asm/mpam_resource.h b/arch/arm64/include/asm/mpam_resource.h
new file mode 100644
index 0000000..4ec2d860
--- /dev/null
+++ b/arch/arm64/include/asm/mpam_resource.h
@@ -0,0 +1,82 @@
+/* mpam resource: like L3, memory */
+
+#ifndef _ASM_ARM64_MPAM_RESOURCE_H
+#define _ASM_ARM64_MPAM_RESOURCE_H
+
+#include <linux/bitops.h>
+
+#define MPAMF_IDR		0x0000
+#define MPAMF_SIDR		0x0008
+#define MPAMF_MSMON_IDR		0x0080
+#define MPAMF_IMPL_IDR		0x0028
+#define MPAMF_CPOR_IDR		0x0030
+#define MPAMF_CCAP_IDR		0x0038
+#define MPAMF_MBW_IDR		0x0040
+#define MPAMF_PRI_IDR		0x0048
+#define MPAMF_CSUMON_IDR	0x0088
+#define MPAMF_MBWUMON_IDR	0x0090
+#define MPAMF_PARTID_NRW_IDR	0x0050
+#define MPAMF_IIDR		0x0018
+#define MPAMF_AIDR		0x0020
+#define MPAMCFG_PART_SEL	0x0100
+#define MPAMCFG_CPBM		0x1000
+#define MPAMCFG_CMAX		0x0108
+#define MPAMCFG_MBW_MIN		0x0200
+#define MPAMCFG_MBW_MAX		0x0208
+#define MPAMCFG_MBW_WINWD	0x0220
+#define MPAMCFG_MBW_PBM		0x2000
+#define MPAMCFG_PRI		0x0400
+#define MPAMCFG_MBW_PROP	0x0500
+#define MPAMCFG_INTPARTID	0x0600
+#define MSMON_CFG_MON_SEL	0x0800
+#define MSMON_CFG_CSU_FLT	0x0810
+#define MSMON_CFG_CSU_CTL	0x0818
+#define MSMON_CFG_MBWU_FLT	0x0820
+#define MSMON_CFG_MBWU_CTL	0x0828
+#define MSMON_CSU		0x0840
+#define MSMON_CSU_CAPTURE	0x0848
+#define MSMON_MBWU		0x0860
+#define MSMON_MBWU_CAPTURE	0x0868
+#define MSMON_CAPT_EVNT		0x0808
+#define MPAMF_ESR		0x00F8
+#define MPAMF_ECR		0x00F0
+
+#define HAS_CCAP_PART		BIT(24)
+#define HAS_CPOR_PART		BIT(25)
+#define HAS_MBW_PART		BIT(26)
+#define HAS_PRI_PART		BIT(27)
+#define HAS_IMPL_IDR		BIT(29)
+#define HAS_MSMON		BIT(30)
+
+/* MPAMF_IDR */
+/* TODO */
+
+#define CPBM_WD_MASK		0xFFFF
+#define CPBM_MASK		0x7FFF
+
+#define BWA_WD			6		/* hard code for P680 */
+#define MBW_MAX_MASK		0xFC00
+#define MBW_MAX_HARDLIM		BIT(31)
+#define MBW_MAX_SET(v)		(MBW_MAX_HARDLIM|((v) << (15 - BWA_WD)))	/* [FIXME] hard code for hardlim */
+
+/*
+ * emulate the mpam nodes
+ * These should be reported by ACPI MPAM Table.
+ */
+
+struct mpam_node {
+	/* MPAM node header */
+	u8              type;   /* MPAM_SMMU, MPAM_CACHE, MPAM_MC */
+	u64             addr;
+	void __iomem	*base;
+	struct cpumask  cpu_mask;
+	u64		default_ctrl;
+
+	/* for debug */
+	char            *cpus_list;
+	char		*name;
+};
+
+int mpam_nodes_init(void);
+
+#endif /* _ASM_ARM64_MPAM_RESOURCE_H */
diff --git a/arch/arm64/include/asm/mpam_sched.h b/arch/arm64/include/asm/mpam_sched.h
index 586b02b..53c3f29 100644
--- a/arch/arm64/include/asm/mpam_sched.h
+++ b/arch/arm64/include/asm/mpam_sched.h
@@ -72,22 +72,22 @@ static void __mpam_sched_in(void)
 		state->cur_rmid = pmg;
 
 		/* set in EL0 */
-		reg = read_sysreg_s(SYS_MPAM0_EL1);
+		reg = mpam_read_sysreg_s(SYS_MPAM0_EL1, "SYS_MPAM0_EL1");
 		reg = reg & (~PARTID_MASK) & partid;
 		reg = reg & (~PMG_MASK) & pmg;
-		write_sysreg_s(reg, SYS_MPAM0_EL1);
+		mpam_write_sysreg_s(reg, SYS_MPAM0_EL1, "SYS_MPAM0_EL1");
 
 		/* set in EL1 */
-		reg = read_sysreg_s(SYS_MPAM1_EL1);
+		reg = mpam_read_sysreg_s(SYS_MPAM1_EL1, "SYS_MPAM1_EL1");
 		reg = reg & (~PARTID_MASK) & partid;
 		reg = reg & (~PMG_MASK) & pmg;
-		write_sysreg_s(reg, SYS_MPAM1_EL1);
+		mpam_write_sysreg_s(reg, SYS_MPAM1_EL1, "SYS_MPAM1_EL1");
 
 		/* set in EL2 */
-		reg = read_sysreg_s(SYS_MPAM2_EL2);
+		reg = mpam_read_sysreg_s(SYS_MPAM2_EL2, "SYS_MPAM2_EL2");
 		reg = reg & (~PARTID_MASK) & partid;
 		reg = reg & (~PMG_MASK) & pmg;
-		write_sysreg_s(reg, SYS_MPAM2_EL2);
+		mpam_write_sysreg_s(reg, SYS_MPAM2_EL2, "SYS_MPAM2_EL2");
 	}
 }
 
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index c6b1ed9..6bf2389 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -59,6 +59,7 @@ arm64-obj-$(CONFIG_ARM_SDE_INTERFACE)	+= sdei.o
 arm64-obj-$(CONFIG_ARM64_SSBD)		+= ssbd.o
 arm64-obj-$(CONFIG_SDEI_WATCHDOG) 	+= watchdog_sdei.o
 arm64-obj-$(CONFIG_MPAM)		+= mpam.o mpam_ctrlmon.o mpam_mon.o
+arm64-obj-$(CONFIG_MPAM)		+= mpam.o mpam_ctrlmon.o mpam_mon.o mpam_resource.o
 
 obj-y					+= $(arm64-obj-y) vdso/ probes/
 obj-m					+= $(arm64-obj-m)
diff --git a/arch/arm64/kernel/mpam.c b/arch/arm64/kernel/mpam.c
index d56203b..519fcf7 100644
--- a/arch/arm64/kernel/mpam.c
+++ b/arch/arm64/kernel/mpam.c
@@ -34,7 +34,9 @@
 #include <linux/resctrlfs.h>
 
 #include <asm/mpam_sched.h>
+#include <asm/mpam_resource.h>
 #include <asm/resctrl.h>
+#include <asm/io.h>
 
 /* Mutex to protect rdtgroup access. */
 DEFINE_MUTEX(resctrl_group_mutex);
@@ -59,51 +61,168 @@
  */
 bool rdt_alloc_capable;
 
+char *mpam_types_str[] = {
+	"MPAM_RESOURCE_SMMU",
+	"MPAM_RESOURCE_CACHE",
+	"MPAM_RESOURCE_MC",
+};
+
+struct mpam_node mpam_node_all[] = {
+	/* P0 DIE 0: cluster 0 */
+	{
+		.name			= "L3T0",
+		.type                   = MPAM_RESOURCE_CACHE,
+		.addr                   = 0x90390000,
+		.cpus_list              = "0",
+		.default_ctrl		= 0x7fff,
+	},
+
+	/* P0 DIE 0: cluster 1 */
+	{
+		.name			= "L3T1",
+		.type                   = MPAM_RESOURCE_CACHE,
+		.addr                   = 0x903a0000,
+		.cpus_list              = "1",
+		.default_ctrl		= 0x7fff,
+	},
+
+	/* P0 DIE 0: cluster 2 */
+	{
+		.name			= "L3T2",
+		.type                   = MPAM_RESOURCE_CACHE,
+		.addr                   = 0x903b0000,
+		.cpus_list              = "2",
+		.default_ctrl		= 0x7fff,
+	},
+
+	/* P0 DIE 0: cluster 3 */
+	{
+		.name			= "L3T3",
+		.type                   = MPAM_RESOURCE_CACHE,
+		.addr                   = 0x903c0000,
+		.cpus_list              = "3",
+		.default_ctrl		= 0x7fff,
+	},
+
+	/* P0 DIE 0: HHA0 */
+	{
+		.name			= "HHA0",
+		.type                   = MPAM_RESOURCE_MC,
+		.addr                   = 0x90410000,
+		.cpus_list              = "0-3",
+	},
+
+	/* P0 DIE 0: HHA1 */
+	{
+		.name			= "HHA1",
+		.type                   = MPAM_RESOURCE_MC,
+		.addr                   = 0x90420000,
+		.cpus_list              = "0-3",
+	},
+	/* other mpam nodes ... */
+};
+
+int mpam_nodes_init(void)
+{
+	int i, ret = 0;
+	size_t num_nodes = ARRAY_SIZE(mpam_node_all);
+	struct mpam_node *n;
+
+	for (i = 0; i < num_nodes; i++) {
+		n = &mpam_node_all[i];
+		ret |= cpulist_parse(n->cpus_list, &n->cpu_mask);
+		n->base = ioremap(n->addr, 0x10000);
+	}
+
+	return ret;
+}
+
+void mpam_nodes_show(void)
+{
+	int i, cpu;
+	size_t num_nodes = ARRAY_SIZE(mpam_node_all);
+	struct mpam_node *n;
+
+	char *types[] = {"MPAM_RESOURCE_SMMU", "MPAM_RESOURCE_CACHE", "MPAM_RESOURCE_MC"};
+
+	for (i = 0; i < num_nodes; i++) {
+		n = &mpam_node_all[i];
+		pr_cont("type: %s; addr = %p; cpus_list = %s; cpus: ",
+			types[n->type], (void *)n->addr, n->cpus_list);
+
+		for_each_cpu(cpu, &n->cpu_mask) {
+			pr_cont("%d, ", cpu);
+		}
+		pr_cont("\n");
+	}
+}
+
+static void
+cat_wrmsr(struct rdt_domain *d, int partid);
+static void
+bw_wrmsr(struct rdt_domain *d, int partid);
+
 #define domain_init(id) LIST_HEAD_INIT(resctrl_resources_all[id].domains)
 
-struct resctrl_resource resctrl_resources_all[] = {
-	[MPAM_RESOURCE_L3] = {
-		.rid			= MPAM_RESOURCE_L3,
-		.name			= "L3",
-		.domains		= domain_init(MPAM_RESOURCE_L3),
-		.fflags			= RFTYPE_RES_CACHE,
+struct raw_resctrl_resource raw_resctrl_resources_all[] = {
+	[MPAM_RESOURCE_SMMU] = {
+		.msr_update		= cat_wrmsr,
+		.parse_ctrlval		= parse_cbm,
+		.format_str		= "%d=%0*x",
 	},
-	[MPAM_RESOURCE_L3DATA] = {
-		.rid			= MPAM_RESOURCE_L3DATA,
-		.name			= "L3DATA",
-		.domains		= domain_init(MPAM_RESOURCE_L3DATA),
-		.fflags			= RFTYPE_RES_CACHE,
+	[MPAM_RESOURCE_CACHE] = {
+		.msr_update		= cat_wrmsr,
+		.parse_ctrlval		= parse_cbm,
+		.format_str		= "%d=%0*x",
 	},
-	[MPAM_RESOURCE_L3CODE] = (
-		.rid			= MPAM_RESOURCE_L3CODE,
-		.name			= "L3CODE",
-		.domains		= domain_init(MPAM_RESOURCE_L3CODE),
-		.fflags			= RFTYPE_RES_CACHE,
+	[MPAM_RESOURCE_MC] = {
+		.msr_update		= bw_wrmsr,
+		.parse_ctrlval		= parse_cbm,	/* [FIXME] add parse_bw() helper */
+		.format_str		= "%d=%0*x",
 	},
-	[MPAM_RESOURCE_L2] = {
-		.rid			= MPAM_RESOURCE_L2,
-		.name			= "L2",
-		.domains		= domain_init(MPAM_RESOURCE_L2),
-		.fflags			= RFTYPE_RES_CACHE,
+};
+
+struct resctrl_resource resctrl_resources_all[] = {
+	[MPAM_RESOURCE_SMMU] = {
+		.rid			= MPAM_RESOURCE_SMMU,
+		.name			= "SMMU",
+		.domains		= domain_init(MPAM_RESOURCE_SMMU),
+		.res			= &raw_resctrl_resources_all[MPAM_RESOURCE_SMMU],
+		.fflags			= RFTYPE_RES_SMMU,
+		.alloc_enabled		= 1,
 	},
-	[MPAM_RESOURCE_L2DATA] = {
-		.rid			= MPAM_RESOURCE_L2DATA,
-		.name			= "L2DATA",
-		.domains		= domain_init(MPAM_RESOURCE_L2DATA),
+	[MPAM_RESOURCE_CACHE] = {
+		.rid			= MPAM_RESOURCE_CACHE,
+		.name			= "L3",
+		.domains		= domain_init(MPAM_RESOURCE_CACHE),
+		.res			= &raw_resctrl_resources_all[MPAM_RESOURCE_CACHE],
 		.fflags			= RFTYPE_RES_CACHE,
+		.alloc_enabled		= 1,
 	},
-	[MPAM_RESOURCE_L2CODE] = {
-		.rid			= MPAM_RESOURCE_L2CODE,
-		.name			= "L2CODE",
-		.domains		= domain_init(MPAM_RESOURCE_L2CODE),
-		.fflags			= RFTYPE_RES_CACHE,
+	[MPAM_RESOURCE_MC] = {
+		.rid			= MPAM_RESOURCE_MC,
+		.name			= "MB",
+		.domains		= domain_init(MPAM_RESOURCE_MC),
+		.res			= &raw_resctrl_resources_all[MPAM_RESOURCE_MC],
+		.fflags			= RFTYPE_RES_MC,
+		.alloc_enabled		= 1,
 	},
 };
 
-static void rdt_get_cache_alloc_cfg(int idx, struct resctrl_resource *r)
+static void
+cat_wrmsr(struct rdt_domain *d, int partid)
+{
+	mpam_writel(partid, d->base + MPAMCFG_PART_SEL);
+	mpam_writel(d->ctrl_val[partid], d->base + MPAMCFG_CPBM);
+}
+
+static void
+bw_wrmsr(struct rdt_domain *d, int partid)
 {
-	r->alloc_capable = true;
-	r->alloc_enabled = true;
+	u64 val = MBW_MAX_SET(d->ctrl_val[partid]);
+
+	mpam_writel(partid, d->base + MPAMCFG_PART_SEL);
+	mpam_writel(val, d->base + MPAMCFG_MBW_MAX);
 }
 
 /*
@@ -125,7 +244,6 @@ static void rdt_get_cache_alloc_cfg(int idx, struct resctrl_resource *r)
 
 void closid_init(void)
 {
-	struct resctrl_resource *r;
 	int resctrl_min_closid = 32;
 
 	closid_free_map = BIT_MASK(resctrl_min_closid) - 1;
@@ -151,14 +269,9 @@ void closid_free(int closid)
 	closid_free_map |= 1 << closid;
 }
 
-static void clear_closid_rmid(int cpu)
-{
-	struct intel_pqr_state *state = this_cpu_ptr(&pqr_state);
-}
-
 static int mpam_online_cpu(unsigned int cpu)
 {
-	pr_info("online cpu\n");
+	pr_info("CPU %2d: online cpu and enable mpam\n", cpu);
 	return 0;
 }
 
@@ -170,15 +283,14 @@ static int mpam_offline_cpu(unsigned int cpu)
 
 static __init bool get_rdt_alloc_resources(void)
 {
-	bool ret = false;
+	bool ret = true;
 
 	return ret;
 }
 
 static __init bool get_rdt_mon_resources(void)
 {
-
-	bool ret = false;
+	bool ret = true;
 
 	return ret;
 }
@@ -193,9 +305,6 @@ static __init bool get_resctrl_resources(void)
 
 void post_resctrl_mount(void)
 {
-	struct rdt_domain *dom;
-	struct resctrl_resource *r;
-
 	if (rdt_alloc_capable)
 		static_branch_enable_cpuslocked(&resctrl_alloc_enable_key);
 	if (rdt_mon_capable)
@@ -208,6 +317,7 @@ void post_resctrl_mount(void)
 static int reset_all_ctrls(struct resctrl_resource *r)
 {
 	pr_info("%s\n", __func__);
+	return 0;
 }
 
 void resctrl_resource_reset(void)
@@ -234,7 +344,6 @@ int parse_rdtgroupfs_options(char *data)
 	return ret;
 }
 
-
 /*
  * This is safe against intel_resctrl_sched_in() called from __switch_to()
  * because __switch_to() is executed with interrupts disabled. A local call
@@ -671,6 +780,100 @@ static int resctrl_group_tasks_show(struct kernfs_open_file *of,
 	},
 };
 
+struct rdt_domain *mpam_find_domain(struct resctrl_resource *r, int id,
+		struct list_head **pos)
+{
+	struct rdt_domain *d;
+	struct list_head *l;
+
+	if (id < 0)
+		return ERR_PTR(id);
+
+	list_for_each(l, &r->domains) {
+		d = list_entry(l, struct rdt_domain, list);
+		/* When id is found, return its domain. */
+		if (id == d->id)
+			return d;
+		/* Stop searching when finding id's position in sorted list. */
+		if (id < d->id)
+			break;
+	}
+
+	if (pos)
+		*pos = l;
+
+	return NULL;
+}
+
+static void mpam_domains_init(struct resctrl_resource *r)
+{
+	int i, cpu, id = 0;
+	size_t num_nodes = ARRAY_SIZE(mpam_node_all);
+	struct mpam_node *n;
+	struct list_head *add_pos = NULL, *l;
+	struct rdt_domain *d;
+	struct raw_resctrl_resource *rr = (struct raw_resctrl_resource *)r->res;
+
+	char *types[] = {"MPAM_RESOURCE_SMMU", "MPAM_RESOURCE_CACHE", "MPAM_RESOURCE_MC"};
+
+	for (i = 0; i < num_nodes; i++) {
+		n = &mpam_node_all[i];
+		if (r->rid != n->type)
+			continue;
+
+		pr_cont("type: %s; addr = %p; cpus_list = %s; cpus: ",
+			types[n->type], (void *)n->addr, n->cpus_list);
+
+		for_each_cpu(cpu, &n->cpu_mask) {
+			pr_cont("%d, ", cpu);
+		}
+		pr_cont("\n");
+
+		d = mpam_find_domain(r, id, &add_pos);
+		if (IS_ERR(d)) {
+			pr_warn("Could't find cache id for cpu %d\n", cpu);
+			return;
+		}
+
+		if (!d)
+			d = kzalloc(sizeof(*d), GFP_KERNEL);
+
+		if (!d)
+			return;
+
+		d->id = id;
+		d->base = n->base;
+		cpumask_copy(&d->cpu_mask, &n->cpu_mask);
+		rr->default_ctrl = n->default_ctrl;
+		rr->num_partid = 32;
+
+		d->cpus_list = n->cpus_list;
+
+		d->ctrl_val = kmalloc_array(rr->num_partid, sizeof(*d->ctrl_val), GFP_KERNEL);
+		if (!d->ctrl_val)
+			return;
+
+		list_add_tail(&d->list, add_pos);
+
+		id++;
+	}
+
+	/*
+	 * for debug
+	 */
+	list_for_each(l, &r->domains) {
+		d = list_entry(l, struct rdt_domain, list);
+
+		pr_cont("domain: %d; type: %s; addr = %p; cpus_list = %s; cpus: ",
+			d->id, types[r->rid], (void *)d->base, d->cpus_list);
+
+		for_each_cpu(cpu, &d->cpu_mask) {
+			pr_cont("%d, ", cpu);
+		}
+		pr_cont("\n");
+	}
+}
+
 static int __init mpam_late_init(void)
 {
 	struct resctrl_resource *r;
@@ -679,6 +882,18 @@ static int __init mpam_late_init(void)
 	if (!get_resctrl_resources())
 		return -ENODEV;
 
+	ret = mpam_nodes_init();
+	if (ret) {
+		pr_err("internal error: bad cpu list\n");
+		return ret;
+	}
+
+	/* for debug */
+	mpam_nodes_show();
+
+	mpam_domains_init(&resctrl_resources_all[MPAM_RESOURCE_CACHE]);
+	mpam_domains_init(&resctrl_resources_all[MPAM_RESOURCE_MC]);
+
 	state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
 				  "arm64/mpam:online:",
 				  mpam_online_cpu, mpam_offline_cpu);
diff --git a/arch/arm64/kernel/mpam_ctrlmon.c b/arch/arm64/kernel/mpam_ctrlmon.c
index b5ef7e2..19c1c19 100644
--- a/arch/arm64/kernel/mpam_ctrlmon.c
+++ b/arch/arm64/kernel/mpam_ctrlmon.c
@@ -30,11 +30,180 @@
 
 #include <asm/resctrl.h>
 
+/*
+ * Check whether a cache bit mask is valid. The SDM says:
+ *	Please note that all (and only) contiguous '1' combinations
+ *	are allowed (e.g. FFFFH, 0FF0H, 003CH, etc.).
+ * Additionally Haswell requires at least two bits set.
+ */
+static bool cbm_validate(char *buf, unsigned long *data, struct raw_resctrl_resource *r)
+{
+	u64 val;
+	int ret;
+
+	ret = kstrtou64(buf, 16, &val);
+	if (ret) {
+		rdt_last_cmd_printf("non-hex character in mask %s\n", buf);
+		return false;
+	}
+
+#if 0
+	if (val == 0 || val > r->default_ctrl) {
+		rdt_last_cmd_puts("mask out of range\n");
+		return false;
+	}
+#endif
+
+	*data = val;
+	return true;
+}
+
+/*
+ * Read one cache bit mask (hex). Check that it is valid for the current
+ * resource type.
+ */
+int parse_cbm(char *buf, struct raw_resctrl_resource *r, struct rdt_domain *d)
+{
+	unsigned long data;
+
+	if (d->have_new_ctrl) {
+		rdt_last_cmd_printf("duplicate domain %d\n", d->id);
+		return -EINVAL;
+	}
+
+	if (!cbm_validate(buf, &data, r))
+		return -EINVAL;
+
+	d->new_ctrl = data;
+	d->have_new_ctrl = true;
+
+	return 0;
+}
+
+/*
+ * For each domain in this resource we expect to find a series of:
+ * id=mask
+ * separated by ";". The "id" is in decimal, and must match one of
+ * the "id"s for this resource.
+ */
+static int parse_line(char *line, struct resctrl_resource *r)
+{
+	struct raw_resctrl_resource *rr = (struct raw_resctrl_resource *)r->res;
+	char *dom = NULL, *id;
+	struct rdt_domain *d;
+	unsigned long dom_id;
+
+
+next:
+	if (!line || line[0] == '\0')
+		return 0;
+	dom = strsep(&line, ";");
+	id = strsep(&dom, "=");
+	if (!dom || kstrtoul(id, 10, &dom_id)) {
+		rdt_last_cmd_puts("Missing '=' or non-numeric domain\n");
+		return -EINVAL;
+	}
+	dom = strim(dom);
+	list_for_each_entry(d, &r->domains, list) {
+		if (d->id == dom_id) {
+			if (rr->parse_ctrlval(dom, (struct raw_resctrl_resource *)&r->res, d))
+				return -EINVAL;
+			goto next;
+		}
+	}
+	return -EINVAL;
+}
+
+static int update_domains(struct resctrl_resource *r, int partid)
+{
+	struct raw_resctrl_resource *rr;
+	struct rdt_domain *d;
+
+	rr = (struct raw_resctrl_resource *)r->res;
+	list_for_each_entry(d, &r->domains, list) {
+		if (d->have_new_ctrl && d->new_ctrl != d->ctrl_val[partid]) {
+			d->ctrl_val[partid] = d->new_ctrl;
+			rr->msr_update(d, partid);
+		}
+	}
+
+	return 0;
+}
+
+static int resctrl_group_parse_resource(char *resname, char *tok, int closid)
+{
+	struct resctrl_resource *r;
+	struct raw_resctrl_resource *rr;
+
+	for_each_resctrl_resource(r) {
+		if (r->alloc_enabled) {
+			rr = (struct raw_resctrl_resource *)r->res;
+			if (!strcmp(resname, r->name) && closid < rr->num_partid)
+				return parse_line(tok, r);
+		}
+	}
+	rdt_last_cmd_printf("unknown/unsupported resource name '%s'\n", resname);
+	return -EINVAL;
+}
 
 ssize_t resctrl_group_schemata_write(struct kernfs_open_file *of,
 				char *buf, size_t nbytes, loff_t off)
 {
-	return 0;
+	struct rdtgroup *rdtgrp;
+	struct rdt_domain *dom;
+	struct resctrl_resource *r;
+	char *tok, *resname;
+	int closid, ret = 0;
+
+	/* Valid input requires a trailing newline */
+	if (nbytes == 0 || buf[nbytes - 1] != '\n')
+		return -EINVAL;
+	buf[nbytes - 1] = '\0';
+
+	rdtgrp = resctrl_group_kn_lock_live(of->kn);
+	if (!rdtgrp) {
+		resctrl_group_kn_unlock(of->kn);
+		return -ENOENT;
+	}
+	rdt_last_cmd_clear();
+
+	closid = rdtgrp->closid;
+
+	for_each_resctrl_resource(r) {
+		if (r->alloc_enabled) {
+			list_for_each_entry(dom, &r->domains, list)
+				dom->have_new_ctrl = false;
+		}
+	}
+
+	while ((tok = strsep(&buf, "\n")) != NULL) {
+		resname = strim(strsep(&tok, ":"));
+		if (!tok) {
+			rdt_last_cmd_puts("Missing ':'\n");
+			ret = -EINVAL;
+			goto out;
+		}
+		if (tok[0] == '\0') {
+			rdt_last_cmd_printf("Missing '%s' value\n", resname);
+			ret = -EINVAL;
+			goto out;
+		}
+		ret = resctrl_group_parse_resource(resname, tok, closid);
+		if (ret)
+			goto out;
+	}
+
+	for_each_resctrl_resource(r) {
+		if (r->alloc_enabled) {
+			ret = update_domains(r, closid);
+			if (ret)
+				goto out;
+		}
+	}
+
+out:
+	resctrl_group_kn_unlock(of->kn);
+	return ret ?: nbytes;
 }
 
 int resctrl_group_schemata_show(struct kernfs_open_file *of,
diff --git a/arch/arm64/kernel/mpam_resource.c b/arch/arm64/kernel/mpam_resource.c
new file mode 100644
index 0000000..9cdda91
--- /dev/null
+++ b/arch/arm64/kernel/mpam_resource.c
@@ -0,0 +1,14 @@
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/kthread.h>
+#include <linux/resctrlfs.h>
+
+#include <asm/mpam_resource.h>
+#include <asm/mpam.h>
+
diff --git a/fs/resctrlfs.c b/fs/resctrlfs.c
index f2676e4..742e08e 100644
--- a/fs/resctrlfs.c
+++ b/fs/resctrlfs.c
@@ -110,7 +110,7 @@ static int __resctrl_group_add_files(struct kernfs_node *kn, unsigned long fflag
 				     struct rftype *rfts, int len)
 {
 	struct rftype *rft;
-	int ret;
+	int ret = 0;
 
 	lockdep_assert_held(&resctrl_group_mutex);
 
@@ -137,7 +137,7 @@ static int __resctrl_group_add_files(struct kernfs_node *kn, unsigned long fflag
 
 static int resctrl_group_add_files(struct kernfs_node *kn, unsigned long fflags)
 {
-	int ret;
+	int ret = 0;
 
 	if (res_common_files)
 		ret = __resctrl_group_add_files(kn, fflags, res_common_files,
-- 
1.8.3.1

