[RFC PATCH v2 10/11] x86/resctrl: Enable asymmetric CAT from CPUID leaf 0x28
From: Tony Luck
Date: Tue Nov 03 2026 - 16:30:01 EST
Asymmetric CAT parameters are enumerated by CPUID leaf 0x28.
resctrl cannot represent per-domain shareable bits, so it cannot use this
enumeration when shareable bits are reported.
Enumerate the per-domain CBM lengths and enable asymmetric L2 CAT when the
feature is supported and has no shareable bits. Use the minimum domain CBM
length for the control's common view, and enable asymmetric CDP when available.
Signed-off-by: Tony Luck <tony.luck@xxxxxxxxx>
---
include/linux/resctrl.h | 2 ++
arch/x86/kernel/cpu/resctrl/core.c | 49 ++++++++++++++++++++++++++++--
2 files changed, 49 insertions(+), 2 deletions(-)
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 8ac799d1feff..efaddd7c5270 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -420,6 +420,7 @@ enum resctrl_ctrl_name {
* Specifically, "rdt_resource_final::name"_"resctrl_ctrl::name".
* For example, with resource name "MB" and control name "MAX" the
* schema entry will be "MB_MAX".
+ * @asymmetric: This control may have different per-domain parameters.
* @bitmap: Bitmap control properties. Used by cache allocation.
* @scalar: Scalar control properties. Valid when @type == RESCTRL_CTRL_SCALAR.
* Used by memory bandwidth allocation.
@@ -436,6 +437,7 @@ struct resctrl_ctrl {
struct list_head domains;
enum resctrl_ctrl_type type;
enum resctrl_ctrl_name name;
+ bool asymmetric;
union {
struct resctrl_ctrl_bitmap bitmap;
struct resctrl_ctrl_scalar scalar;
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index aa0bb32d191e..93d1b153614f 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -348,6 +348,28 @@ static __init bool __rdt_get_mem_config_amd(struct rdt_resource *r)
return true;
}
+static int rdt_get_cache_asym_cbm_len(enum resctrl_res_level rid)
+{
+ union cpuid_0x10_1_eax eax;
+ u32 ebx, ecx, edx;
+ int subleaf;
+
+ switch (rid) {
+ case RDT_RESOURCE_L3:
+ subleaf = 1;
+ break;
+ case RDT_RESOURCE_L2:
+ subleaf = 2;
+ break;
+ default:
+ pr_info("Unexpected resource %d\n", rid);
+ return 0;
+ }
+ cpuid_count(CPUID_LEAF_RDT_A_ASYM, subleaf, &eax.full, &ebx, &ecx, &edx);
+
+ return eax.split.cbm_len + 1;
+}
+
static struct resctrl_ctrl *rdt_get_cache_alloc_cfg(int leaf, int idx, struct rdt_resource *r)
{
struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
@@ -625,8 +647,14 @@ static void domain_add_cpu_ctrl(int cpu, struct rdt_resource *r,
d->hdr.rid = r->rid;
cpumask_set_cpu(cpu, &d->hdr.cpu_mask);
- if (ctrl->type == RESCTRL_CTRL_BITMAP)
- d->cbm_len = ctrl->bitmap.cbm_len;
+ if (ctrl->type == RESCTRL_CTRL_BITMAP) {
+ if (ctrl->asymmetric) {
+ d->cbm_len = rdt_get_cache_asym_cbm_len(r->rid);
+ ctrl->bitmap.cbm_len = min(ctrl->bitmap.cbm_len, d->cbm_len);
+ } else {
+ d->cbm_len = ctrl->bitmap.cbm_len;
+ }
+ }
rdt_domain_reconfigure_cdp(r);
@@ -1091,6 +1119,23 @@ static __init bool get_rdt_alloc_resources(void)
r->alloc_capable = true;
ret = true;
}
+ } else if (rdt_cpu_has(X86_FEATURE_CAT_L2_ASYM)) {
+ /* CPUID 0x28.2 fields are same format as 0x10.1 */
+ r = &rdt_resources_all[RDT_RESOURCE_L2].r_resctrl;
+ ctrl = rdt_get_cache_alloc_cfg(CPUID_LEAF_RDT_A_ASYM, 2, r);
+ if (ctrl) {
+ if (ctrl->bitmap.shareable_bits) {
+ pr_info("No support for asymmetric L2 with shareable bits\n");
+ kfree(container_of(ctrl, struct resctrl_hw_ctrl, r_ctrl));
+ } else {
+ if (rdt_cpu_has(X86_FEATURE_CDP_L2_ASYM))
+ rdt_get_cdp_l2_config();
+ list_add(&ctrl->entry, &r->controls);
+ r->alloc_capable = true;
+ ctrl->asymmetric = true;
+ ret = true;
+ }
+ }
}
if (get_mem_config())
--
2.56.0