From 4bf3a2e1921fe7fe3e3a6b4928d5df8822eb03f6 Mon Sep 17 00:00:00 2001
From: Xie XiuQi <xiexiuqi@huawei.com>
Date: Tue, 29 Jan 2019 17:38:24 +0800
Subject: [PATCH 2819/2944] openEuler: arm64/mpam: support mondata fields

commit b4617397605d3b8842d9e39bb8921223eccc2f92 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    |   1 +
 arch/arm64/include/asm/resctrl.h |   8 ++
 arch/arm64/kernel/mpam_ctrlmon.c | 277 +++++++++++++++++++++++++++++++++++++++
 fs/resctrlfs.c                   |   1 +
 4 files changed, 287 insertions(+)

diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h
index 4f09280..4bb583b 100644
--- a/arch/arm64/include/asm/mpam.h
+++ b/arch/arm64/include/asm/mpam.h
@@ -140,6 +140,7 @@ struct mongroup {
  * @kn:				kernfs node
  * @resctrl_group_list:		linked list for all rdtgroups
  * @closid:			closid for this rdtgroup
+ * #endif
  * @cpu_mask:			CPUs assigned to this rdtgroup
  * @flags:			status bits
  * @waitcount:			how many cpus expect to find this
diff --git a/arch/arm64/include/asm/resctrl.h b/arch/arm64/include/asm/resctrl.h
index cb02aae..ffebafa 100644
--- a/arch/arm64/include/asm/resctrl.h
+++ b/arch/arm64/include/asm/resctrl.h
@@ -55,4 +55,12 @@ int resctrl_group_schemata_show(struct kernfs_open_file *of,
 	     r < resctrl_resources_all + MPAM_NUM_RESOURCES;		\
 	     r++)							\
 
+int mkdir_mondata_all(struct kernfs_node *parent_kn,
+			     struct resctrl_group *prgrp,
+			     struct kernfs_node **dest_kn);
+
+int
+mongroup_create_dir(struct kernfs_node *parent_kn, struct resctrl_group *prgrp,
+		    char *name, struct kernfs_node **dest_kn);
+
 #endif /* _ASM_ARM64_RESCTRL_H */
diff --git a/arch/arm64/kernel/mpam_ctrlmon.c b/arch/arm64/kernel/mpam_ctrlmon.c
index b7af781..78bc262 100644
--- a/arch/arm64/kernel/mpam_ctrlmon.c
+++ b/arch/arm64/kernel/mpam_ctrlmon.c
@@ -28,6 +28,8 @@
 #include <linux/slab.h>
 #include <linux/resctrlfs.h>
 
+#include <asm/mpam.h>
+#include <asm/mpam_resource.h>
 #include <asm/resctrl.h>
 
 /*
@@ -248,3 +250,278 @@ int resctrl_group_schemata_show(struct kernfs_open_file *of,
 	resctrl_group_kn_unlock(of->kn);
 	return ret;
 }
+
+/*
+ * [FIXME]
+ * use pmg as monitor id
+ * just use match_pardid only.
+ */
+static u64 mbwu_read(struct rdt_domain *d, struct rdtgroup *g)
+{
+	u32 pmg = g->mon.rmid;
+
+	mpam_writel(pmg, 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;
+
+	mpam_writel(pmg, d->base + MSMON_CFG_MON_SEL);
+	return mpam_readl(d->base + MSMON_CSU);
+}
+
+int resctrl_group_mondata_show(struct seq_file *m, void *arg)
+{
+	struct kernfs_open_file *of = m->private;
+	struct rdtgroup *rdtgrp;
+	struct rdt_domain *d;
+	int ret = 0;
+
+	rdtgrp = resctrl_group_kn_lock_live(of->kn);
+
+	d = of->kn->priv;
+
+	/* for debug */
+	seq_printf(m, "group: partid: %d, pmg: %d",
+		   rdtgrp->closid, rdtgrp->mon.rmid);
+
+	/* show monitor data */
+
+	resctrl_group_kn_unlock(of->kn);
+	return ret;
+}
+
+static struct kernfs_ops kf_mondata_ops = {
+	.atomic_write_len	= PAGE_SIZE,
+	.seq_show		= resctrl_group_mondata_show,
+};
+
+/* set uid and gid of resctrl_group dirs and files to that of the creator */
+static int resctrl_group_kn_set_ugid(struct kernfs_node *kn)
+{
+	struct iattr iattr = { .ia_valid = ATTR_UID | ATTR_GID,
+				.ia_uid = current_fsuid(),
+				.ia_gid = current_fsgid(), };
+
+	if (uid_eq(iattr.ia_uid, GLOBAL_ROOT_UID) &&
+	    gid_eq(iattr.ia_gid, GLOBAL_ROOT_GID))
+		return 0;
+
+	return kernfs_setattr(kn, &iattr);
+}
+
+#if 0	/* used at remove cpu*/
+/*
+ * Remove all subdirectories of mon_data of ctrl_mon groups
+ * and monitor groups with given domain id.
+ */
+void rmdir_mondata_subdir_allrdtgrp(struct resctrl_resource *r, unsigned int dom_id)
+{
+	struct resctrl_group *prgrp, *crgrp;
+	char name[32];
+
+	if (!r->mon_enabled)
+		return;
+
+	list_for_each_entry(prgrp, &resctrl_all_groups, resctrl_group_list) {
+		sprintf(name, "mon_%s_%02d", r->name, dom_id);
+		kernfs_remove_by_name(prgrp->mon.mon_data_kn, name);
+
+		list_for_each_entry(crgrp, &prgrp->mon.crdtgrp_list, mon.crdtgrp_list)
+			kernfs_remove_by_name(crgrp->mon.mon_data_kn, name);
+	}
+}
+#endif
+
+static int mkdir_mondata_subdir(struct kernfs_node *parent_kn,
+				struct rdt_domain *d,
+				struct resctrl_resource *r, struct resctrl_group *prgrp)
+{
+#if 1
+	struct kernfs_node *kn;
+	char name[32];
+	int ret;
+
+	sprintf(name, "mon_%s_%02d", r->name, d->id);
+
+	kn = __kernfs_create_file(parent_kn, name, 0444,
+				  GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, 0,
+				  &kf_mondata_ops, d, NULL, NULL);
+	if (IS_ERR(kn))
+		return PTR_ERR(kn);
+
+	ret = resctrl_group_kn_set_ugid(kn);
+	if (ret) {
+		kernfs_remove(kn);
+		return ret;
+	}
+
+	return ret;
+#if 0
+	/* create the directory */
+	kn = kernfs_create_dir(parent_kn, name, parent_kn->mode, prgrp);
+	if (IS_ERR(kn))
+		return PTR_ERR(kn);
+
+	/*
+	 * This extra ref will be put in kernfs_remove() and guarantees
+	 * that kn is always accessible.
+	 */
+	kernfs_get(kn);
+	ret = resctrl_group_kn_set_ugid(kn);
+	if (ret)
+		goto out_destroy;
+#endif
+
+
+#if 0
+	ret = mon_addfile(kn, mevt->name, d);
+	if (ret)
+		goto out_destroy;
+
+	kernfs_activate(kn);
+	return 0;
+
+out_destroy:
+	kernfs_remove(kn);
+	return ret;
+#endif
+#else
+	return 0;
+#endif
+}
+
+/*
+ * Add all subdirectories of mon_data for "ctrl_mon" groups
+ * and "monitor" groups with given domain id.
+ */
+void mkdir_mondata_subdir_allrdtgrp(struct resctrl_resource *r,
+				    struct rdt_domain *d)
+{
+	struct kernfs_node *parent_kn;
+	struct resctrl_group *prgrp, *crgrp;
+	struct list_head *head;
+
+	if (!r->mon_enabled)
+		return;
+
+	list_for_each_entry(prgrp, &resctrl_all_groups, resctrl_group_list) {
+		parent_kn = prgrp->mon.mon_data_kn;
+		mkdir_mondata_subdir(parent_kn, d, r, prgrp);
+
+		head = &prgrp->mon.crdtgrp_list;
+		list_for_each_entry(crgrp, head, mon.crdtgrp_list) {
+			parent_kn = crgrp->mon.mon_data_kn;
+			mkdir_mondata_subdir(parent_kn, d, r, crgrp);
+		}
+	}
+}
+
+static int mkdir_mondata_subdir_alldom(struct kernfs_node *parent_kn,
+				       struct resctrl_resource *r,
+				       struct resctrl_group *prgrp)
+{
+	struct rdt_domain *dom;
+	int ret;
+
+	list_for_each_entry(dom, &r->domains, list) {
+		ret = mkdir_mondata_subdir(parent_kn, dom, r, prgrp);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int
+mongroup_create_dir(struct kernfs_node *parent_kn, struct resctrl_group *prgrp,
+		    char *name, struct kernfs_node **dest_kn)
+{
+	struct kernfs_node *kn;
+	int ret;
+
+	/* create the directory */
+	kn = kernfs_create_dir(parent_kn, name, parent_kn->mode, prgrp);
+	if (IS_ERR(kn))
+		return PTR_ERR(kn);
+
+	if (dest_kn)
+		*dest_kn = kn;
+
+	/*
+	 * This extra ref will be put in kernfs_remove() and guarantees
+	 * that @rdtgrp->kn is always accessible.
+	 */
+	kernfs_get(kn);
+
+	ret = resctrl_group_kn_set_ugid(kn);
+	if (ret)
+		goto out_destroy;
+
+	kernfs_activate(kn);
+
+	return 0;
+
+out_destroy:
+	kernfs_remove(kn);
+	return ret;
+}
+
+
+/*
+ * This creates a directory mon_data which contains the monitored data.
+ *
+ * mon_data has one directory for each domain whic are named
+ * in the format mon_<domain_name>_<domain_id>. For ex: A mon_data
+ * with L3 domain looks as below:
+ * ./mon_data:
+ * mon_L3_00
+ * mon_L3_01
+ * mon_L3_02
+ * ...
+ *
+ * Each domain directory has one file per event:
+ * ./mon_L3_00/:
+ * llc_occupancy
+ *
+ */
+int mkdir_mondata_all(struct kernfs_node *parent_kn,
+			     struct resctrl_group *prgrp,
+			     struct kernfs_node **dest_kn)
+{
+	struct resctrl_resource *r;
+	struct kernfs_node *kn;
+	int ret;
+
+	/*
+	 * Create the mon_data directory first.
+	 */
+	ret = mongroup_create_dir(parent_kn, NULL, "mon_data", &kn);
+	if (ret)
+		return ret;
+
+	if (dest_kn)
+		*dest_kn = kn;
+
+	/*
+	 * Create the subdirectories for each domain. Note that all events
+	 * in a domain like L3 are grouped into a resource whose domain is L3
+	 */
+	for_each_resctrl_resource(r) {
+		if (r->mon_enabled) {
+			ret = mkdir_mondata_subdir_alldom(kn, r, prgrp);
+			if (ret)
+				goto out_destroy;
+		}
+	}
+
+	kernfs_activate(kn);
+
+	return 0;
+
+out_destroy:
+	kernfs_remove(kn);
+	return ret;
+}
diff --git a/fs/resctrlfs.c b/fs/resctrlfs.c
index 742e08e..330862d 100644
--- a/fs/resctrlfs.c
+++ b/fs/resctrlfs.c
@@ -72,6 +72,7 @@ static int resctrl_group_add_file(struct kernfs_node *parent_kn, struct rftype *
 	int ret;
 
 	kn = __kernfs_create_file(parent_kn, rft->name, rft->mode,
+				  GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
 				  0, rft->kf_ops, rft, NULL, NULL);
 	if (IS_ERR(kn))
 		return PTR_ERR(kn);
-- 
1.8.3.1

