Commit 26a57873 authored by Wang ShaoBo's avatar Wang ShaoBo Committed by Zheng Zengkai
Browse files

arm64/mpam: Using software-defined id for rdtgroup instead of 32-bit integer



hulk inclusion
category: feature
feature: ARM MPAM support
bugzilla: 48265
CVE: NA

--------------------------------

Currently we use partid and pmg (Performance Monitoring Group) to filter
some performance events so that the performance of a particular partid
and pmg can be monitored, but pmg looks useless except for making a
filter with partid, especially when pmg varies in different MPAM resources,
it makes difficult to allocate pmg resource when creating new mon group
in resctrl sysfs, even causes a lot of waste.

So we use a software-defined sd_closid instead of 32-bit integer to label
each rdtgroup (including mon group), sd_closid include intpartid for
allocation and reqpartid for synchronizing configuration and monitoring,
Given MPAM has narrowing feature, also includes the concept (hw_reqpartid,
hw_intpartid we named), when narrowing is not supported, number of intpartid
and reqpartid equals to hw_reqpartid, otherwise intpartid and reqpartid is
related to minimum number of both hw_reqpartid and hw_intpartid supported
across different resources, by using this way, not only we solve above
problem but also use relax reqpartid for creating new mon group. additionally,
pmg is also preferred when it is available.

e.g.
     hw_intpartid:  0  1  2  3  4  5  6  7
     hw_reqpartid:  0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15

                    |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
                                            |  |  |  |  |  |  |  |
resctrl ctrl group: p0 p1 p2 p3 p4 p5 p6 p7 |  |  |  |  |  |  |  |
                          |     |
resctrl mon group:        |     +-----------------------m4 m5 m6 m7
                          +-----------------m0 m1 m2 m3
                          In this case, use extra reqpartid to create
                          m0, m1, m2, m3 mon group for p2 ctrl group,
                          and m4, m5, m6, m7 for p4.

As we know reqpartid both supports allocating and monitoring filter, we
should synchronize config of ctrl group with child mon groups under this
design, each mon group's configuration indexed by a reqpartid that called
slave is closely following it's father ctrl group that called master
whenever configuration changes. not only that, we let task_struct keep
both intpartid and reqpartid so we can know if tasks belong to a same
ctrl group through intpartid and change cpu's partid by writing MPAMx_ELx
through reqpartid when tasks switching.

Signed-off-by: default avatarWang ShaoBo <bobo.shaobowang@huawei.com>
Reviewed-by: default avatarXiongfeng Wang <wangxiongfeng2@huawei.com>
Reviewed-by: default avatarCheng Jian <cj.chengjian@huawei.com>
Signed-off-by: default avatarYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent ad9850b5
Loading
Loading
Loading
Loading
+7 −11
Original line number Diff line number Diff line
@@ -185,7 +185,7 @@ struct resctrl_staged_config {
	hw_closid_t     hw_closid;
	u32             new_ctrl;
	bool            have_new_ctrl;
	enum resctrl_conf_type  new_ctrl_type;
	enum resctrl_conf_type  conf_type;
};

/* later move to resctrl common directory */
@@ -257,14 +257,10 @@ void post_resctrl_mount(void);
#define mpam_readl(addr) readl(addr)
#define mpam_writel(v, addr) writel(v, addr)

/**
 * struct msr_param - set a range of MSRs from a domain
 * @res:	The resource to use
 * @value:	value
 */
struct sd_closid;

struct msr_param {
	struct resctrl_resource	*res;
	u64			value;
	struct sd_closid *closid;
};

/**
@@ -299,13 +295,13 @@ struct raw_resctrl_resource {
	u16                 hdl_wd;

	void (*msr_update)(struct resctrl_resource *r, struct rdt_domain *d,
					struct list_head *opt_list, int partid);
	u64 (*msr_read)(struct rdt_domain *d, int partid);
			struct list_head *opt_list, struct msr_param *para);
	u64 (*msr_read)(struct rdt_domain *d, struct msr_param *para);

	int			data_width;
	const char		*format_str;
	int (*parse_ctrlval)(char *buf, struct raw_resctrl_resource *r,
			struct resctrl_staged_config *cfg, hw_closid_t closid);
			struct resctrl_staged_config *cfg);

	u16                num_mon;
	u64 (*mon_read)(struct rdt_domain *d, void *md_priv);
+2 −0
Original line number Diff line number Diff line
@@ -95,6 +95,8 @@
 * Set MPAMCFG_INTPARTID internal bit
 */
#define MPAMCFG_INTPARTID_INTERNAL  BIT(16)
#define INTPARTID_INTPARTID_MASK    (BIT(15) - 1)
#define MPAMCFG_INTPARTID_INTPARTID_GET(r) (r & INTPARTID_INTPARTID_MASK)
/*
 * Set MPAMCFG_PART_SEL internal bit
 */
+39 −7
Original line number Diff line number Diff line
@@ -49,12 +49,20 @@ struct mongroup {
	int         init;
};

/**
 * struct sd_closid - software defined closid
 * @intpartid:  closid for this rdtgroup only for allocation
 * @weak_closid:    closid for synchronizing configuration and monitoring
 */
struct sd_closid {
	u32         intpartid;
	u32         reqpartid;
};

/**
 * struct rdtgroup - store rdtgroup's data in resctrl file system.
 * @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
@@ -66,7 +74,7 @@ struct mongroup {
struct rdtgroup {
	struct kernfs_node  *kn;
	struct list_head    resctrl_group_list;
	u32         closid;
	struct sd_closid    closid;
	struct cpumask      cpu_mask;
	int         flags;
	atomic_t        waitcount;
@@ -80,12 +88,17 @@ void schemata_list_destroy(void);

int resctrl_lru_request_mon(void);

int alloc_mon_id(void);
void free_mon_id(u32 id);
int alloc_rmid(void);
void free_rmid(u32 id);

enum closid_type {
	CLOSID_INT    = 0x1,
	CLOSID_REQ      = 0x2,
	CLOSID_NUM_TYPES,
};
int resctrl_id_init(void);
int resctrl_id_alloc(void);
void resctrl_id_free(int id);
int resctrl_id_alloc(enum closid_type);
void resctrl_id_free(enum closid_type, int id);

void update_cpu_closid_rmid(void *info);
void update_closid_rmid(const struct cpumask *cpu_mask, struct resctrl_group *r);
@@ -127,6 +140,25 @@ int resctrl_mkdir_mondata_all_subdir(struct kernfs_node *parent_kn,
struct resctrl_resource *
mpam_resctrl_get_resource(enum resctrl_resource_level level);

int resctrl_update_groups_config(struct rdtgroup *rdtgrp);

#define RESCTRL_MAX_CLOSID 32

/*
 * left 16 bits of closid store parent(master)'s
 * closid, the reset store current group's closid,
 * this used for judging if tasks are allowed to move
 * another ctrlmon/mon group, it is because when
 * a mon group is permited to allocated another
 * closid different from it's parent, only closid
 * is not sufficient to do that.
 */
#define TASK_CLOSID_SET(prclosid, closid)    \
		((prclosid << 16) | closid)

#define TASK_CLOSID_CUR_GET(closid)   \
		(closid & GENMASK(15, 0))
#define TASK_CLOSID_PR_GET(closid)    \
		((closid & GENMASK(31, 16)) >> 16)

#endif /* _ASM_ARM64_RESCTRL_H */
+80 −31
Original line number Diff line number Diff line
@@ -115,10 +115,16 @@ static int resctrl_group_update_domains(struct rdtgroup *rdtgrp,
			struct resctrl_resource *r)
{
	int i;
	u32 partid;
	struct rdt_domain *d;
	struct raw_resctrl_resource *rr;
	struct resctrl_staged_config *cfg;
	hw_closid_t hw_closid;
	struct sd_closid closid;
	struct list_head *head;
	struct rdtgroup *entry;
	struct msr_param para;

	para.closid = &closid;

	rr = r->res;
	list_for_each_entry(d, &r->domains, list) {
@@ -127,15 +133,38 @@ static int resctrl_group_update_domains(struct rdtgroup *rdtgrp,
			if (!cfg[i].have_new_ctrl)
				continue;

			partid = hw_closid_val(cfg[i].hw_closid);
			/* apply cfg */
			if (d->ctrl_val[partid] == cfg[i].new_ctrl)
				continue;
			/*
			 * for ctrl group configuration, hw_closid of cfg[i]
			 * equals to rdtgrp->closid.intpartid.
			 */
			closid.intpartid = hw_closid_val(cfg[i].hw_closid);

			d->ctrl_val[partid] = cfg[i].new_ctrl;
			/* if ctrl group's config has changed, refresh it first. */
			if (d->ctrl_val[closid.intpartid] != cfg[i].new_ctrl) {
				/*
				 * duplicate ctrl group's configuration indexed
				 * by intpartid from domain ctrl_val array.
				 */
				resctrl_cdp_map(clos, rdtgrp->closid.reqpartid,
						cfg[i].conf_type, hw_closid);
				closid.reqpartid = hw_closid_val(hw_closid);

				d->ctrl_val[closid.intpartid] = cfg[i].new_ctrl;
				d->have_new_ctrl = true;
				rr->msr_update(r, d, NULL, &para);
			}
			/*
			 * we should synchronize all child mon groups'
			 * configuration from this ctrl rdtgrp
			 */
			head = &rdtgrp->mon.crdtgrp_list;
			list_for_each_entry(entry, head, mon.crdtgrp_list) {
				resctrl_cdp_map(clos, entry->closid.reqpartid,
					cfg[i].conf_type, hw_closid);
				closid.reqpartid = hw_closid_val(hw_closid);

			rr->msr_update(r, d, NULL, partid);
				rr->msr_update(r, d, NULL, &para);
			}
		}
	}

@@ -171,8 +200,10 @@ static int parse_line(char *line, struct resctrl_resource *r,
	list_for_each_entry(d, &r->domains, list) {
		if (d->id == dom_id) {
			resctrl_cdp_map(clos, closid, t, hw_closid);
			if (rr->parse_ctrlval(dom, rr, &d->staged_cfg[t], hw_closid))
			if (rr->parse_ctrlval(dom, rr, &d->staged_cfg[t]))
				return -EINVAL;
			d->staged_cfg[t].hw_closid = hw_closid;
			d->staged_cfg[t].conf_type = t;
			goto next;
		}
	}
@@ -231,7 +262,7 @@ ssize_t resctrl_group_schemata_write(struct kernfs_open_file *of,

	rdt_last_cmd_clear();

	closid = rdtgrp->closid;
	closid = rdtgrp->closid.intpartid;

	for_each_supported_resctrl_exports(res) {
		r = &res->resctrl_res;
@@ -264,15 +295,7 @@ ssize_t resctrl_group_schemata_write(struct kernfs_open_file *of,
			goto out;
	}

	for_each_supported_resctrl_exports(res) {
		r = &res->resctrl_res;
		if (r->alloc_enabled) {
			ret = resctrl_group_update_domains(rdtgrp, r);
			if (ret)
				goto out;
		}
	}

	ret = resctrl_update_groups_config(rdtgrp);
out:
	resctrl_group_kn_unlock(of->kn);
	return ret ?: nbytes;
@@ -289,21 +312,24 @@ ssize_t resctrl_group_schemata_write(struct kernfs_open_file *of,
 * a single "S" simply.
 */
static void show_doms(struct seq_file *s, struct resctrl_resource *r,
		char *schema_name, int partid)
		char *schema_name, struct sd_closid *closid)
{
	struct raw_resctrl_resource *rr = r->res;
	struct rdt_domain *dom;
	struct msr_param para;
	bool sep = false;
	bool rg = false;
	bool prev_auto_fill = false;
	u32 reg_val;

	para.closid = closid;

	if (r->dom_num > RESCTRL_SHOW_DOM_MAX_NUM)
		rg = true;

	seq_printf(s, "%*s:", max_name_width, schema_name);
	list_for_each_entry(dom, &r->domains, list) {
		reg_val = rr->msr_read(dom, partid);
		reg_val = rr->msr_read(dom, &para);

		if (rg && reg_val == r->default_ctrl &&
				prev_auto_fill == true)
@@ -331,7 +357,7 @@ int resctrl_group_schemata_show(struct kernfs_open_file *of,
	struct resctrl_schema *rs;
	int ret = 0;
	hw_closid_t hw_closid;
	u32 partid;
	struct sd_closid closid;

	rdtgrp = resctrl_group_kn_lock_live(of->kn);
	if (rdtgrp) {
@@ -340,11 +366,15 @@ int resctrl_group_schemata_show(struct kernfs_open_file *of,
			if (!r)
				continue;
			if (r->alloc_enabled) {
				resctrl_cdp_map(clos, rdtgrp->closid,
				resctrl_cdp_map(clos, rdtgrp->closid.intpartid,
					rs->conf_type, hw_closid);
				closid.intpartid = hw_closid_val(hw_closid);

				resctrl_cdp_map(clos, rdtgrp->closid.reqpartid,
					rs->conf_type, hw_closid);
				partid = hw_closid_val(hw_closid);
				if (partid < mpam_sysprops_num_partid())
					show_doms(s, r, rs->name, partid);
				closid.reqpartid = hw_closid_val(hw_closid);

				show_doms(s, r, rs->name, &closid);
			}
		}
	} else {
@@ -465,7 +495,8 @@ static int resctrl_mkdir_mondata_dom(struct kernfs_node *parent_kn,

	md.u.rid = r->rid;
	md.u.domid = d->id;
	resctrl_cdp_map(clos, prgrp->closid, s->conf_type, hw_closid);
	/* monitoring use reqpartid (reqpartid) */
	resctrl_cdp_map(clos, prgrp->closid.reqpartid, s->conf_type, hw_closid);
	md.u.partid = hw_closid_val(hw_closid);
	resctrl_cdp_map(mon, prgrp->mon.mon, s->conf_type, hw_monid);
	md.u.mon = hw_monid_val(hw_monid);
@@ -611,9 +642,9 @@ int resctrl_group_init_alloc(struct rdtgroup *rdtgrp)
	list_for_each_entry(s, &resctrl_all_schema, list) {
		r = s->res;
		if (r->rid == RDT_RESOURCE_MC) {
			rdtgroup_init_mba(r, rdtgrp->closid);
			rdtgroup_init_mba(r, rdtgrp->closid.intpartid);
		} else {
			ret = rdtgroup_init_cat(s, rdtgrp->closid);
			ret = rdtgroup_init_cat(s, rdtgrp->closid.intpartid);
			if (ret < 0)
				return ret;
		}
@@ -627,3 +658,21 @@ int resctrl_group_init_alloc(struct rdtgroup *rdtgrp)

	return 0;
}

int resctrl_update_groups_config(struct rdtgroup *rdtgrp)
{
	int ret = 0;
	struct resctrl_resource *r;
	struct mpam_resctrl_res *res;

	for_each_supported_resctrl_exports(res) {
		r = &res->resctrl_res;
		if (r->alloc_enabled) {
			ret = resctrl_group_update_domains(rdtgrp, r);
			if (ret)
				break;
		}
	}

	return ret;
}
+29 −16
Original line number Diff line number Diff line
@@ -965,7 +965,7 @@ static u32 mpam_device_read_csu_mon(struct mpam_device *dev,
	clt = MSMON_CFG_CTL_MATCH_PARTID | MSMON_CFG_CSU_TYPE;
	if (args->match_pmg)
		clt |= MSMON_CFG_CTL_MATCH_PMG;
	flt = args->partid |
	flt = args->closid.reqpartid |
		(args->pmg << MSMON_CFG_CSU_FLT_PMG_SHIFT);

	/*
@@ -1014,7 +1014,7 @@ static u32 mpam_device_read_mbwu_mon(struct mpam_device *dev,
	clt = MSMON_CFG_CTL_MATCH_PARTID | MSMON_CFG_MBWU_TYPE;
	if (args->match_pmg)
		clt |= MSMON_CFG_CTL_MATCH_PMG;
	flt = args->partid |
	flt = args->closid.reqpartid |
		(args->pmg << MSMON_CFG_MBWU_FLT_PMG_SHIFT);

	/*
@@ -1096,13 +1096,20 @@ static void mpam_device_narrow_map(struct mpam_device *dev, u32 partid,
	mpam_write_reg(dev, MPAMCFG_INTPARTID, intpartid);
}

static int mpam_device_config(struct mpam_device *dev, u32 partid,
static int
mpam_device_config(struct mpam_device *dev, struct sd_closid *closid,
					struct mpam_config *cfg)
{
	u16 cmax = GENMASK(dev->cmax_wd, 0);
	u32 pri_val = 0;
	u16 intpri, dspri, max_intpri, max_dspri;
	u32 mbw_pbm, mbw_max;
	/*
	 * if dev supports narrowing, narrowing first and then apply this slave's
	 * configuration.
	 */
	u32 intpartid = closid->intpartid;
	u32 partid = closid->reqpartid;

	lockdep_assert_held(&dev->lock);

@@ -1115,9 +1122,9 @@ static int mpam_device_config(struct mpam_device *dev, u32 partid,
	 */
	if (mpam_has_feature(mpam_feat_part_nrw, dev->features)) {
		if (cfg && mpam_has_feature(mpam_feat_part_nrw, cfg->valid))
			mpam_device_narrow_map(dev, partid, cfg->intpartid);
			mpam_device_narrow_map(dev, partid, intpartid);
		/* intpartid success, set 16 bit to 1*/
		partid = PART_SEL_SET_INTERNAL(cfg->intpartid);
		partid = PART_SEL_SET_INTERNAL(intpartid);
	}

	mpam_write_reg(dev, MPAMCFG_PART_SEL, partid);
@@ -1199,7 +1206,7 @@ static int mpam_device_config(struct mpam_device *dev, u32 partid,
static void mpam_component_device_sync(void *__ctx)
{
	int err = 0;
	u32 partid;
	u32 reqpartid;
	unsigned long flags;
	struct mpam_device *dev;
	struct mpam_device_sync *ctx = (struct mpam_device_sync *)__ctx;
@@ -1220,12 +1227,16 @@ static void mpam_component_device_sync(void *__ctx)
		err = 0;
		spin_lock_irqsave(&dev->lock, flags);
		if (args) {
			partid = args->partid;
			/*
			 * at this time reqpartid shows where the
			 * configuration was stored.
			 */
			reqpartid = args->closid.reqpartid;
			if (ctx->config_mon)
				err = mpam_device_frob_mon(dev, ctx);
			else
				err = mpam_device_config(dev, partid,
					&comp->cfg[partid]);
				err = mpam_device_config(dev, &args->closid,
					&comp->cfg[reqpartid]);
		} else {
			mpam_reset_device(comp, dev);
		}
@@ -1357,11 +1368,8 @@ static void mpam_component_read_mpamcfg(void *_ctx)
		return;

	reg = args->reg;
	/*
	 * args->partid is possible reqpartid or intpartid,
	 * if narrow enabled, it should be intpartid.
	 */
	partid = args->partid;

	partid = args->closid.reqpartid;

	list_for_each_entry(dev, &comp->devices, comp_list) {
		if (!cpumask_test_cpu(smp_processor_id(),
@@ -1369,8 +1377,13 @@ static void mpam_component_read_mpamcfg(void *_ctx)
			continue;

		spin_lock_irqsave(&dev->lock, flags);
		if (mpam_has_feature(mpam_feat_part_nrw, dev->features))
			partid = PART_SEL_SET_INTERNAL(partid);
		if (mpam_has_feature(mpam_feat_part_nrw, dev->features)) {
			/*
			 * partid is possible reqpartid or intpartid,
			 * if narrow enabled, it should be intpartid.
			 */
			partid = PART_SEL_SET_INTERNAL(args->closid.intpartid);
		}
		mpam_write_reg(dev, MPAMCFG_PART_SEL, partid);
		wmb();
		val = mpam_read_reg(dev, reg);
Loading