From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1554E2517A5 for ; Wed, 1 Jul 2026 13:57:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782914238; cv=none; b=CrGtb8dwxzR9FB0UVVuF6+8Dc28r81ajEIJnEi2TlIP1HJC8IAhqYV6BkBeB9xAm8JnW+52IlH6RtQSzF1VBg04mYixb8YbSmoA++sjt30kT+diDq/XWNPyqLYhKbE9FOWLcGTl1ABdAnSdBasqNI3JIbYDu/n5Fft+MFGgWGNo= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782914238; c=relaxed/simple; bh=C9XH9LXgR6srh0n6xXmnK3UdOEeuCqilUnL4WJnX0wE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=j6tJ7oOyvMZleHTS5kU31jWgv9EZiTmvcoo16sIsHCKT/S7s2FMV77vwTG7UnKGPzzGS5Fy2N7KWQKGLIuEpNoSC6/H3ontbATdbASVH0qQ9Mv/yGu4HSBbDzQbz1x9mBXtmmWsobkJEBtGbUFC7dg8T4Tj1BFswWeDARYN4F4Y= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=TeSf7P/V; arc=none smtp.client-ip=198.175.65.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="TeSf7P/V" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1782914237; x=1814450237; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=C9XH9LXgR6srh0n6xXmnK3UdOEeuCqilUnL4WJnX0wE=; b=TeSf7P/V0eCOArchVOGmX6kKon8zN8dVBE02uAR1IeC1r9zI6XWN4EPn XzU1o2SonFhi7yAoB/8psZPCjc6qs4awlvXPHDGbGZdG0yVD0iembbP8M QGv0pWvXKpNJvP7Jh3A1O82h+qwPE5t7W8VjxyrqZDhZLQBjignUMDKS+ y/yRoiXuBw5nGp6dfDPJ0BN/TyRhp2vG2/qGZR+ZgqGK2PfCLBGJEv7ku fz+dq5VDlskDRZUfHw08pNRKboyFKnK4EoXHIgW8I4rNc5wGZ1YOTHRLn 3wwP67qKC4Vl5ogE/Cg9FxbpPM3tJljhYWIS3MquTwdeVv8xNiIXdO733 Q==; X-CSE-ConnectionGUID: 92/J2eKDQkuN5VfOF0BQ8A== X-CSE-MsgGUID: xGzZHcItR2Cd2EGxSL9f6Q== X-IronPort-AV: E=McAfee;i="6800,10657,11833"; a="83734434" X-IronPort-AV: E=Sophos;i="6.25,141,1779174000"; d="scan'208";a="83734434" Received: from fmviesa007.fm.intel.com ([10.60.135.147]) by orvoesa110.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 01 Jul 2026 06:57:17 -0700 X-CSE-ConnectionGUID: laNXPiPhS0aGsOPxa8JOcw== X-CSE-MsgGUID: Pcv0TpVaSNujMRLWqUuTgA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,141,1779174000"; d="scan'208";a="249207956" Received: from chenyu-dev.sh.intel.com ([10.239.62.107]) by fmviesa007.fm.intel.com with ESMTP; 01 Jul 2026 06:57:11 -0700 From: Chen Yu To: tony.luck@intel.com, reinette.chatre@intel.com Cc: x86@kernel.org, linux-kernel@vger.kernel.org, tglx@kernel.org, bp@alien8.de, mingo@redhat.com, dave.hansen@linux.intel.com, hpa@zytor.com, fenghuay@nvidia.com, babu.moger@amd.com, anil.keshavamurthy@broadcom.com, chen.yu@linux.dev, Chen Yu , Hongyu Ning Subject: [PATCH v5 09/10] x86/resctrl: Introduce helpers to read L3 occupancy via MMIO Date: Wed, 1 Jul 2026 21:47:17 +0800 Message-Id: <28ea318efd3f2379116268c2f2e9cbffee98f138.1782866200.git.yu.c.chen@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Introduce erdt_cpu_has() to verify if a specific RDT feature is backed by an ERDT table. erdt_cpu_has() is derived from rdt_cpu_has(), which not only considers firmware (ERDT table and its sub-tables) support for an event, but also considers userspace input like "rdt=!cmt". erdt_cpu_has() expects the same input parameters as rdt_cpu_has(). Introduce erdt_mon_read(), a helper that retrieves monitoring data for a given RMID and event ID from an ERDT domain. erdt_mon_read() leverages erdt_cpu_has() to check whether the system supports the corresponding ACPI tables, such as ERDT and CMRC (Cache Monitoring Registers for CPU Agents Description). It invokes the low-level MMIO read callbacks (introduced later) if supported. Tested-by: Hongyu Ning Signed-off-by: Chen Yu --- v4->v5: A new patch. It extracts the logic that checks whether a specific RDT feature is backed by ERDT. The original plan was to leverage arch_priv for ERDT-specific operations, but MMIO-based CMT shares interleaved logic with MSR-based CMT, making them difficult to decouple from one another. A helper such as erdt_cpu_has() will therefore simplify differentiation. --- arch/x86/include/asm/resctrl.h | 6 +++++ arch/x86/kernel/cpu/resctrl/core.c | 33 ++++++++++++++++++++++++-- arch/x86/kernel/cpu/resctrl/erdt.c | 12 ++++++++++ arch/x86/kernel/cpu/resctrl/internal.h | 3 +++ arch/x86/kernel/cpu/resctrl/monitor.c | 25 +++++++++++++++++-- fs/resctrl/monitor.c | 6 +++++ include/linux/resctrl.h | 1 + 7 files changed, 82 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h index 575f8408a9e7..0fd4bf85f628 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); +bool erdt_cpu_has(int flag); + static inline bool resctrl_arch_alloc_capable(void) { return rdt_alloc_capable; @@ -131,6 +133,10 @@ static inline unsigned int resctrl_arch_round_mon_val(unsigned int val) { unsigned int scale = boot_cpu_data.x86_cache_occ_scale; + /* ERDT itself factors and rounds the data within erdt.c */ + if (erdt_cpu_has(X86_FEATURE_CQM_OCCUP_LLC)) + return val; + /* h/w works in units of "boot_cpu_data.x86_cache_occ_scale" */ val /= scale; return val * scale; diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c index 2e95586ebe45..5932cf813cb4 100644 --- a/arch/x86/kernel/cpu/resctrl/core.c +++ b/arch/x86/kernel/cpu/resctrl/core.c @@ -895,6 +895,29 @@ bool rdt_cpu_has(int flag) return ret; } +bool erdt_cpu_has(int flag) +{ + struct rdt_options *o; + bool ret; + + ret = erdt_support_features(flag); + + if (!ret) + return ret; + + for (o = rdt_options; o < &rdt_options[NUM_RDT_OPTIONS]; o++) { + if (flag == o->flag) { + if (o->force_off) + ret = false; + if (o->force_on) + ret = true; + break; + } + } + + return ret; +} + bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt) { if (!rdt_cpu_has(X86_FEATURE_BMEC)) @@ -982,7 +1005,10 @@ static __init bool get_rdt_mon_resources(void) struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl; bool ret = false; - if (rdt_cpu_has(X86_FEATURE_CQM_OCCUP_LLC)) { + if (erdt_cpu_has(X86_FEATURE_CQM_OCCUP_LLC)) { + resctrl_enable_mon_event(QOS_L3_OCCUP_EVENT_ID, true, 0, NULL); + ret = true; + } else if (rdt_cpu_has(X86_FEATURE_CQM_OCCUP_LLC)) { resctrl_enable_mon_event(QOS_L3_OCCUP_EVENT_ID, false, 0, NULL); ret = true; } @@ -1000,7 +1026,10 @@ static __init bool get_rdt_mon_resources(void) if (!ret) return false; - return !rdt_get_l3_mon_config(r); + if (rdt_get_l3_mon_config(r)) + return false; + + return r->mon_capable; } static __init void __check_quirks_intel(void) diff --git a/arch/x86/kernel/cpu/resctrl/erdt.c b/arch/x86/kernel/cpu/resctrl/erdt.c index a5754d64fcc1..1114ad4e3b42 100644 --- a/arch/x86/kernel/cpu/resctrl/erdt.c +++ b/arch/x86/kernel/cpu/resctrl/erdt.c @@ -18,6 +18,7 @@ #include #include +#include #include "internal.h" @@ -27,11 +28,17 @@ static bool __erdt_enabled; #define ERDT_VALID_VERSION 1 #define CMRC_SUPPORTED_INDEX_FN 1 +#define UNAVAILABLE_COUNTER BIT_ULL(63) #define RMDD_FLAG_CPU_L3_DOMAIN BIT(0) /* Bitmask of valid sub-tables found in the first RMDD, used to ensure all RMDDs match. */ static u32 valid_subtbl_mask; +bool erdt_support_features(int flag) +{ + return false; +} + int erdt_get_max_rmid(int cpu) { struct erdt_domain_info *d; @@ -50,6 +57,11 @@ int erdt_get_max_rmid(int cpu) return -1; } +int erdt_mon_read(struct rdt_domain_hdr *hdr, int ev_id, int rmid, u64 *val) +{ + return -EIO; +} + static void __iomem *erdt_ioremap(phys_addr_t base, u32 num_pages, const char *desc) { void __iomem *addr; diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h index 6eb0fdea6b63..ecb44f82581e 100644 --- a/arch/x86/kernel/cpu/resctrl/internal.h +++ b/arch/x86/kernel/cpu/resctrl/internal.h @@ -278,8 +278,11 @@ static inline void intel_aet_mon_domain_setup(int cpu, int id, struct rdt_resour static inline bool intel_handle_aet_option(bool force_off, char *tok) { return false; } #endif +bool erdt_support_features(int flag); +bool erdt_cpu_has(int flag); int erdt_get_max_rmid(int cpu); int erdt_init(void); void erdt_exit(void); +int erdt_mon_read(struct rdt_domain_hdr *hdr, int ev_id, int rmid, u64 *val); #endif /* _ASM_X86_RESCTRL_INTERNAL_H */ diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c index f4f4c9015ceb..e6d7037f000b 100644 --- a/arch/x86/kernel/cpu/resctrl/monitor.c +++ b/arch/x86/kernel/cpu/resctrl/monitor.c @@ -279,6 +279,10 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain_hdr *hdr, switch (r->rid) { case RDT_RESOURCE_L3: + if (eventid == QOS_L3_OCCUP_EVENT_ID && + erdt_cpu_has(X86_FEATURE_CQM_OCCUP_LLC)) + return erdt_mon_read(hdr, eventid, rmid, val); + return arch_l3_read_event(hdr, rmid, eventid, val, r); case RDT_RESOURCE_PERF_PKG: return intel_aet_read_event(hdr->id, rmid, arch_priv, val); @@ -423,6 +427,11 @@ int __init rdt_get_l3_mon_config(struct rdt_resource *r) { unsigned int mbm_offset = boot_cpu_data.x86_cache_mbm_width_offset; struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); + /* + * Currently assume all CPU domains share the same maximum RMID + * value from the RMDD table, use CPU0 domain's value. + */ + int erdt_max_rmid = erdt_get_max_rmid(0); unsigned int threshold; u32 eax, ebx, ecx, edx; @@ -430,7 +439,8 @@ int __init rdt_get_l3_mon_config(struct rdt_resource *r) resctrl_rmid_realloc_limit = boot_cpu_data.x86_cache_size * 1024; hw_res->mon_scale = boot_cpu_data.x86_cache_occ_scale / snc_nodes_per_l3_cache; - r->mon.num_rmid = (boot_cpu_data.x86_cache_max_rmid + 1) / snc_nodes_per_l3_cache; + r->mon.num_rmid = (erdt_max_rmid > 0) ? erdt_max_rmid + 1 : + (boot_cpu_data.x86_cache_max_rmid + 1) / snc_nodes_per_l3_cache; hw_res->mbm_width = MBM_CNTR_WIDTH_BASE; if (mbm_offset > 0 && mbm_offset <= MBM_CNTR_WIDTH_OFFSET_MAX) @@ -477,7 +487,18 @@ int __init rdt_get_l3_mon_config(struct rdt_resource *r) hw_res->mbm_cntr_assign_enabled = true; } - r->mon_capable = true; + /* + * If the platform has ERDT but the SNC is enabled, + * this monitor should not be enabled. + */ + if (erdt_cpu_has(X86_FEATURE_CQM_OCCUP_LLC) && + snc_nodes_per_l3_cache > 1) { + WARN_ONCE(1, "ERDT is enabled but SNC%d is enabled, monitors for resource[%s] should be disabled\n", + snc_nodes_per_l3_cache, r->name); + resctrl_disable_mon_event(QOS_L3_OCCUP_EVENT_ID); + } else { + r->mon_capable = true; + } return 0; } diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c index 6a7c86a72c51..2cf03e4cf72a 100644 --- a/fs/resctrl/monitor.c +++ b/fs/resctrl/monitor.c @@ -1034,6 +1034,12 @@ bool resctrl_enable_mon_event(enum resctrl_event_id eventid, bool any_cpu, return true; } +void resctrl_disable_mon_event(enum resctrl_event_id eventid) +{ + if (mon_event_all[eventid].enabled) + mon_event_all[eventid].enabled = false; +} + bool resctrl_is_mon_event_enabled(enum resctrl_event_id eventid) { return eventid >= QOS_FIRST_EVENT && eventid < QOS_NUM_EVENTS && diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index 73ff522448a0..dfde025432ab 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -420,6 +420,7 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid); bool resctrl_enable_mon_event(enum resctrl_event_id eventid, bool any_cpu, unsigned int binary_bits, void *arch_priv); +void resctrl_disable_mon_event(enum resctrl_event_id eventid); bool resctrl_is_mon_event_enabled(enum resctrl_event_id eventid); -- 2.45.2