Commit 42f6e869 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'x86_cache_for_v5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 resource control updates from Borislav Petkov:
 "A first round of changes towards splitting the arch-specific bits from
  the filesystem bits of resctrl, the ultimate goal being to support
  ARM's equivalent technology MPAM, with the same fs interface (James
  Morse)"

* tag 'x86_cache_for_v5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (25 commits)
  x86/resctrl: Make resctrl_arch_get_config() return its value
  x86/resctrl: Merge the CDP resources
  x86/resctrl: Expand resctrl_arch_update_domains()'s msr_param range
  x86/resctrl: Remove rdt_cdp_peer_get()
  x86/resctrl: Merge the ctrl_val arrays
  x86/resctrl: Calculate the index from the configuration type
  x86/resctrl: Apply offset correction when config is staged
  x86/resctrl: Make ctrlval arrays the same size
  x86/resctrl: Pass configuration type to resctrl_arch_get_config()
  x86/resctrl: Add a helper to read a closid's configuration
  x86/resctrl: Rename update_domains() to resctrl_arch_update_domains()
  x86/resctrl: Allow different CODE/DATA configurations to be staged
  x86/resctrl: Group staged configuration into a separate struct
  x86/resctrl: Move the schemata names into struct resctrl_schema
  x86/resctrl: Add a helper to read/set the CDP configuration
  x86/resctrl: Swizzle rdt_resource and resctrl_schema in pseudo_lock_region
  x86/resctrl: Pass the schema to resctrl filesystem functions
  x86/resctrl: Add resctrl_arch_get_num_closid()
  x86/resctrl: Store the effective num_closid in the schema
  x86/resctrl: Walk the resctrl schema list instead of an arch list
  ...
parents ced119b6 111136e6
Loading
Loading
Loading
Loading
+110 −166
Original line number Diff line number Diff line
@@ -57,128 +57,57 @@ static void
mba_wrmsr_amd(struct rdt_domain *d, struct msr_param *m,
	      struct rdt_resource *r);

#define domain_init(id) LIST_HEAD_INIT(rdt_resources_all[id].domains)
#define domain_init(id) LIST_HEAD_INIT(rdt_resources_all[id].r_resctrl.domains)

struct rdt_resource rdt_resources_all[] = {
struct rdt_hw_resource rdt_resources_all[] = {
	[RDT_RESOURCE_L3] =
	{
		.r_resctrl = {
			.rid			= RDT_RESOURCE_L3,
			.name			= "L3",
		.domains		= domain_init(RDT_RESOURCE_L3),
		.msr_base		= MSR_IA32_L3_CBM_BASE,
		.msr_update		= cat_wrmsr,
			.cache_level		= 3,
			.cache = {
				.min_cbm_bits	= 1,
			.cbm_idx_mult	= 1,
			.cbm_idx_offset	= 0,
			},
			.domains		= domain_init(RDT_RESOURCE_L3),
			.parse_ctrlval		= parse_cbm,
			.format_str		= "%d=%0*x",
			.fflags			= RFTYPE_RES_CACHE,
		},
	[RDT_RESOURCE_L3DATA] =
	{
		.rid			= RDT_RESOURCE_L3DATA,
		.name			= "L3DATA",
		.domains		= domain_init(RDT_RESOURCE_L3DATA),
		.msr_base		= MSR_IA32_L3_CBM_BASE,
		.msr_update		= cat_wrmsr,
		.cache_level		= 3,
		.cache = {
			.min_cbm_bits	= 1,
			.cbm_idx_mult	= 2,
			.cbm_idx_offset	= 0,
		},
		.parse_ctrlval		= parse_cbm,
		.format_str		= "%d=%0*x",
		.fflags			= RFTYPE_RES_CACHE,
	},
	[RDT_RESOURCE_L3CODE] =
	{
		.rid			= RDT_RESOURCE_L3CODE,
		.name			= "L3CODE",
		.domains		= domain_init(RDT_RESOURCE_L3CODE),
		.msr_base		= MSR_IA32_L3_CBM_BASE,
		.msr_update		= cat_wrmsr,
		.cache_level		= 3,
		.cache = {
			.min_cbm_bits	= 1,
			.cbm_idx_mult	= 2,
			.cbm_idx_offset	= 1,
		},
		.parse_ctrlval		= parse_cbm,
		.format_str		= "%d=%0*x",
		.fflags			= RFTYPE_RES_CACHE,
	},
	[RDT_RESOURCE_L2] =
	{
		.r_resctrl = {
			.rid			= RDT_RESOURCE_L2,
			.name			= "L2",
		.domains		= domain_init(RDT_RESOURCE_L2),
		.msr_base		= MSR_IA32_L2_CBM_BASE,
		.msr_update		= cat_wrmsr,
			.cache_level		= 2,
			.cache = {
				.min_cbm_bits	= 1,
			.cbm_idx_mult	= 1,
			.cbm_idx_offset	= 0,
		},
		.parse_ctrlval		= parse_cbm,
		.format_str		= "%d=%0*x",
		.fflags			= RFTYPE_RES_CACHE,
	},
	[RDT_RESOURCE_L2DATA] =
	{
		.rid			= RDT_RESOURCE_L2DATA,
		.name			= "L2DATA",
		.domains		= domain_init(RDT_RESOURCE_L2DATA),
		.msr_base		= MSR_IA32_L2_CBM_BASE,
		.msr_update		= cat_wrmsr,
		.cache_level		= 2,
		.cache = {
			.min_cbm_bits	= 1,
			.cbm_idx_mult	= 2,
			.cbm_idx_offset	= 0,
			},
			.domains		= domain_init(RDT_RESOURCE_L2),
			.parse_ctrlval		= parse_cbm,
			.format_str		= "%d=%0*x",
			.fflags			= RFTYPE_RES_CACHE,
		},
	[RDT_RESOURCE_L2CODE] =
	{
		.rid			= RDT_RESOURCE_L2CODE,
		.name			= "L2CODE",
		.domains		= domain_init(RDT_RESOURCE_L2CODE),
		.msr_base		= MSR_IA32_L2_CBM_BASE,
		.msr_update		= cat_wrmsr,
		.cache_level		= 2,
		.cache = {
			.min_cbm_bits	= 1,
			.cbm_idx_mult	= 2,
			.cbm_idx_offset	= 1,
		},
		.parse_ctrlval		= parse_cbm,
		.format_str		= "%d=%0*x",
		.fflags			= RFTYPE_RES_CACHE,
	},
	[RDT_RESOURCE_MBA] =
	{
		.r_resctrl = {
			.rid			= RDT_RESOURCE_MBA,
			.name			= "MB",
		.domains		= domain_init(RDT_RESOURCE_MBA),
			.cache_level		= 3,
			.domains		= domain_init(RDT_RESOURCE_MBA),
			.parse_ctrlval		= parse_bw,
			.format_str		= "%d=%*u",
			.fflags			= RFTYPE_RES_MB,
		},
	},
};

static unsigned int cbm_idx(struct rdt_resource *r, unsigned int closid)
{
	return closid * r->cache.cbm_idx_mult + r->cache.cbm_idx_offset;
}

/*
 * cache_alloc_hsw_probe() - Have to probe for Intel haswell server CPUs
 * as they do not have CPUID enumeration support for Cache allocation.
@@ -199,7 +128,8 @@ static unsigned int cbm_idx(struct rdt_resource *r, unsigned int closid)
 */
static inline void cache_alloc_hsw_probe(void)
{
	struct rdt_resource *r  = &rdt_resources_all[RDT_RESOURCE_L3];
	struct rdt_hw_resource *hw_res = &rdt_resources_all[RDT_RESOURCE_L3];
	struct rdt_resource *r  = &hw_res->r_resctrl;
	u32 l, h, max_cbm = BIT_MASK(20) - 1;

	if (wrmsr_safe(MSR_IA32_L3_CBM_BASE, max_cbm, 0))
@@ -211,7 +141,7 @@ static inline void cache_alloc_hsw_probe(void)
	if (l != max_cbm)
		return;

	r->num_closid = 4;
	hw_res->num_closid = 4;
	r->default_ctrl = max_cbm;
	r->cache.cbm_len = 20;
	r->cache.shareable_bits = 0xc0000;
@@ -225,7 +155,7 @@ static inline void cache_alloc_hsw_probe(void)
bool is_mba_sc(struct rdt_resource *r)
{
	if (!r)
		return rdt_resources_all[RDT_RESOURCE_MBA].membw.mba_sc;
		return rdt_resources_all[RDT_RESOURCE_MBA].r_resctrl.membw.mba_sc;

	return r->membw.mba_sc;
}
@@ -253,12 +183,13 @@ static inline bool rdt_get_mb_table(struct rdt_resource *r)

static bool __get_mem_config_intel(struct rdt_resource *r)
{
	struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
	union cpuid_0x10_3_eax eax;
	union cpuid_0x10_x_edx edx;
	u32 ebx, ecx, max_delay;

	cpuid_count(0x00000010, 3, &eax.full, &ebx, &ecx, &edx.full);
	r->num_closid = edx.split.cos_max + 1;
	hw_res->num_closid = edx.split.cos_max + 1;
	max_delay = eax.split.max_delay + 1;
	r->default_ctrl = MAX_MBA_BW;
	r->membw.arch_needs_linear = true;
@@ -287,12 +218,13 @@ static bool __get_mem_config_intel(struct rdt_resource *r)

static bool __rdt_get_mem_config_amd(struct rdt_resource *r)
{
	struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
	union cpuid_0x10_3_eax eax;
	union cpuid_0x10_x_edx edx;
	u32 ebx, ecx;

	cpuid_count(0x80000020, 1, &eax.full, &ebx, &ecx, &edx.full);
	r->num_closid = edx.split.cos_max + 1;
	hw_res->num_closid = edx.split.cos_max + 1;
	r->default_ctrl = MAX_MBA_BW_AMD;

	/* AMD does not use delay */
@@ -317,12 +249,13 @@ static bool __rdt_get_mem_config_amd(struct rdt_resource *r)

static void rdt_get_cache_alloc_cfg(int idx, struct rdt_resource *r)
{
	struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
	union cpuid_0x10_1_eax eax;
	union cpuid_0x10_x_edx edx;
	u32 ebx, ecx;

	cpuid_count(0x00000010, idx, &eax.full, &ebx, &ecx, &edx.full);
	r->num_closid = edx.split.cos_max + 1;
	hw_res->num_closid = edx.split.cos_max + 1;
	r->cache.cbm_len = eax.split.cbm_len + 1;
	r->default_ctrl = BIT_MASK(eax.split.cbm_len + 1) - 1;
	r->cache.shareable_bits = ebx & r->default_ctrl;
@@ -331,43 +264,35 @@ 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];
	struct rdt_resource *r = &rdt_resources_all[type];

	r->num_closid = r_l->num_closid / 2;
	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[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
mba_wrmsr_amd(struct rdt_domain *d, struct msr_param *m, struct rdt_resource *r)
{
	unsigned int i;
	struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d);
	struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);

	for (i = m->low; i < m->high; i++)
		wrmsrl(r->msr_base + i, d->ctrl_val[i]);
		wrmsrl(hw_res->msr_base + i, hw_dom->ctrl_val[i]);
}

/*
@@ -389,19 +314,23 @@ mba_wrmsr_intel(struct rdt_domain *d, struct msr_param *m,
		struct rdt_resource *r)
{
	unsigned int i;
	struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d);
	struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);

	/*  Write the delay values for mba. */
	for (i = m->low; i < m->high; i++)
		wrmsrl(r->msr_base + i, delay_bw_map(d->ctrl_val[i], r));
		wrmsrl(hw_res->msr_base + i, delay_bw_map(hw_dom->ctrl_val[i], r));
}

static void
cat_wrmsr(struct rdt_domain *d, struct msr_param *m, struct rdt_resource *r)
{
	unsigned int i;
	struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d);
	struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);

	for (i = m->low; i < m->high; i++)
		wrmsrl(r->msr_base + cbm_idx(r, i), d->ctrl_val[i]);
		wrmsrl(hw_res->msr_base + i, hw_dom->ctrl_val[i]);
}

struct rdt_domain *get_domain_from_cpu(int cpu, struct rdt_resource *r)
@@ -417,16 +346,22 @@ struct rdt_domain *get_domain_from_cpu(int cpu, struct rdt_resource *r)
	return NULL;
}

u32 resctrl_arch_get_num_closid(struct rdt_resource *r)
{
	return resctrl_to_arch_res(r)->num_closid;
}

void rdt_ctrl_update(void *arg)
{
	struct msr_param *m = arg;
	struct rdt_hw_resource *hw_res = resctrl_to_arch_res(m->res);
	struct rdt_resource *r = m->res;
	int cpu = smp_processor_id();
	struct rdt_domain *d;

	d = get_domain_from_cpu(cpu, r);
	if (d) {
		r->msr_update(d, m, r);
		hw_res->msr_update(d, m, r);
		return;
	}
	pr_warn_once("cpu %d not found in any domain for resource %s\n",
@@ -468,6 +403,7 @@ struct rdt_domain *rdt_find_domain(struct rdt_resource *r, int id,

void setup_default_ctrlval(struct rdt_resource *r, u32 *dc, u32 *dm)
{
	struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
	int i;

	/*
@@ -476,7 +412,7 @@ void setup_default_ctrlval(struct rdt_resource *r, u32 *dc, u32 *dm)
	 * For Memory Allocation: Set b/w requested to 100%
	 * and the bandwidth in MBps to U32_MAX
	 */
	for (i = 0; i < r->num_closid; i++, dc++, dm++) {
	for (i = 0; i < hw_res->num_closid; i++, dc++, dm++) {
		*dc = r->default_ctrl;
		*dm = MBA_MAX_MBPS;
	}
@@ -484,26 +420,30 @@ void setup_default_ctrlval(struct rdt_resource *r, u32 *dc, u32 *dm)

static int domain_setup_ctrlval(struct rdt_resource *r, struct rdt_domain *d)
{
	struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
	struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d);
	struct msr_param m;
	u32 *dc, *dm;

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

	dm = kmalloc_array(r->num_closid, sizeof(*d->mbps_val), GFP_KERNEL);
	dm = kmalloc_array(hw_res->num_closid, sizeof(*hw_dom->mbps_val),
			   GFP_KERNEL);
	if (!dm) {
		kfree(dc);
		return -ENOMEM;
	}

	d->ctrl_val = dc;
	d->mbps_val = dm;
	hw_dom->ctrl_val = dc;
	hw_dom->mbps_val = dm;
	setup_default_ctrlval(r, dc, dm);

	m.low = 0;
	m.high = r->num_closid;
	r->msr_update(d, &m, r);
	m.high = hw_res->num_closid;
	hw_res->msr_update(d, &m, r);
	return 0;
}

@@ -560,6 +500,7 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r)
{
	int id = get_cpu_cacheinfo_id(cpu, r->cache_level);
	struct list_head *add_pos = NULL;
	struct rdt_hw_domain *hw_dom;
	struct rdt_domain *d;

	d = rdt_find_domain(r, id, &add_pos);
@@ -575,10 +516,11 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r)
		return;
	}

	d = kzalloc_node(sizeof(*d), GFP_KERNEL, cpu_to_node(cpu));
	if (!d)
	hw_dom = kzalloc_node(sizeof(*hw_dom), GFP_KERNEL, cpu_to_node(cpu));
	if (!hw_dom)
		return;

	d = &hw_dom->d_resctrl;
	d->id = id;
	cpumask_set_cpu(cpu, &d->cpu_mask);

@@ -607,6 +549,7 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r)
static void domain_remove_cpu(int cpu, struct rdt_resource *r)
{
	int id = get_cpu_cacheinfo_id(cpu, r->cache_level);
	struct rdt_hw_domain *hw_dom;
	struct rdt_domain *d;

	d = rdt_find_domain(r, id, NULL);
@@ -614,6 +557,7 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r)
		pr_warn("Couldn't find cache id for CPU %d\n", cpu);
		return;
	}
	hw_dom = resctrl_to_arch_dom(d);

	cpumask_clear_cpu(cpu, &d->cpu_mask);
	if (cpumask_empty(&d->cpu_mask)) {
@@ -646,16 +590,16 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r)
		if (d->plr)
			d->plr->d = NULL;

		kfree(d->ctrl_val);
		kfree(d->mbps_val);
		kfree(hw_dom->ctrl_val);
		kfree(hw_dom->mbps_val);
		bitmap_free(d->rmid_busy_llc);
		kfree(d->mbm_total);
		kfree(d->mbm_local);
		kfree(d);
		kfree(hw_dom);
		return;
	}

	if (r == &rdt_resources_all[RDT_RESOURCE_L3]) {
	if (r == &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl) {
		if (is_mbm_enabled() && cpu == d->mbm_work_cpu) {
			cancel_delayed_work(&d->mbm_over);
			mbm_setup_overflow_handler(d, 0);
@@ -732,13 +676,8 @@ static int resctrl_offline_cpu(unsigned int cpu)
static __init void rdt_init_padding(void)
{
	struct rdt_resource *r;
	int cl;

	for_each_alloc_capable_rdt_resource(r) {
		cl = strlen(r->name);
		if (cl > max_name_width)
			max_name_width = cl;

		if (r->data_width > max_data_width)
			max_data_width = r->data_width;
	}
@@ -827,19 +766,22 @@ static bool __init rdt_cpu_has(int flag)

static __init bool get_mem_config(void)
{
	struct rdt_hw_resource *hw_res = &rdt_resources_all[RDT_RESOURCE_MBA];

	if (!rdt_cpu_has(X86_FEATURE_MBA))
		return false;

	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
		return __get_mem_config_intel(&rdt_resources_all[RDT_RESOURCE_MBA]);
		return __get_mem_config_intel(&hw_res->r_resctrl);
	else if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
		return __rdt_get_mem_config_amd(&rdt_resources_all[RDT_RESOURCE_MBA]);
		return __rdt_get_mem_config_amd(&hw_res->r_resctrl);

	return false;
}

static __init bool get_rdt_alloc_resources(void)
{
	struct rdt_resource *r;
	bool ret = false;

	if (rdt_alloc_capable)
@@ -849,14 +791,16 @@ static __init bool get_rdt_alloc_resources(void)
		return false;

	if (rdt_cpu_has(X86_FEATURE_CAT_L3)) {
		rdt_get_cache_alloc_cfg(1, &rdt_resources_all[RDT_RESOURCE_L3]);
		r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
		rdt_get_cache_alloc_cfg(1, r);
		if (rdt_cpu_has(X86_FEATURE_CDP_L3))
			rdt_get_cdp_l3_config();
		ret = true;
	}
	if (rdt_cpu_has(X86_FEATURE_CAT_L2)) {
		/* CPUID 0x10.2 fields are same format at 0x10.1 */
		rdt_get_cache_alloc_cfg(2, &rdt_resources_all[RDT_RESOURCE_L2]);
		r = &rdt_resources_all[RDT_RESOURCE_L2].r_resctrl;
		rdt_get_cache_alloc_cfg(2, r);
		if (rdt_cpu_has(X86_FEATURE_CDP_L2))
			rdt_get_cdp_l2_config();
		ret = true;
@@ -870,6 +814,8 @@ static __init bool get_rdt_alloc_resources(void)

static __init bool get_rdt_mon_resources(void)
{
	struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;

	if (rdt_cpu_has(X86_FEATURE_CQM_OCCUP_LLC))
		rdt_mon_features |= (1 << QOS_L3_OCCUP_EVENT_ID);
	if (rdt_cpu_has(X86_FEATURE_CQM_MBM_TOTAL))
@@ -880,7 +826,7 @@ static __init bool get_rdt_mon_resources(void)
	if (!rdt_mon_features)
		return false;

	return !rdt_get_mon_l3_config(&rdt_resources_all[RDT_RESOURCE_L3]);
	return !rdt_get_mon_l3_config(r);
}

static __init void __check_quirks_intel(void)
@@ -918,42 +864,40 @@ static __init bool get_rdt_resources(void)

static __init void rdt_init_res_defs_intel(void)
{
	struct rdt_hw_resource *hw_res;
	struct rdt_resource *r;

	for_each_rdt_resource(r) {
		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;
		} else if (r->rid == RDT_RESOURCE_MBA) {
			r->msr_base = MSR_IA32_MBA_THRTL_BASE;
			r->msr_update = mba_wrmsr_intel;
			hw_res->msr_base = MSR_IA32_MBA_THRTL_BASE;
			hw_res->msr_update = mba_wrmsr_intel;
		}
	}
}

static __init void rdt_init_res_defs_amd(void)
{
	struct rdt_hw_resource *hw_res;
	struct rdt_resource *r;

	for_each_rdt_resource(r) {
		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;
		} else if (r->rid == RDT_RESOURCE_MBA) {
			r->msr_base = MSR_IA32_MBA_BW_BASE;
			r->msr_update = mba_wrmsr_amd;
			hw_res->msr_base = MSR_IA32_MBA_BW_BASE;
			hw_res->msr_update = mba_wrmsr_amd;
		}
	}
}
+117 −46
Original line number Diff line number Diff line
@@ -57,20 +57,23 @@ static bool bw_validate(char *buf, unsigned long *data, struct rdt_resource *r)
	return true;
}

int parse_bw(struct rdt_parse_data *data, struct rdt_resource *r,
int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s,
	     struct rdt_domain *d)
{
	struct resctrl_staged_config *cfg;
	struct rdt_resource *r = s->res;
	unsigned long bw_val;

	if (d->have_new_ctrl) {
	cfg = &d->staged_config[s->conf_type];
	if (cfg->have_new_ctrl) {
		rdt_last_cmd_printf("Duplicate domain %d\n", d->id);
		return -EINVAL;
	}

	if (!bw_validate(data->buf, &bw_val, r))
		return -EINVAL;
	d->new_ctrl = bw_val;
	d->have_new_ctrl = true;
	cfg->new_ctrl = bw_val;
	cfg->have_new_ctrl = true;

	return 0;
}
@@ -125,13 +128,16 @@ static bool cbm_validate(char *buf, u32 *data, struct rdt_resource *r)
 * Read one cache bit mask (hex). Check that it is valid for the current
 * resource type.
 */
int parse_cbm(struct rdt_parse_data *data, struct rdt_resource *r,
int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s,
	      struct rdt_domain *d)
{
	struct rdtgroup *rdtgrp = data->rdtgrp;
	struct resctrl_staged_config *cfg;
	struct rdt_resource *r = s->res;
	u32 cbm_val;

	if (d->have_new_ctrl) {
	cfg = &d->staged_config[s->conf_type];
	if (cfg->have_new_ctrl) {
		rdt_last_cmd_printf("Duplicate domain %d\n", d->id);
		return -EINVAL;
	}
@@ -160,12 +166,12 @@ int parse_cbm(struct rdt_parse_data *data, struct rdt_resource *r,
	 * The CBM may not overlap with the CBM of another closid if
	 * either is exclusive.
	 */
	if (rdtgroup_cbm_overlaps(r, d, cbm_val, rdtgrp->closid, true)) {
	if (rdtgroup_cbm_overlaps(s, d, cbm_val, rdtgrp->closid, true)) {
		rdt_last_cmd_puts("Overlaps with exclusive group\n");
		return -EINVAL;
	}

	if (rdtgroup_cbm_overlaps(r, d, cbm_val, rdtgrp->closid, false)) {
	if (rdtgroup_cbm_overlaps(s, d, cbm_val, rdtgrp->closid, false)) {
		if (rdtgrp->mode == RDT_MODE_EXCLUSIVE ||
		    rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
			rdt_last_cmd_puts("Overlaps with other group\n");
@@ -173,8 +179,8 @@ int parse_cbm(struct rdt_parse_data *data, struct rdt_resource *r,
		}
	}

	d->new_ctrl = cbm_val;
	d->have_new_ctrl = true;
	cfg->new_ctrl = cbm_val;
	cfg->have_new_ctrl = true;

	return 0;
}
@@ -185,9 +191,12 @@ int parse_cbm(struct rdt_parse_data *data, struct rdt_resource *r,
 * 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 rdt_resource *r,
static int parse_line(char *line, struct resctrl_schema *s,
		      struct rdtgroup *rdtgrp)
{
	enum resctrl_conf_type t = s->conf_type;
	struct resctrl_staged_config *cfg;
	struct rdt_resource *r = s->res;
	struct rdt_parse_data data;
	char *dom = NULL, *id;
	struct rdt_domain *d;
@@ -213,9 +222,10 @@ static int parse_line(char *line, struct rdt_resource *r,
		if (d->id == dom_id) {
			data.buf = dom;
			data.rdtgrp = rdtgrp;
			if (r->parse_ctrlval(&data, r, d))
			if (r->parse_ctrlval(&data, s, d))
				return -EINVAL;
			if (rdtgrp->mode ==  RDT_MODE_PSEUDO_LOCKSETUP) {
				cfg = &d->staged_config[t];
				/*
				 * In pseudo-locking setup mode and just
				 * parsed a valid CBM that should be
@@ -224,9 +234,9 @@ static int parse_line(char *line, struct rdt_resource *r,
				 * the required initialization for single
				 * region and return.
				 */
				rdtgrp->plr->r = r;
				rdtgrp->plr->s = s;
				rdtgrp->plr->d = d;
				rdtgrp->plr->cbm = d->new_ctrl;
				rdtgrp->plr->cbm = cfg->new_ctrl;
				d->plr = rdtgrp->plr;
				return 0;
			}
@@ -236,28 +246,72 @@ static int parse_line(char *line, struct rdt_resource *r,
	return -EINVAL;
}

int update_domains(struct rdt_resource *r, int closid)
static u32 get_config_index(u32 closid, enum resctrl_conf_type type)
{
	switch (type) {
	default:
	case CDP_NONE:
		return closid;
	case CDP_CODE:
		return closid * 2 + 1;
	case CDP_DATA:
		return closid * 2;
	}
}

static bool apply_config(struct rdt_hw_domain *hw_dom,
			 struct resctrl_staged_config *cfg, u32 idx,
			 cpumask_var_t cpu_mask, bool mba_sc)
{
	struct rdt_domain *dom = &hw_dom->d_resctrl;
	u32 *dc = !mba_sc ? hw_dom->ctrl_val : hw_dom->mbps_val;

	if (cfg->new_ctrl != dc[idx]) {
		cpumask_set_cpu(cpumask_any(&dom->cpu_mask), cpu_mask);
		dc[idx] = cfg->new_ctrl;

		return true;
	}

	return false;
}

int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
{
	struct resctrl_staged_config *cfg;
	struct rdt_hw_domain *hw_dom;
	struct msr_param msr_param;
	enum resctrl_conf_type t;
	cpumask_var_t cpu_mask;
	struct rdt_domain *d;
	bool mba_sc;
	u32 *dc;
	int cpu;
	u32 idx;

	if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
		return -ENOMEM;

	msr_param.low = closid;
	msr_param.high = msr_param.low + 1;
	msr_param.res = r;

	mba_sc = is_mba_sc(r);
	msr_param.res = NULL;
	list_for_each_entry(d, &r->domains, list) {
		dc = !mba_sc ? d->ctrl_val : d->mbps_val;
		if (d->have_new_ctrl && d->new_ctrl != dc[closid]) {
			cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
			dc[closid] = d->new_ctrl;
		hw_dom = resctrl_to_arch_dom(d);
		for (t = 0; t < CDP_NUM_TYPES; t++) {
			cfg = &hw_dom->d_resctrl.staged_config[t];
			if (!cfg->have_new_ctrl)
				continue;

			idx = get_config_index(closid, t);
			if (!apply_config(hw_dom, cfg, idx, cpu_mask, mba_sc))
				continue;

			if (!msr_param.res) {
				msr_param.low = idx;
				msr_param.high = msr_param.low + 1;
				msr_param.res = r;
			} else {
				msr_param.low = min(msr_param.low, idx);
				msr_param.high = max(msr_param.high, idx + 1);
			}
		}
	}

@@ -284,11 +338,11 @@ int update_domains(struct rdt_resource *r, int closid)
static int rdtgroup_parse_resource(char *resname, char *tok,
				   struct rdtgroup *rdtgrp)
{
	struct rdt_resource *r;
	struct resctrl_schema *s;

	for_each_alloc_enabled_rdt_resource(r) {
		if (!strcmp(resname, r->name) && rdtgrp->closid < r->num_closid)
			return parse_line(tok, r, rdtgrp);
	list_for_each_entry(s, &resctrl_schema_all, list) {
		if (!strcmp(resname, s->name) && rdtgrp->closid < s->num_closid)
			return parse_line(tok, s, rdtgrp);
	}
	rdt_last_cmd_printf("Unknown or unsupported resource name '%s'\n", resname);
	return -EINVAL;
@@ -297,6 +351,7 @@ static int rdtgroup_parse_resource(char *resname, char *tok,
ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
				char *buf, size_t nbytes, loff_t off)
{
	struct resctrl_schema *s;
	struct rdtgroup *rdtgrp;
	struct rdt_domain *dom;
	struct rdt_resource *r;
@@ -327,9 +382,9 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
		goto out;
	}

	for_each_alloc_enabled_rdt_resource(r) {
		list_for_each_entry(dom, &r->domains, list)
			dom->have_new_ctrl = false;
	list_for_each_entry(s, &resctrl_schema_all, list) {
		list_for_each_entry(dom, &s->res->domains, list)
			memset(dom->staged_config, 0, sizeof(dom->staged_config));
	}

	while ((tok = strsep(&buf, "\n")) != NULL) {
@@ -349,8 +404,9 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
			goto out;
	}

	for_each_alloc_enabled_rdt_resource(r) {
		ret = update_domains(r, rdtgrp->closid);
	list_for_each_entry(s, &resctrl_schema_all, list) {
		r = s->res;
		ret = resctrl_arch_update_domains(r, rdtgrp->closid);
		if (ret)
			goto out;
	}
@@ -371,19 +427,31 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
	return ret ?: nbytes;
}

static void show_doms(struct seq_file *s, struct rdt_resource *r, int closid)
u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d,
			    u32 closid, enum resctrl_conf_type type)
{
	struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d);
	u32 idx = get_config_index(closid, type);

	if (!is_mba_sc(r))
		return hw_dom->ctrl_val[idx];
	return hw_dom->mbps_val[idx];
}

static void show_doms(struct seq_file *s, struct resctrl_schema *schema, int closid)
{
	struct rdt_resource *r = schema->res;
	struct rdt_domain *dom;
	bool sep = false;
	u32 ctrl_val;

	seq_printf(s, "%*s:", max_name_width, r->name);
	seq_printf(s, "%*s:", max_name_width, schema->name);
	list_for_each_entry(dom, &r->domains, list) {
		if (sep)
			seq_puts(s, ";");

		ctrl_val = (!is_mba_sc(r) ? dom->ctrl_val[closid] :
			    dom->mbps_val[closid]);
		ctrl_val = resctrl_arch_get_config(r, dom, closid,
						   schema->conf_type);
		seq_printf(s, r->format_str, dom->id, max_data_width,
			   ctrl_val);
		sep = true;
@@ -394,16 +462,17 @@ static void show_doms(struct seq_file *s, struct rdt_resource *r, int closid)
int rdtgroup_schemata_show(struct kernfs_open_file *of,
			   struct seq_file *s, void *v)
{
	struct resctrl_schema *schema;
	struct rdtgroup *rdtgrp;
	struct rdt_resource *r;
	int ret = 0;
	u32 closid;

	rdtgrp = rdtgroup_kn_lock_live(of->kn);
	if (rdtgrp) {
		if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
			for_each_alloc_enabled_rdt_resource(r)
				seq_printf(s, "%s:uninitialized\n", r->name);
			list_for_each_entry(schema, &resctrl_schema_all, list) {
				seq_printf(s, "%s:uninitialized\n", schema->name);
			}
		} else if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
			if (!rdtgrp->plr->d) {
				rdt_last_cmd_clear();
@@ -411,15 +480,15 @@ int rdtgroup_schemata_show(struct kernfs_open_file *of,
				ret = -ENODEV;
			} else {
				seq_printf(s, "%s:%d=%x\n",
					   rdtgrp->plr->r->name,
					   rdtgrp->plr->s->res->name,
					   rdtgrp->plr->d->id,
					   rdtgrp->plr->cbm);
			}
		} else {
			closid = rdtgrp->closid;
			for_each_alloc_enabled_rdt_resource(r) {
				if (closid < r->num_closid)
					show_doms(s, r, closid);
			list_for_each_entry(schema, &resctrl_schema_all, list) {
				if (closid < schema->num_closid)
					show_doms(s, schema, closid);
			}
		}
	} else {
@@ -449,6 +518,7 @@ void mon_event_read(struct rmid_read *rr, struct rdt_resource *r,
int rdtgroup_mondata_show(struct seq_file *m, void *arg)
{
	struct kernfs_open_file *of = m->private;
	struct rdt_hw_resource *hw_res;
	u32 resid, evtid, domid;
	struct rdtgroup *rdtgrp;
	struct rdt_resource *r;
@@ -468,7 +538,8 @@ int rdtgroup_mondata_show(struct seq_file *m, void *arg)
	domid = md.u.domid;
	evtid = md.u.evtid;

	r = &rdt_resources_all[resid];
	hw_res = &rdt_resources_all[resid];
	r = &hw_res->r_resctrl;
	d = rdt_find_domain(r, domid, NULL);
	if (IS_ERR_OR_NULL(d)) {
		ret = -ENOENT;
@@ -482,7 +553,7 @@ int rdtgroup_mondata_show(struct seq_file *m, void *arg)
	else if (rr.val & RMID_VAL_UNAVAIL)
		seq_puts(m, "Unavailable\n");
	else
		seq_printf(m, "%llu\n", rr.val * r->mon_scale);
		seq_printf(m, "%llu\n", rr.val * hw_res->mon_scale);

out:
	rdtgroup_kn_unlock(of->kn);
+72 −159

File changed.

Preview size limit exceeded, changes collapsed.

+27 −17

File changed.

Preview size limit exceeded, changes collapsed.

+6 −6
Original line number Diff line number Diff line
@@ -250,7 +250,7 @@ static void pseudo_lock_region_clear(struct pseudo_lock_region *plr)
	plr->line_size = 0;
	kfree(plr->kmem);
	plr->kmem = NULL;
	plr->r = NULL;
	plr->s = NULL;
	if (plr->d)
		plr->d->plr = NULL;
	plr->d = NULL;
@@ -294,10 +294,10 @@ static int pseudo_lock_region_init(struct pseudo_lock_region *plr)

	ci = get_cpu_cacheinfo(plr->cpu);

	plr->size = rdtgroup_cbm_to_size(plr->r, plr->d, plr->cbm);
	plr->size = rdtgroup_cbm_to_size(plr->s->res, plr->d, plr->cbm);

	for (i = 0; i < ci->num_leaves; i++) {
		if (ci->info_list[i].level == plr->r->cache_level) {
		if (ci->info_list[i].level == plr->s->res->cache_level) {
			plr->line_size = ci->info_list[i].coherency_line_size;
			return 0;
		}
@@ -688,8 +688,8 @@ int rdtgroup_locksetup_enter(struct rdtgroup *rdtgrp)
	 *   resource, the portion of cache used by it should be made
	 *   unavailable to all future allocations from both resources.
	 */
	if (rdt_resources_all[RDT_RESOURCE_L3DATA].alloc_enabled ||
	    rdt_resources_all[RDT_RESOURCE_L2DATA].alloc_enabled) {
	if (resctrl_arch_get_cdp_enabled(RDT_RESOURCE_L3) ||
	    resctrl_arch_get_cdp_enabled(RDT_RESOURCE_L2)) {
		rdt_last_cmd_puts("CDP enabled\n");
		return -EINVAL;
	}
@@ -800,7 +800,7 @@ bool rdtgroup_cbm_overlaps_pseudo_locked(struct rdt_domain *d, unsigned long cbm
	unsigned long cbm_b;

	if (d->plr) {
		cbm_len = d->plr->r->cache.cbm_len;
		cbm_len = d->plr->s->res->cache.cbm_len;
		cbm_b = d->plr->cbm;
		if (bitmap_intersects(&cbm, &cbm_b, cbm_len))
			return true;
Loading