Re: [RFC PATCH 05/31] x86/resctrl: Parse ACPI CMRC table
From: Luck, Tony
Date: Tue Aug 04 2026 - 13:20:22 EST
On Mon, Aug 03, 2026 at 12:03:48AM +0800, Chen Yu wrote:
> The CMRC (Cache Monitoring Registers for CPU Agents Description) sub-table of
> ERDT describes the MMIO registers used to read cache monitoring counters (e.g.
> LLC occupancy) for an RMD.
>
> Parse each CMRC sub-table, ioremap its register window, and save a copy of the
> CMRC table in the corresponding ERDT domain entry so that later monitoring code
> can read the counters via MMIO.
>
> Suggested-by: Tony Luck <tony.luck@xxxxxxxxx>
> Tested-by: Hongyu Ning <hongyu.ning@xxxxxxxxxxxxxxx>
> Reviewed-by: Thomas Gleixner <tglx@xxxxxxxxxx>
> Signed-off-by: Chen Yu <yu.c.chen@xxxxxxxxx>
See the "Ordering of commit tags" section in Documentation/process/maintainer-tip.rst
> ---
> arch/x86/include/asm/resctrl.h | 2 +
> arch/x86/kernel/cpu/resctrl/erdt.c | 57 ++++++++++++++++++++++++++
> arch/x86/kernel/cpu/resctrl/internal.h | 6 ++-
> 3 files changed, 64 insertions(+), 1 deletion(-)
>
> diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h
> index 575f8408a9e7..e60c2aea7ebd 100644
> --- a/arch/x86/include/asm/resctrl.h
> +++ b/arch/x86/include/asm/resctrl.h
> @@ -49,6 +49,8 @@ DECLARE_STATIC_KEY_FALSE(rdt_enable_key);
> DECLARE_STATIC_KEY_FALSE(rdt_alloc_enable_key);
> DECLARE_STATIC_KEY_FALSE(rdt_mon_enable_key);
>
> +int erdt_get_scale(void);
> +
> static inline bool resctrl_arch_alloc_capable(void)
> {
> return rdt_alloc_capable;
> diff --git a/arch/x86/kernel/cpu/resctrl/erdt.c b/arch/x86/kernel/cpu/resctrl/erdt.c
> index 6257869d0db2..422618991927 100644
> --- a/arch/x86/kernel/cpu/resctrl/erdt.c
> +++ b/arch/x86/kernel/cpu/resctrl/erdt.c
> @@ -23,6 +23,7 @@ static LIST_HEAD(domain_info_list);
> static bool erdt_enabled;
>
> #define ERDT_VALID_VERSION 1
> +#define CMRC_SUPPORTED_INDEX_FN 1
> #define RMDD_FLAG_CPU_L3_DOMAIN BIT(0)
>
> /* Bitmask of valid sub-tables found in the first RMDD, used to ensure all RMDDs match. */
> @@ -33,11 +34,19 @@ static u16 first_rmdd_domain_id;
>
> static int erdt_max_rmid;
>
> +/* Scale to bytes for the monitoring counters when ERDT is enabled. */
> +static int erdt_scale;
Single value for scale? See below.
> +
> int erdt_get_max_rmid(void)
> {
> return erdt_max_rmid;
> }
>
> +int erdt_get_scale(void)
> +{
> + return erdt_scale;
> +}
> +
> static void __iomem *erdt_ioremap(phys_addr_t base, u32 num_pages, const char *desc)
> {
> void __iomem *addr;
> @@ -67,6 +76,7 @@ static void erdt_iounmap_domain(struct erdt_domain_info *domain)
> static void cleanup_one_domain(struct erdt_domain_info *d)
> {
> erdt_iounmap_domain(d);
> + kfree(d->cmrc);
> kfree(d);
> }
>
> @@ -100,6 +110,43 @@ static __init int cacd_init(struct acpi_subtbl_hdr_16 *subtbl,
> return 0;
> }
>
> +static __init int cmrc_init(struct acpi_subtbl_hdr_16 *subtbl,
> + struct erdt_domain_info *domain_info)
> +{
> + struct acpi_erdt_cmrc *cmrc = (struct acpi_erdt_cmrc *)subtbl;
> +
> + if (cmrc->header.length < sizeof(*cmrc)) {
> + pr_warn(FW_BUG "Truncated CMRC subtable\n");
> + return -EIO;
> + }
> +
> + if (cmrc->index_fn != CMRC_SUPPORTED_INDEX_FN) {
> + pr_info("Unsupported CMRC index function %u\n", cmrc->index_fn);
> + return -EIO;
> + }
> +
> + if (!cmrc->clump_size) {
> + pr_warn(FW_BUG "CMRC clump_size is zero\n");
> + return -EIO;
> + }
> +
> + domain_info->base[ERDT_MMIO_CMRC_BASE] =
> + erdt_ioremap(cmrc->cmt_reg_base, cmrc->cmt_reg_size, "CMRC base");
> + if (!domain_info->base[ERDT_MMIO_CMRC_BASE])
> + return -EIO;
> +
> + domain_info->cmrc = kmemdup(cmrc, cmrc->header.length, GFP_KERNEL);
> + if (!domain_info->cmrc) {
> + iounmap(domain_info->base[ERDT_MMIO_CMRC_BASE]);
> + domain_info->base[ERDT_MMIO_CMRC_BASE] = NULL;
> + return -ENOMEM;
> + }
> +
> + erdt_scale = max_t(int, erdt_scale, cmrc->up_scale);
I'd expect that on a machine all CMRC tables would report the same
up_scale factor. But RDT architecture allows them to be different. Two
ways to handle this:
1) Check that they are all the same. Complain if they are different and
don't enable cache occupancy events.
2) Save the value for each domain and use that value to upscale when
reporting to user.
Picking the max value doesn't feel like a good answer.
> +
> + return 0;
> +}
-Tony