Introduce MMIO-based CMT access for Enhanced RDT
Subsystems (2)
v6 cover Introduce MMIO-based CMT access for Enhanced RDT
v5: https://lore.kernel.org/lkml/[email protected]/
v4: https://lore.kernel.org/lkml/[email protected]/
v3: https://lore.kernel.org/lkml/[email protected]/
v2: https://lore.kernel.org/lkml/[email protected]/
v1: https://lore.kernel.org/lkml/[email protected]/
Intel Enhanced Resource Director Technology (ERDT) extends the existing RDT framework with two major capabilities:
1. MMIO-based access to monitoring and allocation registers, replacing the legacy MSR-based interface.
2. Region-aware RDT for fine-grained control over different tiers of
memory (e.g., CXL.mem, DDR).
This is described in the Intel RDT Architecture Specification:
https://cdrdv2-public.intel.com/789566/356688-intel-rdt-arch-spec.pdf
This patch set focuses on the first part: enabling MMIO-based access for Cache Monitoring Technology (CMT), while CAT/MBM/MBA are still using MSR. The platform advertises the MMIO register layout through the ACPI ERDT (Enhanced Resource Director Technology) table, which contains sub-tables describing per-domain register regions for monitoring and allocation.
With ERDT, L3 cache occupancy counters are read via MMIO rather than MSR, allowing the reads to be performed from any CPU without requiring cross-CPU IPIs. This series parses the relevant ACPI sub-tables (RMDD, CMRC), prepares the resctrl monitor infrastructure for MMIO-based reads, and adds initial support for reading L3 occupancy via the CMRC interface.
kselftest of CMT and L3_CAT has passed with minor adjustment at
https://lore.kernel.org/lkml/[email protected]/.
V6 has gone through local sashiko review, with false positives left unaddressed.
Major changes from V5 to V6:
- Reorder the series so that the x86/topology change, which touches a different subsystem, comes first. (Reinette Chatre)
- Drop the v5 "x86/resctrl: Replace 'msr' in monitoring data identifiers" patch. None of the renamed identifiers are used by the MMIO code. (Reinette Chatre)
- Split the domain setup into erdt_cpu_valid() and erdt_l3_mon_domain_setup(). Validation now happens in domain_add_cpu_mon() before the CPU is added to the domain cpumask, and attaching ERDT data to a freshly created domain (Reinette Chatre)
- Drop the SNC special case and the new resctrl_disable_mon_event(). (Reinette Chatre)
- resctrl_arch_round_mon_val() now rounds to the ERDT scale instead of returning the value unchanged (Reinette Chatre)
- Make erdt_get_max_rmid() a global value instead of a per-CPU lookup. (Reinette Chatre)
- Use struct cpumask instead of cpumask_var_t, list_for_each_entry() instead of open coded container_of(), and document every member of struct erdt_domain_info. (Reinette Chatre)
Thanks Tony, Reinette, Thomas, Hongyu for your time to look at this patch set.
Changes from V4 to V5:
There are some major changes since v4:
- (biggest change) Eliminate the xarray for runtime lookups; embed struct erdt_domain_info directly in rdt_hw_l3_mon_domain and assign during l3_mon_domain_setup().
- Separate CPUID and ACPI enumeration cleanly. Do not use CPUID feature flags to gate MMIO-based monitoring. Use ACPI table presence (e.g., CMRC table) to determine event enablement.
- Use ACPI RMDD's own "Max RMID" field for MMIO access instead of relying on CPUID's max RMID (which applies to MSR).
- Enforce the SNC constraint in code rather than burying it behind a comment WARN. Disable mon_capable in rdt_get_l3_mon_config() when ERDT is enabled and snc_nodes_per_l3_cache > 1.
- Split non-resctrl changes (topology.c, apic.h) into a separate preparatory patch prefixed with x86/topology.
- Move the "depends on X86" to "X86_64" adjustment to a separate patch with explicit justification in its changelog.
Changes from V3 to V4:
- Remove the redundant table length check in subtbl_valid() (Thomas Gleixner)
- Reuse subtbl_valid() for all the table iteration (Thomas Gleixner)
- Refine the commit log of [PATCH 5/6] to state that this change is a preparation for [PATCH 6/6] rather than fixing an existing issue (Thomas Gleixner, Reinette Chatre, Tony Luck)
- Fix if CACD lists all CPUs in the LLC domain (sashiko)
- Deal with a corner case that if there is no valid RMDD tables, the erdt_enabled_flag should remain false.(sashiko)
- Add Thomas's Reviewed-by and Hongyu's Tested-by.
Changes from V2 to V3:
- Wrap __resctrl_arch_late_init() to avoid the goto logic. (Thomas Gleixner)
- Make the variables in struct erdt_domain_info tabular format (Thomas Gleixner)
- Remove tail comments (Thomas Gleixner)
- Make the name of erdt_enabled() and variable in it consistent and comprehensible. (Thomas Gleixner)
- Use topo_lookup_cpuid() to search the CPU id according to the x2apic id (Thomas Gleixner)
- Fix kernel doc comment format (Thomas Gleixner)
- Use brackets for multiple lines "if" case. (Thomas Gleixner)
- Let the parameter for cacd_init() to fully utilize 100 characters. (Thomas Gleixner)
- Variables are reordered in reverse fir-tree.(Thomas Gleixner)
- Added a named constant and use it in the rmdd->flags check. (Thomas Gleixner)
- Introduce helper functions to make the code readable when iterating the RMDD tables. (Thomas Gleixner)
- Make the macros tabular format. (Thomas Gleixner)
Changes from V1 to V2:
- Add #include <linux/cleanup.h> to follow the "include-what-you-use" best practice (Tony Luck)
- Fix 3 issues reported by:
https://sashiko.dev/#/patchset/cover.1779872016.git.yu.c.chen%40intel.com
Remove the variable of cacd in struct erdt_domain_info as it will never be used after initialization.
Invoke erdt_exit() to avoid resource leak if rdt_alloc_capable and rdt_mon_capable are both false.
Adjust the comments suggested by sashiko.
Anil S Keshavamurthy (1):
x86/resctrl: Parse ACPI ERDT table and save CACD cpumask for RMDD
domains
Chen Yu (7):
x86/topology: Export topo_lookup_cpuid() for resctrl use x86/resctrl: Require 64-bit x86 for resctrl support x86/resctrl: Attach ACPI ERDT information to L3 mon domain on CPU
online
x86/resctrl: Parse ACPI CMRC table
x86/resctrl: Refactor the monitor read function x86/resctrl: Introduce erdt_cpu_has() and erdt_support() x86/resctrl: Add MMIO-based LLC occupancy monitoring support
Tony Luck (1):
fs/resctrl: Do not invoke smp_processor_id() in preemptible context
arch/x86/Kconfig | 4 +- arch/x86/include/asm/apic.h | 1 + arch/x86/include/asm/resctrl.h | 11 +- arch/x86/kernel/cpu/resctrl/Makefile | 1 + arch/x86/kernel/cpu/resctrl/core.c | 53 ++- arch/x86/kernel/cpu/resctrl/erdt.c | 453 +++++++++++++++++++++++++ arch/x86/kernel/cpu/resctrl/internal.h | 49 ++- arch/x86/kernel/cpu/resctrl/monitor.c | 36 +- arch/x86/kernel/cpu/topology.c | 2 +- fs/resctrl/monitor.c | 44 ++- 10 files changed, 627 insertions(+), 27 deletions(-) create mode 100644 arch/x86/kernel/cpu/resctrl/erdt.c
Signature · 1 line
2.25.1
PATCH v6 1/9 x86/topology: Export topo_lookup_cpuid() for resctrl use
Enhanced RDT (ERDT) enumerates its monitoring and control resources through ACPI tables that identify each CPU by its x2APIC ID. To associate this firmware-provided data with the kernel's per-CPU structures, ERDT must translate those x2APIC IDs into logical CPU numbers.
topo_lookup_cpuid() already performs this translation, but it is static to topology.c and therefore not reachable from resctrl.
Export topo_lookup_cpuid() and add its declaration to asm/apic.h so that ERDT can resolve x2APIC IDs from ACPI tables to logical CPU numbers.
No functional change intended.
---v5->v6:
Move this patch to the beginning of the series because it touches a different subsystem than the rest of the series. (Reinette Chatre) Order the commit tags per Documentation/process/maintainer-tip.rst. (Reinette Chatre)
--- arch/x86/include/asm/apic.h | 1 + arch/x86/kernel/cpu/topology.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-)
arch/x86/include/asm/apic.h +1 -0
@@ -54,6 +54,7 @@ static inline void x86_32_probe_apic(void) { }#endif extern u32 cpuid_to_apicid[]; +int topo_lookup_cpuid (u32 apic_id);#define CPU_ACPIID_INVALID U32_MAX
arch/x86/kernel/cpu/topology.c +1 -1
@@ -92,7 +92,7 @@ static inline u32 topo_apicid(u32 apicid, enum x86_topology_domains dom)return apicid & (UINT_MAX << x86_topo_system.dom_shifts[dom -1 ]); } -static int topo_lookup_cpuid (u32 apic_id) +int topo_lookup_cpuid (u32 apic_id) {int i;
Signature · 1 line
2.25.1
Reinette Chatre
maintainerRe: [PATCH v6 1/9] x86/topology: Export topo_lookup_cpuid() for resctrl use
Hi Chenyu,
Quoted 1 line · Chen Yu
Enhanced RDT (ERDT) enumerates its monitoring and control resources
Please use at least 80 characters per line. The checkpatch warnings about 75 characters can be ignored. For context, please see
https://lore.kernel.org/lkml/20250916105447.GCaMlB976WLxHHeNMD@fat_crate.local/
Please check entire series.
Quoted 9 lines
through ACPI tables that identify each CPU by its x2APIC ID. To associate this firmware-provided data with the kernel's per-CPU structures, ERDT must translate those x2APIC IDs into logical CPU numbers.
topo_lookup_cpuid()already performs this translation, but it is static totopology.cand therefore not reachable from resctrl.Export
topo_lookup_cpuid()and add its declaration toasm/apic.hso
To support this change you could add a motivation why this particular header file was chosen. For example,
"add its declaration to asm/apic.h" -> "add its declaration to asm/apic.h that already exposes the inverse mapping"
Quoted 8 lines
that ERDT can resolve x2APIC IDs from ACPI tables to logical CPU numbers.
No functional change intended.
Signed-off-by Chen Yu <[email protected]>Tested-by Hongyu Ning <[email protected]>---
| Reviewed-by: Reinette Chatre <[email protected]>
Reinette
Re: [PATCH v6 1/9] x86/topology: Export topo_lookup_cpuid() for resctrl use
Hi Reinette,
Quoted 11 lines · Reinette Chatre
Hi Chenyu,
Quoted 1 line · Chen Yu
Enhanced RDT (ERDT) enumerates its monitoring and control resources
Please use at least 80 characters per line. The checkpatch warnings about 75 characters can be ignored. For context, please see
https://lore.kernel.org/lkml/20250916105447.GCaMlB976WLxHHeNMD@fat_crate.local/Please check entire series.
Got it, will check and fix them accordingly.
Quoted 8 lines
Quoted 8 lines
through ACPI tables that identify each CPU by its x2APIC ID. To associate this firmware-provided data with the kernel's per-CPU structures, ERDT must translate those x2APIC IDs into logical CPU numbers.
topo_lookup_cpuid()already performs this translation, but it is static totopology.cand therefore not reachable from resctrl.
Quoted 7 lines
Quoted 1 line
Export
topo_lookup_cpuid()and add its declaration toasm/apic.hsoTo support this change you could add a motivation why this particular header file was chosen. For example,
"add its declaration toasm/apic.h" -> "add its declaration toasm/apic.hthat already exposes the inverse mapping"
OK, will adjust it.
Quoted 11 lines
Quoted 8 lines
that ERDT can resolve x2APIC IDs from ACPI tables to logical CPU numbers.
No functional change intended.
Signed-off-by Chen Yu <[email protected]>Tested-by Hongyu Ning <[email protected]>---
| Reviewed-by: Reinette Chatre <[email protected]>
Thanks!
Chenyu
Quoted 1 line
Reinette
PATCH v6 2/9 x86/resctrl: Require 64-bit x86 for resctrl support
In reply to Chen YuAll known hardware that supports Intel RDT or AMD QoS is 64-bit. Future enhancements like MMIO-based Enhanced RDT (ERDT) monitoring require readq()/writeq() which are only available on 64-bit. There is also no realistic use case for users to build a 32-bit kernel on a server and enable resctrl.
Drop 32-bit support by changing the X86_CPU_RESCTRL dependency from X86 to X86_64.
Since X86_CPU_RESCTRL now implies X86_64, remove the redundant X86_64 dependency from X86_CPU_RESCTRL_INTEL_AET.
---v5->v6:
Order the tags per Documentation/process/maintainer-tip.rst.
--- arch/x86/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/Kconfig +2 -2
@@ -514,7 +514,7 @@ config X86_MPPARSE config X86_CPU_RESCTRL bool "x86 CPU resource control support" - depends on X86 && (CPU_SUP_INTEL || CPU_SUP_AMD) + depends on X86_64 && (CPU_SUP_INTEL || CPU_SUP_AMD) depends on MISC_FILESYSTEMS select ARCH_HAS_CPU_RESCTRL select RESCTRL_FS
@@ -537,7 +537,7 @@ config X86_CPU_RESCTRL config X86_CPU_RESCTRL_INTEL_AET bool "Intel Application Energy Telemetry" - depends on X86_64 && X86_CPU_RESCTRL && CPU_SUP_INTEL && INTEL_PMT_TELEMETRY=y && INTEL_TPMI=y + depends on X86_CPU_RESCTRL && CPU_SUP_INTEL && INTEL_PMT_TELEMETRY=y && INTEL_TPMI=y help Enable per-RMID telemetry events in resctrl.
Signature · 1 line
2.25.1
Reinette Chatre
maintainerRe: [PATCH v6 2/9] x86/resctrl: Require 64-bit x86 for resctrl support
Hi Chenyu,
Quoted 9 lines · Chen Yu
All known hardware that supports Intel RDT or AMD QoS is 64-bit. Future enhancements like MMIO-based Enhanced RDT (ERDT) monitoring require readq()/writeq() which are only available on 64-bit. There is also no realistic use case for users to build a 32-bit kernel on a server and enable resctrl.
Drop 32-bit support by changing the
X86_CPU_RESCTRLdependency from X86 toX86_64.
Quoted 6 lines
Since
X86_CPU_RESCTRLnow impliesX86_64, remove the redundantX86_64dependency fromX86_CPU_RESCTRL_INTEL_AET.Signed-off-by Chen Yu <[email protected]>Tested-by Hongyu Ning <[email protected]>---
Reviewed at:
https://lore.kernel.org/lkml/[email protected]/
Reinette
Luck, Tony
maintainerRE: [PATCH v6 2/9] x86/resctrl: Require 64-bit x86 for resctrl support
Quoted 2 lines
Reviewed at:
https://lore.kernel.org/lkml/[email protected]/
Reinette,
I've written up this draft for next series. Are you looking for something like this?
x86/resctrl: Require 64-bit x86 for resctrl support
All known hardware that supports Intel RDT or AMD QoS is 64-bit.
On x86 the maximum supported memory size on a 32-bit kernel is 64GB (when PAE is enabled). Linux imposes additional constraints since each 4KByte page requires a 64-byte "struct page" which must reside in the always-mapped 3-4GByte range of the 32-bit kernel virtual address space. This means the maximum supported memory size is slightly above 32GB, but at that memory size there are considerable inefficiencies as over half of kernel virtual memory is dedicated to the page structures.
The earliest server processor to support resctrl was Intel Haswell, released in 2014. It supported four memory channels, and production systems were advised to populate all channels to provide sufficient memory bandwidth to keep the cores busy. Best value DIMMs in 2014 were 16GB. So even a single socket Haswell system would have more memory than could be addressed by a 32-bit kernel.
Drop 32-bit support by changing the X86_CPU_RESCTRL dependency from X86 to X86_64.
Since X86_CPU_RESCTRL now implies X86_64, remove the redundant X86_64 dependency from X86_CPU_RESCTRL_INTEL_AET.
-Tony
Reinette Chatre
maintainerRe: [PATCH v6 2/9] x86/resctrl: Require 64-bit x86 for resctrl support
Hi Tony,
Quoted 19 lines · Tony
Quoted 2 lines
Reviewed at:
https://lore.kernel.org/lkml/[email protected]/Reinette,
I've written up this draft for next series. Are you looking for something like this?
x86/resctrl: Require 64-bit x86 for resctrl support
All known hardware that supports Intel RDT or AMD QoS is 64-bit.
On x86 the maximum supported memory size on a 32-bit kernel is 64GB (when PAE is enabled). Linux imposes additional constraints since each 4KByte page requires a 64-byte "struct page" which must reside in the always-mapped 3-4GByte range of the 32-bit kernel virtual address space. This means the maximum supported memory size is slightly above 32GB, but at that memory size there are considerable inefficiencies as over half of kernel virtual memory is dedicated to the page structures.
Quoted 5 lines
The earliest server processor to support resctrl was Intel Haswell, released in 2014. It supported four memory channels, and production systems were advised to populate all channels to provide sufficient memory bandwidth to keep the cores busy. Best value DIMMs in 2014 were 16GB. So even a single socket Haswell system would have more memory than could be addressed by a 32-bit kernel.
I assume above aims to justify the "no realistic use case for users to build a 32-bit kernel on a server and enable resctrl"?
To be specific, my comment about RDT not being a "server" feature was made with Apollo Lake [1] in mind. That system showed up in scenarios where servers do not typically venture and per [1] its max memory size (8GB) is significantly less than what servers can support.
Apart from that it was the "no realistic use case" that tripped me. At best I think we can say that we are not aware of 32-bit use cases?
Quoted 6 lines
Drop 32-bit support by changing the
X86_CPU_RESCTRLdependency from X86 toX86_64.Since
X86_CPU_RESCTRLnow impliesX86_64, remove the redundantX86_64dependency fromX86_CPU_RESCTRL_INTEL_AET.
Reinette
Luck, Tony
maintainerRE: [PATCH v6 2/9] x86/resctrl: Require 64-bit x86 for resctrl support
Quoted 3 lines
To be specific, my comment about RDT not being a "server" feature was made with Apollo Lake [1] in mind. That system showed up in scenarios where servers do not typically venture and per [1] its max memory size (8GB) is significantly less than what servers can support.
Even with just 8GB you should really use 64-bit.
I can't find a link to the original of this quote, but there are several places where other people reference it. I've personally heard Linus say something along the same lines.
"On the OS level, it's advantageous for the virtual address space to be larger than the physical
address space. It needs to be bigger, by a factor of at least two, and that's quite frankly pushing it, and you're much better off having a factor of ten or more. Anybody who doesn't get that is a moron. End of discussion." -- Linus Torvalds
-Tony
Re: [PATCH v6 2/9] x86/resctrl: Require 64-bit x86 for resctrl support
Quoted 4 lines · Tony
Quoted 3 lines
To be specific, my comment about RDT not being a "server" feature was made with Apollo Lake [1] in mind. That system showed up in scenarios where servers do not typically venture and per [1] its max memory size (8GB) is significantly less than what servers can support.
Even with just 8GB you should really use 64-bit.
Just in practice, 32-bit is very lightly tested. We're generally not even supporting new CPU features on 32-bit even if the hardware supports it. Think of shadow stacks, for instance.
It's actually increasingly hard to even find a modern 32-bit distro.
So it really has nothing to do with high memory. It just practically that the arch/x86 32-bit code is increasingly there for legacy reasons. Its testing goes down every day and the testing of *new* features is for all intents and purposes zero.
Honestly, the only people who complain about 32-bit support going away are folks who "test" it regularly. It's quite rare to see anyone actually "using" a 32-bit system.
Reinette Chatre
maintainerRe: [PATCH v6 2/9] x86/resctrl: Require 64-bit x86 for resctrl support
Quoted 12 lines · Dave Hansen
Quoted 4 lines · Tony
Quoted 3 lines
To be specific, my comment about RDT not being a "server" feature was made with Apollo Lake [1] in mind. That system showed up in scenarios where servers do not typically venture and per [1] its max memory size (8GB) is significantly less than what servers can support.
Even with just 8GB you should really use 64-bit.
Just in practice, 32-bit is very lightly tested. We're generally not even supporting new CPU features on 32-bit even if the hardware supports it. Think of shadow stacks, for instance.
It's actually increasingly hard to even find a modern 32-bit distro.
Quoted 8 lines
So it really has nothing to do with high memory. It just practically that the
arch/x8632-bit code is increasingly there for legacy reasons. Its testing goes down every day and the testing of *new* features is for all intents and purposes zero.Honestly, the only people who complain about 32-bit support going away are folks who "test" it regularly. It's quite rare to see anyone actually "using" a 32-bit system.
I do support this change and clearly stated so in my original review [1].
My comments were only regarding accuracy of the motivation used in the changelog.
Reinette
Borislav Petkov
maintainerRe: [PATCH v6 2/9] x86/resctrl: Require 64-bit x86 for resctrl support
Quoted 2 lines · Reinette Chatre
My comments were only regarding accuracy of the motivation used in the changelog.
Well, what should be the motivation? How about "no one cares about 32-bit and if people wanna use resctrl on it, they're on their own."?
Yeah, we are spread less than thin on 64-bit already, there simply are no resources for 32-bit. And willingness to support it even less. We have the 64-bit architecture for more than 20 years now. It is time we finally let go of 32-bit.
In the end of the day, it is very simple: lack of resources and prioritization of same.
HTH.
Signature · 4 lines
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquetteReinette Chatre
maintainerRe: [PATCH v6 2/9] x86/resctrl: Require 64-bit x86 for resctrl support
Quoted 6 lines · Borislav Petkov
Quoted 2 lines · Reinette Chatre
My comments were only regarding accuracy of the motivation used in the changelog.
Well, what should be the motivation? How about "no one cares about 32-bit and if people wanna use resctrl on it, they're on their own."?
It is clear to me that there is no need for a strong motivation for this change that x86 maintainers already support. Even so, I find no justification for using misinformation in the changelog that makes this change. This was my only feedback to the original commit as I aim to support precise changelogs that are not confusing.
Reinette
Borislav Petkov
maintainerRe: [PATCH v6 2/9] x86/resctrl: Require 64-bit x86 for resctrl support
Quoted 5 lines · Reinette Chatre
It is clear to me that there is no need for a strong motivation for this change that x86 maintainers already support. Even so, I find no justification for using misinformation in the changelog that makes this change. This was my only feedback to the original commit as I aim to support precise changelogs that are not confusing.
... and I gave you more justification reasons to choose from.
:-)
Signature · 4 lines
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquetteRe: [PATCH v6 2/9] x86/resctrl: Require 64-bit x86 for resctrl support
In reply to Reinette ChatreHi Reinette,
Quoted 6 lines · Reinette Chatre
Quoted 4 lines · Borislav Petkov
Quoted 2 lines · Reinette Chatre
My comments were only regarding accuracy of the motivation used in the changelog.
Quoted 9 lines
Quoted 2 lines
Well, what should be the motivation? How about "no one cares about 32-bit and if people wanna use resctrl on it, they're on their own."?
It is clear to me that there is no need for a strong motivation for this change that x86 maintainers already support. Even so, I find no justification for using misinformation in the changelog that makes this change. This was my only feedback to the original commit as I aim to support precise changelogs that are not confusing.
How about replacing "There is also no realistic use case for users to build a 32-bit kernel on a server" with the following description:
"32-bit x86 is maintained for legacy reasons. New CPU features are generally not enabled for 32-bit system, its test coverage keeps shrinking, and modern 32-bit distributions have become rare."
thanks,
Chenyu
Re: [PATCH v6 2/9] x86/resctrl: Require 64-bit x86 for resctrl support
Quoted 3 lines · Chen Yu
"32-bit x86 is maintained for legacy reasons. New CPU features are generally not enabled for 32-bit system, its test coverage keeps shrinking, and modern 32-bit distributions have become rare."
What would folks think about plopping something like the following text in to Documentation/arch/x86/32bit-kernels.rst ?
Would that clear things up?
---
=========================================
Supporting new features on 32-bit kernels
=========================================
While it is possible to compile and run a 32-bit kernel on 64-bit capable hardware, it is impractical and discouraged. Processors capable of running 64-bit kernels are expected to do so.
The last 32-bit processor to come out of Intel or AMD was a Quark CPU in 2013. Before that the most recent were some Atom CPUs in 2008.
Distros supporting 32-bit kernels and userspace are disappearing. For example, in 2026 Ubuntu and Fedora no longer have support, with Debian being the most notable holdout still maintaining 32-bit options.
New Processor Features
======================
When adding support for a new processor feature in 2026 and beyond it should, by default, be:
config NEW_SNAZZY_CPU_FEATURE
depends X86_64This ensures that the folks developing this feature do not waste resources making it work on 32-bit kernels running on 64-bit hardware.
It is also acceptable to add this restriction to existing processor features if 32-bit kernel support is adding maintenance burden, especially if the feature was only ever available on 64-bit processors.
New Software Features
=====================
Let's say you are enhancing ftrace or adding a debugging feature that has no strict dependency on processor features. It does not need to be restricted to 64-bit only. But you might want to consider doing so if it simplifies your implementation.
For instance, sometimes it adds complexity to support HIGHMEM. You may add a dependency on X86_64 in cases where it is impractical or simply challenging to support 32-bit kernels.
Re: [PATCH v6 2/9] x86/resctrl: Require 64-bit x86 for resctrl support
Quoted 10 lines · Dave Hansen
Quoted 3 lines · Chen Yu
"32-bit x86 is maintained for legacy reasons. New CPU features are generally not enabled for 32-bit system, its test coverage keeps shrinking, and modern 32-bit distributions have become rare."
What would folks think about plopping something like the following text in to
Documentation/arch/x86/32bit-kernels.rst?Would that clear things up?
Thanks, Dave, for the detailed document. It will be very helpful.
Quoted 10 lines
---
=========================================
Supporting new features on 32-bit kernels
=========================================While it is possible to compile and run a 32-bit kernel on 64-bit capable hardware, it is impractical and discouraged. Processors capable of running 64-bit kernels are expected to do so.
Quoted 6 lines
The last 32-bit processor to come out of Intel or AMD was a Quark CPU in 2013. Before that the most recent were some Atom CPUs in 2008.
Distros supporting 32-bit kernels and userspace are disappearing. For example, in 2026 Ubuntu and Fedora no longer have support, with Debian being the most notable holdout still maintaining 32-bit options.
According to
https://www.debian.org/releases/trixie/release-notes/issues.en.html#i386-reduced-support
"From trixie, i386 is no longer supported as a regular architecture"
Quoted 9 lines
New Processor Features
======================When adding support for a new processor feature in 2026 and beyond it should, by default, be:
config NEW_SNAZZY_CPU_FEATURE depends X86_64
depends on X86_64
thanks,
Chenyu
Quoted 19 lines
This ensures that the folks developing this feature do not waste resources making it work on 32-bit kernels running on 64-bit hardware.
It is also acceptable to add this restriction to existing processor features if 32-bit kernel support is adding maintenance burden, especially if the feature was only ever available on 64-bit processors.
New Software Features
=====================Let's say you are enhancing ftrace or adding a debugging feature that has no strict dependency on processor features. It does not need to be restricted to 64-bit only. But you might want to consider doing so if it simplifies your implementation.
For instance, sometimes it adds complexity to support HIGHMEM. You may add a dependency on
X86_64in cases where it is impractical or simply challenging to support 32-bit kernels.
Borislav Petkov
maintainerRe: [PATCH v6 2/9] x86/resctrl: Require 64-bit x86 for resctrl support
In reply to Dave HansenQuoted 2 lines · Dave Hansen
What would folks think about plopping something like the following text in to
Documentation/arch/x86/32bit-kernels.rst?
Call that "32bit-deprecated.txt" so that it is clear before you even open it.
:-P
But yap, let's do it.
Signature · 4 lines
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquetteRe: [PATCH v6 2/9] x86/resctrl: Require 64-bit x86 for resctrl support
In reply to Dave HansenQuoted 3 lines · Dave Hansen
Honestly, the only people who complain about 32-bit support going away are folks who "test" it regularly. It's quite rare to see anyone actually "using" a 32-bit system.
I've for a long time advocated detecting LM during the 32bit boot and simply aborting with a message: "Go run the x86_64 kernel!".
Borislav Petkov
maintainerRe: [PATCH v6 2/9] x86/resctrl: Require 64-bit x86 for resctrl support
Quoted 2 lines · Peter Zijlstra
I've for a long time advocated detecting LM during the 32bit boot and simply aborting with a message: "Go run the
x86_64kernel!".
Ack to that. Let's do it and see who complains.
Signature · 4 lines
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquetteLuck, Tony
maintainerRE: [PATCH v6 2/9] x86/resctrl: Require 64-bit x86 for resctrl support
Quoted 4 lines
Quoted 2 lines
I've for a long time advocated detecting LM during the 32bit boot and simply aborting with a message: "Go run the
x86_64kernel!".Ack to that. Let's do it and see who complains.
Probably everyone running regression tests of 32-bit kernels on hardware, rather than in Qemu. Unless they have some 20 year old Yonah CPUs still running.
-Tony
Borislav Petkov
maintainerRe: [PATCH v6 2/9] x86/resctrl: Require 64-bit x86 for resctrl support
Quoted 2 lines · Tony
Probably everyone running regression tests of 32-bit kernels on hardware, rather than in Qemu.
You mean you know of people who actully willingly waste electricity for that?
Signature · 4 lines
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquettePATCH v6 3/9 x86/resctrl: Parse ACPI ERDT table and save CACD cpumask for RMDD domains
In reply to Chen YuFrom: Anil S Keshavamurthy <[email protected]>
Parse the RMDD subtables within the ERDT ACPI table and their nested CACD entries to construct per-domain CPU masks.
There is one ERDT table per platform. Each RMDD describes one resource management domain (RMD), also known as an L3 domain, and carries MMIO base information for later monitoring support.
For each RMDD, parse the associated CACD, map its x2APIC IDs to logical CPUs, and save the resulting CPU mask. This mask associates each ERDT domain with the CPUs that belong to it and is used later when attaching ERDT data to resctrl monitoring domains.
---v5->v6:
Make the changelog specific to this patch instead of describing all ERDT sub-tables, and say "one ERDT table" instead of "one ERDT". (Reinette Chatre)
Move ERDT_MMIO_CMRC_BASE to the patch that uses it. (Reinette Chatre) Drop the unused linux/cpu.h and linux/xarray.h includes. (Reinette Chatre)
Rename __erdt_enabled to erdt_enabled and add a comment describing what it means. (Reinette Chatre)
Drop the CPU parameter from erdt_get_max_rmid(). There is one global ERDT max RMID, computed while the RMDD tables are parsed. (Reinette Chatre)
Use list_for_each_entry() and list_for_each_entry_safe() instead of open coding container_of(). (Reinette Chatre)
Drop the size_t casts from check_mul_overflow(). (Reinette Chatre) Drop the unnecessary braces after "if (!addr)". (Reinette Chatre) Use struct cpumask instead of cpumask_var_t and drop the zalloc_cpumask_var()/free_cpumask_var() calls. (Reinette Chatre) Rename parse_rmdd_entry() to parse_rmdd_table(), an RMDD is a sub-table and not an entry. (Reinette Chatre)
Add the unit to the invalid RMDD length message. (Reinette Chatre) Note in a comment that an RMDD table can have more than one CACD sub-table. (Reinette Chatre)
Print the domain IDs of both RMDDs in the sub-table mismatch warning. (Reinette Chatre)
Drop the unclear "max_rmid > INT_MAX" test. (Reinette Chatre) Print the ERDT revision found together with the expected one, and use %u for unsigned values. (Reinette Chatre)
Document every member of struct erdt_domain_info and rename its struct list_head member from "list" to "entry". (Reinette Chatre)
--- arch/x86/kernel/cpu/resctrl/Makefile | 1 + arch/x86/kernel/cpu/resctrl/core.c | 14 +- arch/x86/kernel/cpu/resctrl/erdt.c | 266 +++++++++++++++++++++++++ arch/x86/kernel/cpu/resctrl/internal.h | 31 +++ 4 files changed, 311 insertions(+), 1 deletion(-) create mode 100644 arch/x86/kernel/cpu/resctrl/erdt.c
arch/x86/kernel/cpu/resctrl/Makefile +1 -0
@@ -2,6 +2,7 @@ obj-$(CONFIG_X86_CPU_RESCTRL) += core.o rdtgroup.o monitor.o obj-$(CONFIG_X86_CPU_RESCTRL) += ctrlmondata.o obj-$(CONFIG_X86_CPU_RESCTRL_INTEL_AET) += intel_aet.o +obj-$(CONFIG_X86_CPU_RESCTRL) += erdt.o obj-$(CONFIG_RESCTRL_FS_PSEUDO_LOCK) += pseudo_lock.o # To allow define_trace.h's recursive include:
arch/x86/kernel/cpu/resctrl/core.c +13 -1
@@ -1013,6 +1013,7 @@ static __init void check_quirks(void)static __init bool get_rdt_resources (void ) { +erdt_init (); rdt_alloc_capable =get_rdt_alloc_resources (); rdt_mon_capable =get_rdt_mon_resources ();
@@ -1114,7 +1115,7 @@ void resctrl_cpu_detect(struct cpuinfo_x86 *c) } } -static int __init resctrl_arch_late_init (void ) +static int __init __resctrl_arch_late_init (void ) {struct rdt_resource *r;int state, ret, i;
@@ -1157,6 +1158,15 @@ static int __init resctrl_arch_late_init(void)return 0 ; } +static int __init resctrl_arch_late_init (void ) +{ +int ret =__resctrl_arch_late_init (); + +if (ret) +erdt_exit (); +return ret; +} +late_initcall (resctrl_arch_late_init); static void __exit resctrl_arch_exit(void)
@@ -1166,6 +1176,8 @@ static void __exit resctrl_arch_exit(void)cpuhp_remove_state (rdt_online);resctrl_exit (); + +erdt_exit (); }__exitcall (resctrl_arch_exit);
arch/x86/kernel/cpu/resctrl/erdt.c new file +266 -0
266 lines not on this page · raw message
arch/x86/kernel/cpu/resctrl/internal.h +31 -0
@@ -21,6 +21,33 @@#define RMID_VAL_UNAVAIL BIT_ULL(62) +/* +* Index into erdt_domain_info::base[] for each MMIO region. +* @ERDT_MMIO_RMDD_CREG: RMDD control register base address +*/ +enum erdt_mmio_type { +ERDT_MMIO_RMDD_CREG , +ERDT_MMIO_LAST =ERDT_MMIO_RMDD_CREG +}; + +#define ERDT_MMIO_NUM_TYPES (ERDT_MMIO_LAST + 1) + +/** +* struct erdt_domain_info - Per-domain ERDT information +* @base: Array of ioremapped MMIO region base addresses, indexed by ERDT_MMIO_* type +* @cpu_mask: CPUs belonging to this resource management domain +* @max_rmid: Maximum RMID supported by this domain +* @dom_id: L3 cache ID shared by all CPUs in this domain (-1 if unset) +* @entry: Links into the global domain_info_list +*/ +struct erdt_domain_info { +void __iomem *base[ERDT_MMIO_NUM_TYPES ]; +struct cpumask cpu_mask; +u32 max_rmid; +int dom_id; +struct list_head entry; +}; +/* * With the above fields in use 62 bits remain in MSR_IA32_QM_CTR for * data to be returned. The counter width is discovered from the hardware
@@ -253,4 +280,8 @@ static inline void intel_aet_mon_domain_setup(int cpu, int id, struct rdt_resourstatic inline bool intel_handle_aet_option (bool force_off,char *tok) {return false; }#endif +int erdt_get_max_rmid (void ); +int erdt_init (void ); +void erdt_exit (void ); +#endif /* _ASM_X86_RESCTRL_INTERNAL_H */
Signature · 1 line
2.25.1
Reinette Chatre
maintainerRe: [PATCH v6 3/9] x86/resctrl: Parse ACPI ERDT table and save CACD cpumask for RMDD domains
Hi Chenyu,
Quoted 4 lines · Chen Yu
From: Anil S Keshavamurthy <[email protected]>
Parse the RMDD subtables within the ERDT ACPI table and their nested CACD entries to construct per-domain CPU masks.
The changelog always needs to start with context. Please see "Changelog" in Documentation/process/maintainer-tip.rst for complete expectations.
Quoted 2 lines
There is one ERDT table per platform. Each RMDD describes one resource
I do not think what "RMDD" stands for has been introduced at this point yet.
Quoted 4 lines
management domain (RMD), also known as an L3 domain, and carries MMIO base information for later monitoring support.
For each RMDD, parse the associated CACD, map its x2APIC IDs to logical
What is "CACD"? Please always expand acronym before its first use.
Quoted 3 lines
CPUs, and save the resulting CPU mask. This mask associates each ERDT domain with the CPUs that belong to it and is used later when attaching ERDT data to resctrl monitoring domains.
Please let each patch description stand on its own without referring to later patches in series. If a patch provides capability in preparation for future changes then you can use language like,
"Associate every ERDT domain with the CPUs that belong to it to prepare
for attaching ERDT data to resctrl monitoring domains."
Quoted 25 lines
--- arch/x86/kernel/cpu/resctrl/Makefile | 1 + arch/x86/kernel/cpu/resctrl/core.c | 14 +- arch/x86/kernel/cpu/resctrl/erdt.c | 266 +++++++++++++++++++++++++ arch/x86/kernel/cpu/resctrl/internal.h | 31 +++ 4 files changed, 311 insertions(+), 1 deletion(-) create mode 100644 arch/x86/kernel/cpu/resctrl/erdt.carch/x86/kernel/cpu/resctrl/Makefile +1
-0@@ -2,6 +2,7 @@ obj-$(CONFIG_X86_CPU_RESCTRL) += core.o rdtgroup.o monitor.o obj-$(CONFIG_X86_CPU_RESCTRL) += ctrlmondata.o obj-$(CONFIG_X86_CPU_RESCTRL_INTEL_AET) += intel_aet.o +obj-$(CONFIG_X86_CPU_RESCTRL) += erdt.o obj-$(CONFIG_RESCTRL_FS_PSEUDO_LOCK) += pseudo_lock.o # To allow define_trace.h's recursive include:arch/x86/kernel/cpu/resctrl/core.c +0
-0
arch/x86/kernel/cpu/resctrl/core.c static __init void check_quirks(void) · line 1019
Quoted 7 lines
arch/x86/kernel/cpu/resctrl/core.c +1
-0@@ -1013,6 +1013,7 @@ static __init void check_quirks(void)static __init bool get_rdt_resources (void ) { +erdt_init (); rdt_alloc_capable =get_rdt_alloc_resources (); rdt_mon_capable =get_rdt_mon_resources ();
Functions are not expected to leave dangling state when they return failure. get_rdt_resources() returning false is considered a failure and now the caller is left to clean up the dangling state which is not a familiar pattern to use and thus something that can/will trip people.
On top of this this implementation pushes the cleanup very far from even the caller making this unfamiliar pattern even harder to recognize.
Please let get_rdt_resources() clean up after itself on failure to find any resources.
Quoted 11 lines
arch/x86/kernel/cpu/resctrl/core.c +1
-1@@ -1114,7 +1115,7 @@ void resctrl_cpu_detect(struct cpuinfo_x86 *c) } } -static int __init resctrl_arch_late_init (void ) +static int __init __resctrl_arch_late_init (void ) {struct rdt_resource *r;int state, ret, i;@@ -1157,6 +1158,15 @@ static int __init resctrl_arch_late_init(void)return 0 ;
arch/x86/kernel/cpu/resctrl/core.c static int __init resctrl_arch_late_init(void) · line 1168
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/core.c +8
-0} +static int __init resctrl_arch_late_init (void ) +{ +int ret =__resctrl_arch_late_init (); + +if (ret) +erdt_exit (); +return ret; +}
Related to earlier comment on cleanup I find this cleanup to be asymmentrical and inconsistent with how resctrl usually does cleanup. Why not do cleanup in (original) resctrl_arch_late_init() to be consistent with other cleanup when failures are encountered during initialization, for example, cpuhp_remove_state()? I find that having the cleanup handled where error is encountered is easier to understand.
arch/x86/kernel/cpu/resctrl/core.c static void __exit resctrl_arch_exit(void) · line 1180
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/core.c +3
-0+late_initcall (resctrl_arch_late_init); static void __exit resctrl_arch_exit(void)@@ -1166,6 +1176,8 @@ static void __exit resctrl_arch_exit(void)cpuhp_remove_state (rdt_online);resctrl_exit (); + +erdt_exit ();
Here the cleanup is indeed done in the same place as cleanup of other init work (cpuhp_remove_state()).
Quoted 33 lines
arch/x86/kernel/cpu/resctrl/core.c +0
-0}__exitcall (resctrl_arch_exit);arch/x86/kernel/cpu/resctrl/erdt.c new file +24
-0@@ -0,0 +1,266 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* +* Enhanced Resource Director Technology (ERDT) +* +* Copyright (C) 2026 Intel Corporation +* +*/ + +#define pr_fmt (fmt) "resctrl: " fmt + +#include <linux/acpi.h> +#include <linux/overflow.h> +#include <linux/resctrl.h> +#include <linux/sizes.h> + +#include <asm/apic.h> + +#include "internal.h" + +static LIST_HEAD (domain_info_list); + +/* True when the ERDT ACPI table describes at least one domain with at least one CPU. */ +static bool erdt_enabled; +
arch/x86/kernel/cpu/resctrl/erdt.c line 34
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +10
-0+#define ERDT_VALID_VERSION 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. */ +static u32 valid_subtbl_mask; + +/* Domain ID of the first RMDD that established @valid_subtbl_mask, for diagnostics. */ +static u16 first_rmdd_domain_id; + +static int erdt_max_rmid;
Could this ever be negative? Could this instead be of same type as the value it is initialized with? Looks like this will improve type safety with the min_t() usage then using the accurate and consistent type of both parameters?
I also think a comment describing erdt_max_rmid will be helpful, especially considering that it has "max" in its name but then its value is determined using the *minimum* of all domains' RMID?
Quoted 5 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +5
-0+ +int erdt_get_max_rmid (void ) +{ +return erdt_max_rmid; +}
arch/x86/kernel/cpu/resctrl/erdt.c line 49
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +10
-0+ +static void __iomem *erdt_ioremap (phys_addr_t base,u32 num_pages,const char *desc) +{ +void __iomem *addr; +size_t size; + +if (check_mul_overflow (num_pages,SZ_4K , &size)) +return NULL ; + + addr =ioremap (base, size);
The types seem to target a function with prototype ioremap(phys_addr_t base, size_t size) but I find arch/x86/include/asm/io.h to declare:
void __iomem *ioremap(resource_size_t offset, unsigned long size);
Since it is this code that determines the type it could just use matching accurate type from the beginning?
arch/x86/kernel/cpu/resctrl/erdt.c line 52
Quoted 3 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +3
-0+if (!addr) +pr_warn (FW_BUG "ERDT: Failed to map %s at phys addr %pa (size: %u pages)\n" , + desc, &base, num_pages);
Please align to open parenthesis.
Quoted 19 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +19
-0+ +return addr; +} + +static void erdt_iounmap_domain (struct erdt_domain_info *domain) +{ +for (int i =0 ; i <ERDT_MMIO_NUM_TYPES ; i++) { +if (domain->base[i]) { +iounmap (domain->base[i]); + domain->base[i] =NULL ; + } + } +} + +static void cleanup_one_domain (struct erdt_domain_info *d) +{ +erdt_iounmap_domain (d); +kfree (d); +}
arch/x86/kernel/cpu/resctrl/erdt.c line 81
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +10
-0+ +/* +* Save CACD information for this RMDD: +* convert the X2APIC to CPU and save them in a mask. +*/ +static __init int cacd_init (struct acpi_subtbl_hdr_16 *subtbl, +struct erdt_domain_info *domain_info) +{ +struct acpi_erdt_cacd *cacd = (struct acpi_erdt_cacd *)subtbl; +int num_ids, cpu;
Can num_ids ever be negative? If not, please use unsigned type.
Quoted 51 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +51
-0+ +if (cacd->header.length <struct_size (cacd,X2APICIDS ,1 )) { +pr_warn (FW_BUG "Invalid x2apicid CACD table\n" ); +return -EIO ; + } + + num_ids = (cacd->header.length -sizeof (*cacd)) /sizeof (cacd->X2APICIDS[0 ]); + +for (int i =0 ; i < num_ids; i++) { + cpu =topo_lookup_cpuid (cacd->X2APICIDS[i]); +if (cpu <0 ) { +pr_warn (FW_BUG "Unknown x2apicid 0x%x\n" , cacd->X2APICIDS[i]); +return -EIO ; + } + +cpumask_set_cpu (cpu, &domain_info->cpu_mask); + } + +return 0 ; +} + +static inline struct acpi_subtbl_hdr_16 *rmdd_subtbl (struct acpi_erdt_rmdd *rmdd) +{ +return (void *)rmdd +sizeof (*rmdd); +} + +static inline struct acpi_subtbl_hdr_16 *next_subtbl (struct acpi_subtbl_hdr_16 *subtbl) +{ +return (void *)subtbl + subtbl->length; +} + +static inline bool subtbl_valid (void *end,struct acpi_subtbl_hdr_16 *subtbl) +{ +/* Ensure the header is within bounds before dereferencing it. */ +if ((void *)subtbl +sizeof (*subtbl) > end) +return false; + +/* A sub-table must be at least as large as its header. */ +if (subtbl->length <sizeof (*subtbl)) +return false; + +/* The entire sub-table (including body) must fit within the parent. */ +if ((void *)subtbl + subtbl->length > end) +return false; + +return true; +} + +static __init bool parse_rmdd_table (struct acpi_subtbl_hdr_16 *rmdd_hdr) +{ +struct erdt_domain_info *domain_info;
arch/x86/kernel/cpu/resctrl/erdt.c line 142
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +10
-0+struct acpi_subtbl_hdr_16 *subtbl; +struct acpi_erdt_rmdd *rmdd; +u32 subtbl_mask =0 ; + +if (rmdd_hdr->length <sizeof (*rmdd)) { +pr_warn (FW_BUG "Invalid RMDD length %u bytes\n" , rmdd_hdr->length); +return false; + } + + rmdd = (struct acpi_erdt_rmdd *)rmdd_hdr;
Could this initialization be done at time of declaration to be consistent with the other functions parsing tables? The length comparison could then use rmdd->header.length to match how this check is done in all the other places. Being consistent makes the code much easier to understand.
Quoted 9 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +9
-0+ +/* Quietly ignore non-CPU-based L3 domains */ +if (!(rmdd->flags &RMDD_FLAG_CPU_L3_DOMAIN )) +return true; + + domain_info =kzalloc_obj (*domain_info,GFP_KERNEL ); +if (!domain_info) +return false; +
arch/x86/kernel/cpu/resctrl/erdt.c line 161
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +10
-0+ domain_info->dom_id =-1 ; + + domain_info->base[ERDT_MMIO_RMDD_CREG ] = +erdt_ioremap (rmdd->creg_base, rmdd->creg_size,"RMDD ctrl base" ); +if (!domain_info->base[ERDT_MMIO_RMDD_CREG ]) + goto cleanup; + +for (subtbl =rmdd_subtbl (rmdd); +subtbl_valid ((void *)rmdd + rmdd->header.length, subtbl); + subtbl =next_subtbl (subtbl)) {
I find it curious how the implementation varies in how the tables are parsed. For example, here it uses a for () loop to cycle through the tables while enumerate_erdt_table() uses a while() loop for what appears to be the same flow. Are they actually different? Why are the two different patterns needed?
Quoted 49 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +49
-0+switch (subtbl->type) { +/* An RMDD table has one or more CACD sub-table(s) */ +case ACPI_ERDT_TYPE_CACD : +if (cacd_init (subtbl, domain_info)) + goto cleanup; + + subtbl_mask |=BIT (ACPI_ERDT_TYPE_CACD ); +break ; +default : +break ; + } + } + +if (!subtbl_mask) + goto cleanup; + +/* +* Require all RMDDs to support same set of sub-tables +*/ +if (!valid_subtbl_mask) { + valid_subtbl_mask = subtbl_mask; + first_rmdd_domain_id = rmdd->domain_id; + }else if (subtbl_mask != valid_subtbl_mask) { +pr_warn (FW_BUG "RMDD %u sub-table set does not match the first RMDD %u\n" , + rmdd->domain_id, first_rmdd_domain_id); + goto cleanup; + } + +if (!rmdd->max_rmid) { +pr_warn (FW_BUG "Unreasonable RMDD max_rmid %u\n" , rmdd->max_rmid); + goto cleanup; + } + domain_info->max_rmid = rmdd->max_rmid; + +if (!erdt_max_rmid) + erdt_max_rmid = rmdd->max_rmid; +else + erdt_max_rmid =min_t (int, erdt_max_rmid, rmdd->max_rmid); + +list_add (&domain_info->entry, &domain_info_list); + +return true; + +cleanup: +cleanup_one_domain (domain_info); +return false; +} + +void erdt_exit (void )
arch/x86/kernel/cpu/resctrl/erdt.c line 220
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +10
-0+{ +struct erdt_domain_info *d, *tmp; + +list_for_each_entry_safe (d, tmp, &domain_info_list, entry) { +list_del (&d->entry); +cleanup_one_domain (d); + } + erdt_enabled = false; + valid_subtbl_mask =0 ; + first_rmdd_domain_id =0 ;
Should erdt_max_rmid be reset also?
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +10
-0+} + +static __init int enumerate_erdt_table (struct acpi_table_header *table_hdr) +{ +struct acpi_table_erdt *erdt = (struct acpi_table_erdt *)table_hdr; +struct acpi_subtbl_hdr_16 *subtbl; +void *table_end; + +if (erdt->header.revision !=ERDT_VALID_VERSION ) { + pr_info("Unsupported ERDT table revision %u (expected %u)\n",
arch/x86/kernel/cpu/resctrl/erdt.c line 240
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +10
-0+ erdt->header.revision, ERDT_VALID_VERSION); +return -EINVAL ; + } + +if (erdt->header.length <sizeof (*erdt)) { +pr_warn (FW_BUG "ERDT: Invalid table length %u bytes\n" , erdt->header.length); +return -EINVAL ; + } + + subtbl = (void *)erdt +sizeof (struct acpi_table_erdt );
Please use sizeof(*erdt)
Quoted 38 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +26
-0+ table_end = (void *)erdt + erdt->header.length; + +while (subtbl_valid (table_end, subtbl)) { +if (subtbl->type ==ACPI_ERDT_TYPE_RMDD && + !parse_rmdd_table (subtbl)) + goto cleanup; + + subtbl =next_subtbl (subtbl); + } + +if (list_empty (&domain_info_list)) + goto cleanup; + + erdt_enabled = true; + +return 0 ; + +cleanup: +erdt_exit (); +return -EINVAL ; +} + +int __init erdt_init (void ) +{ +return acpi_table_parse (ACPI_SIG_ERDT , enumerate_erdt_table); +}arch/x86/kernel/cpu/resctrl/internal.h +4
-0@@ -21,6 +21,33 @@#define RMID_VAL_UNAVAIL BIT_ULL(62) +/* +* Index into erdt_domain_info::base[] for each MMIO region. +* @ERDT_MMIO_RMDD_CREG: RMDD control register base address +*/
arch/x86/kernel/cpu/resctrl/internal.h line 37
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/internal.h +10
-0+enum erdt_mmio_type { +ERDT_MMIO_RMDD_CREG , +ERDT_MMIO_LAST =ERDT_MMIO_RMDD_CREG +}; + +#define ERDT_MMIO_NUM_TYPES (ERDT_MMIO_LAST + 1) + +/** +* struct erdt_domain_info - Per-domain ERDT information +* @base: Array of ioremapped MMIO region base addresses, indexed by ERDT_MMIO_* type
I think "type" can be dropped? The enum is already implicitly an "MMIO type"?
Quoted 17 lines
arch/x86/kernel/cpu/resctrl/internal.h +13
-0+* @cpu_mask: CPUs belonging to this resource management domain +* @max_rmid: Maximum RMID supported by this domain +* @dom_id: L3 cache ID shared by all CPUs in this domain (-1 if unset) +* @entry: Links into the global domain_info_list +*/ +struct erdt_domain_info { +void __iomem *base[ERDT_MMIO_NUM_TYPES ]; +struct cpumask cpu_mask; +u32 max_rmid; +int dom_id; +struct list_head entry; +}; +/* * With the above fields in use 62 bits remain in MSR_IA32_QM_CTR for * data to be returned. The counter width is discovered from the hardware
arch/x86/kernel/cpu/resctrl/internal.h static inline void intel_aet_mon_domain_setup(int cpu, int id, struct rdt_resour · line 287
Quoted 8 lines
arch/x86/kernel/cpu/resctrl/internal.h +4
-0@@ -253,4 +280,8 @@ static inline void intel_aet_mon_domain_setup(int cpu, int id, struct rdt_resourstatic inline bool intel_handle_aet_option (bool force_off,char *tok) {return false; }#endif +int erdt_get_max_rmid (void ); +int erdt_init (void ); +void erdt_exit (void ); +#endif /* _ASM_X86_RESCTRL_INTERNAL_H */
Reinette
Re: [PATCH v6 3/9] x86/resctrl: Parse ACPI ERDT table and save CACD cpumask for RMDD domains
Hi Reinette,
Quoted 12 lines · Reinette Chatre
Hi Chenyu,
Quoted 4 lines · Chen Yu
From: Anil S Keshavamurthy <[email protected]>
Parse the RMDD subtables within the ERDT ACPI table and their nested CACD entries to construct per-domain CPU masks.
The changelog always needs to start with context. Please see "Changelog" in
Documentation/process/maintainer-tip.rstfor complete expectations.
OK, I will first add some background information (including what ERDT and CACD are).
Quoted 16 lines
Quoted 2 lines
There is one ERDT table per platform. Each RMDD describes one resource
I do not think what "RMDD" stands for has been introduced at this point yet.
Quoted 4 lines
management domain (RMD), also known as an L3 domain, and carries MMIO base information for later monitoring support.
For each RMDD, parse the associated CACD, map its x2APIC IDs to logical
What is "CACD"? Please always expand acronym before its first use.
Quoted 3 lines
CPUs, and save the resulting CPU mask. This mask associates each ERDT domain with the CPUs that belong to it and is used later when attaching ERDT data to resctrl monitoring domains.
Quoted 6 lines
Please let each patch description stand on its own without referring to later patches in series. If a patch provides capability in preparation for future changes then you can use language like,
"Associate every ERDT domain with the CPUs that belong to it to prepare
for attaching ERDT data to resctrl monitoring domains."
Thanks for the guidance, will adjust it.
Quoted 11 lines
arch/x86/kernel/cpu/resctrl/core.c static __init void check_quirks(void) · line 1018
Quoted 6 lines
static
__initboolget_rdt_resources(void)
{arch/x86/kernel/cpu/resctrl/core.c +1
-0+erdt_init (); rdt_alloc_capable =get_rdt_alloc_resources (); rdt_mon_capable =get_rdt_mon_resources ();Functions are not expected to leave dangling state when they return failure.
get_rdt_resources()returning false is considered a failure and now the caller is left to clean up the dangling state which is not a familiar pattern to use and thus something that can/will trip people.
Quoted 5 lines
On top of this this implementation pushes the cleanup very far from even the caller making this unfamiliar pattern even harder to recognize.
Please let
get_rdt_resources()clean up after itself on failure to find any resources.
The original intent was to encapsulate the cleanup logic as a helper function (erdt_exit()), since it is needed in multiple places across the code. All other call sites invoke this function when necessary. If we place the cleanup call directly inside resctrl_arch_late_init(), it would only execute erdt_exit() once within that function. Alternatively, if we let get_rdt_resources() handle cleanup via erdt_exit(), then we would need to add explicit erdt_exit() calls in __resctrl_arch_late_init() for each failure path - for example, when cpuhp_setup_state() fails or when resctrl_init() fails. Anyway, if code readability is a priority, I'll change the logic as suggested.
Quoted 13 lines
Quoted 13 lines
arch/x86/kernel/cpu/resctrl/core.c +1
-1@@ -1114,7 +1115,7 @@ void resctrl_cpu_detect(struct cpuinfo_x86 *c) } } -static int __init resctrl_arch_late_init (void ) +static int __init __resctrl_arch_late_init (void ) {struct rdt_resource *r;int state, ret, i;@@ -1157,6 +1158,15 @@ static int __init resctrl_arch_late_init(void)return 0 ; }
Quoted 15 lines
arch/x86/kernel/cpu/resctrl/core.c static int __init resctrl_arch_late_init(void) · line 1168
Quoted 8 lines
arch/x86/kernel/cpu/resctrl/core.c +8
-0+static int __init resctrl_arch_late_init (void ) +{ +int ret =__resctrl_arch_late_init (); + +if (ret) +erdt_exit (); +return ret; +}Related to earlier comment on cleanup I find this cleanup to be asymmentrical and inconsistent with how resctrl usually does cleanup. Why not do cleanup in (original)
resctrl_arch_late_init()to be consistent with other cleanup when failures are encountered during initialization, for example,cpuhp_remove_state()? I find that having the cleanup handled where error is encountered is easier to understand.
Thomas previously suggested this approach to avoid using goto.
https://lore.kernel.org/lkml/871pem5jnh.ffs@fw13/
However, I agree that we can adopt the individual cleanup strategy instead, as it will improve code readability.
Quoted 7 lines
Quoted 7 lines
arch/x86/kernel/cpu/resctrl/core.c +1
-0+late_initcall (resctrl_arch_late_init); static void __exit resctrl_arch_exit(void)@@ -1166,6 +1176,8 @@ static void __exit resctrl_arch_exit(void)cpuhp_remove_state (rdt_online);
Quoted 8 lines
arch/x86/kernel/cpu/resctrl/core.c static void __exit resctrl_arch_exit(void) · line 1180
Quoted 3 lines
arch/x86/kernel/cpu/resctrl/core.c +2
-0resctrl_exit (); + +erdt_exit ();Here the cleanup is indeed done in the same place as cleanup of other init work (
cpuhp_remove_state()).
Understood. I will ensure consistency whenever cpuhp_remove_state() is called, erdt_exit() will also be invoked in the original resctrl_arch_late_init().
Quoted 10 lines
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +9
-0} +/* True when the ERDT ACPI table describes at least one domain with at least one CPU. */ +static bool erdt_enabled; + +#define ERDT_VALID_VERSION 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. */ +static u32 valid_subtbl_mask; +
Quoted 9 lines
arch/x86/kernel/cpu/resctrl/erdt.c line 34
Quoted 4 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +4
-0+/* Domain ID of the first RMDD that established @valid_subtbl_mask, for diagnostics. */ +static u16 first_rmdd_domain_id; + +static int erdt_max_rmid;Could this ever be negative? Could this instead be of same type as the value it is initialized with? Looks like this will improve type safety with the
min_t()usage then using the accurate and consistent type of both parameters?
It should not be negative, let me convert it into u32 and use min() directly.
Quoted 4 lines
I also think a comment describing
erdt_max_rmidwill be helpful, especially considering that it has "max" in its name but then its value is determined using the *minimum* of all domains' RMID?
OK, let me add the following comment when Tony also raised this question. resctrl_rmid_realloc_threshold is a single global value,
and resctrl_arch_round_mon_val() takes no domain argument, so a single scale has to be derived from the per-domain cmrc->up_scale. max() was chosen because the rounding is a floor: a larger scale yields a slightly lower threshold, i.e. an RMID has to drop to a slightly lower occupancy before it is reused.
https://lore.kernel.org/all/[email protected]/
Quoted 20 lines
Quoted 5 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +5
-0+ +int erdt_get_max_rmid (void ) +{ +return erdt_max_rmid; +}arch/x86/kernel/cpu/resctrl/erdt.c line 49
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +10
-0+ +static void __iomem *erdt_ioremap (phys_addr_t base,u32 num_pages,const char *desc) +{ +void __iomem *addr; +size_t size; + +if (check_mul_overflow (num_pages,SZ_4K , &size)) +return NULL ; + + addr =ioremap (base, size);The types seem to target a function with prototype
ioremap(phys_addr_t base, size_t size)but I findarch/x86/include/asm/io.hto declare:
void__iomem*ioremap(resource_size_t offset, unsigned long size);
Quoted 3 lines
Since it is this code that determines the type it could just use matching accurate type from the beginning?
OK, let me switch it to unsigned long to be consistent with x86 declaration.
Quoted 6 lines
arch/x86/kernel/cpu/resctrl/erdt.c line 52
Quoted 3 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +3
-0+if (!addr) +pr_warn (FW_BUG "ERDT: Failed to map %s at phys addr %pa (size: %u pages)\n" , + desc, &base, num_pages);Please align to open parenthesis.
OK.
Quoted 8 lines
arch/x86/kernel/cpu/resctrl/erdt.c line 81
Quoted 5 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +5
-0+static __init int cacd_init (struct acpi_subtbl_hdr_16 *subtbl, +struct erdt_domain_info *domain_info) +{ +struct acpi_erdt_cacd *cacd = (struct acpi_erdt_cacd *)subtbl; +int num_ids, cpu;Can
num_idsever be negative? If not, please use unsigned type.
It will not be negative, let me switch it to unsigned int.
Quoted 10 lines
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +10
-0+static __init bool parse_rmdd_table (struct acpi_subtbl_hdr_16 *rmdd_hdr) +{ +struct erdt_domain_info *domain_info; +struct acpi_subtbl_hdr_16 *subtbl; +struct acpi_erdt_rmdd *rmdd; +u32 subtbl_mask =0 ; + +if (rmdd_hdr->length <sizeof (*rmdd)) { +pr_warn (FW_BUG "Invalid RMDD length %u bytes\n" , rmdd_hdr->length); +return false;
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c line 142
Quoted 3 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +3
-0+ } + + rmdd = (struct acpi_erdt_rmdd *)rmdd_hdr;Could this initialization be done at time of declaration to be consistent with the other functions parsing tables? The length comparison could then use
rmdd->header.lengthto match how this check is done in all the other places. Being consistent makes the code much easier to understand.
OK, will modify the code.
Quoted 16 lines
Quoted 16 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +16
-0+ +/* Quietly ignore non-CPU-based L3 domains */ +if (!(rmdd->flags &RMDD_FLAG_CPU_L3_DOMAIN )) +return true; + + domain_info =kzalloc_obj (*domain_info,GFP_KERNEL ); +if (!domain_info) +return false; + + domain_info->dom_id =-1 ; + + domain_info->base[ERDT_MMIO_RMDD_CREG ] = +erdt_ioremap (rmdd->creg_base, rmdd->creg_size,"RMDD ctrl base" ); +if (!domain_info->base[ERDT_MMIO_RMDD_CREG ]) + goto cleanup; +
Quoted 9 lines
arch/x86/kernel/cpu/resctrl/erdt.c line 161
Quoted 3 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +3
-0+for (subtbl =rmdd_subtbl (rmdd); +subtbl_valid ((void *)rmdd + rmdd->header.length, subtbl); + subtbl =next_subtbl (subtbl)) {I find it curious how the implementation varies in how the tables are parsed. For example, here it uses a for () loop to cycle through the tables while
enumerate_erdt_table()uses awhile()loop for what appears to be the same flow. Are they actually different? Why are the two different patterns needed?
Let me switch them both to "for" loop to keep consistence.
Quoted 5 lines
Quoted 5 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +5
-0+void erdt_exit (void ) +{ +struct erdt_domain_info *d, *tmp; + +list_for_each_entry_safe (d, tmp, &domain_info_list, entry) {
Quoted 9 lines
arch/x86/kernel/cpu/resctrl/erdt.c line 220
Quoted 6 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +6
-0+list_del (&d->entry); +cleanup_one_domain (d); + } + erdt_enabled = false; + valid_subtbl_mask =0 ; + first_rmdd_domain_id =0 ;Should
erdt_max_rmidbe reset also?
Yes, let me fix this.
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c line 240
Quoted 7 lines
arch/x86/kernel/cpu/resctrl/erdt.c new file +7
-0+ +if (erdt->header.length <sizeof (*erdt)) { +pr_warn (FW_BUG "ERDT: Invalid table length %u bytes\n" , erdt->header.length); +return -EINVAL ; + } + + subtbl = (void *)erdt +sizeof (struct acpi_table_erdt );Please use
sizeof(*erdt)
OK, will do.
Quoted 4 lines
Quoted 4 lines
arch/x86/kernel/cpu/resctrl/internal.h +4
-0+enum erdt_mmio_type { +ERDT_MMIO_RMDD_CREG , +ERDT_MMIO_LAST =ERDT_MMIO_RMDD_CREG +};
Quoted 9 lines
arch/x86/kernel/cpu/resctrl/internal.h line 37
Quoted 6 lines
arch/x86/kernel/cpu/resctrl/internal.h +6
-0+ +#define ERDT_MMIO_NUM_TYPES (ERDT_MMIO_LAST + 1) + +/** +* struct erdt_domain_info - Per-domain ERDT information +* @base: Array of ioremapped MMIO region base addresses, indexed by ERDT_MMIO_* type I think "type" can be dropped? The enum is already implicitly an "MMIO type"?
Got it, will remove this "type".
thanks,
Chenyu
Reinette Chatre
maintainerRe: [PATCH v6 3/9] x86/resctrl: Parse ACPI ERDT table and save CACD cpumask for RMDD domains
Hi Chenyu,
Quoted 21 lines · Chen Yu
Quoted 14 lines · Reinette Chatre
arch/x86/kernel/cpu/resctrl/core.c static __init void check_quirks(void) · line 1018
Quoted 6 lines · Chen Yu
static
__initboolget_rdt_resources(void)
{arch/x86/kernel/cpu/resctrl/core.c +1
-0+erdt_init (); rdt_alloc_capable =get_rdt_alloc_resources (); rdt_mon_capable =get_rdt_mon_resources ();Functions are not expected to leave dangling state when they return failure.
get_rdt_resources()returning false is considered a failure and now the caller is left to clean up the dangling state which is not a familiar pattern to use and thus something that can/will trip people.Quoted 5 lines
On top of this this implementation pushes the cleanup very far from even the caller making this unfamiliar pattern even harder to recognize.
Please let
get_rdt_resources()clean up after itself on failure to find any resources.
Quoted 8 lines
The original intent was to encapsulate the cleanup logic as a helper function (
erdt_exit()), since it is needed in multiple places across the code. All other call sites invoke this function when necessary. If we place the cleanup call directly insideresctrl_arch_late_init(), it would only executeerdt_exit()once within that function. Alternatively, if we letget_rdt_resources()handle cleanup viaerdt_exit(), then we would need to add expliciterdt_exit()calls in__resctrl_arch_late_init()for each failure path - for example, whencpuhp_setup_state()fails or whenresctrl_init()fails. Anyway, if code readability is a priority, I'll change the logic as suggested.
Yes, code readability is a priority. It is not all just about code readability. Please consider all the points I mentioned above. I do not see any justification for get_rdt_resources() leaving dangling state on failure. This is something that will get tripped over in the next inevitable refactor. Apart from that, adding a single "cleanup" function at one location down in the call stack is convenient for *this* implementation based on the *current* state of the code but while doing so it breaks custom, not just of resctrl but of the rest of the kernel also, and because of that makes this code difficult to build on and maintain.
Quoted 30 lines
Quoted 14 lines
Quoted 14 lines
arch/x86/kernel/cpu/resctrl/core.c +1
-1@@ -1114,7 +1115,7 @@ void resctrl_cpu_detect(struct cpuinfo_x86 *c) } } -static int __init resctrl_arch_late_init (void ) +static int __init __resctrl_arch_late_init (void ) {struct rdt_resource *r;int state, ret, i;@@ -1157,6 +1158,15 @@ static int __init resctrl_arch_late_init(void)return 0 ; }Quoted 15 lines
arch/x86/kernel/cpu/resctrl/core.c static int __init resctrl_arch_late_init(void) · line 1168
Quoted 8 lines
arch/x86/kernel/cpu/resctrl/core.c +8
-0+static int __init resctrl_arch_late_init (void ) +{ +int ret =__resctrl_arch_late_init (); + +if (ret) +erdt_exit (); +return ret; +}Related to earlier comment on cleanup I find this cleanup to be asymmentrical and inconsistent with how resctrl usually does cleanup. Why not do cleanup in (original)
resctrl_arch_late_init()to be consistent with other cleanup when failures are encountered during initialization, for example,cpuhp_remove_state()? I find that having the cleanup handled where error is encountered is easier to understand.
Quoted 4 lines
Thomas previously suggested this approach to avoid using goto.
https://lore.kernel.org/lkml/871pem5jnh.ffs@fw13/
However, I agree that we can adopt the individual cleanup strategy instead, as it will improve code readability.
I see that that Thomas's comment is made in response to this snippet:
Review static int __init resctrl_arch_late_init(void) · line 1136
Quoted 9 lines
(quoted diff) +3
-2@@ -1130,20 +1131,24 @@ static int __init resctrl_arch_late_init(void) check_quirks(); - if (!get_rdt_resources()) - return -ENODEV; + if (!get_rdt_resources()) { + ret = -ENODEV; + goto out;
Above is the issue I mentioned earlier where get_rdt_resources() leaves dangling state. If it cleaned up after itself on failure as is the custom in the kernel then resctrl_arch_late_init() does not have to.
If the goal is to avoid goto in __resctrl_arch_late_init() then the failure paths that follow get_rdt_resources() can just call erdt_exit() directly to make obvious where what needs to be cleaned up.
As the suggestion is implemented the cleanup is inconsistent with __resctrl_arch_late_init() doing its own cleanup for code run _after_ erdt_init() and leaving the erdt_init() cleanup to be done further down the stack by __resctrl_arch_late_init()'s caller. While technically correct this inconsistency adds unnecessary complexity and another place that will get tripped over in the next inevitable refactor.
Reinette
Re: [PATCH v6 3/9] x86/resctrl: Parse ACPI ERDT table and save CACD cpumask for RMDD domains
Quoted 2 lines · Reinette Chatre
Hi Chenyu,
[ ... ]
Quoted 9 lines
Yes, code readability is a priority. It is not all just about code readability. Please consider all the points I mentioned above. I do not see any justification for
get_rdt_resources()leaving dangling state on failure. This is something that will get tripped over in the next inevitable refactor. Apart from that, adding a single "cleanup" function at one location down in the call stack is convenient for *this* implementation based on the *current* state of the code but while doing so it breaks custom, not just of resctrl but of the rest of the kernel also, and because of that makes this code difficult to build on and maintain.
goto out;
Quoted 9 lines
Above is the issue I mentioned earlier where
get_rdt_resources()leaves dangling state. If it cleaned up after itself on failure as is the custom in the kernel thenresctrl_arch_late_init()does not have to.If the goal is to avoid goto in
__resctrl_arch_late_init()then the failure paths that followget_rdt_resources()can just callerdt_exit()directly to make obvious where what needs to be cleaned up.
Quoted 6 lines
As the suggestion is implemented the cleanup is inconsistent with
__resctrl_arch_late_init()doing its own cleanup for code run _after_erdt_init()and leaving theerdt_init()cleanup to be done further down the stack by __resctrl_arch_late_init()'s caller. While technically correct this inconsistency adds unnecessary complexity and another place that will get tripped over in the next inevitable refactor.
I see. This is very helpful guidance. I'll adjust the code accordingly.
thanks,
Chenyu
PATCH v6 4/9 x86/resctrl: Attach ACPI ERDT information to L3 mon domain on CPU online
In reply to Chen YuReading LLC occupancy counters via MMIO requires the per-domain ERDT information, parsed earlier from the ACPI ERDT table, to be reachable from the resctrl L3 monitoring domain. Nothing links the two yet, so the monitoring code cannot locate the MMIO registers of a domain.
ERDT and CPUID enumerate CPU-to-L3-domain membership independently:
CPUID leaf 4 describes the L3 cache topology, while the firmware CACD sub-table lists the CPUs of each ERDT domain. Both views must agree on a CPU's L3 domain for that CPU to be monitored safely.
When a CPU comes online, validate that firmware and CPUID agree on its L3 domain before adding it to a resctrl monitoring domain. Exclude the CPU from all monitoring domains on a mismatch because a topology inconsistency between ERDT and CPUID indicates a firmware defect that makes the CPU's domain placement unreliable for any resource. Otherwise attach the matching ERDT domain information to the L3 monitoring domain so that later code can read monitoring data via ERDT and its sub-tables.
---v5->v6:
Call erdt_cpu_valid() in domain_add_cpu_mon() before the CPU is added to the domain cpu_mask, and bail out early on a mismatch. (Reinette Chatre)
Drop the redundant pr_warn() in the caller, the callee already warns. (Reinette Chatre)
Use list_for_each_entry(). (Reinette Chatre)
Make the domain information pointer const instead of documenting it as read only in a comment. (Reinette Chatre)
Adjust the ERDT/CPUID mismatch check that the CPUs disagrees with ERDT/CPUID domain is excluded from resctrl.
(Reinette Chatre)
--- arch/x86/kernel/cpu/resctrl/core.c | 11 ++++- arch/x86/kernel/cpu/resctrl/erdt.c | 66 ++++++++++++++++++++++++++ arch/x86/kernel/cpu/resctrl/internal.h | 5 ++ 3 files changed, 81 insertions(+), 1 deletion(-)
arch/x86/kernel/cpu/resctrl/core.c +10 -1
@@ -580,6 +580,9 @@ static void domain_add_cpu_mon(int cpu, struct rdt_resource *r)return ; } +if (!erdt_cpu_valid (cpu)) +return ; + hdr =resctrl_find_domain (&r->mon_domains, id, &add_pos);if (hdr)cpumask_set_cpu (cpu, &hdr->cpu_mask);
@@ -589,8 +592,14 @@ static void domain_add_cpu_mon(int cpu, struct rdt_resource *r)/* Update the mbm_assign_mode state for the CPU if supported */ if (r->mon.mbm_cntr_assignable)resctrl_arch_mbm_cntr_assign_set_one (r); -if (!hdr) +if (!hdr) {l3_mon_domain_setup (cpu, id, r, add_pos); + hdr =resctrl_find_domain (&r->mon_domains, id,NULL ); + } + +if (hdr) +erdt_l3_mon_domain_setup (cpu, hdr); +break ;case RDT_RESOURCE_PERF_PKG :if (!hdr)
arch/x86/kernel/cpu/resctrl/erdt.c +66 -0
72 lines not on this page · raw message
arch/x86/kernel/cpu/resctrl/internal.h +5 -0
@@ -99,14 +99,19 @@ struct rdt_hw_ctrl_domain {* @arch_mbm_states: Per-event pointer to the MBM event's saved state. * An MBM event's state is an array of struct arch_mbm_state * indexed by RMID on x86. +* @d_info: ERDT table information of this domain * * Members of this structure are accessed via helpers that provide abstraction. */ struct rdt_hw_l3_mon_domain {struct rdt_l3_mon_domain d_resctrl;struct arch_mbm_state *arch_mbm_states[QOS_NUM_L3_MBM_EVENTS ]; +const struct erdt_domain_info *d_info; }; +bool erdt_cpu_valid (int cpu); +void erdt_l3_mon_domain_setup (int cpu,struct rdt_domain_hdr *hdr); +static inline struct rdt_hw_ctrl_domain *resctrl_to_arch_ctrl_dom (struct rdt_ctrl_domain *r) { return container_of(r, struct rdt_hw_ctrl_domain, d_resctrl);
Signature · 1 line
2.25.1
Reinette Chatre
maintainerRe: [PATCH v6 4/9] x86/resctrl: Attach ACPI ERDT information to L3 mon domain on CPU online
Hi Chenyu,
Quoted 2 lines · Chen Yu
Reading LLC occupancy counters via MMIO requires the per-domain ERDT information, parsed earlier from the ACPI ERDT table, to be reachable
Please avoid using terms about a patch's position in a series. You can just drop "earlier".
Quoted 8 lines
from the resctrl L3 monitoring domain. Nothing links the two yet, so the monitoring code cannot locate the MMIO registers of a domain.
ERDT and CPUID enumerate CPU-to-L3-domain membership independently:
CPUID leaf 4 describes the L3 cache topology, while the firmware CACD sub-table lists the CPUs of each ERDT domain. Both views must agree on a CPU's L3 domain for that CPU to be monitored safely.
Quoted 7 lines
When a CPU comes online, validate that firmware and CPUID agree on its L3 domain before adding it to a resctrl monitoring domain. Exclude the CPU from all monitoring domains on a mismatch because a topology inconsistency between ERDT and CPUID indicates a firmware defect that makes the CPU's domain placement unreliable for any resource. Otherwise attach the matching ERDT domain information to the L3 monitoring domain so that later code can read monitoring data via ERDT and its sub-tables.
(similar comment as above)
"so that later code can read monitoring data via ERDT and its sub-tables" -> "so that monitoring data can be read via ERDT and its sub-tables"
Quoted 5 lines
Suggested-by Reinette Chatre <[email protected]>Signed-off-by Chen Yu <[email protected]>Tested-by Hongyu Ning <[email protected]>---
...
arch/x86/kernel/cpu/resctrl/core.c static void domain_add_cpu_mon(int cpu, struct rdt_resource *r) · line 585
Quoted 11 lines
arch/x86/kernel/cpu/resctrl/core.c +3
-0@@ -580,6 +580,9 @@ static void domain_add_cpu_mon(int cpu, struct rdt_resource *r)return ; } +if (!erdt_cpu_valid (cpu)) +return ; +
Including this check in domain_add_cpu_mon() means that it is repeated for every monitoring resource. I think this check only needs to be done once? How about moving it to resctrl_arch_online_cpu() where this check can be done before cycling through *any* (monitoring or control) resource?
While domain_info_list is initialized early, this validity check makes concurrent changes to it so locking is required. The current implementation already does this modification with domain_list_lock held but it is not made explicit that this list is now under the protection of this lock. Please add a snippet to the comment above the domain_list_lock to document that it is now also used to protect domain_info_list.
Quoted 5 lines
arch/x86/kernel/cpu/resctrl/core.c +0
-0hdr =resctrl_find_domain (&r->mon_domains, id, &add_pos);if (hdr)cpumask_set_cpu (cpu, &hdr->cpu_mask);@@ -589,8 +592,14 @@ static void domain_add_cpu_mon(int cpu, struct rdt_resource *r)/* Update the mbm_assign_mode state for the CPU if supported */
arch/x86/kernel/cpu/resctrl/core.c static void domain_add_cpu_mon(int cpu, struct rdt_resource *r) · line 601
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/core.c +6
-1if (r->mon.mbm_cntr_assignable)resctrl_arch_mbm_cntr_assign_set_one (r); -if (!hdr) +if (!hdr) {l3_mon_domain_setup (cpu, id, r, add_pos); + hdr =resctrl_find_domain (&r->mon_domains, id,NULL ); + } + +if (hdr) +erdt_l3_mon_domain_setup (cpu, hdr);
The additional search for "hdr" seems unnecessary. Could l3_mon_domain_setup() just call erdt_l3_mon_domain_setup() directly?
Quoted 13 lines
arch/x86/kernel/cpu/resctrl/core.c +1
-0+break ;case RDT_RESOURCE_PERF_PKG :if (!hdr)arch/x86/kernel/cpu/resctrl/erdt.c +1
-0@@ -207,6 +207,72 @@ static __init bool parse_rmdd_table(struct acpi_subtbl_hdr_16 *rmdd_hdr)return false; } +bool erdt_cpu_valid (int cpu)
arch/x86/kernel/cpu/resctrl/erdt.c static __init bool parse_rmdd_table(struct acpi_subtbl_hdr_16 *rmdd_hdr) · line 220
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c +10
-0+{ +struct erdt_domain_info *d; +int dom_id; + +if (!erdt_enabled) +return true; + + dom_id =get_cpu_cacheinfo_id (cpu,RESCTRL_L3_CACHE ); +if (dom_id <0 ) +return true;
Should this be "false"? Perhaps also with a warning similar to domain_add_cpu_mon()'s warning when the domain ID cannot be determined?
Quoted 4 lines
arch/x86/kernel/cpu/resctrl/erdt.c +4
-0+ +/* +* Find the erdt_domain_info that contains this CPU, +* check if all CPUs in erdt_domain_info's cpumask
arch/x86/kernel/cpu/resctrl/erdt.c static __init bool parse_rmdd_table(struct acpi_subtbl_hdr_16 *rmdd_hdr) · line 234
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c +10
-0+* have the same id(L3 id). +* +* For example, erdt_domain_info reports: +* domain0: CPU0, CPU2, domain1: CPU1, CPU3 +* rdt_domain_hdr reports: +* domain0: CPU0, CPU1, domain1: CPU2, CPU3 +* As a result, CPU1, CPU2 should not be covered by resctrl. +*/ +list_for_each_entry (d, &domain_info_list, entry) { +
(unnecessary empty line)
Quoted 23 lines
arch/x86/kernel/cpu/resctrl/erdt.c +23
-0+if (cpumask_test_cpu (cpu, &d->cpu_mask)) { +if (d->dom_id ==-1 ) { + d->dom_id = dom_id; + }else if (d->dom_id != dom_id) { +pr_warn (FW_BUG "CPU%d's id=%d not equal to CACD domain(%*pbl) id=%d, skip this CPU\n" , + cpu, dom_id,cpumask_pr_args (&d->cpu_mask), d->dom_id); + +return false; + } + +return true; + } + } + +pr_warn (FW_BUG "Cannot find CACD domain for CPU%d\n" , cpu); +return false; +} + +/* +* Associate ERDT table information with this domain. +*/ +void erdt_l3_mon_domain_setup (int cpu,struct rdt_domain_hdr *hdr) +{
arch/x86/kernel/cpu/resctrl/erdt.c static __init bool parse_rmdd_table(struct acpi_subtbl_hdr_16 *rmdd_hdr) · line 267
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c +10
-0+struct rdt_hw_l3_mon_domain *hw_dom; +struct erdt_domain_info *d; + +if (!erdt_enabled) +return ; + + hw_dom = resctrl_to_arch_mon_dom(container_of(hdr, struct rdt_l3_mon_domain, hdr)); + +list_for_each_entry (d, &domain_info_list, entry) { +if (cpumask_test_cpu (cpu, &d->cpu_mask)) {
Any motivation for why the cpumask is used as a test instead of the domain ID?
arch/x86/kernel/cpu/resctrl/erdt.c static __init bool parse_rmdd_table(struct acpi_subtbl_hdr_16 *rmdd_hdr) · line 270
Quoted 3 lines
arch/x86/kernel/cpu/resctrl/erdt.c +3
-0+/* Assign the ERDT information to hw_dom */ +if (!hw_dom->d_info) + hw_dom->d_info = d;
This should become obvious if this initialization is done from l3_mon_domain_setup() where hw_mon would have been kzalloc'ed. This means that if hw_dom->d_info is already initialized that there would be *two* ERDT domains that map to an existing resctrl monitoring domain. That looks to be something to complain about?
Quoted 22 lines
arch/x86/kernel/cpu/resctrl/erdt.c +5
-0+return ; + } + } +} +void erdt_exit (void ) {struct erdt_domain_info *d, *tmp;arch/x86/kernel/cpu/resctrl/internal.h +1
-0@@ -99,14 +99,19 @@ struct rdt_hw_ctrl_domain {* @arch_mbm_states: Per-event pointer to the MBM event's saved state. * An MBM event's state is an array of struct arch_mbm_state * indexed by RMID on x86. +* @d_info: ERDT table information of this domain * * Members of this structure are accessed via helpers that provide abstraction. */ struct rdt_hw_l3_mon_domain {struct rdt_l3_mon_domain d_resctrl;
arch/x86/kernel/cpu/resctrl/internal.h struct rdt_hw_ctrl_domain { · line 117
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/internal.h +4
-0struct arch_mbm_state *arch_mbm_states[QOS_NUM_L3_MBM_EVENTS ]; +const struct erdt_domain_info *d_info; }; +bool erdt_cpu_valid (int cpu); +void erdt_l3_mon_domain_setup (int cpu,struct rdt_domain_hdr *hdr); +static inline struct rdt_hw_ctrl_domain *resctrl_to_arch_ctrl_dom (struct rdt_ctrl_domain *r) { return container_of(r, struct rdt_hw_ctrl_domain, d_resctrl);
Reinette
Re: [PATCH v6 4/9] x86/resctrl: Attach ACPI ERDT information to L3 mon domain on CPU online
Hi Reinette,
Quoted 9 lines · Reinette Chatre
Hi Chenyu,
Quoted 2 lines · Chen Yu
Reading LLC occupancy counters via MMIO requires the per-domain ERDT information, parsed earlier from the ACPI ERDT table, to be reachable
Please avoid using terms about a patch's position in a series. You can just drop "earlier".
Got it, will do.
Quoted 6 lines
Quoted 1 line
so that later code can read monitoring data via ERDT and its sub-tables.
(similar comment as above)
"so that later code can read monitoring data via ERDT and its sub-tables" -> "so that monitoring data can be read via ERDT and its sub-tables"
OK, will do.
Quoted 16 lines
Quoted 5 lines
Suggested-by Reinette Chatre <[email protected]>Signed-off-by Chen Yu <[email protected]>Tested-by Hongyu Ning <[email protected]>---
...
Quoted 8 lines
arch/x86/kernel/cpu/resctrl/core.c +0
-0@@ -580,6 +580,9 @@ static void domain_add_cpu_mon(int cpu, struct rdt_resource *r)return ; }
Quoted 8 lines
arch/x86/kernel/cpu/resctrl/core.c static void domain_add_cpu_mon(int cpu, struct rdt_resource *r) · line 585
Quoted 3 lines
arch/x86/kernel/cpu/resctrl/core.c +3
-0+if (!erdt_cpu_valid (cpu)) +return ; +Including this check in
domain_add_cpu_mon()means that it is repeated for every monitoring resource. I think this check only needs to be done once? How about moving it toresctrl_arch_online_cpu()where this check can be done before cycling through *any* (monitoring or control) resource?
Yes, moving it to resctrl_arch_online_cpu() is more reasonable, will adjust the code.
Quoted 6 lines
While
domain_info_listis initialized early, this validity check makes concurrent changes to it so locking is required. The current implementation already does this modification withdomain_list_lockheld but it is not made explicit that this list is now under the protection of this lock. Please add a snippet to the comment above thedomain_list_lockto document that it is now also used to protectdomain_info_list.
OK, will add lockdep_assert_held(&domain_list_lock) in erdt_cpu_valid().
Quoted 10 lines
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/core.c +1
-1hdr =resctrl_find_domain (&r->mon_domains, id, &add_pos);if (hdr)cpumask_set_cpu (cpu, &hdr->cpu_mask);@@ -589,8 +592,14 @@ static void domain_add_cpu_mon(int cpu, struct rdt_resource *r)/* Update the mbm_assign_mode state for the CPU if supported */ if (r->mon.mbm_cntr_assignable)resctrl_arch_mbm_cntr_assign_set_one (r); -if (!hdr) +if (!hdr) {l3_mon_domain_setup (cpu, id, r, add_pos);
Quoted 9 lines
arch/x86/kernel/cpu/resctrl/core.c static void domain_add_cpu_mon(int cpu, struct rdt_resource *r) · line 601
Quoted 5 lines
arch/x86/kernel/cpu/resctrl/core.c +5
-0+ hdr =resctrl_find_domain (&r->mon_domains, id,NULL ); + } + +if (hdr) +erdt_l3_mon_domain_setup (cpu, hdr);The additional search for "hdr" seems unnecessary. Could
l3_mon_domain_setup()just callerdt_l3_mon_domain_setup()directly?
OK, l3_mon_domain_setup() can leverage erdt_l3_mon_domain_setup() to attach the ERDT domain to the corresponding newly-created hw domain. And later when other CPUs of the same domain are onlined, they share the same hw_dom, so there is no need to re-attach the ERDT domain again. I'll adjust the code accordingly.
Quoted 6 lines
Quoted 6 lines
arch/x86/kernel/cpu/resctrl/core.c +6
-0+bool erdt_cpu_valid (int cpu) +{ +struct erdt_domain_info *d; +int dom_id; + +if (!erdt_enabled)
Quoted 9 lines
arch/x86/kernel/cpu/resctrl/core.c
Quoted 5 lines
arch/x86/kernel/cpu/resctrl/core.c +5
-0+return true; + + dom_id =get_cpu_cacheinfo_id (cpu,RESCTRL_L3_CACHE ); +if (dom_id <0 ) +return true;Should this be "false"? Perhaps also with a warning similar to domain_add_cpu_mon()'s warning when the domain ID cannot be determined?
Right, will fix this and also !erdt_enabled case, and add a warning here.
Quoted 8 lines
Quoted 8 lines
arch/x86/kernel/cpu/resctrl/core.c +8
-0+ +/* +* Find the erdt_domain_info that contains this CPU, +* check if all CPUs in erdt_domain_info's cpumask +* have the same id(L3 id). +* +* For example, erdt_domain_info reports: +* domain0: CPU0, CPU2, domain1: CPU1, CPU3
Quoted 9 lines
arch/x86/kernel/cpu/resctrl/core.c
Quoted 6 lines
arch/x86/kernel/cpu/resctrl/core.c +6
-0+* rdt_domain_hdr reports: +* domain0: CPU0, CPU1, domain1: CPU2, CPU3 +* As a result, CPU1, CPU2 should not be covered by resctrl. +*/ +list_for_each_entry (d, &domain_info_list, entry) { +(unnecessary empty line)
OK, will remove this.
Quoted 27 lines
Quoted 27 lines
arch/x86/kernel/cpu/resctrl/core.c +27
-0+if (cpumask_test_cpu (cpu, &d->cpu_mask)) { +if (d->dom_id ==-1 ) { + d->dom_id = dom_id; + }else if (d->dom_id != dom_id) { +pr_warn (FW_BUG "CPU%d's id=%d not equal to CACD domain(%*pbl) id=%d, skip this CPU\n" , + cpu, dom_id,cpumask_pr_args (&d->cpu_mask), d->dom_id); + +return false; + } + +return true; + } + } + +pr_warn (FW_BUG "Cannot find CACD domain for CPU%d\n" , cpu); +return false; +} + +/* +* Associate ERDT table information with this domain. +*/ +void erdt_l3_mon_domain_setup (int cpu,struct rdt_domain_hdr *hdr) +{ +struct rdt_hw_l3_mon_domain *hw_dom; +struct erdt_domain_info *d; + +if (!erdt_enabled)
Quoted 9 lines
arch/x86/kernel/cpu/resctrl/core.c
Quoted 6 lines
arch/x86/kernel/cpu/resctrl/core.c +6
-0+return ; + + hw_dom = resctrl_to_arch_mon_dom(container_of(hdr, struct rdt_l3_mon_domain, hdr)); + +list_for_each_entry (d, &domain_info_list, entry) { +if (cpumask_test_cpu (cpu, &d->cpu_mask)) {Any motivation for why the cpumask is used as a test instead of the domain ID?
Let me switch to to compare the erdt_domain.id and the llc_id directly.
Quoted 9 lines
arch/x86/kernel/cpu/resctrl/core.c
Quoted 3 lines
arch/x86/kernel/cpu/resctrl/core.c +3
-0+/* Assign the ERDT information to hw_dom */ +if (!hw_dom->d_info) + hw_dom->d_info = d;This should become obvious if this initialization is done from
l3_mon_domain_setup()wherehw_monwould have been kzalloc'ed. This means that ifhw_dom->d_infois already initialized that there would be *two* ERDT domains that map to an existing resctrl monitoring domain. That looks to be something to complain about?
Yes, this should be a firmware bug and let me add a warning here.
thanks,
Chenyu
PATCH v6 5/9 x86/resctrl: Parse ACPI CMRC table
In reply to Chen YuThe 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.
---v5->v6:
Say that a copy of the CMRC table is saved, the code does not save a pointer to the ACPI table. (Reinette Chatre)
Use cmrc->header.length instead of subtbl->length, for consistency with cacd_init(). (Reinette Chatre)
Replace the "TBD: Only 1 CMRR per domain is allowed?" comment with a description of what the code actually does. (Reinette Chatre) Introduce ERDT_MMIO_CMRC_BASE here instead of in the RMDD parsing patch, since this is the patch that uses it. (Reinette Chatre) Order the commit tags per Documentation/process/maintainer-tip.rst. (Reinette Chatre)
--- 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(-)
arch/x86/include/asm/resctrl.h +2 -0
@@ -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;
arch/x86/kernel/cpu/resctrl/erdt.c +57 -0
92 lines not on this page · raw message
arch/x86/kernel/cpu/resctrl/internal.h +5 -1
@@ -24,10 +24,12 @@/* * Index into erdt_domain_info::base[] for each MMIO region. * @ERDT_MMIO_RMDD_CREG: RMDD control register base address +* @ERDT_MMIO_CMRC_BASE: CMRC monitoring register base address */ enum erdt_mmio_type {ERDT_MMIO_RMDD_CREG , -ERDT_MMIO_LAST =ERDT_MMIO_RMDD_CREG +ERDT_MMIO_CMRC_BASE , +ERDT_MMIO_LAST =ERDT_MMIO_CMRC_BASE };#define ERDT_MMIO_NUM_TYPES (ERDT_MMIO_LAST + 1)
@@ -35,6 +37,7 @@ enum erdt_mmio_type {/** * struct erdt_domain_info - Per-domain ERDT information * @base: Array of ioremapped MMIO region base addresses, indexed by ERDT_MMIO_* type +* @cmrc: Copy of the ACPI CMRC sub-table for this domain * @cpu_mask: CPUs belonging to this resource management domain * @max_rmid: Maximum RMID supported by this domain * @dom_id: L3 cache ID shared by all CPUs in this domain (-1 if unset)
@@ -42,6 +45,7 @@ enum erdt_mmio_type {*/ struct erdt_domain_info {void __iomem *base[ERDT_MMIO_NUM_TYPES ]; +struct acpi_erdt_cmrc *cmrc;struct cpumask cpu_mask;u32 max_rmid;int dom_id;
Signature · 1 line
2.25.1
Reinette Chatre
maintainerRe: [PATCH v6 5/9] x86/resctrl: Parse ACPI CMRC table
Hi Chenyu,
Quoted 3 lines · Chen Yu
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.
nit: "an RMD" -> "a monitoring domain"
Quoted 3 lines
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
nit: drop "later"
Quoted 7 lines
can read the counters via MMIO.
Suggested-by Tony Luck <[email protected]>Signed-off-by Chen Yu <[email protected]>Tested-by Hongyu Ning <[email protected]>Reviewed-by Thomas Gleixner <[email protected]>---
...
Quoted 26 lines
arch/x86/include/asm/resctrl.h +2
-0@@ -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;arch/x86/kernel/cpu/resctrl/erdt.c +1
-0@@ -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. */
arch/x86/kernel/cpu/resctrl/erdt.c static u16 first_rmdd_domain_id; · line 37
Quoted 4 lines
arch/x86/kernel/cpu/resctrl/erdt.c +1
-0@@ -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. */
hmmm ... when looking ahead at patch #9 this does not seem to be how this value is used? Instead, when a monitoring counter is read it is scaled using the per-domain acpi_erdt_cmrc::up_scale?
Instead this seems to be the scale used to set/initialize resctrl_rmid_realloc_threshold that is used by the limbo handler?
arch/x86/kernel/cpu/resctrl/erdt.c static u16 first_rmdd_domain_id; · line 38
Quoted 1 line
arch/x86/kernel/cpu/resctrl/erdt.c +1
-0+static int erdt_scale;
Can the scale ever be negative? Could it be unsigned int? Actually, looks like the original MSR based scale obtained via CPUID.(EAX=0FH,ECX=1H) is 32 bits while this new scale value from CMRC is 64 bits. The existing code can thus not accommodate the new values and need to be updated?
arch/x86/kernel/cpu/resctrl/erdt.c static u16 first_rmdd_domain_id; · line 40
Quoted 2 lines
arch/x86/kernel/cpu/resctrl/erdt.c +1
-0+int erdt_get_max_rmid (void )
Can this be negative?
Quoted 21 lines
arch/x86/kernel/cpu/resctrl/erdt.c +6
-0{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); }
arch/x86/kernel/cpu/resctrl/erdt.c static __init int cacd_init(struct acpi_subtbl_hdr_16 *subtbl, · line 119
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c +7
-0@@ -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" );
Please note there is inconsistency wrt "subtable" vs "sub-table" in error messages.
Quoted 16 lines
arch/x86/kernel/cpu/resctrl/erdt.c +16
-0+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 ])
arch/x86/kernel/cpu/resctrl/erdt.c static __init int cacd_init(struct acpi_subtbl_hdr_16 *subtbl, · line 145
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c +10
-0+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);
Please add a comment to describe why maximum of all domains' scale value is used. This comment may be best placed at global definition of erdt_scale.
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c +4
-0+ +return 0 ; +} +static inline struct acpi_subtbl_hdr_16 *rmdd_subtbl (struct acpi_erdt_rmdd *rmdd) {return (void *)rmdd +sizeof (*rmdd);@@ -166,6 +213,16 @@ static __init bool parse_rmdd_table(struct acpi_subtbl_hdr_16 *rmdd_hdr) goto cleanup;
arch/x86/kernel/cpu/resctrl/erdt.c static __init bool parse_rmdd_table(struct acpi_subtbl_hdr_16 *rmdd_hdr) · line 224
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c +9
-0subtbl_mask |=BIT (ACPI_ERDT_TYPE_CACD ); +break ; +case ACPI_ERDT_TYPE_CMRC : +/* +* Only one CMRC is supported per domain as there is no +* method to distinguish different CMRCs within a domain. +*/ +if (!(subtbl_mask &BIT (ACPI_ERDT_TYPE_CMRC )) && + !cmrc_init (subtbl, domain_info)) + subtbl_mask |=BIT (ACPI_ERDT_TYPE_CMRC );
How is cmrc_init() failure handled?
Quoted 31 lines
arch/x86/kernel/cpu/resctrl/erdt.c +1
-0+break ;default :break ;arch/x86/kernel/cpu/resctrl/internal.h +4
-1@@ -24,10 +24,12 @@/* * Index into erdt_domain_info::base[] for each MMIO region. * @ERDT_MMIO_RMDD_CREG: RMDD control register base address +* @ERDT_MMIO_CMRC_BASE: CMRC monitoring register base address */ enum erdt_mmio_type {ERDT_MMIO_RMDD_CREG , -ERDT_MMIO_LAST =ERDT_MMIO_RMDD_CREG +ERDT_MMIO_CMRC_BASE , +ERDT_MMIO_LAST =ERDT_MMIO_CMRC_BASE };#define ERDT_MMIO_NUM_TYPES (ERDT_MMIO_LAST + 1)@@ -35,6 +37,7 @@ enum erdt_mmio_type {/** * struct erdt_domain_info - Per-domain ERDT information * @base: Array of ioremapped MMIO region base addresses, indexed by ERDT_MMIO_* type +* @cmrc: Copy of the ACPI CMRC sub-table for this domain * @cpu_mask: CPUs belonging to this resource management domain * @max_rmid: Maximum RMID supported by this domain * @dom_id: L3 cache ID shared by all CPUs in this domain (-1 if unset)
arch/x86/kernel/cpu/resctrl/internal.h enum erdt_mmio_type { · line 51
Quoted 7 lines
arch/x86/kernel/cpu/resctrl/internal.h +1
-0@@ -42,6 +45,7 @@ enum erdt_mmio_type {*/ struct erdt_domain_info {void __iomem *base[ERDT_MMIO_NUM_TYPES ]; +struct acpi_erdt_cmrc *cmrc;struct cpumask cpu_mask;u32 max_rmid;int dom_id;
Reinette
Re: [PATCH v6 5/9] x86/resctrl: Parse ACPI CMRC table
Hi Reinette,
Quoted 9 lines · Reinette Chatre
Hi Chenyu,
Quoted 3 lines · Chen Yu
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.
nit: "an RMD" -> "a monitoring domain"
OK, will change it.
Quoted 6 lines
Quoted 3 lines
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
nit: drop "later"
OK.
Quoted 11 lines
Quoted 3 lines
static int
erdt_max_rmid;+/* Scale to bytes for the monitoring counters when ERDT is enabled. */
hmmm ... when looking ahead at patch #9 this does not seem to be how this value is used? Instead, when a monitoring counter is read it is scaled using the per-domain
acpi_erdt_cmrc::up_scale?Instead this seems to be the scale used to set/initialize
resctrl_rmid_realloc_thresholdthat is used by the limbo handler?
Yes, erdt_scale is used only for limbo handler, and the cmrc::up_scale is actually used by monitor count. Let me change the comment above.
Quoted 3 lines
Quoted 1 line
+static int
erdt_scale;Can the scale ever be negative? Could it be unsigned int?
It would not be negative, let me switch it to unsigned int, but..
Quoted 5 lines
Actually, looks like the original
MSR based scale obtained via CPUID.(EAX=0FH,ECX=1H) is 32 bits while this new scale value from CMRC is 64 bits. The existing code can thus not accommodate the new values and need to be updated?
Yes, the legacy CPUID reports it as 32 bits, while CMRC is declared as 64 bits.
In theory, we should change the scale type from unsigned int to u64 to accommodate both the legacy CPUID and CMRC. However, it seems unlikely that the scale would exceed 32 bits. If the scale were 32 bits, the L3 occupancy would be at least 2^32 − 1, which is about 4 GB. We have not yet seen platform with 4 GB of L3 cache. So perhaps we can keep erdt_scale as unsigned int for now IMO.
Quoted 5 lines
Quoted 2 lines
+
interdt_get_max_rmid(void)Can this be negative?
It would not be negative, let me convert it into unsigned int.
Quoted 11 lines
arch/x86/kernel/cpu/resctrl/erdt.c static __init int cacd_init(struct acpi_subtbl_hdr_16 *subtbl, · line 119
Quoted 8 lines
arch/x86/kernel/cpu/resctrl/erdt.c +7
-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" );Please note there is inconsistency wrt "subtable" vs "sub-table" in error messages.
OK, will check the code to fix them.
Quoted 12 lines
arch/x86/kernel/cpu/resctrl/erdt.c static __init int cacd_init(struct acpi_subtbl_hdr_16 *subtbl, · line 145
Quoted 8 lines
arch/x86/kernel/cpu/resctrl/erdt.c +8
-0+ 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);Please add a comment to describe why maximum of all domains' scale value is used. This comment may be best placed at global definition of
erdt_scale.
OK, let add the explanation around erdt_scale.
Quoted 10 lines
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c +4
-0+ +return 0 ; +} +static inline struct acpi_subtbl_hdr_16 *rmdd_subtbl (struct acpi_erdt_rmdd *rmdd) {return (void *)rmdd +sizeof (*rmdd);@@ -166,6 +213,16 @@ static __init bool parse_rmdd_table(struct acpi_subtbl_hdr_16 *rmdd_hdr) goto cleanup;
Quoted 13 lines
arch/x86/kernel/cpu/resctrl/erdt.c static __init bool parse_rmdd_table(struct acpi_subtbl_hdr_16 *rmdd_hdr) · line 224
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/erdt.c +9
-0subtbl_mask |=BIT (ACPI_ERDT_TYPE_CACD ); +break ; +case ACPI_ERDT_TYPE_CMRC : +/* +* Only one CMRC is supported per domain as there is no +* method to distinguish different CMRCs within a domain. +*/ +if (!(subtbl_mask &BIT (ACPI_ERDT_TYPE_CMRC )) && + !cmrc_init (subtbl, domain_info)) + subtbl_mask |=BIT (ACPI_ERDT_TYPE_CMRC );How is
cmrc_init()failure handled?
On second thought, the cleanup needs to be performed. That is, the region-aware RDT should enable CMT, MBA, and MBM collectively; otherwise, the system falls back to the legacy interface. This could keep the code easier to maintain. I will address this in the next version.
thanks,
Chenyu
Reinette Chatre
maintainerRe: [PATCH v6 5/9] x86/resctrl: Parse ACPI CMRC table
Hi Chenyu,
Quoted 9 lines · Yu C
Quoted 7 lines · Reinette Chatre
On 7/25/26 2:23 AM, Chen Yu wrote:
Actually, looks like the original
MSR based scale obtained via CPUID.(EAX=0FH,ECX=1H) is 32 bits while this new scale value from CMRC is 64 bits. The existing code can thus not accommodate the new values and need to be updated?
Quoted 7 lines
Yes, the legacy CPUID reports it as 32 bits, while CMRC is declared as 64 bits.
In theory, we should change the scale type from unsigned int to u64 to accommodate both the legacy CPUID and CMRC. However, it seems unlikely that the scale would exceed 32 bits. If the scale were 32 bits, the L3 occupancy would be at least 2^32 − 1, which is about 4 GB. We have not yet seen platform with 4 GB of L3 cache. So perhaps we can keep
erdt_scaleas unsigned int for now IMO.
It sounds like you are saying that the spec you are enabling should not be using 64 bits for this value. It is unexpected to me that work on enabling of a spec adds such constraint without clear motivation. If you find that the spec is not correct then I think it would be better to have it changed there instead of building what appears to be unsupported assumptions into resctrl.
Reinette
Re: [PATCH v6 5/9] x86/resctrl: Parse ACPI CMRC table
Hi Reinette,
Quoted 21 lines · Reinette Chatre
Hi Chenyu,
Quoted 9 lines · Yu C
Quoted 7 lines · Reinette Chatre
On 7/25/26 2:23 AM, Chen Yu wrote:
Actually, looks like the original
MSR based scale obtained via CPUID.(EAX=0FH,ECX=1H) is 32 bits while this new scale value from CMRC is 64 bits. The existing code can thus not accommodate the new values and need to be updated?Quoted 7 lines
Yes, the legacy CPUID reports it as 32 bits, while CMRC is declared as 64 bits.
In theory, we should change the scale type from unsigned int to u64 to accommodate both the legacy CPUID and CMRC. However, it seems unlikely that the scale would exceed 32 bits. If the scale were 32 bits, the L3 occupancy would be at least 2^32 − 1, which is about 4 GB. We have not yet seen platform with 4 GB of L3 cache. So perhaps we can keep
erdt_scaleas unsigned int for now IMO.
Quoted 5 lines
It sounds like you are saying that the spec you are enabling should not be using 64 bits for this value. It is unexpected to me that work on enabling of a spec adds such constraint without clear motivation. If you find that the spec is not correct then I think it would be better to have it changed there instead of building what appears to be unsupported assumptions into resctrl.
OK, let me check with the team.
thanks,
Chenyu
Luck, Tony
maintainerRe: [PATCH v6 5/9] x86/resctrl: Parse ACPI CMRC table
Quoted 23 lines · Yu C
Hi Reinette,
Quoted 20 lines · Reinette Chatre
Hi Chenyu,
Quoted 15 lines · Yu C
Quoted 6 lines · Reinette Chatre
On 7/25/26 2:23 AM, Chen Yu wrote:
Actually, looks like the original
MSR based scale obtained via CPUID.(EAX=0FH,ECX=1H) is 32 bits while this new scale value from CMRC is 64 bits. The existing code can thus not accommodate the new values and need to be updated?Yes, the legacy CPUID reports it as 32 bits, while CMRC is declared as 64 bits.
In theory, we should change the scale type from unsigned int to u64 to accommodate both the legacy CPUID and CMRC. However, it seems unlikely that the scale would exceed 32 bits. If the scale were 32 bits, the L3 occupancy would be at least 2^32 − 1, which is about 4 GB. We have not yet seen platform with 4 GB of L3 cache. So perhaps we can keep
erdt_scaleas unsigned int for now IMO.
Quoted 7 lines
Quoted 5 lines
It sounds like you are saying that the spec you are enabling should not be using 64 bits for this value. It is unexpected to me that work on enabling of a spec adds such constraint without clear motivation. If you find that the spec is not correct then I think it would be better to have it changed there instead of building what appears to be unsupported assumptions into resctrl.
OK, let me check with the team.
Looking at the RDT architecture spec that defines the CMRC table it looks to me like the "CMT Counter Upscaling Factor" was made 8-bytes just to round the table out to a whole number or quad-words.
This value represents the granularity of cache occupancy reporting. The feature would be worthless if this was >=4GB no matter how large the LLC cache may be in future generations.
If large values are a big concern then perhaps include a sanity check in the code:
if (cmrc->upscale >= SZ_4G) pr_warn(FW_BUG "insane CMRC upscale value 0x%llx\n", cmrc->upscale);
Quoted 3 lines
thanks,
Chenyu
-Tony
Re: [PATCH v6 5/9] x86/resctrl: Parse ACPI CMRC table
Quoted 23 lines · Tony
Quoted 7 lines
Quoted 7 lines
Quoted 5 lines
In theory, we should change the scale type from unsigned int to u64 to accommodate both the legacy CPUID and CMRC. However, it seems unlikely that the scale would exceed 32 bits. If the scale were 32 bits, the L3 occupancy would be at least 2^32 − 1, which is about 4 GB. We have not yet seen platform with 4 GB of L3 cache. So perhaps we can keep
erdt_scaleas unsigned int for now IMO.Quoted 7 lines
Quoted 5 lines
It sounds like you are saying that the spec you are enabling should not be using 64 bits for this value. It is unexpected to me that work on enabling of a spec adds such constraint without clear motivation. If you find that the spec is not correct then I think it would be better to have it changed there instead of building what appears to be unsupported assumptions into resctrl.
OK, let me check with the team.
Looking at the RDT architecture spec that defines the CMRC table it looks to me like the "CMT Counter Upscaling Factor" was made 8-bytes just to round the table out to a whole number or quad-words.
This value represents the granularity of cache occupancy reporting. The feature would be worthless if this was >=4GB no matter how large the LLC cache may be in future generations.
Quoted 5 lines
If large values are a big concern then perhaps include a sanity check in the code:
if (cmrc->upscale >= SZ_4G) pr_warn(FW_BUG "insane CMRC upscale value 0x%llx\n", cmrc->upscale);
Got it. The upscale factor should not exceed 32 bits, and the major monitor value should come from the 'counter' part. I'll add the above check in the next version.
thanks,
Chenyu
PATCH v6 6/9 x86/resctrl: Refactor the monitor read function
In reply to Chen YuSplit the monitor read helper into an L3 read path and an AET (Intel Application Energy Telemetry) read path. This makes the two distinct monitoring sources easier to extend independently and prepares the L3 path for ERDT-based MMIO reads.
No functional change.
---v5->v6:
Drop "added in a later patch". (Reinette Chatre)
--- arch/x86/kernel/cpu/resctrl/monitor.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-)
arch/x86/kernel/cpu/resctrl/monitor.c +19 -8
@@ -239,9 +239,9 @@ static u64 get_corrected_val(struct rdt_resource *r, struct rdt_l3_mon_domain *dreturn chunks * hw_res->mon_scale; } -int resctrl_arch_rmid_read (struct rdt_resource *r,struct rdt_domain_hdr *hdr, -u32 unused,u32 rmid,enum resctrl_event_id eventid, -void *arch_priv,u64 *val,void *ignored) +static int arch_l3_read_event (struct rdt_domain_hdr *hdr,u32 rmid, +enum resctrl_event_id eventid,u64 *val, +struct rdt_resource *r) {struct rdt_hw_l3_mon_domain *hw_dom;struct rdt_l3_mon_domain *d;
@@ -251,11 +251,6 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain_hdr *hdr,int cpu;int ret; -resctrl_arch_rmid_read_context_check (); - -if (r->rid ==RDT_RESOURCE_PERF_PKG ) -return intel_aet_read_event (hdr->id, rmid, arch_priv, val); -if (!domain_header_is_valid (hdr,RESCTRL_MON_DOMAIN ,RDT_RESOURCE_L3 ))return -EINVAL ;
@@ -281,6 +276,22 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain_hdr *hdr,return ret; } +int resctrl_arch_rmid_read (struct rdt_resource *r,struct rdt_domain_hdr *hdr, +u32 unused,u32 rmid,enum resctrl_event_id eventid, +void *arch_priv,u64 *val,void *ignored) +{ +resctrl_arch_rmid_read_context_check (); + +switch (r->rid) { +case RDT_RESOURCE_L3 : +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); +default : +return -EINVAL ; + } +} +static int __cntr_id_read (u32 cntr_id,u64 *val) {u64 msr_val;
Signature · 1 line
2.25.1
Reinette Chatre
maintainerRe: [PATCH v6 6/9] x86/resctrl: Refactor the monitor read function
Hi Chenyu,
Quoted 5 lines · Chen Yu
arch/x86/kernel/cpu/resctrl/monitor.c +0
-0
arch/x86/kernel/cpu/resctrl/monitor.c static u64 get_corrected_val(struct rdt_resource *r, struct rdt_l3_mon_domain *d · line 244
Quoted 9 lines
arch/x86/kernel/cpu/resctrl/monitor.c +3
-3@@ -239,9 +239,9 @@ static u64 get_corrected_val(struct rdt_resource *r, struct rdt_l3_mon_domain *dreturn chunks * hw_res->mon_scale; } -int resctrl_arch_rmid_read (struct rdt_resource *r,struct rdt_domain_hdr *hdr, -u32 unused,u32 rmid,enum resctrl_event_id eventid, -void *arch_priv,u64 *val,void *ignored) +static int arch_l3_read_event (struct rdt_domain_hdr *hdr,u32 rmid, +enum resctrl_event_id eventid,u64 *val, +struct rdt_resource *r)
Could you please keep the same parameter order as original resctrl_arch_rmid_read()?
Reinette
Re: [PATCH v6 6/9] x86/resctrl: Refactor the monitor read function
Quoted 9 lines · Reinette Chatre
arch/x86/kernel/cpu/resctrl/monitor.c static u64 get_corrected_val(struct rdt_resource *r, struct rdt_l3_mon_domain *d · line 244
Quoted 6 lines
arch/x86/kernel/cpu/resctrl/monitor.c +3
-3-int resctrl_arch_rmid_read (struct rdt_resource *r,struct rdt_domain_hdr *hdr, -u32 unused,u32 rmid,enum resctrl_event_id eventid, -void *arch_priv,u64 *val,void *ignored) +static int arch_l3_read_event (struct rdt_domain_hdr *hdr,u32 rmid, +enum resctrl_event_id eventid,u64 *val, +struct rdt_resource *r)Could you please keep the same parameter order as original
resctrl_arch_rmid_read()?
Got it, will adjust the order.
thanks,
Chenyu
PATCH v6 7/9 fs/resctrl: Do not invoke smp_processor_id() in preemptible context
In reply to Chen YuFrom: Tony Luck <[email protected]>
LLC occupancy can be read on any CPU when the counter is accessed via MMIO, so such an event is read from task context on whatever CPU the caller happens to be running on rather than being bounced to a CPU in the monitoring domain. mon_evt::any_cpu marks these CPU-agnostic events.
__l3_mon_event_count() calls smp_processor_id() to find the CPU to read from. For an any_cpu event that lookup is unsafe:
the code runs in preemptible task context, so smp_processor_id() emits a debug warning.
Skip the current-CPU lookup when an event's any_cpu flag is set, events with this flag do not require execution on a specific CPU. For legacy MSR-based access, update rmid_read::err if the reading of the event was dispatched to a wrong CPU, according to the change at:
https://lore.kernel.org/lkml/6b3c66a49788828bd8c04a6911bd74c91ccd56f3.1782857711.git.reinette.chatre@intel.com/
---v5->v6:
Drop "in a follow-up patch" from the changelog. (Reinette Chatre) Set rmid_read::err when an MSR based read is dispatched to a CPU outside the monitoring domain, to align with the conflicting change at
https://lore.kernel.org/lkml/6b3c66a49788828bd8c04a6911bd74c91ccd56f3.1782857711.git.reinette.chatre@intel.com/
(Reinette Chatre)
--- fs/resctrl/monitor.c | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-)
fs/resctrl/monitor.c +34 -10
@@ -422,9 +422,37 @@ static void mbm_cntr_free(struct rdt_l3_mon_domain *d, int cntr_id)memset (&d->cntr_cfg[cntr_id],0 ,sizeof (*d->cntr_cfg)); } +/** +* cpu_on_correct_domain() - Check if current CPU is in the correct +* domain for the event. +* @rr: The rmid_read structure containing event and domain information. +* +* Context: Preemptible process context when @rr->evt->any_cpu is set. +* Non-migratable process context (via smp_call_on_cpu()) or +* non-preemptible context (via smp_call_function_any()) when +* the event must be read on a specific CPU. +* Return: true if the current CPU can read this event, false otherwise. +*/ +static bool cpu_on_correct_domain (struct rmid_read *rr) +{ +int cpu; + +/* Any CPU is OK for this event */ +if (rr->evt->any_cpu) +return true; + + cpu =smp_processor_id (); + +/* Single domain. Must be on a CPU in that domain. */ +if (rr->hdr) +return cpumask_test_cpu (cpu, &rr->hdr->cpu_mask); + +/* Summing domains that share a cache, must be on a CPU for that cache. */ +return cpumask_test_cpu (cpu, &rr->ci->shared_cpu_map); +} +static int __l3_mon_event_count (struct rdtgroup *rdtgrp,struct rmid_read *rr) { -int cpu =smp_processor_id ();u32 closid = rdtgrp->closid;u32 rmid = rdtgrp->mon.rmid;struct rdt_l3_mon_domain *d;
@@ -457,9 +485,6 @@ static int __l3_mon_event_count(struct rdtgroup *rdtgrp, struct rmid_read *rr)return 0 ; } -/* Reading a single domain, must be on a CPU in that domain. */ -if (!cpumask_test_cpu (cpu, &d->hdr.cpu_mask)) -return -EINVAL ;if (rr->is_mbm_cntr) rr->err =resctrl_arch_cntr_read (rr->r, d, closid, rmid, cntr_id, rr->evt->evtid, &tval);
@@ -477,7 +502,6 @@ static int __l3_mon_event_count(struct rdtgroup *rdtgrp, struct rmid_read *rr)static int __l3_mon_event_count_sum (struct rdtgroup *rdtgrp,struct rmid_read *rr) { -int cpu =smp_processor_id ();u32 closid = rdtgrp->closid;u32 rmid = rdtgrp->mon.rmid;struct rdt_l3_mon_domain *d;
@@ -495,10 +519,6 @@ static int __l3_mon_event_count_sum(struct rdtgroup *rdtgrp, struct rmid_read *rreturn -EINVAL ; } -/* Summing domains that share a cache, must be on a CPU for that cache. */ -if (!cpumask_test_cpu (cpu, &rr->ci->shared_cpu_map)) -return -EINVAL ; -/* * Legacy files must report the sum of an event across all * domains that share the same L3 cache instance.
@@ -529,7 +549,11 @@ static int __mon_event_count(struct rdtgroup *rdtgrp, struct rmid_read *rr) {switch (rr->r->rid) {case RDT_RESOURCE_L3 : -WARN_ON_ONCE (rr->evt->any_cpu); +if (!cpu_on_correct_domain (rr)) { + rr->err = -EIO ; +return -EINVAL ; + } +if (rr->hdr)return __l3_mon_event_count (rdtgrp, rr);else
Signature · 1 line
2.25.1
Reinette Chatre
maintainerRe: [PATCH v6 7/9] fs/resctrl: Do not invoke smp_processor_id() in preemptible context
Hi Chenyu,
Quoted 6 lines · Chen Yu
From: Tony Luck <[email protected]>
LLC occupancy can be read on any CPU when the counter is accessed via MMIO, so such an event is read from task context on whatever CPU the caller happens to be running on rather than being bounced to a CPU in the monitoring domain.
mon_evt::any_cpumarks these CPU-agnostic events.
Please let the context describe what the *current* code does. This changelog describes context that does not exist (yet) and then presents the change in this patch as a bugfix. This is not accurate and misrepresents this change.
Quoted 11 lines
__l3_mon_event_count()callssmp_processor_id()to find the CPU to read from. For anany_cpuevent that lookup is unsafe:
the code runs in preemptible task context, sosmp_processor_id()emits a debug warning.Skip the current-CPU lookup when an event's
any_cpuflag is set, events with this flag do not require execution on a specific CPU. For legacy MSR-based access, updatermid_read::errif the reading of the event was dispatched to a wrong CPU, according to the change at:
https://lore.kernel.org/lkml/6b3c66a49788828bd8c04a6911bd74c91ccd56f3.1782857711.git.reinette.chatre@intel.com/
This has been merged now so it should not be necessary to call this out, at least in this format
Quoted 5 lines
Signed-off-by Tony Luck <[email protected]>Signed-off-by Chen Yu <[email protected]>Tested-by Hongyu Ning <[email protected]>---
Reinette
Re: [PATCH v6 7/9] fs/resctrl: Do not invoke smp_processor_id() in preemptible context
Quoted 5 lines · Reinette Chatre
Hi Chenyu,
Quoted 2 lines · Chen Yu
From: Tony Luck <[email protected]>
Quoted 9 lines
Quoted 4 lines
LLC occupancy can be read on any CPU when the counter is accessed via MMIO, so such an event is read from task context on whatever CPU the caller happens to be running on rather than being bounced to a CPU in the monitoring domain.
mon_evt::any_cpumarks these CPU-agnostic events.Please let the context describe what the *current* code does. This changelog describes context that does not exist (yet) and then presents the change in this patch as a bugfix. This is not accurate and misrepresents this change.
OK, let me remove above description which has not yet been introduced.
Quoted 6 lines
Quoted 6 lines
__l3_mon_event_count()callssmp_processor_id()to find the CPU to read from. For anany_cpuevent that lookup is unsafe:
the code runs in preemptible task context, sosmp_processor_id()emits a debug warning.
Quoted 9 lines
Quoted 5 lines
Skip the current-CPU lookup when an event's
any_cpuflag is set, events with this flag do not require execution on a specific CPU. For legacy MSR-based access, updatermid_read::errif the reading of the event was dispatched to a wrong CPU, according to the change at:
https://lore.kernel.org/lkml/6b3c66a49788828bd8c04a6911bd74c91ccd56f3.1782857711.git.reinette.chatre@intel.com/This has been merged now so it should not be necessary to call this out, at least in this format
OK, I'll adjust the description to avoid mentioning the above change.
thanks,
Chenyu
PATCH v6 8/9 x86/resctrl: Introduce erdt_cpu_has() and erdt_support()
In reply to Chen YuIntroduce 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". Similar to rdt_cpu_has(), erdt_cpu_has() expects an x86 feature flag as parameter.
Introduce erdt_support() as a helper called by erdt_cpu_has() to check whether the ERDT firmware supports a given feature.
erdt_support() deliberately claims no feature yet and returns false. A feature may only be reported as ERDT backed once the low level accessors that read its monitoring data via MMIO exist, otherwise callers would take the ERDT path and find no implementation behind it. Features are added to erdt_support() as their MMIO implementations are introduced.
---v5->v6:
New patch. Split out of the v5 "x86/resctrl: Introduce helpers to read L3 occupancy via MMIO" patch, which carried two logical changes. (Reinette Chatre)
Rename erdt_support_features() to erdt_support(). (Reinette Chatre) Reword "expects x86 feature flag as parameters" to "expects an x86 feature flag as parameter". (Reinette Chatre)
Explain in the changelog why erdt_support() returns false here: a feature is only reported as ERDT backed once the MMIO accessors that read its monitoring data exist. (Reinette Chatre)
Drop the unused asm/cpufeatures.h include. (Reinette Chatre)
--- arch/x86/include/asm/resctrl.h | 1 + arch/x86/kernel/cpu/resctrl/core.c | 23 +++++++++++++++++++++++ arch/x86/kernel/cpu/resctrl/erdt.c | 5 +++++ arch/x86/kernel/cpu/resctrl/internal.h | 2 ++ 4 files changed, 31 insertions(+)
arch/x86/include/asm/resctrl.h +1 -0
@@ -49,6 +49,7 @@ 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);int erdt_get_scale (void );static inline bool resctrl_arch_alloc_capable (void )
arch/x86/kernel/cpu/resctrl/core.c +23 -0
@@ -887,6 +887,29 @@ bool rdt_cpu_has(int flag)return ret; } +bool erdt_cpu_has (int flag) +{ +struct rdt_options *o; +bool ret; + + ret =erdt_support (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 ))
arch/x86/kernel/cpu/resctrl/erdt.c +5 -0
@@ -37,6 +37,11 @@ static int erdt_max_rmid;/* Scale to bytes for the monitoring counters when ERDT is enabled. */ static int erdt_scale; +bool erdt_support (int flag) +{ +return false; +} +int erdt_get_max_rmid (void ) {return erdt_max_rmid;
arch/x86/kernel/cpu/resctrl/internal.h +2 -0
@@ -289,6 +289,8 @@ static inline void intel_aet_mon_domain_setup(int cpu, int id, struct rdt_resourstatic inline bool intel_handle_aet_option (bool force_off,char *tok) {return false; }#endif +bool erdt_support (int flag); +bool erdt_cpu_has (int flag);int erdt_get_max_rmid (void );int erdt_init (void );void erdt_exit (void );
Signature · 1 line
2.25.1
Reinette Chatre
maintainerRe: [PATCH v6 8/9] x86/resctrl: Introduce erdt_cpu_has() and erdt_support()
Hi Chenyu,
Quoted 7 lines · Chen Yu
Introduce
erdt_cpu_has()to verify if a specific RDT feature is backed by an ERDT table.erdt_cpu_has()is derived fromrdt_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". Similar tordt_cpu_has(),erdt_cpu_has()expects an x86 feature flag as parameter.
Quoted 6 lines
Introduce
erdt_support()as a helper called byerdt_cpu_has()to check whether the ERDT firmware supports a given feature.
erdt_support()deliberately claims no feature yet and returns false. A feature may only be reported as ERDT backed once the low level accessors that read its monitoring data via MMIO exist, otherwise callers would
Are these helpers limited to monitoring ERDT features? First paragraph mentions "support for an event" and above mentions "read its monitoring data" that imply these helpers are limited to monitoring features but I do not think this is the case?
Quoted 2 lines
take the ERDT path and find no implementation behind it. Features are added to
erdt_support()as their MMIO implementations are introduced.
nit: "are added" -> "should be added"
Quoted 27 lines
Signed-off-by Chen Yu <[email protected]>Tested-by Hongyu Ning <[email protected]>---
v5->v6:
New patch. Split out of the v5 "x86/resctrl: Introduce helpers to read L3 occupancy via MMIO" patch, which carried two logical changes. (Reinette Chatre)
Renameerdt_support_features()toerdt_support(). (Reinette Chatre) Reword "expects x86 feature flag as parameters" to "expects an x86 feature flag as parameter". (Reinette Chatre)
Explain in the changelog whyerdt_support()returns false here: a feature is only reported as ERDT backed once the MMIO accessors that read its monitoring data exist. (Reinette Chatre)
Drop the unusedasm/cpufeatures.hinclude. (Reinette Chatre)--- arch/x86/include/asm/resctrl.h | 1 + arch/x86/kernel/cpu/resctrl/core.c | 23 +++++++++++++++++++++++ arch/x86/kernel/cpu/resctrl/erdt.c | 5 +++++ arch/x86/kernel/cpu/resctrl/internal.h | 2 ++ 4 files changed, 31 insertions(+)arch/x86/include/asm/resctrl.h +0
-0
arch/x86/include/asm/resctrl.h DECLARE_STATIC_KEY_FALSE(rdt_enable_key); · line 54
Quoted 6 lines
arch/x86/include/asm/resctrl.h +1
-0@@ -49,6 +49,7 @@ 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);int erdt_get_scale (void );
Can this declaration be dropped? Below there is a duplicate declaration added to arch/x86/kernel/cpu/resctrl/internal.h that should be sufficient?
Quoted 56 lines
arch/x86/include/asm/resctrl.h +0
-0static inline bool resctrl_arch_alloc_capable (void )arch/x86/kernel/cpu/resctrl/core.c +23
-0@@ -887,6 +887,29 @@ bool rdt_cpu_has(int flag)return ret; } +bool erdt_cpu_has (int flag) +{ +struct rdt_options *o; +bool ret; + + ret =erdt_support (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 ))arch/x86/kernel/cpu/resctrl/erdt.c +5
-0@@ -37,6 +37,11 @@ static int erdt_max_rmid;/* Scale to bytes for the monitoring counters when ERDT is enabled. */ static int erdt_scale; +bool erdt_support (int flag) +{ +return false; +} +int erdt_get_max_rmid (void ) {return erdt_max_rmid;arch/x86/kernel/cpu/resctrl/internal.h +0
-0
arch/x86/kernel/cpu/resctrl/internal.h static inline void intel_aet_mon_domain_setup(int cpu, int id, struct rdt_resour · line 296
Quoted 8 lines
arch/x86/kernel/cpu/resctrl/internal.h +2
-0@@ -289,6 +289,8 @@ static inline void intel_aet_mon_domain_setup(int cpu, int id, struct rdt_resourstatic inline bool intel_handle_aet_option (bool force_off,char *tok) {return false; }#endif +bool erdt_support (int flag); +bool erdt_cpu_has (int flag);int erdt_get_max_rmid (void );int erdt_init (void );void erdt_exit (void );
Reinette
Re: [PATCH v6 8/9] x86/resctrl: Introduce erdt_cpu_has() and erdt_support()
Hi Reinette,
Quoted 13 lines · Reinette Chatre
Hi Chenyu,
Quoted 10 lines · Chen Yu
Introduce
erdt_cpu_has()to verify if a specific RDT feature is backed by an ERDT table.erdt_cpu_has()is derived fromrdt_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". Similar tordt_cpu_has(),erdt_cpu_has()expects an x86 feature flag as parameter.Introduce
erdt_support()as a helper called byerdt_cpu_has()to check whether the ERDT firmware supports a given feature.
Quoted 9 lines
Quoted 3 lines
erdt_support()deliberately claims no feature yet and returns false. A feature may only be reported as ERDT backed once the low level accessors that read its monitoring data via MMIO exist, otherwise callers wouldAre these helpers limited to monitoring ERDT features? First paragraph mentions "support for an event" and above mentions "read its monitoring data" that imply these helpers are limited to monitoring features but I do not think this is the case?
They are not only for monitoring features, but for monitor/allocation features. Let me adjust the description.
Quoted 5 lines
Quoted 2 lines
take the ERDT path and find no implementation behind it. Features are added to
erdt_support()as their MMIO implementations are introduced.nit: "are added" -> "should be added"
OK.
Quoted 30 lines
Quoted 30 lines
Signed-off-by Chen Yu <[email protected]>Tested-by Hongyu Ning <[email protected]>---
v5->v6:
New patch. Split out of the v5 "x86/resctrl: Introduce helpers to read L3 occupancy via MMIO" patch, which carried two logical changes. (Reinette Chatre)
Renameerdt_support_features()toerdt_support(). (Reinette Chatre) Reword "expects x86 feature flag as parameters" to "expects an x86 feature flag as parameter". (Reinette Chatre)
Explain in the changelog whyerdt_support()returns false here: a feature is only reported as ERDT backed once the MMIO accessors that read its monitoring data exist. (Reinette Chatre)
Drop the unusedasm/cpufeatures.hinclude. (Reinette Chatre)--- arch/x86/include/asm/resctrl.h | 1 + arch/x86/kernel/cpu/resctrl/core.c | 23 +++++++++++++++++++++++ arch/x86/kernel/cpu/resctrl/erdt.c | 5 +++++ arch/x86/kernel/cpu/resctrl/internal.h | 2 ++ 4 files changed, 31 insertions(+)arch/x86/include/asm/resctrl.h +0
-0@@ -49,6 +49,7 @@ DECLARE_STATIC_KEY_FALSE(rdt_enable_key);DECLARE_STATIC_KEY_FALSE (rdt_alloc_enable_key);DECLARE_STATIC_KEY_FALSE (rdt_mon_enable_key);
Quoted 7 lines
arch/x86/include/asm/resctrl.h DECLARE_STATIC_KEY_FALSE(rdt_enable_key); · line 54
Quoted 3 lines
arch/x86/include/asm/resctrl.h +1
-0+bool erdt_cpu_has (int flag);int erdt_get_scale (void );Can this declaration be dropped? Below there is a duplicate declaration added to
arch/x86/kernel/cpu/resctrl/internal.hthat should be sufficient?
This declaration is needed by [PATCH 9/9] in resctrl_arch_round_mon_val(), which uses erdt_cpu_has(). Maybe we can drop erdt_cpu_has() from internal.h, although I thought exposing both erdt_cpu_has() and erdt_support() might be useful too.
thanks,
Chenyu
PATCH v6 9/9 x86/resctrl: Add MMIO-based LLC occupancy monitoring support
In reply to Chen YuAdd erdt_mon_read() to read LLC occupancy via MMIO and use it when the platform supports ERDT. Register the L3 occupancy event with ERDT enabled when available, falling back to the MSR-based path otherwise.
Use the CMRC (Cache Monitoring Registers for CPU Agents Description) ACPI sub-table to read LLC occupancy counters for each RMID via MMIO when ERDT is enabled. This CMRC information is stored in the rdt_hw_l3_mon_domain, which could be accessed directly.
Currently, the per-domain limbo handler is still in use. There is no need to switch to a global limbo handler, because even after such a switch, the worker thread would still have to iterate through all domains one by one. The per-domain handler already accomplishes this using a worker thread rather than costly IPIs, so there is no clear benefit to switching to a global handler.
---v5->v6:
Merge the MMIO read helper from the v5 "x86/resctrl: Introduce helpers to read L3 occupancy via MMIO" patch into the v5 "x86/resctrl: Enable read L3 occupancy via MMIO" patch, so that erdt_mon_read() is introduced in the same patch that calls it and the series stays bisectable.
Round to the ERDT scale in resctrl_arch_round_mon_val() instead of returning the value unchanged (Reinette Chatre)
Explain in the changelog why the per-domain limbo handler is kept even though the occupancy counters can be read from any CPU. Drop the SNC WARN_ONCE() and the new resctrl_disable_mon_event() API. (Reinette Chatre)
Use accurate types for erdt_mon_read(): u32 for the RMID and enum resctrl_event_id for the event. (Reinette Chatre) Compute the CMRC MMIO offset in cmrc_index_function_1() only, instead of open coding the same formula twice. (Reinette Chatre) Fix the Unavailable bit of the MMIO L3 occupancy counter. Per the RDT architecture specification it is bit 63 and not bit 62, and it is only defined when bit 0 of the CMRC flags is set. Document that struct rdt_hw_resource::mon_scale only applies to the MSR path. The v5 patch "x86/resctrl: Replace 'msr' in monitoring data identifiers" that carried this note is dropped. (Reinette Chatre)
--- arch/x86/include/asm/resctrl.h | 8 +++- arch/x86/kernel/cpu/resctrl/core.c | 5 ++- arch/x86/kernel/cpu/resctrl/erdt.c | 59 ++++++++++++++++++++++++++ arch/x86/kernel/cpu/resctrl/internal.h | 7 ++- arch/x86/kernel/cpu/resctrl/monitor.c | 9 +++- 5 files changed, 84 insertions(+), 4 deletions(-)
arch/x86/include/asm/resctrl.h +7 -1
@@ -132,7 +132,13 @@ static inline void __resctrl_sched_in(struct task_struct *tsk)static inline unsigned int resctrl_arch_round_mon_val (unsigned int val) { -unsigned int scale = boot_cpu_data.x86_cache_occ_scale; +unsigned int scale = boot_cpu_data.x86_cache_occ_scale, escale; + +if (erdt_cpu_has (X86_FEATURE_CQM_OCCUP_LLC )) { + escale =erdt_get_scale (); +if (escale) + scale = escale; + }/* h/w works in units of "boot_cpu_data.x86_cache_occ_scale" */ val /= scale;
arch/x86/kernel/cpu/resctrl/core.c +4 -1
@@ -997,7 +997,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; }
arch/x86/kernel/cpu/resctrl/erdt.c +59 -0
77 lines not on this page · raw message
arch/x86/kernel/cpu/resctrl/internal.h +6 -1
@@ -158,7 +158,11 @@ struct msr_param {* which has been corrected for features like CDP. * @msr_base: Base MSR address for CBMs * @msr_update: Function pointer to update QOS MSRs -* @mon_scale: cqm counter * mon_scale = occupancy in bytes +* @mon_scale: Scale factor applied to a raw counter value on the +* MSR-based read path: CMT occupancy counter * mon_scale = +* occupancy in bytes, and MBM chunk count * mon_scale = bytes +* transferred. ERDT reads occupancy via MMIO and applies its +* own firmware-provided scale instead. * @mbm_width: Monitor width, to detect and correct for overflow. * @cdp_enabled: CDP state of this resource * @mbm_cntr_assign_enabled: ABMC feature is enabled
@@ -292,6 +296,7 @@ static inline bool intel_handle_aet_option(bool force_off, char *tok) { return fbool erdt_support (int flag);bool erdt_cpu_has (int flag);int erdt_get_max_rmid (void ); +int erdt_mon_read (struct rdt_domain_hdr *hdr,enum resctrl_event_id evtid,u32 rmid,u64 *val);int erdt_init (void );void erdt_exit (void );
arch/x86/kernel/cpu/resctrl/monitor.c +8 -1
@@ -284,6 +284,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);
@@ -430,12 +434,15 @@ int __init rdt_get_l3_mon_config(struct rdt_resource *r)struct rdt_hw_resource *hw_res =resctrl_to_arch_res (r);unsigned int threshold;u32 eax, ebx, ecx, edx; +int max_rmid; snc_nodes_per_l3_cache =snc_get_config (); + max_rmid =erdt_cpu_has (X86_FEATURE_CQM_OCCUP_LLC ) ? +erdt_get_max_rmid () : boot_cpu_data.x86_cache_max_rmid; 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 = (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 )
Signature · 1 line
2.25.1
Reinette Chatre
maintainerRe: [PATCH v6 9/9] x86/resctrl: Add MMIO-based LLC occupancy monitoring support
Hi Chenyu,
Quoted 9 lines · Chen Yu
Add
erdt_mon_read()to read LLC occupancy via MMIO and use it when the platform supports ERDT. Register the L3 occupancy event with ERDT enabled when available, falling back to the MSR-based path otherwise.Use the CMRC (Cache Monitoring Registers for CPU Agents Description) ACPI sub-table to read LLC occupancy counters for each RMID via MMIO when ERDT is enabled. This CMRC information is stored in the
rdt_hw_l3_mon_domain, which could be accessed directly.
Please write in imperative tone.
Quoted 6 lines
Currently, the per-domain limbo handler is still in use. There is no need to switch to a global limbo handler, because even after such a switch, the worker thread would still have to iterate through all domains one by one. The per-domain handler already accomplishes this using a worker thread rather than costly IPIs, so there is no clear benefit to switching to a global handler.
Could you please elaborate how a global limbo handler would require IPIs?
arch/x86/include/asm/resctrl.h static inline void __resctrl_sched_in(struct task_struct *tsk) · line 135
Quoted 10 lines
arch/x86/include/asm/resctrl.h +1
-1@@ -132,7 +132,13 @@ static inline void __resctrl_sched_in(struct task_struct *tsk)static inline unsigned int resctrl_arch_round_mon_val (unsigned int val) { -unsigned int scale = boot_cpu_data.x86_cache_occ_scale; +unsigned int scale = boot_cpu_data.x86_cache_occ_scale, escale;
related to earlier topic, "scale" being unsigned int is ok since x86_cache_occ_scale is initialized from 32bits. As I understand it the ERDT scale value is initialized from 64 bits instead so the existing types do not seem to accommodate?
Quoted 41 lines
arch/x86/include/asm/resctrl.h +6
-0+ +if (erdt_cpu_has (X86_FEATURE_CQM_OCCUP_LLC )) { + escale =erdt_get_scale (); +if (escale) + scale = escale; + }/* h/w works in units of "boot_cpu_data.x86_cache_occ_scale" */ val /= scale;arch/x86/kernel/cpu/resctrl/core.c +4
-1@@ -997,7 +997,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; }arch/x86/kernel/cpu/resctrl/erdt.c +4
-0@@ -26,6 +26,10 @@ static bool erdt_enabled;#define CMRC_SUPPORTED_INDEX_FN 1#define RMDD_FLAG_CPU_L3_DOMAIN BIT(0) +/* Set in a monitoring counter when it holds no valid data to report. */ +#define UNAVAILABLE_COUNTER BIT_ULL(63) +#define CMRC_FLAG_UNAVAILABLE_BIT BIT(0) +/* Bitmask of valid sub-tables found in the first RMDD, used to ensure all RMDDs match. */ static u32 valid_subtbl_mask;
arch/x86/kernel/cpu/resctrl/erdt.c static int erdt_scale; · line 48
Quoted 6 lines
arch/x86/kernel/cpu/resctrl/erdt.c +3
-0@@ -39,6 +43,9 @@ static int erdt_scale;bool erdt_support (int flag) { +if (flag ==X86_FEATURE_CQM_OCCUP_LLC ) +return valid_subtbl_mask &BIT (ACPI_ERDT_TYPE_CMRC ); +
Is the plan to keep adding more if() statements as new flags need to be tested?
Quoted 103 lines
arch/x86/kernel/cpu/resctrl/erdt.c +52
-0return false; }@@ -52,6 +59,58 @@ int erdt_get_scale(void)return erdt_scale; } +static u32 cmrc_index_function_1 (struct acpi_erdt_cmrc *cmrc,u32 rmid) +{ +/* +* MMIO_offset_for_RMID# = +* (RMID / ClumpSize) * Stride + +* (RMID % ClumpSize) * 8 +*/ +return (rmid / cmrc->clump_size) * cmrc->clump_stride + + (rmid % cmrc->clump_size) *8 ; +} + +static int erdt_read_l3_occupancy (const struct erdt_domain_info *d,u32 rmid,u64 *val) +{ +struct acpi_erdt_cmrc *cmrc; +u64 l3_cmt_count; +u32 offset; + + cmrc = d->cmrc; +if (!cmrc) +return -EIO ; + + offset =cmrc_index_function_1 (cmrc, rmid); +/* Overflow of cmt_reg_size * SZ_4K already validated in erdt_ioremap(). */ +if (offset +sizeof (u64) > (u32 )cmrc->cmt_reg_size *SZ_4K ) +return -EINVAL ; + + l3_cmt_count =readq (d->base[ERDT_MMIO_CMRC_BASE ] + offset); +if ((cmrc->flags &CMRC_FLAG_UNAVAILABLE_BIT ) && + (l3_cmt_count &UNAVAILABLE_COUNTER )) +return -EINVAL ; + + *val = l3_cmt_count * cmrc->up_scale; + +return 0 ; +} + +int erdt_mon_read (struct rdt_domain_hdr *hdr,enum resctrl_event_id evtid,u32 rmid,u64 *val) +{ +struct rdt_hw_l3_mon_domain *hw_dom; +const struct erdt_domain_info *d; + + hw_dom = resctrl_to_arch_mon_dom(container_of(hdr, struct rdt_l3_mon_domain, hdr)); + d = hw_dom->d_info; +if (!d) +return -EIO ; + +if (evtid ==QOS_L3_OCCUP_EVENT_ID ) +return erdt_read_l3_occupancy (d, rmid, val); + +return -EIO ; +} +static void __iomem *erdt_ioremap (phys_addr_t base,u32 num_pages,const char *desc) {void __iomem *addr;arch/x86/kernel/cpu/resctrl/internal.h +6
-1@@ -158,7 +158,11 @@ struct msr_param {* which has been corrected for features like CDP. * @msr_base: Base MSR address for CBMs * @msr_update: Function pointer to update QOS MSRs -* @mon_scale: cqm counter * mon_scale = occupancy in bytes +* @mon_scale: Scale factor applied to a raw counter value on the +* MSR-based read path: CMT occupancy counter * mon_scale = +* occupancy in bytes, and MBM chunk count * mon_scale = bytes +* transferred. ERDT reads occupancy via MMIO and applies its +* own firmware-provided scale instead. * @mbm_width: Monitor width, to detect and correct for overflow. * @cdp_enabled: CDP state of this resource * @mbm_cntr_assign_enabled: ABMC feature is enabled @@ -292,6 +296,7 @@ static inline bool intel_handle_aet_option(bool force_off, char *tok) { return fbool erdt_support (int flag);bool erdt_cpu_has (int flag);int erdt_get_max_rmid (void ); +int erdt_mon_read (struct rdt_domain_hdr *hdr,enum resctrl_event_id evtid,u32 rmid,u64 *val);int erdt_init (void );void erdt_exit (void );arch/x86/kernel/cpu/resctrl/monitor.c +4
-0@@ -284,6 +284,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);
arch/x86/kernel/cpu/resctrl/monitor.c int __init rdt_get_l3_mon_config(struct rdt_resource *r) · line 442
Quoted 9 lines
arch/x86/kernel/cpu/resctrl/monitor.c +3
-0@@ -430,12 +434,15 @@ int __init rdt_get_l3_mon_config(struct rdt_resource *r)struct rdt_hw_resource *hw_res =resctrl_to_arch_res (r);unsigned int threshold;u32 eax, ebx, ecx, edx; +int max_rmid; snc_nodes_per_l3_cache =snc_get_config (); + max_rmid =erdt_cpu_has (X86_FEATURE_CQM_OCCUP_LLC ) ? +erdt_get_max_rmid () : boot_cpu_data.x86_cache_max_rmid;
This does not look right. Wouldn't this use the ERDT supported RMID for the MBM events also even though they are read via MSR?
arch/x86/kernel/cpu/resctrl/monitor.c int __init rdt_get_l3_mon_config(struct rdt_resource *r) · line 444
Quoted 2 lines
arch/x86/kernel/cpu/resctrl/monitor.c +0
-0resctrl_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;
Should the scale used by ERDT also be adjusted when SNC enabled?
arch/x86/kernel/cpu/resctrl/monitor.c int __init rdt_get_l3_mon_config(struct rdt_resource *r) · line 448
Quoted 5 lines
arch/x86/kernel/cpu/resctrl/monitor.c +1
-1- r->mon.num_rmid = (boot_cpu_data.x86_cache_max_rmid +1 ) / snc_nodes_per_l3_cache; + r->mon.num_rmid = (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 )
Reinette
Re: [PATCH v6 9/9] x86/resctrl: Add MMIO-based LLC occupancy monitoring support
Hi Reinette,
Quoted 8 lines · Reinette Chatre
Hi Chenyu,
Quoted 5 lines · Chen Yu
Add
erdt_mon_read()to read LLC occupancy via MMIO and use it when the platform supports ERDT. Register the L3 occupancy event with ERDT enabled when available, falling back to the MSR-based path otherwise.
Quoted 7 lines
Quoted 4 lines
Use the CMRC (Cache Monitoring Registers for CPU Agents Description) ACPI sub-table to read LLC occupancy counters for each RMID via MMIO when ERDT is enabled. This CMRC information is stored in the
rdt_hw_l3_mon_domain, which could be accessed directly.Please write in imperative tone.
OK, let me try to rewrite it(I suppose you were refereeing to:
This CMRC information is stored -> Store the CMRC information)
Quoted 9 lines
Quoted 6 lines
Currently, the per-domain limbo handler is still in use. There is no need to switch to a global limbo handler, because even after such a switch, the worker thread would still have to iterate through all domains one by one. The per-domain handler already accomplishes this using a worker thread rather than costly IPIs, so there is no clear benefit to switching to a global handler.
Could you please elaborate how a global limbo handler would require IPIs?
The global limbo handler does not require IPIs. Previously, I wondered what the benefit would be of switching from a per-domain limbo handler to a global one.
per-domain handler:
N workers, each worker calculates the current occupancy of that domain for a rmid. If the occupancy of all the domains drops below the threshold, recycle that rmid. No IPI involved.
global handler:
One worker iterates over every domain. If the occupancy of all domains drops below the threshold, it recycles the RMID - with no IPI involved.
For both the per-domain and the global handler, no IPI is involved, and we still have to iterate over every domain. So it seems that there is not much benefit in switching to the global handler, IIUC.
Quoted 6 lines
Quoted 6 lines
arch/x86/include/asm/resctrl.h +0
-0@@ -132,7 +132,13 @@ static inline void __resctrl_sched_in(struct task_struct *tsk)
Quoted 10 lines
arch/x86/include/asm/resctrl.h static inline void __resctrl_sched_in(struct task_struct *tsk) · line 135
Quoted 4 lines
arch/x86/include/asm/resctrl.h +1
-1static inline unsigned int resctrl_arch_round_mon_val (unsigned int val) { -unsigned int scale = boot_cpu_data.x86_cache_occ_scale; +unsigned int scale = boot_cpu_data.x86_cache_occ_scale, escale;related to earlier topic, "scale" being unsigned int is ok since
x86_cache_occ_scaleis initialized from 32bits. As I understand it the ERDT scale value is initialized from 64 bits instead so the existing types do not seem to accommodate?
As you mentioned in another thread, there seems to be an inconsistency in the spec, I'll check with the team.
Quoted 12 lines
arch/x86/include/asm/resctrl.h static int erdt_scale; · line 48
Quoted 8 lines
arch/x86/include/asm/resctrl.h +3
-0@@ -39,6 +43,9 @@ static int erdt_scale;bool erdt_support (int flag) { +if (flag ==X86_FEATURE_CQM_OCCUP_LLC ) +return valid_subtbl_mask &BIT (ACPI_ERDT_TYPE_CMRC ); +Is the plan to keep adding more
if()statements as new flags need to be tested?
Yes. For example, to also support MBM:
if (flag == X86_FEATURE_CQM_OCCUP_LLC)
return valid_subtbl_mask & BIT(ACPI_ERDT_TYPE_CMRC);
if (flag == X86_FEATURE_CQM_MBM_TOTAL) return valid_subtbl_mask & BIT(ACPI_ERDT_TYPE_MMRC);
return false;
}
Quoted 6 lines
Quoted 6 lines
arch/x86/include/asm/resctrl.h +1
-0@@ -430,12 +434,15 @@ int __init rdt_get_l3_mon_config(struct rdt_resource *r)struct rdt_hw_resource *hw_res =resctrl_to_arch_res (r);unsigned int threshold;u32 eax, ebx, ecx, edx; +int max_rmid;
Quoted 8 lines
arch/x86/include/asm/resctrl.h int __init rdt_get_l3_mon_config(struct rdt_resource *r) · line 442
Quoted 4 lines
arch/x86/include/asm/resctrl.h +2
-0snc_nodes_per_l3_cache =snc_get_config (); + max_rmid =erdt_cpu_has (X86_FEATURE_CQM_OCCUP_LLC ) ? +erdt_get_max_rmid () : boot_cpu_data.x86_cache_max_rmid;This does not look right. Wouldn't this use the ERDT supported RMID for the MBM events also even though they are read via MSR?
Got it, this is a bug that might impact the MBM. Let me use min() to get the minimal rmid between the erdt and the legacy one.
Quoted 5 lines
arch/x86/include/asm/resctrl.h int __init rdt_get_l3_mon_config(struct rdt_resource *r) · line 444
Quoted 2 lines
arch/x86/include/asm/resctrl.h +0
-0resctrl_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;Should the scale used by ERDT also be adjusted when SNC enabled?
My understanding is that the reason hw_res->mon_scale is divided by snc_nodes_per_l3_cache is that one LLC is composed of several SNC nodes. Therefore, when we sum up the monitor data from all SNC domains, we need to scale down mon_scale per domain to avoid "over-counting". For the platform on which we are enabling MMIO-based CMT, I am not sure whether SNC will be supported. But we can still adjust the scale for each SNC configuration to ensure future compatibility. Let me change the code.
thanks,
Chenyu
Reinette Chatre
maintainerRe: [PATCH v6 9/9] x86/resctrl: Add MMIO-based LLC occupancy monitoring support
Hi Chenyu,
Quoted 12 lines · Yu C
Quoted 11 lines · Reinette Chatre
Quoted 9 lines · Chen Yu
Add
erdt_mon_read()to read LLC occupancy via MMIO and use it when the platform supports ERDT. Register the L3 occupancy event with ERDT enabled when available, falling back to the MSR-based path otherwise.Use the CMRC (Cache Monitoring Registers for CPU Agents Description) ACPI sub-table to read LLC occupancy counters for each RMID via MMIO when ERDT is enabled. This CMRC information is stored in the
rdt_hw_l3_mon_domain, which could be accessed directly.
Quoted 5 lines
Quoted 2 lines
Please write in imperative tone.
OK, let me try to rewrite it(I suppose you were refereeing to:
This CMRC information is stored -> Store the CMRC information)
I was, yes.
Quoted 19 lines
Quoted 10 lines
Quoted 7 lines
Currently, the per-domain limbo handler is still in use. There is no need to switch to a global limbo handler, because even after such a switch, the worker thread would still have to iterate through all domains one by one. The per-domain handler already accomplishes this using a worker thread rather than costly IPIs, so there is no clear benefit to switching to a global handler.
Could you please elaborate how a global limbo handler would require IPIs?
The global limbo handler does not require IPIs. Previously, I wondered what the benefit would be of switching from a per-domain limbo handler to a global one.
per-domain handler:
N workers, each worker calculates the current occupancy of that domain for a rmid. If the occupancy of all the domains drops below the threshold, recycle that rmid. No IPI involved.
Quoted 7 lines
global handler:
One worker iterates over every domain. If the occupancy of all domains drops below the threshold, it recycles the RMID - with no IPI involved.For both the per-domain and the global handler, no IPI is involved, and we still have to iterate over every domain. So it seems that there is not much benefit in switching to the global handler, IIUC.
There is still 1 vs N threads to consider but to me it is also not clear whether it justifies the complication of supporting two thread models.
Quoted 31 lines
Quoted 16 lines
arch/x86/include/asm/resctrl.h static inline void __resctrl_sched_in(struct task_struct *tsk) · line 134
Quoted 10 lines
arch/x86/include/asm/resctrl.h +1
-1@@ -132,7 +132,13 @@ static inline void __resctrl_sched_in(struct task_struct *tsk) static inline unsigned int resctrl_arch_round_mon_val(unsigned int val) { - unsigned int scale = boot_cpu_data.x86_cache_occ_scale; + unsigned int scale = boot_cpu_data.x86_cache_occ_scale, escale;related to earlier topic, "scale" being unsigned int is ok since
x86_cache_occ_scaleis initialized from 32bits. As I understand it the ERDT scale value is initialized from 64 bits instead so the existing types do not seem to accommodate?As you mentioned in another thread, there seems to be an inconsistency in the spec, I'll check with the team.
Quoted 10 lines
arch/x86/include/asm/resctrl.h static inline void __resctrl_sched_in(struct task_struct *tsk) · line 140
Quoted 6 lines
arch/x86/include/asm/resctrl.h +3
-0@@ -39,6 +43,9 @@ static int erdt_scale; bool erdt_support(int flag) { + if (flag == X86_FEATURE_CQM_OCCUP_LLC) + return valid_subtbl_mask & BIT(ACPI_ERDT_TYPE_CMRC); +Is the plan to keep adding more
if()statements as new flags need to be tested?
Quoted 8 lines
Yes. For example, to also support MBM:
if (flag ==
X86_FEATURE_CQM_OCCUP_LLC)
returnvalid_subtbl_mask&BIT(ACPI_ERDT_TYPE_CMRC);if (flag ==
X86_FEATURE_CQM_MBM_TOTAL)
returnvalid_subtbl_mask&BIT(ACPI_ERDT_TYPE_MMRC);
Your example makes it clear that the possible values of @flag are mutually exclusive. The sequential evaluation as above is not optimal. Every if() needs to be evaluated until the match is found. I would suggest that this uses switch() instead.
Reinette
Update for Sashiko review: https://sashiko.dev/#/patchset/cover.1784968626.git.yu.c.chen%40intel.com
TL;DR
Sashiko reported 9 issues in total, after evaluation, 1/9 is a valid concern. The next v7 version will be posted with that fix, after v7's direction has been confirmed by the resctrl community.
The issue sashiko reported:
Patch 9: [PATCH v6 9/9] x86/resctrl: Add MMIO-based LLC occupancy monitoring support
Quoted 4 lines
arch/x86/kernel/cpu/resctrl/monitor.c +0
-0
[ ... ]
Quoted 4 lines
arch/x86/kernel/cpu/resctrl/monitor.c +0
-0@@ -430,12 +434,15 @@ int __init rdt_get_l3_mon_config(struct rdt_resource *r)struct rdt_hw_resource *hw_res =resctrl_to_arch_res (r);unsigned int threshold;u32 eax, ebx, ecx, edx;
arch/x86/kernel/cpu/resctrl/monitor.c int __init rdt_get_l3_mon_config(struct rdt_resource *r) · line 445
Quoted 10 lines
arch/x86/kernel/cpu/resctrl/monitor.c +4
-1+int max_rmid; snc_nodes_per_l3_cache =snc_get_config (); + max_rmid =erdt_cpu_has (X86_FEATURE_CQM_OCCUP_LLC ) ? +erdt_get_max_rmid () : boot_cpu_data.x86_cache_max_rmid; 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 = (max_rmid +1 ) / snc_nodes_per_l3_cache;
If the ERDT table specifies a max_rmid that is larger than the hardware MSR limit, could this cause an unhandled #GP exception?
Yes, we should use the min of these two:
+ max_rmid = erdt_cpu_has(X86_FEATURE_CQM_OCCUP_LLC) ?
+ min(erdt_get_max_rmid(), boot_cpu_data.x86_cache_max_rmid) :
+ boot_cpu_data.x86_cache_max_rmid;
thanks,
Chenyu