Commit 5c3b63cd authored by James Morse's avatar James Morse Committed by Borislav Petkov
Browse files

x86/resctrl: Merge the CDP resources



resctrl uses struct rdt_resource to describe the available hardware
resources. The domains of the CDP aliases share a single ctrl_val[]
array. The only differences between the struct rdt_hw_resource aliases
is the name and conf_type.

The name from struct rdt_hw_resource is visible to user-space. To
support another architecture, as many user-visible details should be
handled in the filesystem parts of the code that is common to all
architectures. The name and conf_type go together.

Remove conf_type and the CDP aliases. When CDP is supported and enabled,
schemata_list_create() can create two schemata using the single
resource, generating the CODE/DATA suffix to the schema name itself.

This allows the alloc_ctrlval_array() and complications around free()ing
the ctrl_val arrays to be removed.

Signed-off-by: default avatarJames Morse <james.morse@arm.com>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Reviewed-by: default avatarJamie Iles <jamie@nuviainc.com>
Reviewed-by: default avatarReinette Chatre <reinette.chatre@intel.com>
Tested-by: default avatarBabu Moger <babu.moger@amd.com>
Link: https://lkml.kernel.org/r/20210728170637.25610-25-james.morse@arm.com
parent 327364d5
Loading
Loading
Loading
Loading
+12 −166
Original line number Diff line number Diff line
@@ -62,7 +62,6 @@ mba_wrmsr_amd(struct rdt_domain *d, struct msr_param *m,
struct rdt_hw_resource rdt_resources_all[] = {
	[RDT_RESOURCE_L3] =
	{
		.conf_type			= CDP_NONE,
		.r_resctrl = {
			.rid			= RDT_RESOURCE_L3,
			.name			= "L3",
@@ -78,45 +77,8 @@ struct rdt_hw_resource rdt_resources_all[] = {
		.msr_base		= MSR_IA32_L3_CBM_BASE,
		.msr_update		= cat_wrmsr,
	},
	[RDT_RESOURCE_L3DATA] =
	{
		.conf_type			= CDP_DATA,
		.r_resctrl = {
			.rid			= RDT_RESOURCE_L3DATA,
			.name			= "L3DATA",
			.cache_level		= 3,
			.cache = {
				.min_cbm_bits	= 1,
			},
			.domains		= domain_init(RDT_RESOURCE_L3DATA),
			.parse_ctrlval		= parse_cbm,
			.format_str		= "%d=%0*x",
			.fflags			= RFTYPE_RES_CACHE,
		},
		.msr_base		= MSR_IA32_L3_CBM_BASE,
		.msr_update		= cat_wrmsr,
	},
	[RDT_RESOURCE_L3CODE] =
	{
		.conf_type			= CDP_CODE,
		.r_resctrl = {
			.rid			= RDT_RESOURCE_L3CODE,
			.name			= "L3CODE",
			.cache_level		= 3,
			.cache = {
				.min_cbm_bits	= 1,
			},
			.domains		= domain_init(RDT_RESOURCE_L3CODE),
			.parse_ctrlval		= parse_cbm,
			.format_str		= "%d=%0*x",
			.fflags			= RFTYPE_RES_CACHE,
		},
		.msr_base		= MSR_IA32_L3_CBM_BASE,
		.msr_update		= cat_wrmsr,
	},
	[RDT_RESOURCE_L2] =
	{
		.conf_type			= CDP_NONE,
		.r_resctrl = {
			.rid			= RDT_RESOURCE_L2,
			.name			= "L2",
@@ -132,45 +94,8 @@ struct rdt_hw_resource rdt_resources_all[] = {
		.msr_base		= MSR_IA32_L2_CBM_BASE,
		.msr_update		= cat_wrmsr,
	},
	[RDT_RESOURCE_L2DATA] =
	{
		.conf_type			= CDP_DATA,
		.r_resctrl = {
			.rid			= RDT_RESOURCE_L2DATA,
			.name			= "L2DATA",
			.cache_level		= 2,
			.cache = {
				.min_cbm_bits	= 1,
			},
			.domains		= domain_init(RDT_RESOURCE_L2DATA),
			.parse_ctrlval		= parse_cbm,
			.format_str		= "%d=%0*x",
			.fflags			= RFTYPE_RES_CACHE,
		},
		.msr_base		= MSR_IA32_L2_CBM_BASE,
		.msr_update		= cat_wrmsr,
	},
	[RDT_RESOURCE_L2CODE] =
	{
		.conf_type			= CDP_CODE,
		.r_resctrl = {
			.rid			= RDT_RESOURCE_L2CODE,
			.name			= "L2CODE",
			.cache_level		= 2,
			.cache = {
				.min_cbm_bits	= 1,
			},
			.domains		= domain_init(RDT_RESOURCE_L2CODE),
			.parse_ctrlval		= parse_cbm,
			.format_str		= "%d=%0*x",
			.fflags			= RFTYPE_RES_CACHE,
		},
		.msr_base		= MSR_IA32_L2_CBM_BASE,
		.msr_update		= cat_wrmsr,
	},
	[RDT_RESOURCE_MBA] =
	{
		.conf_type			= CDP_NONE,
		.r_resctrl = {
			.rid			= RDT_RESOURCE_MBA,
			.name			= "MB",
@@ -339,40 +264,24 @@ static void rdt_get_cache_alloc_cfg(int idx, struct rdt_resource *r)
	r->alloc_enabled = true;
}

static void rdt_get_cdp_config(int level, int type)
static void rdt_get_cdp_config(int level)
{
	struct rdt_resource *r_l = &rdt_resources_all[level].r_resctrl;
	struct rdt_hw_resource *hw_res_l = resctrl_to_arch_res(r_l);
	struct rdt_resource *r = &rdt_resources_all[type].r_resctrl;
	struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);

	hw_res->num_closid = hw_res_l->num_closid;
	r->cache.cbm_len = r_l->cache.cbm_len;
	r->default_ctrl = r_l->default_ctrl;
	r->cache.shareable_bits = r_l->cache.shareable_bits;
	r->data_width = (r->cache.cbm_len + 3) / 4;
	r->alloc_capable = true;
	/*
	 * By default, CDP is disabled. CDP can be enabled by mount parameter
	 * "cdp" during resctrl file system mount time.
	 */
	r->alloc_enabled = false;
	rdt_resources_all[level].cdp_enabled = false;
	rdt_resources_all[type].cdp_enabled = false;
	r_l->cdp_capable = true;
	r->cdp_capable = true;
	rdt_resources_all[level].r_resctrl.cdp_capable = true;
}

static void rdt_get_cdp_l3_config(void)
{
	rdt_get_cdp_config(RDT_RESOURCE_L3, RDT_RESOURCE_L3DATA);
	rdt_get_cdp_config(RDT_RESOURCE_L3, RDT_RESOURCE_L3CODE);
	rdt_get_cdp_config(RDT_RESOURCE_L3);
}

static void rdt_get_cdp_l2_config(void)
{
	rdt_get_cdp_config(RDT_RESOURCE_L2, RDT_RESOURCE_L2DATA);
	rdt_get_cdp_config(RDT_RESOURCE_L2, RDT_RESOURCE_L2CODE);
	rdt_get_cdp_config(RDT_RESOURCE_L2);
}

static void
@@ -509,57 +418,6 @@ void setup_default_ctrlval(struct rdt_resource *r, u32 *dc, u32 *dm)
	}
}

static u32 *alloc_ctrlval_array(struct rdt_resource *r, struct rdt_domain *d,
				bool mba_sc)
{
	/* these are for the underlying hardware, they may not match r/d */
	struct rdt_domain *underlying_domain;
	struct rdt_hw_resource *hw_res;
	struct rdt_hw_domain *hw_dom;
	bool remapped;

	switch (r->rid) {
	case RDT_RESOURCE_L3DATA:
	case RDT_RESOURCE_L3CODE:
		hw_res = &rdt_resources_all[RDT_RESOURCE_L3];
		remapped = true;
		break;
	case RDT_RESOURCE_L2DATA:
	case RDT_RESOURCE_L2CODE:
		hw_res = &rdt_resources_all[RDT_RESOURCE_L2];
		remapped = true;
		break;
	default:
		hw_res = resctrl_to_arch_res(r);
		remapped = false;
	}

	/*
	 * If we changed the resource, we need to search for the underlying
	 * domain. Doing this for all resources would make it tricky to add the
	 * first resource, as domains aren't added to a resource list until
	 * after the ctrlval arrays have been allocated.
	 */
	if (remapped)
		underlying_domain = rdt_find_domain(&hw_res->r_resctrl, d->id,
						    NULL);
	else
		underlying_domain = d;
	hw_dom = resctrl_to_arch_dom(underlying_domain);

	if (mba_sc) {
		if (hw_dom->mbps_val)
			return hw_dom->mbps_val;
		return kmalloc_array(hw_res->num_closid,
				     sizeof(*hw_dom->mbps_val), GFP_KERNEL);
	} else {
		if (hw_dom->ctrl_val)
			return hw_dom->ctrl_val;
		return kmalloc_array(hw_res->num_closid,
				     sizeof(*hw_dom->ctrl_val), GFP_KERNEL);
	}
}

static int domain_setup_ctrlval(struct rdt_resource *r, struct rdt_domain *d)
{
	struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
@@ -567,11 +425,13 @@ static int domain_setup_ctrlval(struct rdt_resource *r, struct rdt_domain *d)
	struct msr_param m;
	u32 *dc, *dm;

	dc = alloc_ctrlval_array(r, d, false);
	dc = kmalloc_array(hw_res->num_closid, sizeof(*hw_dom->ctrl_val),
			   GFP_KERNEL);
	if (!dc)
		return -ENOMEM;

	dm = alloc_ctrlval_array(r, d, true);
	dm = kmalloc_array(hw_res->num_closid, sizeof(*hw_dom->mbps_val),
			   GFP_KERNEL);
	if (!dm) {
		kfree(dc);
		return -ENOMEM;
@@ -730,14 +590,8 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r)
		if (d->plr)
			d->plr->d = NULL;

		/* temporary: these four don't have a unique ctrlval array */
		if (r->rid != RDT_RESOURCE_L3CODE &&
		    r->rid != RDT_RESOURCE_L3DATA &&
		    r->rid != RDT_RESOURCE_L2CODE &&
		    r->rid != RDT_RESOURCE_L2DATA) {
		kfree(hw_dom->ctrl_val);
		kfree(hw_dom->mbps_val);
		}
		bitmap_free(d->rmid_busy_llc);
		kfree(d->mbm_total);
		kfree(d->mbm_local);
@@ -1017,11 +871,7 @@ static __init void rdt_init_res_defs_intel(void)
		hw_res = resctrl_to_arch_res(r);

		if (r->rid == RDT_RESOURCE_L3 ||
		    r->rid == RDT_RESOURCE_L3DATA ||
		    r->rid == RDT_RESOURCE_L3CODE ||
		    r->rid == RDT_RESOURCE_L2 ||
		    r->rid == RDT_RESOURCE_L2DATA ||
		    r->rid == RDT_RESOURCE_L2CODE) {
		    r->rid == RDT_RESOURCE_L2) {
			r->cache.arch_has_sparse_bitmaps = false;
			r->cache.arch_has_empty_bitmaps = false;
			r->cache.arch_has_per_cpu_cfg = false;
@@ -1041,11 +891,7 @@ static __init void rdt_init_res_defs_amd(void)
		hw_res = resctrl_to_arch_res(r);

		if (r->rid == RDT_RESOURCE_L3 ||
		    r->rid == RDT_RESOURCE_L3DATA ||
		    r->rid == RDT_RESOURCE_L3CODE ||
		    r->rid == RDT_RESOURCE_L2 ||
		    r->rid == RDT_RESOURCE_L2DATA ||
		    r->rid == RDT_RESOURCE_L2CODE) {
		    r->rid == RDT_RESOURCE_L2) {
			r->cache.arch_has_sparse_bitmaps = true;
			r->cache.arch_has_empty_bitmaps = true;
			r->cache.arch_has_per_cpu_cfg = true;
+0 −6
Original line number Diff line number Diff line
@@ -369,7 +369,6 @@ struct rdt_parse_data {

/**
 * struct rdt_hw_resource - arch private attributes of a resctrl resource
 * @conf_type:		The type that should be used when configuring. temporary
 * @r_resctrl:		Attributes of the resource used directly by resctrl.
 * @num_closid:		Maximum number of closid this hardware can support,
 *			regardless of CDP. This is exposed via
@@ -387,7 +386,6 @@ struct rdt_parse_data {
 * msr_update and msr_base.
 */
struct rdt_hw_resource {
	enum resctrl_conf_type	conf_type;
	struct rdt_resource	r_resctrl;
	u32			num_closid;
	unsigned int		msr_base;
@@ -418,11 +416,7 @@ extern struct dentry *debugfs_resctrl;

enum resctrl_res_level {
	RDT_RESOURCE_L3,
	RDT_RESOURCE_L3DATA,
	RDT_RESOURCE_L3CODE,
	RDT_RESOURCE_L2,
	RDT_RESOURCE_L2DATA,
	RDT_RESOURCE_L2CODE,
	RDT_RESOURCE_MBA,

	/* Must be the last */
+73 −67
Original line number Diff line number Diff line
@@ -1880,10 +1880,10 @@ void rdt_domain_reconfigure_cdp(struct rdt_resource *r)
	if (!r->cdp_capable)
		return;

	if (r == &rdt_resources_all[RDT_RESOURCE_L2DATA].r_resctrl)
	if (r->rid == RDT_RESOURCE_L2)
		l2_qos_cfg_update(&hw_res->cdp_enabled);

	if (r == &rdt_resources_all[RDT_RESOURCE_L3DATA].r_resctrl)
	if (r->rid == RDT_RESOURCE_L3)
		l3_qos_cfg_update(&hw_res->cdp_enabled);
}

@@ -1912,68 +1912,42 @@ static int set_mba_sc(bool mba_sc)
	return 0;
}

static int cdp_enable(int level, int data_type, int code_type)
static int cdp_enable(int level)
{
	struct rdt_resource *r_ldata = &rdt_resources_all[data_type].r_resctrl;
	struct rdt_resource *r_lcode = &rdt_resources_all[code_type].r_resctrl;
	struct rdt_resource *r_l = &rdt_resources_all[level].r_resctrl;
	int ret;

	if (!r_l->alloc_capable || !r_ldata->alloc_capable ||
	    !r_lcode->alloc_capable)
	if (!r_l->alloc_capable)
		return -EINVAL;

	ret = set_cache_qos_cfg(level, true);
	if (!ret) {
		r_l->alloc_enabled = false;
		r_ldata->alloc_enabled = true;
		r_lcode->alloc_enabled = true;
	if (!ret)
		rdt_resources_all[level].cdp_enabled = true;
		rdt_resources_all[data_type].cdp_enabled = true;
		rdt_resources_all[code_type].cdp_enabled = true;
	}

	return ret;
}

static void cdp_disable(int level, int data_type, int code_type)
static void cdp_disable(int level)
{
	struct rdt_hw_resource *r_hw = &rdt_resources_all[level];
	struct rdt_resource *r = &r_hw->r_resctrl;

	r->alloc_enabled = r->alloc_capable;

	if (r_hw->cdp_enabled) {
		rdt_resources_all[data_type].r_resctrl.alloc_enabled = false;
		rdt_resources_all[code_type].r_resctrl.alloc_enabled = false;
		set_cache_qos_cfg(level, false);
		r_hw->cdp_enabled = false;
		rdt_resources_all[data_type].cdp_enabled = false;
		rdt_resources_all[code_type].cdp_enabled = false;
	}
}

int resctrl_arch_set_cdp_enabled(enum resctrl_res_level l, bool enable)
{
	struct rdt_hw_resource *hw_res = &rdt_resources_all[l];
	enum resctrl_res_level code_type, data_type;

	if (!hw_res->r_resctrl.cdp_capable)
		return -EINVAL;

	if (l == RDT_RESOURCE_L3) {
		code_type = RDT_RESOURCE_L3CODE;
		data_type = RDT_RESOURCE_L3DATA;
	} else if (l == RDT_RESOURCE_L2) {
		code_type = RDT_RESOURCE_L2CODE;
		data_type = RDT_RESOURCE_L2DATA;
	} else {
		return -EINVAL;
	}

	if (enable)
		return cdp_enable(l, data_type, code_type);
		return cdp_enable(l);

	cdp_disable(l, data_type, code_type);
	cdp_disable(l);

	return 0;
}
@@ -2072,24 +2046,35 @@ static int rdt_enable_ctx(struct rdt_fs_context *ctx)
	return ret;
}

static int schemata_list_create(void)
static int schemata_list_add(struct rdt_resource *r, enum resctrl_conf_type type)
{
	struct resctrl_schema *s;
	struct rdt_resource *r;
	const char *suffix = "";
	int ret, cl;

	for_each_alloc_enabled_rdt_resource(r) {
	s = kzalloc(sizeof(*s), GFP_KERNEL);
	if (!s)
		return -ENOMEM;

	s->res = r;
		s->conf_type = resctrl_to_arch_res(r)->conf_type;
	s->num_closid = resctrl_arch_get_num_closid(r);
	if (resctrl_arch_get_cdp_enabled(r->rid))
		s->num_closid /= 2;

		ret = snprintf(s->name, sizeof(s->name), r->name);
	s->conf_type = type;
	switch (type) {
	case CDP_CODE:
		suffix = "CODE";
		break;
	case CDP_DATA:
		suffix = "DATA";
		break;
	case CDP_NONE:
		suffix = "";
		break;
	}

	ret = snprintf(s->name, sizeof(s->name), "%s%s", r->name, suffix);
	if (ret >= sizeof(s->name)) {
		kfree(s);
		return -EINVAL;
@@ -2100,8 +2085,7 @@ static int schemata_list_create(void)
	/*
	 * If CDP is supported by this resource, but not enabled,
	 * include the suffix. This ensures the tabular format of the
		 * schemata file does not change between mounts of the
		 * filesystem.
	 * schemata file does not change between mounts of the filesystem.
	 */
	if (r->cdp_capable && !resctrl_arch_get_cdp_enabled(r->rid))
		cl += 4;
@@ -2111,11 +2095,33 @@ static int schemata_list_create(void)

	INIT_LIST_HEAD(&s->list);
	list_add(&s->list, &resctrl_schema_all);
	}

	return 0;
}

static int schemata_list_create(void)
{
	struct rdt_resource *r;
	int ret = 0;

	for_each_alloc_enabled_rdt_resource(r) {
		if (resctrl_arch_get_cdp_enabled(r->rid)) {
			ret = schemata_list_add(r, CDP_CODE);
			if (ret)
				break;

			ret = schemata_list_add(r, CDP_DATA);
		} else {
			ret = schemata_list_add(r, CDP_NONE);
		}

		if (ret)
			break;
	}

	return ret;
}

static void schemata_list_destroy(void)
{
	struct resctrl_schema *s, *tmp;