[PATCH v3 3/5] x86,fs/resctrl: Move MSR_IA32_L{2,3}_QOS_CFG scope property to x86 resource

From: Reinette Chatre

Date: Wed Nov 04 2026 - 21:14:23 EST


MSR_IA32_L{2,3}_QOS_CFG enable code and data prioritization on x86. On
Intel the registers have the scope of the associated cache while on AMD
they have CPU scope. The scope is recorded as a property of the cache
resource's control, of which each cache resource currently supports only
one.

The scope of MSR_IA32_L{2,3}_QOS_CFG is only relevant to x86. Even so, the
property is found among the resctrl filesystem's cache properties while only
x86 code sets and reads it. Keeping the property with the cache control
properties would also duplicate it across all controls of a resource when
resources support multiple controls.

Make the scope of MSR_IA32_L{2,3}_QOS_CFG a property of the x86 hardware
resource and name it for the registers it describes now that it no longer
needs to be generic.

Signed-off-by: Reinette Chatre <reinette.chatre@xxxxxxxxx>
Reviewed-by: Chen Yu <yu.c.chen@xxxxxxxxx>
Reviewed-by: Tony Luck <tony.luck@xxxxxxxxx>
---
Changes since RFC v1:
- Remove stray ";" in kernel-doc comment.

Changes since RFC v2:
- Rewrite changelog, shorten subject.
- Rework comment instead of copy&paste the original.
- Rename property to be more specific now that it does not need to aim
for generic resctrl filesystem support.

Changes since v1:
- Update kernel-doc to make clear property is only relevant to cache
resources.
- Rewrite changelog.

Changes since v2:
- Add Chenyu and Tony's Reviewed-by tags.
---
arch/x86/kernel/cpu/resctrl/core.c | 7 ++++---
arch/x86/kernel/cpu/resctrl/internal.h | 4 ++++
arch/x86/kernel/cpu/resctrl/rdtgroup.c | 4 +++-
include/linux/resctrl.h | 3 ---
4 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index f96f7cf255d0..e647c3aa065a 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -444,6 +444,7 @@ static int get_domain_id_from_scope(int cpu, enum resctrl_scope scope)

static void domain_add_cpu_ctrl(int cpu, struct rdt_resource *r)
{
+ struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
int id = get_domain_id_from_scope(cpu, r->ctrl_scope);
struct rdt_hw_ctrl_domain *hw_dom;
struct list_head *add_pos = NULL;
@@ -466,7 +467,7 @@ static void domain_add_cpu_ctrl(int cpu, struct rdt_resource *r)
d = container_of(hdr, struct rdt_ctrl_domain, hdr);

cpumask_set_cpu(cpu, &d->hdr.cpu_mask);
- if (r->cache.arch_has_per_cpu_cfg)
+ if (hw_res->qos_cfg_has_cpu_scope)
rdt_domain_reconfigure_cdp(r);
return;
}
@@ -1001,7 +1002,7 @@ static __init void rdt_init_res_defs_intel(void)

if (r->rid == RDT_RESOURCE_L3 ||
r->rid == RDT_RESOURCE_L2) {
- r->cache.arch_has_per_cpu_cfg = false;
+ hw_res->qos_cfg_has_cpu_scope = false;
r->cache.min_cbm_bits = 1;
} else if (r->rid == RDT_RESOURCE_MBA) {
hw_res->msr_base = MSR_IA32_MBA_THRTL_BASE;
@@ -1020,8 +1021,8 @@ static __init void rdt_init_res_defs_amd(void)

if (r->rid == RDT_RESOURCE_L3 ||
r->rid == RDT_RESOURCE_L2) {
+ hw_res->qos_cfg_has_cpu_scope = true;
r->cache.arch_has_sparse_bitmasks = true;
- r->cache.arch_has_per_cpu_cfg = true;
r->cache.min_cbm_bits = 0;
} else if (r->rid == RDT_RESOURCE_MBA) {
hw_res->msr_base = MSR_IA32_MBA_BW_BASE;
diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h
index e3cfa0c10e92..670ce9272b51 100644
--- a/arch/x86/kernel/cpu/resctrl/internal.h
+++ b/arch/x86/kernel/cpu/resctrl/internal.h
@@ -125,6 +125,9 @@ struct msr_param {
* @mon_scale: cqm counter * mon_scale = occupancy in bytes
* @mbm_width: Monitor width, to detect and correct for overflow.
* @cdp_enabled: CDP state of this resource
+ * @qos_cfg_has_cpu_scope: Only for the L2 and L3 resources: true if
+ * MSR_IA32_L{2,3}_QOS_CFG has CPU scope, false if
+ * the scope matches the associated cache.
* @mbm_cntr_assign_enabled: ABMC feature is enabled
* @sdciae_enabled: SDCIAE feature (backing "io_alloc") is enabled.
*
@@ -140,6 +143,7 @@ struct rdt_hw_resource {
unsigned int mon_scale;
unsigned int mbm_width;
bool cdp_enabled;
+ bool qos_cfg_has_cpu_scope;
bool mbm_cntr_assign_enabled;
bool sdciae_enabled;
};
diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
index 5ffa39fa86fa..6e4eeccd4891 100644
--- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c
+++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
@@ -131,6 +131,7 @@ static void l2_qos_cfg_update(void *arg)

static int set_cache_qos_cfg(int level, bool enable)
{
+ struct rdt_hw_resource *hw_res;
void (*update)(void *arg);
struct rdt_ctrl_domain *d;
struct rdt_resource *r_l;
@@ -151,8 +152,9 @@ static int set_cache_qos_cfg(int level, bool enable)
return -ENOMEM;

r_l = &rdt_resources_all[level].r_resctrl;
+ hw_res = resctrl_to_arch_res(r_l);
list_for_each_entry_rcu(d, &r_l->ctrl_domains, hdr.list, lockdep_is_cpus_held()) {
- if (r_l->cache.arch_has_per_cpu_cfg)
+ if (hw_res->qos_cfg_has_cpu_scope)
/* Pick all the CPUs in the domain instance */
for_each_cpu(cpu, &d->hdr.cpu_mask)
cpumask_set_cpu(cpu, cpu_mask);
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 66dc9813c888..b6b4519a5190 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -215,8 +215,6 @@ struct rdt_l3_mon_domain {
* @shareable_bits: Bitmask of shareable resource with other
* executing entities
* @arch_has_sparse_bitmasks: True if a bitmask like f00f is valid.
- * @arch_has_per_cpu_cfg: True if QOS_CFG register for this cache
- * level has CPU scope.
* @io_alloc_capable: True if portion of the cache can be configured
* for I/O traffic.
*/
@@ -225,7 +223,6 @@ struct resctrl_cache {
unsigned int min_cbm_bits;
unsigned int shareable_bits;
bool arch_has_sparse_bitmasks;
- bool arch_has_per_cpu_cfg;
bool io_alloc_capable;
};

--
2.56.0