From 04b4e153373e92deceb8fdb08981315cce2672b2 Mon Sep 17 00:00:00 2001 From: Xie XiuQi Date: Tue, 29 Jan 2019 17:38:35 +0800 Subject: [PATCH 2830/2944] openEuler: arm64/mpam: support monitor commit 49b25cbf20fb67a0dcedd863246ea6b312f6fd12 openEuler-1.0 hulk inclusion category: feature bugzilla: 5510 CVE: NA Signed-off-by: Xie XiuQi Reviewed-by: Hanjun Guo Signed-off-by: Yang Yingliang Signed-off-by: Xin Hao Reviewed-by: Baolin Wang --- arch/arm64/include/asm/mpam.h | 18 +++- arch/arm64/kernel/mpam.c | 193 +++++++++++++++++++++++++++++++++++---- arch/arm64/kernel/mpam_ctrlmon.c | 47 ++++++++-- arch/arm64/kernel/mpam_mon.c | 33 ++++++- fs/resctrlfs.c | 10 +- 5 files changed, 268 insertions(+), 33 deletions(-) diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h index b4c7d68..4b800ab 100644 --- a/arch/arm64/include/asm/mpam.h +++ b/arch/arm64/include/asm/mpam.h @@ -127,12 +127,14 @@ enum rdt_group_type { * @parent: parent rdtgrp * @crdtgrp_list: child rdtgroup node list * @rmid: rmid for this rdtgroup + * @mon: monnitor id */ struct mongroup { struct kernfs_node *mon_data_kn; struct rdtgroup *parent; struct list_head crdtgrp_list; u32 rmid; + u32 mon; int init; }; @@ -164,7 +166,8 @@ struct rdtgroup { extern int max_name_width, max_data_width; /* rdtgroup.flags */ -#define RDT_DELETED 1 +#define RDT_DELETED BIT(0) +#define RDT_CTRLMON BIT(1) /** * struct rdt_domain - group of cpus sharing an RDT resource @@ -327,8 +330,9 @@ struct raw_resctrl_resource { int (*parse_ctrlval) (char *buf, struct raw_resctrl_resource *r, struct rdt_domain *d); int num_pmg; + int num_mon; u64 (*mon_read) (struct rdt_domain *d, struct rdtgroup *g); - int (*mon_write) (struct rdt_domain *d, struct rdtgroup *g, u32 match); + int (*mon_write) (struct rdt_domain *d, struct rdtgroup *g, bool enable); }; int parse_cbm(char *buf, struct raw_resctrl_resource *r, struct rdt_domain *d); @@ -346,4 +350,14 @@ struct raw_resctrl_resource { struct rdt_domain *mpam_find_domain(struct resctrl_resource *r, int id, struct list_head **pos); +int resctrl_group_alloc_mon(struct rdtgroup *grp); + +void mon_init(void); +int alloc_mon(void); +void free_mon(u32 mon); + +int resctrl_mkdir_ctrlmon_mondata(struct kernfs_node *parent_kn, + struct rdtgroup *prgrp, + struct kernfs_node **dest_kn); + #endif /* _ASM_ARM64_MPAM_H */ diff --git a/arch/arm64/kernel/mpam.c b/arch/arm64/kernel/mpam.c index 4261c64..c172a41 100644 --- a/arch/arm64/kernel/mpam.c +++ b/arch/arm64/kernel/mpam.c @@ -168,8 +168,8 @@ void mpam_nodes_show(void) static u64 mbwu_read(struct rdt_domain *d, struct rdtgroup *g); static u64 csu_read(struct rdt_domain *d, struct rdtgroup *g); -static int mbwu_write(struct rdt_domain *d, struct rdtgroup *g, u32 match); -static int csu_write(struct rdt_domain *d, struct rdtgroup *g, u32 match); +static int mbwu_write(struct rdt_domain *d, struct rdtgroup *g, bool enable); +static int csu_write(struct rdt_domain *d, struct rdtgroup *g, bool enable); #define domain_init(id) LIST_HEAD_INIT(resctrl_resources_all[id].domains) @@ -266,43 +266,55 @@ u64 bw_rdmsr(struct rdt_domain *d, int partid) */ static u64 mbwu_read(struct rdt_domain *d, struct rdtgroup *g) { - u32 pmg = g->mon.rmid; + u32 mon = g->mon.mon; - mpam_writel(pmg, d->base + MSMON_CFG_MON_SEL); + mpam_writel(mon, d->base + MSMON_CFG_MON_SEL); return mpam_readl(d->base + MSMON_MBWU); } static u64 csu_read(struct rdt_domain *d, struct rdtgroup *g) { - u32 pmg = g->mon.rmid; + u32 mon = g->mon.mon; - mpam_writel(pmg, d->base + MSMON_CFG_MON_SEL); + mpam_writel(mon, d->base + MSMON_CFG_MON_SEL); return mpam_readl(d->base + MSMON_CSU); } -static int mbwu_write(struct rdt_domain *d, struct rdtgroup *g, u32 match) +static int mbwu_write(struct rdt_domain *d, struct rdtgroup *g, bool enable) { - u32 pmg = g->mon.rmid; - u32 partid = g->closid; - u32 flt = MSMON_CFG_FLT_SET(pmg, partid); - u32 ctl = MSMON_CFG_MBWU_CTL_SET(match); + u32 mon, pmg, partid, flt, ctl = 0; + + if (enable) { + mon = g->mon.mon; + pmg = g->mon.rmid; + partid = g->closid; + flt = MSMON_CFG_FLT_SET(pmg, partid); + ctl = MSMON_CFG_MBWU_CTL_SET(MSMON_MATCH_PMG|MSMON_MATCH_PARTID); + + mpam_writel(mon, d->base + MSMON_CFG_MON_SEL); + mpam_writel(flt, d->base + MSMON_CFG_MBWU_FLT); + } - mpam_writel(pmg, d->base + MSMON_CFG_MON_SEL); - mpam_writel(flt, d->base + MSMON_CFG_MBWU_FLT); mpam_writel(ctl, d->base + MSMON_CFG_MBWU_CTL); return 0; } -static int csu_write(struct rdt_domain *d, struct rdtgroup *g, u32 match) +static int csu_write(struct rdt_domain *d, struct rdtgroup *g, bool enable) { - u32 pmg = g->mon.rmid; - u32 partid = g->closid; - u32 flt = MSMON_CFG_FLT_SET(pmg, partid); - u32 ctl = MSMON_CFG_CSU_CTL_SET(match); + u32 mon, pmg, partid, flt, ctl = 0; + + if (enable) { + mon = g->mon.mon; + pmg = g->mon.rmid; + partid = g->closid; + flt = MSMON_CFG_FLT_SET(pmg, partid); + ctl = MSMON_CFG_CSU_CTL_SET(MSMON_MATCH_PMG|MSMON_MATCH_PARTID); + + mpam_writel(mon, d->base + MSMON_CFG_MON_SEL); + mpam_writel(flt, d->base + MSMON_CFG_CSU_FLT); + } - mpam_writel(pmg, d->base + MSMON_CFG_MON_SEL); - mpam_writel(flt, d->base + MSMON_CFG_CSU_FLT); mpam_writel(ctl, d->base + MSMON_CFG_CSU_CTL); return 0; @@ -933,6 +945,139 @@ static int resctrl_group_tasks_show(struct kernfs_open_file *of, return ret; } +int resctrl_ctrlmon_enable(struct kernfs_node *parent_kn, + struct resctrl_group *prgrp, + struct kernfs_node **dest_kn) +{ + int ret; + + pr_info("%s: out of monitors: ret %d, MON_GROUP %d\n", + __func__, prgrp->type, RDTMON_GROUP); + /* only for RDTCTRL_GROUP */ + if (prgrp->type == RDTMON_GROUP) + return 0; + + ret = alloc_mon(); + if (ret < 0) { + rdt_last_cmd_puts("out of monitors\n"); + pr_info("out of monitors: ret %d\n", ret); + return ret; + } + prgrp->mon.mon = ret; + prgrp->mon.rmid = 0; + + pr_info("%s: prev dest_kn %016llx, closid %d, flags %d, type %d, rmid %d, mon %d\n", + __func__, (u64)*dest_kn, prgrp->closid, prgrp->flags, prgrp->type, + prgrp->mon.rmid, prgrp->mon.mon); + + ret = mkdir_mondata_all(parent_kn, prgrp, dest_kn); + if (ret) { + rdt_last_cmd_puts("kernfs subdir error\n"); + free_mon(ret); + } + + pr_info("%s: post dest_kn %016llx, closid %d, flags %d, type %d, rmid %d, mon %d\n", + __func__, (u64)*dest_kn, prgrp->closid, prgrp->flags, prgrp->type, + prgrp->mon.rmid, prgrp->mon.mon); + + return ret; +} + +int resctrl_ctrlmon_disable(struct kernfs_node *kn_mondata, + struct resctrl_group *prgrp) +{ + struct resctrl_resource *r; + struct raw_resctrl_resource *rr; + struct rdt_domain *dom; + int ret, mon = prgrp->mon.mon; + + /* only for RDTCTRL_GROUP */ + if (prgrp->type == RDTMON_GROUP) + return 0; + + /* disable monitor before free mon */ + for_each_resctrl_resource(r) { + if (r->mon_enabled) { + rr = (struct raw_resctrl_resource *)r->res; + + list_for_each_entry(dom, &r->domains, list) { + rr->mon_write(dom, prgrp, false); + } + } + } + + free_mon(mon); + + pr_info("%s: prev kn_mondta %016llx, closid %d, flags %d, type %d, rmid %d, mon %d\n", + __func__, (u64)kn_mondata, prgrp->closid, prgrp->flags, prgrp->type, + prgrp->mon.rmid, prgrp->mon.mon); + + kernfs_remove(kn_mondata); + + pr_info("%s: post kn_mondta %016llx, closid %d, flags %d, type %d, rmid %d, mon %d\n", + __func__, (u64)kn_mondata, prgrp->closid, prgrp->flags, prgrp->type, + prgrp->mon.rmid, prgrp->mon.mon); + + return ret; +} + +static ssize_t resctrl_group_ctrlmon_write(struct kernfs_open_file *of, + char *buf, size_t nbytes, loff_t off) +{ + struct rdtgroup *rdtgrp; + int ret = 0; + int ctrlmon; + + if (kstrtoint(strstrip(buf), 0, &ctrlmon) || ctrlmon < 0) + return -EINVAL; + rdtgrp = resctrl_group_kn_lock_live(of->kn); + rdt_last_cmd_clear(); + + pr_info("%s: prev of->kn %016llx, closid %d, flags %d, type %d, rmid %d, mon %d\n", + __func__, (u64)of->kn, rdtgrp->closid, rdtgrp->flags, rdtgrp->type, + rdtgrp->mon.rmid, rdtgrp->mon.mon); + + if (rdtgrp) { + if ((rdtgrp->flags & RDT_CTRLMON) && !ctrlmon) { + /* [FIXME] disable & remove mon_data dir */ + rdtgrp->flags &= ~RDT_CTRLMON; + resctrl_ctrlmon_disable(rdtgrp->mon.mon_data_kn, rdtgrp); + } else if (!(rdtgrp->flags & RDT_CTRLMON) && ctrlmon) { + rdtgrp->flags |= RDT_CTRLMON; + resctrl_ctrlmon_enable(rdtgrp->kn, rdtgrp, + &rdtgrp->mon.mon_data_kn); + } else { + ret = -ENOENT; + } + } else { + ret = -ENOENT; + } + + pr_info("%s: post of->kn %016llx, closid %d, flags %d, type %d, rmid %d, mon %d\n", + __func__, (u64)of->kn, rdtgrp->closid, rdtgrp->flags, rdtgrp->type, + rdtgrp->mon.rmid, rdtgrp->mon.mon); + + resctrl_group_kn_unlock(of->kn); + + return ret ?: nbytes; +} + +static int resctrl_group_ctrlmon_show(struct kernfs_open_file *of, + struct seq_file *s, void *v) +{ + struct rdtgroup *rdtgrp; + int ret = 0; + + rdtgrp = resctrl_group_kn_lock_live(of->kn); + if (rdtgrp) + seq_printf(s, "%d", !!(rdtgrp->flags & RDT_CTRLMON)); + else + ret = -ENOENT; + resctrl_group_kn_unlock(of->kn); + + return ret; +} + /* rdtgroup information files for one cache resource. */ static struct rftype res_specific_files[] = { { @@ -989,6 +1134,14 @@ static int resctrl_group_tasks_show(struct kernfs_open_file *of, .seq_show = resctrl_group_schemata_show, .fflags = RF_CTRL_BASE, }, + { + .name = "ctrlmon", + .mode = 0644, + .kf_ops = &resctrl_group_kf_single_ops, + .write = resctrl_group_ctrlmon_write, + .seq_show = resctrl_group_ctrlmon_show, + .fflags = RF_CTRL_BASE, + }, }; struct rdt_domain *mpam_find_domain(struct resctrl_resource *r, int id, diff --git a/arch/arm64/kernel/mpam_ctrlmon.c b/arch/arm64/kernel/mpam_ctrlmon.c index 70a4b57..1e5b2a2 100644 --- a/arch/arm64/kernel/mpam_ctrlmon.c +++ b/arch/arm64/kernel/mpam_ctrlmon.c @@ -128,9 +128,6 @@ static int update_domains(struct resctrl_resource *r, struct rdtgroup *g) d->ctrl_val[partid] = d->new_ctrl; rr->msr_update(d, partid); } - - /* only match partid for monitoring this whole group */ - rr->mon_write(d, g, MSMON_MATCH_PARTID); } return 0; @@ -307,14 +304,15 @@ int resctrl_group_mondata_show(struct seq_file *m, void *arg) } md.priv = of->kn->priv; - pr_info("%s: resname %s, rid %d, domid %d, partid %d, pmg %d, (group: partid %d, pmg %d)\n", + pr_info("%s: resname %s, rid %d, domid %d, partid %d, pmg %d, (group: partid %d, pmg %d, mon %d)\n", __func__, resname, md.u.rid, md.u.domid, md.u.partid, md.u.pmg, rdtgrp->closid, - rdtgrp->mon.rmid + rdtgrp->mon.rmid, + rdtgrp->mon.mon ); r = &resctrl_resources_all[md.u.rid]; @@ -409,9 +407,8 @@ static int mkdir_mondata_subdir(struct kernfs_node *parent_kn, } - /* set mon id for mon_groups */ - if (prgrp->type == RDTMON_GROUP) - rr->mon_write(d, prgrp, MSMON_MATCH_PMG); + /* [FIXME] Could we remove the MATCH_* param ? */ + rr->mon_write(d, prgrp, true); return ret; #if 0 @@ -583,3 +580,37 @@ int mkdir_mondata_all(struct kernfs_node *parent_kn, kernfs_remove(kn); return ret; } + +int resctrl_mkdir_ctrlmon_mondata(struct kernfs_node *parent_kn, + struct resctrl_group *prgrp, + struct kernfs_node **dest_kn) +{ + int ret; + + /* disalbe monitor by default for mpam. */ + if (prgrp->type == RDTCTRL_GROUP) + return 0; + + ret = alloc_mon(); + if (ret < 0) { + rdt_last_cmd_puts("out of monitors\n"); + return ret; + } + prgrp->mon.mon = ret; + + ret = alloc_mon_id(); + if (ret < 0) { + rdt_last_cmd_puts("out of PMGs\n"); + free_mon(prgrp->mon.mon); + return ret; + } + + prgrp->mon.rmid = ret; + + ret = mkdir_mondata_all(parent_kn, prgrp, dest_kn); + if (ret) { + rdt_last_cmd_puts("kernfs subdir error\n"); + free_mon(ret); + } + return ret; +} diff --git a/arch/arm64/kernel/mpam_mon.c b/arch/arm64/kernel/mpam_mon.c index 38fe892..ae946b2 100644 --- a/arch/arm64/kernel/mpam_mon.c +++ b/arch/arm64/kernel/mpam_mon.c @@ -36,11 +36,13 @@ bool rdt_mon_capable; static int pmg_free_map; - +void mon_init(void); void pmg_init(void) { int pmg_max = 16; + mon_init(); + pmg_free_map = BIT_MASK(pmg_max) - 1; /* pmg 0 is always reserved for the default group */ @@ -65,6 +67,35 @@ void free_pmg(u32 pmg) pmg_free_map |= 1 << pmg; } +static int mon_free_map; +void mon_init(void) +{ + // [FIXME] hard code for max mon. + int mon_max = 8; + + mon_free_map = BIT_MASK(mon_max) - 1; + + /* pmg 0 is always reserved for the default group */ + mon_free_map &= ~1; +} + +int alloc_mon(void) +{ + u32 mon = ffs(mon_free_map); + + if (mon == 0) + return -ENOSPC; + + mon--; + mon_free_map &= ~(1 << mon); + + return mon; +} + +void free_mon(u32 mon) +{ + mon_free_map |= 1 << mon; +} /* * As of now the RMIDs allocation is global. diff --git a/fs/resctrlfs.c b/fs/resctrlfs.c index 0ffe8b1..6f5c5f1 100644 --- a/fs/resctrlfs.c +++ b/fs/resctrlfs.c @@ -554,6 +554,9 @@ static int mkdir_resctrl_prepare(struct kernfs_node *parent_kn, } if (resctrl_mon_capable) { +#ifdef CONFIG_ARM64 + resctrl_mkdir_ctrlmon_mondata(kn, rdtgrp, &rdtgrp->mon.mon_data_kn); +#else ret = alloc_mon_id(); if (ret < 0) { rdt_last_cmd_puts("out of RMIDs\n"); @@ -566,6 +569,7 @@ static int mkdir_resctrl_prepare(struct kernfs_node *parent_kn, rdt_last_cmd_puts("kernfs subdir error\n"); goto out_idfree; } +#endif } kernfs_activate(kn); @@ -574,8 +578,10 @@ static int mkdir_resctrl_prepare(struct kernfs_node *parent_kn, */ return 0; +#ifndef CONFIG_ARM64 out_idfree: free_mon_id(rdtgrp->mon.rmid); +#endif out_destroy: kernfs_remove(rdtgrp->kn); out_free_rgrp: @@ -740,7 +746,7 @@ static void resctrl_group_rm_mon(struct resctrl_group *rdtgrp, cpumask_or(tmpmask, tmpmask, &rdtgrp->cpu_mask); update_closid_rmid(tmpmask, NULL); - rdtgrp->flags = RDT_DELETED; + rdtgrp->flags |= RDT_DELETED; free_mon_id(rdtgrp->mon.rmid); /* @@ -789,7 +795,7 @@ static void resctrl_group_rm_ctrl(struct resctrl_group *rdtgrp, cpumask_var_t tm cpumask_or(tmpmask, tmpmask, &rdtgrp->cpu_mask); update_closid_rmid(tmpmask, NULL); - rdtgrp->flags = RDT_DELETED; + rdtgrp->flags |= RDT_DELETED; resctrl_id_free(rdtgrp->closid); free_mon_id(rdtgrp->mon.rmid); -- 1.8.3.1