From 19cab98fba25040817f1a6b9b6b70c6b458a169a Mon Sep 17 00:00:00 2001 From: Xie XiuQi Date: Tue, 29 Jan 2019 17:38:15 +0800 Subject: [PATCH] arm64/mpam: use mpam_{read/write}_sysreg_s for debug hulk inclusion category: feature bugzilla: 5510 CVE: NA Signed-off-by: Xie XiuQi Reviewed-by: Hanjun Guo Signed-off-by: Yang Yingliang --- 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 + +#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 54d0b1d38a4e..8e3e00d7c2d8 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -61,6 +61,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 #include +#include #include +#include /* 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 +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + diff --git a/fs/resctrlfs.c b/fs/resctrlfs.c index 9cb92658ed2d..625f4ae093b5 100644 --- a/fs/resctrlfs.c +++ b/fs/resctrlfs.c @@ -109,7 +109,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); @@ -136,7 +136,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, -- GitLab