mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Tony Luck <tony.luck@intel.com>
To: Fenghua Yu <fenghuay@nvidia.com>,
	Reinette Chatre <reinette.chatre@intel.com>,
	Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>,
	Peter Newman <peternewman@google.com>,
	James Morse <james.morse@arm.com>,
	Babu Moger <babu.moger@amd.com>,
	Drew Fustini <dfustini@baylibre.com>,
	Dave Martin <Dave.Martin@arm.com>, Chen Yu <yu.c.chen@intel.com>
Cc: x86@kernel.org, linux-kernel@vger.kernel.org,
	patches@lists.linux.dev, Tony Luck <tony.luck@intel.com>
Subject: [RFC PATCH 6/8] arm,x86,fs/resctrl: Prepare for asymmetric caches
Date: Mon, 26 Oct 2026 14:57:16 -0700	[thread overview]
Message-ID: <20261026215718.16810-7-tony.luck@intel.com> (raw)
In-Reply-To: <20261026215718.16810-1-tony.luck@intel.com>

Each struct resctrl_ctrl carries a struct resctrl_ctrl_bitmap that describes
properties (cbm_len, min_cbm_bits, shareable_bits, flags) shared by every
control domain using that control. This assumes all domains of a control are
symmetric. Future asymmetric systems may have control domains with differing
bitmap properties, in particular a @cbm_len that varies by cache instance.

Add a field to the rdt_ctrl_domain structure to store per-domain cache
bitmap lengths.

Update code that reads cbm_len to use the per-domain copy instead of the
resctrl_ctrl copy, so that domain-specific values will be picked up when
asymmetric domains are enumerated.

Signed-off-by: Tony Luck <tony.luck@intel.com>
---
 include/linux/resctrl.h                | 10 +++++++--
 arch/x86/kernel/cpu/resctrl/core.c     | 23 ++++++++++++++++---
 arch/x86/kernel/cpu/resctrl/rdtgroup.c |  2 +-
 drivers/resctrl/mpam_resctrl.c         | 19 +++++++++++-----
 fs/resctrl/ctrlmondata.c               |  9 ++++----
 fs/resctrl/pseudo_lock.c               |  2 +-
 fs/resctrl/rdtgroup.c                  | 31 ++++++++++++++------------
 7 files changed, 65 insertions(+), 31 deletions(-)

diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index f58a9e773ff6..8ac799d1feff 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -184,12 +184,15 @@ static inline bool domain_header_is_valid(struct rdt_domain_hdr *hdr,
  * @mbps_val:		When mba_sc is enabled, this holds the array of user
  *			specified control values for mba_sc in MBps, indexed
  *			by closid
+ * @cbm_len:		Length of cache bitmask for a cache control in this
+ *			domain
  */
 struct rdt_ctrl_domain {
 	struct rdt_domain_hdr		hdr;
 	struct pseudo_lock_region	*plr;
 	struct resctrl_staged_config	staged_config[CDP_NUM_TYPES];
 	u32				*mbps_val;
+	unsigned int			cbm_len;
 };
 
 /**
@@ -597,8 +600,11 @@ void resctrl_arch_sync_cpu_closid_rmid(void *info);
  * resctrl_get_default_ctrlval() - Return the default control value for this
  *                                 control.
  * @ctrl:	The control whose default control type is queried.
+ * @d:		The control domain to query, or NULL if @ctrl's properties
+ *		should be used instead (e.g. when no domain exists yet).
  */
-static inline u32 resctrl_get_default_ctrlval(struct resctrl_ctrl *ctrl)
+static inline u32 resctrl_get_default_ctrlval(struct resctrl_ctrl *ctrl,
+					      struct rdt_ctrl_domain *d)
 {
 	switch (ctrl->type) {
 	case RESCTRL_CTRL_BITMAP:
@@ -606,7 +612,7 @@ static inline u32 resctrl_get_default_ctrlval(struct resctrl_ctrl *ctrl)
 		 * Should map to 100% allocation as exposed to user space
 		 * via "cbm_mask".
 		 */
-		return BIT_MASK(ctrl->bitmap.cbm_len) - 1;
+		return BIT_MASK(d ? d->cbm_len : ctrl->bitmap.cbm_len) - 1;
 	case RESCTRL_CTRL_SCALAR:
 		return ctrl->scalar.reset_val;
 	}
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index c26fc75ccc07..f6b7358e50d7 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -485,14 +485,14 @@ void rdt_ctrl_update(void *arg)
 }
 
 static void setup_default_ctrlval(struct rdt_resource *r, struct resctrl_ctrl *ctrl,
-				  u32 *dc)
+				  u32 *dc, struct rdt_ctrl_domain *d)
 {
 	struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
 	int i;
 
 	/* Initialize the control MSRs to their reset values. */
 	for (i = 0; i < hw_res->num_closid; i++, dc++)
-		*dc = resctrl_get_default_ctrlval(ctrl);
+		*dc = resctrl_get_default_ctrlval(ctrl, d);
 }
 
 static void ctrl_domain_free(struct rdt_hw_ctrl_domain *hw_dom)
@@ -525,7 +525,7 @@ static int domain_setup_ctrlval(struct rdt_resource *r, struct resctrl_ctrl *ctr
 		return -ENOMEM;
 
 	hw_dom->ctrl_val = dc;
-	setup_default_ctrlval(r, ctrl, dc);
+	setup_default_ctrlval(r, ctrl, dc, d);
 
 	m.res = r;
 	m.ctrl = ctrl;
@@ -585,6 +585,22 @@ static int get_domain_id_from_scope(int cpu, enum resctrl_scope scope)
 	return -EINVAL;
 }
 
+/*
+ * Take a snapshot of the cache bitmask length for cache controls (with
+ * the assumption that there is only one cache control for a resource).
+ */
+static void rdt_sync_ctrl_bitmap(struct rdt_resource *r, struct rdt_ctrl_domain *d)
+{
+	struct resctrl_ctrl *ctrl;
+
+	for_each_resource_ctrl(ctrl, r) {
+		if (ctrl->type != RESCTRL_CTRL_BITMAP)
+			continue;
+		d->cbm_len = ctrl->bitmap.cbm_len;
+		break;
+	}
+}
+
 static void domain_add_cpu_ctrl(int cpu, struct rdt_resource *r,
 				struct resctrl_ctrl *ctrl)
 {
@@ -625,6 +641,7 @@ static void domain_add_cpu_ctrl(int cpu, struct rdt_resource *r,
 	d->hdr.type = RESCTRL_CTRL_DOMAIN;
 	d->hdr.rid = r->rid;
 	cpumask_set_cpu(cpu, &d->hdr.cpu_mask);
+	rdt_sync_ctrl_bitmap(r, d);
 
 	rdt_domain_reconfigure_cdp(r);
 
diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
index edf42c59d7c1..691cd9fb1687 100644
--- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c
+++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
@@ -257,7 +257,7 @@ void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
 			hw_dom = resctrl_to_arch_ctrl_dom(d);
 
 			for (i = 0; i < hw_res->num_closid; i++)
-				hw_dom->ctrl_val[i] = resctrl_get_default_ctrlval(ctrl);
+				hw_dom->ctrl_val[i] = resctrl_get_default_ctrlval(ctrl, d);
 			msr_param.dom = d;
 			smp_call_function_any(&d->hdr.cpu_mask, rdt_ctrl_update, &msr_param, 1);
 		}
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 7a3afb6a411e..e420ca81434b 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -1246,7 +1246,7 @@ static int mpam_resctrl_control_init(struct mpam_resctrl_res *res)
 		 * we have configured the SMMU and GIC not to do this 'all the
 		 * bits' is the correct answer here.
 		 */
-		mpam_ctrl->r_ctrl.bitmap.shareable_bits = resctrl_get_default_ctrlval(&mpam_ctrl->r_ctrl);
+		mpam_ctrl->r_ctrl.bitmap.shareable_bits = resctrl_get_default_ctrlval(&mpam_ctrl->r_ctrl, NULL);
 		list_add(&mpam_ctrl->r_ctrl.entry, &r->controls);
 		r->alloc_capable = true;
 		break;
@@ -1411,7 +1411,7 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct resctrl_ctrl *ctrl,
 	lockdep_assert_cpus_held();
 
 	if (!mpam_is_enabled())
-		return resctrl_get_default_ctrlval(ctrl);
+		return resctrl_get_default_ctrlval(ctrl, d);
 
 	res = container_of(r, struct mpam_resctrl_res, resctrl_res);
 	dom = container_of(d, struct mpam_resctrl_dom, resctrl_ctrl_dom);
@@ -1440,12 +1440,12 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct resctrl_ctrl *ctrl,
 		}
 		fallthrough;
 	default:
-		return resctrl_get_default_ctrlval(ctrl);
+		return resctrl_get_default_ctrlval(ctrl, d);
 	}
 
 	if (!r->alloc_capable || partid >= resctrl_arch_get_num_closid(r) ||
 	    !mpam_has_feature(configured_by, cfg))
-		return resctrl_get_default_ctrlval(ctrl);
+		return resctrl_get_default_ctrlval(ctrl, d);
 
 	switch (configured_by) {
 	case mpam_feat_cpor_part:
@@ -1453,7 +1453,7 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct resctrl_ctrl *ctrl,
 	case mpam_feat_mbw_max:
 		return mbw_max_to_percent(cfg->mbw_max, cprops);
 	default:
-		return resctrl_get_default_ctrlval(ctrl);
+		return resctrl_get_default_ctrlval(ctrl, d);
 	}
 }
 
@@ -1864,16 +1864,23 @@ int mpam_resctrl_online_cpu(unsigned int cpu)
 
 		if (r->alloc_capable) {
 			for_each_resource_ctrl(ctrl, r) {
+				struct rdt_ctrl_domain *ctrl_d;
+
 				dom = mpam_resctrl_get_ctrl_domain_from_cpu(cpu, ctrl);
 				if (!dom) {
 					dom = mpam_resctrl_alloc_ctrl_domain(cpu, res, ctrl);
 					if (IS_ERR(dom))
 						return PTR_ERR(dom);
 				} else {
-					struct rdt_ctrl_domain *ctrl_d = &dom->resctrl_ctrl_dom;
+					ctrl_d = &dom->resctrl_ctrl_dom;
 
 					mpam_resctrl_online_domain_hdr(cpu, &ctrl_d->hdr);
 				}
+
+				if (ctrl->type == RESCTRL_CTRL_BITMAP) {
+					ctrl_d = &dom->resctrl_ctrl_dom;
+					ctrl_d->cbm_len = ctrl->bitmap.cbm_len;
+				}
 			}
 		}
 		if (r->mon_capable) {
diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c
index 627998fed555..90274fdb0364 100644
--- a/fs/resctrl/ctrlmondata.c
+++ b/fs/resctrl/ctrlmondata.c
@@ -189,10 +189,11 @@ static int parse_bw(struct rdt_parse_data *data, struct rdt_resource_final *f,
  * requires at least two bits set.
  * AMD allows non-contiguous bitmasks.
  */
-static bool cbm_validate(char *buf, u32 *data, struct resctrl_ctrl *ctrl)
+static bool cbm_validate(char *buf, u32 *data, struct rdt_ctrl_domain *d,
+			 struct resctrl_ctrl *ctrl)
 {
-	u32 supported_bits = BIT_MASK(ctrl->bitmap.cbm_len) - 1;
-	unsigned int cbm_len = ctrl->bitmap.cbm_len;
+	u32 supported_bits = BIT_MASK(d->cbm_len) - 1;
+	unsigned int cbm_len = d->cbm_len;
 	unsigned long first_bit, zero_bit, val;
 	int ret;
 
@@ -255,7 +256,7 @@ static int parse_cbm(struct rdt_parse_data *data, struct rdt_resource_final *f,
 		return -EINVAL;
 	}
 
-	if (!cbm_validate(data->buf, &cbm_val, ctrl))
+	if (!cbm_validate(data->buf, &cbm_val, d, ctrl))
 		return -EINVAL;
 
 	if ((mode == RDT_MODE_EXCLUSIVE || mode == RDT_MODE_SHAREABLE) &&
diff --git a/fs/resctrl/pseudo_lock.c b/fs/resctrl/pseudo_lock.c
index 17b99a075eaf..1f2e2da28bc5 100644
--- a/fs/resctrl/pseudo_lock.c
+++ b/fs/resctrl/pseudo_lock.c
@@ -637,7 +637,7 @@ bool rdtgroup_cbm_overlaps_pseudo_locked(struct rdt_ctrl_domain *d, unsigned lon
 		return false;
 	}
 
-	cbm_len = ctrl->bitmap.cbm_len;
+	cbm_len = d->cbm_len;
 	cbm_b = d->plr->cbm;
 	if (bitmap_intersects(&cbm, &cbm_b, cbm_len))
 		return true;
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 7119ad0029c1..46d39332706e 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -1106,7 +1106,7 @@ static int rdt_default_ctrl_show(struct kernfs_open_file *of,
 	if (!ctrl)
 		goto out_unlock;
 
-	seq_printf(seq, "%x\n", resctrl_get_default_ctrlval(ctrl));
+	seq_printf(seq, "%x\n", resctrl_get_default_ctrlval(ctrl, NULL));
 
 out_unlock:
 	info_kn_unlock(of->kn);
@@ -1250,7 +1250,7 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of,
 			hw_shareable |= ctrl_val;
 		}
 
-		for (i = ctrl->bitmap.cbm_len - 1; i >= 0; i--) {
+		for (i = dom->cbm_len - 1; i >= 0; i--) {
 			pseudo_locked = dom->plr ? dom->plr->cbm : 0;
 			hwb = test_bit(i, &hw_shareable);
 			swb = test_bit(i, &sw_shareable);
@@ -1546,7 +1546,7 @@ static bool __rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_ctrl_doma
 	/* Check for any overlap with regions used by hardware directly */
 	if (!exclusive) {
 		ctrl_b = ctrl->bitmap.shareable_bits;
-		if (bitmap_intersects(&cbm, &ctrl_b, ctrl->bitmap.cbm_len))
+		if (bitmap_intersects(&cbm, &ctrl_b, d->cbm_len))
 			return true;
 	}
 
@@ -1556,7 +1556,7 @@ static bool __rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_ctrl_doma
 		mode = rdtgroup_mode_by_closid(i);
 		if (closid_allocated(i) && i != closid &&
 		    mode != RDT_MODE_PSEUDO_LOCKSETUP) {
-			if (bitmap_intersects(&cbm, &ctrl_b, ctrl->bitmap.cbm_len)) {
+			if (bitmap_intersects(&cbm, &ctrl_b, d->cbm_len)) {
 				if (exclusive) {
 					if (mode == RDT_MODE_EXCLUSIVE)
 						return true;
@@ -1761,10 +1761,10 @@ unsigned int rdtgroup_cbm_to_size(struct rdt_resource *r, struct resctrl_ctrl *c
 	if (WARN_ON_ONCE(r->ctrl_scope != RESCTRL_L2_CACHE && r->ctrl_scope != RESCTRL_L3_CACHE))
 		return size;
 
-	num_b = bitmap_weight(&cbm, ctrl->bitmap.cbm_len);
+	num_b = bitmap_weight(&cbm, d->cbm_len);
 	ci = get_cpu_cacheinfo_level(cpumask_any(&d->hdr.cpu_mask), r->ctrl_scope);
 	if (ci)
-		size = ci->size / ctrl->bitmap.cbm_len * num_b;
+		size = ci->size / d->cbm_len * num_b;
 
 	return size;
 }
@@ -2479,7 +2479,7 @@ static int resctrl_ctrl_max_show(struct kernfs_open_file *of,
 			seq_printf(seq, "%d=%u", d->hdr.id, ctrl->scalar.max);
 			break;
 		case RESCTRL_CTRL_BITMAP:
-			seq_printf(seq, "%d=%lx", d->hdr.id, BIT_MASK(ctrl->bitmap.cbm_len) - 1);
+			seq_printf(seq, "%d=%lx", d->hdr.id, BIT_MASK(d->cbm_len) - 1);
 			break;
 		}
 		sep = true;
@@ -4227,6 +4227,9 @@ static int mkdir_mondata_all(struct kernfs_node *parent_kn,
  * cbm_ensure_valid - Enforce validity on provided CBM
  * @_val:	Candidate CBM
  * @r:		RDT resource to which the CBM belongs
+ * @d:		RDT domain to which the CBM belongs. Its bitmap properties
+ *		(e.g. @cbm_len) are used since these may differ from
+ *		@ctrl's on asymmetric systems.
  * @ctrl:	Properties of the bitmap control CBM should be tested against.
  *
  * The provided CBM represents all cache portions available for use. This
@@ -4241,10 +4244,10 @@ static int mkdir_mondata_all(struct kernfs_node *parent_kn,
  *
  * Return: A CBM that is valid for resource @r.
  */
-static u32 cbm_ensure_valid(u32 _val, struct rdt_resource *r,
+static u32 cbm_ensure_valid(u32 _val, struct rdt_resource *r, struct rdt_ctrl_domain *d,
 			    struct resctrl_ctrl *ctrl)
 {
-	unsigned int cbm_len = ctrl->bitmap.cbm_len;
+	unsigned int cbm_len = d->cbm_len;
 	unsigned long first_bit, zero_bit;
 	unsigned long val;
 
@@ -4312,20 +4315,20 @@ static int __init_one_rdt_domain(struct rdt_ctrl_domain *d, struct rdt_resource_
 	}
 	if (d->plr && d->plr->cbm > 0)
 		used_b |= d->plr->cbm;
-	unused_b = used_b ^ (BIT_MASK(ctrl->bitmap.cbm_len) - 1);
-	unused_b &= BIT_MASK(ctrl->bitmap.cbm_len) - 1;
+	unused_b = used_b ^ (BIT_MASK(d->cbm_len) - 1);
+	unused_b &= BIT_MASK(d->cbm_len) - 1;
 	cfg->new_ctrl |= unused_b;
 	/*
 	 * Force the initial CBM to be valid, user can
 	 * modify the CBM based on system availability.
 	 */
-	cfg->new_ctrl = cbm_ensure_valid(cfg->new_ctrl, r, ctrl);
+	cfg->new_ctrl = cbm_ensure_valid(cfg->new_ctrl, r, d, ctrl);
 	/*
 	 * Assign the u32 CBM to an unsigned long to ensure that
 	 * bitmap_weight() does not access out-of-bound memory.
 	 */
 	tmp_cbm = cfg->new_ctrl;
-	if (bitmap_weight(&tmp_cbm, ctrl->bitmap.cbm_len) < ctrl->bitmap.min_cbm_bits) {
+	if (bitmap_weight(&tmp_cbm, d->cbm_len) < ctrl->bitmap.min_cbm_bits) {
 		rdt_last_cmd_printf("No space on %s:%d\n", f->name, d->hdr.id);
 		return -ENOSPC;
 	}
@@ -4373,7 +4376,7 @@ static void rdtgroup_init_mba(struct rdt_resource *r, struct resctrl_ctrl *ctrl,
 		}
 
 		cfg = &d->staged_config[CDP_NONE];
-		cfg->new_ctrl = resctrl_get_default_ctrlval(ctrl);
+		cfg->new_ctrl = resctrl_get_default_ctrlval(ctrl, d);
 		cfg->have_new_ctrl = true;
 	}
 }
-- 
2.56.0


  parent reply	other threads:[~2026-10-26 21:57 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-26 21:57 [RFC PATCH 0/8] arm,x86,fs/resctrl: Support asymmetric L2 cache allocation Tony Luck
2026-10-26 21:57 ` [RFC PATCH 1/8] fs/resctrl: Change UI of "max" file (merge back into earlier patches) Tony Luck
2026-10-26 21:57 ` [RFC PATCH 2/8] x86/resctrl: Add L2CAT quirk for Intel Panther Lake Tony Luck
2026-10-26 21:57 ` [RFC PATCH 3/8] x86/cpuid: Add and use defines for Intel RDT enumeration leaves Tony Luck
2026-10-26 21:57 ` [RFC PATCH 4/8] x86/resctrl: Add X86_FEATURE bits for asymmetric L2 Tony Luck
2026-10-26 21:57 ` [RFC PATCH 5/8] x86/resctrl: Refactor rdt_get_cache_alloc_cfg() Tony Luck
2026-10-26 21:57 ` Tony Luck [this message]
2026-10-26 21:57 ` [RFC PATCH 7/8] x86/resctrl: Check for and enable asymmetric L2 cache allocation Tony Luck
2026-10-26 21:57 ` [RFC PATCH 8/8] fs/resctrl: Suppress creation of cbm_mask info file on asymmetric systems Tony Luck
2026-10-26 22:30 ` [RFC PATCH 0/8] arm,x86,fs/resctrl: Support asymmetric L2 cache allocation Reinette Chatre

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261026215718.16810-7-tony.luck@intel.com \
    --to=tony.luck@intel.com \
    --cc=Dave.Martin@arm.com \
    --cc=babu.moger@amd.com \
    --cc=dfustini@baylibre.com \
    --cc=fenghuay@nvidia.com \
    --cc=james.morse@arm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=maciej.wieczor-retman@intel.com \
    --cc=patches@lists.linux.dev \
    --cc=peternewman@google.com \
    --cc=reinette.chatre@intel.com \
    --cc=x86@kernel.org \
    --cc=yu.c.chen@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®