From: Xie XiuQi <xiexiuqi(a)huawei.com>
commit 19cab98fba25040817f1a6b9b6b70c6b458a169a openEuler-1.0
hulk inclusion
category: feature
bugzilla: 5510
CVE: NA
Signed-off-by: Xie XiuQi <xiexiuqi(a)huawei.com>
Reviewed-by: Hanjun Guo <guohanjun(a)huawei.com>
Signed-off-by: Yang Yingliang <yangyingliang(a)huawei.com>
Signed-off-by: Xin Hao <haoxing990(a)gmail.com>
---
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 6f051f3229e2..61bca6334850 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 @@ extern struct resctrl_resource resctrl_resources_all[];
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 @@ int parse_rdtgroupfs_options(char *data);
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 @@ void post_resctrl_mount(void);
#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 000000000000..4ec2d8605cbc
--- /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 586b02b55844..53c3f29417ab 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 c6b1ed993891..6bf2389d0648 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 d56203bcfb68..519fcf72836d 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 @@ int max_name_width, max_data_width;
*/
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 int closid_free_map;
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 struct rftype res_specific_files[] = {
},
};
+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 b5ef7e2163db..19c1c19a4195 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 000000000000..9cdda91ecb67
--- /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 f2676e4ba817..742e08eaa581 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,
--
2.31.0