* [PATCH v2 0/8] x86/resctrl: Support for AMD Global (Slow) Memory Bandwidth Allocation
@ 2026-04-24 1:41 Babu Moger
2026-04-24 1:41 ` [PATCH v2 1/8] x86,fs/resctrl: Add support for Global Bandwidth Enforcement (GLBE) Babu Moger
` (7 more replies)
0 siblings, 8 replies; 9+ messages in thread
From: Babu Moger @ 2026-04-24 1:41 UTC (permalink / raw)
To: corbet, tony.luck, reinette.chatre, tglx, mingo, bp, dave.hansen
Cc: skhan, x86, Dave.Martin, james.morse, babu.moger, hpa, akpm,
rdunlap, dapeng1.mi, kees, elver, lirongqing, ebiggers, paulmck,
seanjc, pawan.kumar.gupta, nikunj, yazen.ghannam, peterz,
chang.seok.bae, kim.phillips, thomas.lendacky, naveen,
elena.reshetova, xin, linux-doc, linux-kernel, eranian,
peternewman
This series adds resctrl support for two new AMD memory-bandwidth
allocation features:
- GMBA - Global Memory Bandwidth Allocation (hardware name: GLBE).
Bounds DRAM bandwidth for groups of threads that span
multiple L3 QoS domains, rather than being per-L3 like MBA.
- GSMBA - Global Slow Memory Bandwidth Allocation (hardware name:
GLSBE). The CXL.memory / slow-memory counterpart of GMBA,
analogous to how SMBA relates to MBA.
Both features share a new "NPS-node" control domain: a set of QoS (L3)
domains grouped together and aligned to the system's NPS (Nodes Per
Socket) BIOS configuration. Although the control domain is NPS-scoped,
the underlying bandwidth-limit MSRs (MSR_IA32_GMBA_BW_BASE 0xc0000600,
MSR_IA32_GSMBA_BW_BASE 0xc0000680) are instantiated per L3. Programming
a single control domain therefore requires writing the MSR on one CPU
per L3 that the domain spans - a new pattern for resctrl. Patches 2/8
and 3/8 introduce that infrastructure so the new resources can reuse
it.
The features are documented in:
AMD64 Zen6 Platform Quality of Service (PQOS) Extensions,
Publication # 69193 Revision 1.00, Issue Date March 2026
available at https://bugzilla.kernel.org/show_bug.cgi?id=206537
Series overview
---------------
Patches 1-5 to enable GMBA:
1/8 x86,fs/resctrl: Add support for Global Bandwidth Enforcement (GLBE)
2/8 x86/resctrl: Add RESCTRL_NPS_NODE scope for AMD NPS-aligned domains
Add a new ctrl_scope value for resctrl resources whose control
domain spans multiple L3s within an NPS node.
3/8 x86/resctrl: Update control MSRs per L3 for NPS-scoped resources
Add resctrl_arch_update_nps(): builds a cpumask with one CPU per
distinct L3 in the domain, then issues rdt_ctrl_update() via
smp_call_function_many() on that mask. Falls back to the full
domain mask if the scratch masks cannot be built. Route
resctrl_arch_update_domains() and resctrl_arch_reset_all_ctrls()
through this helper when ctrl_scope == RESCTRL_NPS_NODE.
4/8 x86,fs/resctrl: Add the resource for Global Memory Bandwidth Allocation
Register RDT_RESOURCE_GMBA in rdt_resources_all[] with
ctrl_scope=RESCTRL_NPS_NODE and schema_fmt=RANGE, add commands to
discover feature details.
5/8 fs/resctrl: Add the documentation for Global Memory Bandwidth Allocation
Add examples in Documentation/filesystems/resctrl.rst.
Patches 6-8 to enable GSMBA in the same shape:
6/8 x86,fs/resctrl: Add support for Global Slow Memory Bandwidth Allocation
7/8 x86,fs/resctrl: Add the resource for Global Slow Memory Bandwidth Allocation
Register RDT_RESOURCE_GSMBA with ctrl_scope=RESCTRL_NPS_NODE.
8/8 fs/resctrl: Add the documentation for Global Slow Memory Bandwidth Allocation
Add examples in Documentation/filesystems/resctrl.rst.
Changes since v1
----------------
- Earlier sent RFC(v1) with Global Bandwidth Enforcement (GLBE) and
Privilege Level Zero Association (PLZA). This series only handles
Global Memory Bandwidth Allocation. Both the features are sent separately.
- Documentation
* Fixed grammar in the GMBA / GSMBA sections of resctrl.rst.
* Added examples to update GMBA and GSMBA in resctrl.rst documentation.
- Major changes are releated to RESCTRL_NPS_NODE scope handling.
- Commit messages
* Reworked the changelogs in all the patches.
Previous Revisions:
v1 : https://lore.kernel.org/lkml/cover.1769029977.git.babu.moger@amd.com/
---
base-commit: 216fe4b3e06754e73c79a88b1df7e9806e41f29d
Signed-off-by: Babu Moger <babu.moger@amd.com>
Babu Moger (8):
x86,fs/resctrl: Add support for Global Bandwidth Enforcement (GLBE)
x86/resctrl: Add RESCTRL_NPS_NODE scope for AMD NPS-aligned domains
x86/resctrl: Update control MSRs per L3 for NPS-scoped resources
x86,fs/resctrl: Add the resource for Global Bandwidth Allocation
fs/resctrl: Add the documentation for Global Memory Bandwidth
Allocation
x86,fs/resctrl: Add support for Global Slow Memory Bandwidth
Allocation
x86,fs/resctrl: Add the resource for Global Slow Memory Bandwidth
Allocation
fs/resctrl: Add the documentation for Global Slow Memory Bandwidth
Allocation
.../admin-guide/kernel-parameters.txt | 2 +-
Documentation/filesystems/resctrl.rst | 81 ++++++++++++++
arch/x86/include/asm/cpufeatures.h | 3 +-
arch/x86/include/asm/msr-index.h | 2 +
arch/x86/kernel/cpu/resctrl/core.c | 101 +++++++++++++++++-
arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 90 +++++++++++++++-
arch/x86/kernel/cpu/resctrl/internal.h | 1 +
arch/x86/kernel/cpu/resctrl/rdtgroup.c | 15 ++-
arch/x86/kernel/cpu/scattered.c | 2 +
fs/resctrl/ctrlmondata.c | 5 +-
fs/resctrl/rdtgroup.c | 25 ++++-
include/linux/resctrl.h | 3 +
12 files changed, 313 insertions(+), 17 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 1/8] x86,fs/resctrl: Add support for Global Bandwidth Enforcement (GLBE)
2026-04-24 1:41 [PATCH v2 0/8] x86/resctrl: Support for AMD Global (Slow) Memory Bandwidth Allocation Babu Moger
@ 2026-04-24 1:41 ` Babu Moger
2026-04-24 1:41 ` [PATCH v2 2/8] x86/resctrl: Add RESCTRL_NPS_NODE scope for AMD NPS-aligned domains Babu Moger
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Babu Moger @ 2026-04-24 1:41 UTC (permalink / raw)
To: corbet, tony.luck, reinette.chatre, tglx, mingo, bp, dave.hansen
Cc: skhan, x86, Dave.Martin, james.morse, babu.moger, hpa, akpm,
rdunlap, dapeng1.mi, kees, elver, lirongqing, ebiggers, paulmck,
seanjc, pawan.kumar.gupta, nikunj, yazen.ghannam, peterz,
chang.seok.bae, kim.phillips, thomas.lendacky, naveen,
elena.reshetova, xin, linux-doc, linux-kernel, eranian,
peternewman
On AMD systems, the existing MBA feature allows the user to set a bandwidth
limit for each QoS domain. However, multiple QoS domains share system
memory bandwidth as a resource. In order to ensure that system memory
bandwidth is not over-utilized, the user must statically partition the
available system bandwidth between the active QoS domains. Active domains
are those that have at least one thread running in them. If a QoS domain is
not active, its bandwidth allocation is not used by any thread and is
effectively wasted. On the other hand, if a QoS domain is active but its
bandwidth allocation is too low, threads running in that domain may not be
able to utilize the full potential of the system memory bandwidth. This
typically results in system memory being under-utilized since not all QoS
domains are using their full bandwidth allocation.
AMD PQoS Global Bandwidth Enforcement (GLBE) provides a mechanism for
software to specify bandwidth limits for groups of threads that span
multiple QoS domains. This collection of QoS domains is referred to as a
GLBE control domain. The GLBE ceiling sets a maximum limit on memory
bandwidth in GLBE control domain. Bandwidth is shared by all threads in a
Class of Service (COS) across every QoS domain managed by the GLBE control
domain. The GLBE control domain is configurable using the BIOS setup
utility.
By default the GLBE control domain is aligned to system NPS (Nodes Per
Socket) configuration. NPS is a BIOS-level setting on AMD processors
that determines how many NUMA (Non Uniform Memory Access) nodes each CPU
socket is divided into. NPS allows administrators to tune memory locality,
bandwidth, and latency for different workloads.
GLBE support is reported through CPUID.8000_0020_EBX_x0[GLBE] (bit 7). When
this bit is set to 1, the platform supports GLBE.
Since the AMD Memory Bandwidth Enforcement feature is represented as MBA,
the Global Bandwidth Enforcement feature will be shown as GMBA to maintain
consistent naming.
Add GMBA support to resctrl and introduce a kernel parameter that allows
enabling or disabling the feature at boot time.
The GLBE feature details are documented in:
AMD64 Zen6 Platform Quality of Service (PQOS) Extensions:
Publication # 69193 Revision: 1.00, Issue Date: March 2026
available at https://bugzilla.kernel.org/show_bug.cgi?id=206537
Signed-off-by: Babu Moger <babu.moger@amd.com>
---
v2: Updated the commit message to include more details about active QoS domains.
Updated the commit message to clarify that the GLBE control domain is
configurable using the BIOS setup utility is aligned to NPS.
Added link to the PQOS spec.
---
Documentation/admin-guide/kernel-parameters.txt | 2 +-
arch/x86/include/asm/cpufeatures.h | 2 +-
arch/x86/kernel/cpu/resctrl/core.c | 2 ++
arch/x86/kernel/cpu/scattered.c | 1 +
4 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index cf3807641d89..f23cad453f17 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -6452,7 +6452,7 @@ Kernel parameters
rdt= [HW,X86,RDT]
Turn on/off individual RDT features. List is:
cmt, mbmtotal, mbmlocal, l3cat, l3cdp, l2cat, l2cdp,
- mba, smba, bmec, abmc, sdciae, energy[:guid],
+ mba, gmba, smba, bmec, abmc, sdciae, energy[:guid],
perf[:guid].
E.g. to turn on cmt and turn off mba use:
rdt=cmt,!mba
diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index 1d506e5d6f46..356f7a11d47c 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -508,7 +508,6 @@
#define X86_FEATURE_ABMC (21*32+15) /* Assignable Bandwidth Monitoring Counters */
#define X86_FEATURE_MSR_IMM (21*32+16) /* MSR immediate form instructions */
#define X86_FEATURE_SGX_EUPDATESVN (21*32+17) /* Support for ENCLS[EUPDATESVN] instruction */
-
#define X86_FEATURE_SDCIAE (21*32+18) /* L3 Smart Data Cache Injection Allocation Enforcement */
#define X86_FEATURE_CLEAR_CPU_BUF_VM_MMIO (21*32+19) /*
* Clear CPU buffers before VM-Enter if the vCPU
@@ -516,6 +515,7 @@
* and purposes if CLEAR_CPU_BUF_VM is set).
*/
#define X86_FEATURE_X2AVIC_EXT (21*32+20) /* AMD SVM x2AVIC support for 4k vCPUs */
+#define X86_FEATURE_GMBA (21*32+21) /* Global Memory Bandwidth Allocation */
/*
* BUG word(s)
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index 7667cf7c4e94..269265d98ad7 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -795,6 +795,7 @@ enum {
RDT_FLAG_L2_CAT,
RDT_FLAG_L2_CDP,
RDT_FLAG_MBA,
+ RDT_FLAG_GMBA,
RDT_FLAG_SMBA,
RDT_FLAG_BMEC,
RDT_FLAG_ABMC,
@@ -822,6 +823,7 @@ static struct rdt_options rdt_options[] __ro_after_init = {
RDT_OPT(RDT_FLAG_L2_CAT, "l2cat", X86_FEATURE_CAT_L2),
RDT_OPT(RDT_FLAG_L2_CDP, "l2cdp", X86_FEATURE_CDP_L2),
RDT_OPT(RDT_FLAG_MBA, "mba", X86_FEATURE_MBA),
+ RDT_OPT(RDT_FLAG_GMBA, "gmba", X86_FEATURE_GMBA),
RDT_OPT(RDT_FLAG_SMBA, "smba", X86_FEATURE_SMBA),
RDT_OPT(RDT_FLAG_BMEC, "bmec", X86_FEATURE_BMEC),
RDT_OPT(RDT_FLAG_ABMC, "abmc", X86_FEATURE_ABMC),
diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c
index 837d6a4b0c28..077cf452c257 100644
--- a/arch/x86/kernel/cpu/scattered.c
+++ b/arch/x86/kernel/cpu/scattered.c
@@ -60,6 +60,7 @@ static const struct cpuid_bit cpuid_bits[] = {
{ X86_FEATURE_BMEC, CPUID_EBX, 3, 0x80000020, 0 },
{ X86_FEATURE_ABMC, CPUID_EBX, 5, 0x80000020, 0 },
{ X86_FEATURE_SDCIAE, CPUID_EBX, 6, 0x80000020, 0 },
+ { X86_FEATURE_GMBA, CPUID_EBX, 7, 0x80000020, 0 },
{ X86_FEATURE_TSA_SQ_NO, CPUID_ECX, 1, 0x80000021, 0 },
{ X86_FEATURE_TSA_L1_NO, CPUID_ECX, 2, 0x80000021, 0 },
{ X86_FEATURE_AMD_WORKLOAD_CLASS, CPUID_EAX, 22, 0x80000021, 0 },
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 2/8] x86/resctrl: Add RESCTRL_NPS_NODE scope for AMD NPS-aligned domains
2026-04-24 1:41 [PATCH v2 0/8] x86/resctrl: Support for AMD Global (Slow) Memory Bandwidth Allocation Babu Moger
2026-04-24 1:41 ` [PATCH v2 1/8] x86,fs/resctrl: Add support for Global Bandwidth Enforcement (GLBE) Babu Moger
@ 2026-04-24 1:41 ` Babu Moger
2026-04-24 1:41 ` [PATCH v2 3/8] x86/resctrl: Update control MSRs per L3 for NPS-scoped resources Babu Moger
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Babu Moger @ 2026-04-24 1:41 UTC (permalink / raw)
To: corbet, tony.luck, reinette.chatre, tglx, mingo, bp, dave.hansen
Cc: skhan, x86, Dave.Martin, james.morse, babu.moger, hpa, akpm,
rdunlap, dapeng1.mi, kees, elver, lirongqing, ebiggers, paulmck,
seanjc, pawan.kumar.gupta, nikunj, yazen.ghannam, peterz,
chang.seok.bae, kim.phillips, thomas.lendacky, naveen,
elena.reshetova, xin, linux-doc, linux-kernel, eranian,
peternewman
Global Memory Bandwidth Allocation (GMBA) control domains on AMD follow the
Nodes Per Socket (NPS) configuration. With NPS 4 there is a single domain
per package; otherwise the domain aligns with the NUMA node.
By default, all QOS Domains in the system are included in a single GLBE
Control Domain. However, BIOS options may establish several GLBE Control
Domains within the system using NPS configuration. When configured, each
NUMA node functions as an individual GLBE domain, except when the system is
configured in NPS=4 mode in which case only a single GLBE domain exists
which contains all QOS Domains in the system.
Add RESCTRL_NPS_NODE to enum resctrl_scope and implement
get_domain_id_nps().
Signed-off-by: Babu Moger <babu.moger@amd.com>
---
v2: Add RESCTRL_NPS_NODE scope to add support for NPS-aligned resource.
---
arch/x86/kernel/cpu/resctrl/core.c | 20 ++++++++++++++++++++
include/linux/resctrl.h | 1 +
2 files changed, 21 insertions(+)
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index 269265d98ad7..0f58f5e3b853 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -451,6 +451,24 @@ static int l3_mon_domain_mbm_alloc(u32 num_rmid, struct rdt_hw_l3_mon_domain *hw
return -ENOMEM;
}
+/**
+ * get_domain_id_nps() - Domain id for %RESCTRL_NPS_NODE (AMD NPS / GMBA)
+ * @cpu: CPU to query.
+ *
+ * Global memory bandwidth allocation (GMBA) control domains on AMD follow
+ * the socket NPS layout. With NPS 4 there is a single control domain per
+ * package, so every CPU maps to domain id 0. For other NPS settings the
+ * domain matches the CPU's NUMA node.
+ *
+ * Return: 0 when NPS is 4, otherwise the NUMA node id for @cpu.
+ */
+static int get_domain_id_nps(int cpu)
+{
+ if (topology_num_nodes_per_package() == 4)
+ return 0;
+ return cpu_to_node(cpu);
+}
+
static int get_domain_id_from_scope(int cpu, enum resctrl_scope scope)
{
switch (scope) {
@@ -459,6 +477,8 @@ static int get_domain_id_from_scope(int cpu, enum resctrl_scope scope)
return get_cpu_cacheinfo_id(cpu, scope);
case RESCTRL_L3_NODE:
return cpu_to_node(cpu);
+ case RESCTRL_NPS_NODE:
+ return get_domain_id_nps(cpu);
case RESCTRL_PACKAGE:
return topology_physical_package_id(cpu);
default:
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 006e57fd7ca5..80290ded0b82 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -271,6 +271,7 @@ enum resctrl_scope {
RESCTRL_L2_CACHE = 2,
RESCTRL_L3_CACHE = 3,
RESCTRL_L3_NODE,
+ RESCTRL_NPS_NODE,
RESCTRL_PACKAGE,
};
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 3/8] x86/resctrl: Update control MSRs per L3 for NPS-scoped resources
2026-04-24 1:41 [PATCH v2 0/8] x86/resctrl: Support for AMD Global (Slow) Memory Bandwidth Allocation Babu Moger
2026-04-24 1:41 ` [PATCH v2 1/8] x86,fs/resctrl: Add support for Global Bandwidth Enforcement (GLBE) Babu Moger
2026-04-24 1:41 ` [PATCH v2 2/8] x86/resctrl: Add RESCTRL_NPS_NODE scope for AMD NPS-aligned domains Babu Moger
@ 2026-04-24 1:41 ` Babu Moger
2026-04-24 1:41 ` [PATCH v2 4/8] x86,fs/resctrl: Add the resource for Global Bandwidth Allocation Babu Moger
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Babu Moger @ 2026-04-24 1:41 UTC (permalink / raw)
To: corbet, tony.luck, reinette.chatre, tglx, mingo, bp, dave.hansen
Cc: skhan, x86, Dave.Martin, james.morse, babu.moger, hpa, akpm,
rdunlap, dapeng1.mi, kees, elver, lirongqing, ebiggers, paulmck,
seanjc, pawan.kumar.gupta, nikunj, yazen.ghannam, peterz,
chang.seok.bae, kim.phillips, thomas.lendacky, naveen,
elena.reshetova, xin, linux-doc, linux-kernel, eranian,
peternewman
AMD Global Memory Bandwidth Allocation (GMBA) uses the new
RESCTRL_NPS_NODE ctrl_scope. On these CPUs the control MSRs are
implemented per L3 complex, so a single resctrl control domain can span
several L3s and every L3 in the domain must have its MSRs programmed.
For non-NPS scopes this is already handled: resctrl_arch_update_domains()
and resctrl_arch_reset_all_ctrls() use smp_call_function_any() on the
domain CPU mask, which is sufficient because one CPU per domain is enough
to program the MSRs. That is not sufficient for RESCTRL_NPS_NODE, where
rdt_ctrl_update() must run on one CPU per distinct L3 within the domain.
Add two helpers in ctrlmondata.c:
- resctrl_get_l3_mask() builds a cpumask containing exactly one CPU per
unique L3 cacheinfo id observed in the domain mask.
- resctrl_arch_update_nps() allocates the scratch masks, calls
resctrl_get_l3_mask() and issues rdt_ctrl_update() via
smp_call_function_many() on the per-L3 mask. If the scratch cpumask
or L3-id bitmap allocation fails, or the per-L3 mask ends up empty,
it falls back to smp_call_function_many() on the full domain mask.
This is conservative (more IPIs than strictly needed) but guarantees
every L3 in the domain is covered.
Route resctrl_arch_update_domains() and resctrl_arch_reset_all_ctrls()
through resctrl_arch_update_nps() when ctrl_scope == RESCTRL_NPS_NODE,
and keep the existing smp_call_function_any() path for every other
scope. Existing L3/MBA/SMBA resources therefore see no functional
change.
Signed-off-by: Babu Moger <babu.moger@amd.com>
---
v2: New patch to handle NPS-scoped MSR Update.
---
arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 90 ++++++++++++++++++++++-
arch/x86/kernel/cpu/resctrl/internal.h | 1 +
arch/x86/kernel/cpu/resctrl/rdtgroup.c | 15 +++-
3 files changed, 100 insertions(+), 6 deletions(-)
diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
index b20e705606b8..afa6e78ca61b 100644
--- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
+++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
@@ -41,6 +41,86 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
return 0;
}
+/**
+ * resctrl_get_l3_mask() - One CPU per distinct L3 within a resctrl domain
+ * @domain_mask: Full domain CPU mask (typically &d->hdr.cpu_mask).
+ * @l3_mask: Output mask. Cleared on entry, then populated with exactly
+ * one CPU per unique L3 cacheinfo id observed in @domain_mask.
+ * Always a subset of @domain_mask; may end up empty if no CPU
+ * in @domain_mask has a valid L3 id.
+ *
+ * For %RESCTRL_NPS_NODE controls (e.g. AMD GMBA) the control MSRs are
+ * instantiated per L3 complex, so a single IPI per resctrl domain is not
+ * sufficient. Callers are expected to run rdt_ctrl_update() on each CPU in
+ * @l3_mask to cover every L3 that participates in the domain
+ * (see resctrl_arch_update_nps()).
+ *
+ * Return: @l3_mask on success, %NULL if the scratch L3-id bitmap could not
+ * be allocated (in which case @l3_mask is left cleared).
+ */
+static struct cpumask *resctrl_get_l3_mask(const struct cpumask *domain_mask,
+ struct cpumask *l3_mask)
+{
+ unsigned long *l3_dom_id;
+ int cpu, id;
+
+ cpumask_clear(l3_mask);
+ l3_dom_id = bitmap_zalloc(nr_cpu_ids, GFP_KERNEL);
+ if (!l3_dom_id)
+ return NULL;
+
+ for_each_cpu(cpu, domain_mask) {
+ id = get_cpu_cacheinfo_id(cpu, RESCTRL_L3_CACHE);
+ if (id < 0 || id >= nr_cpu_ids)
+ continue;
+ if (test_bit(id, l3_dom_id))
+ continue;
+ set_bit(id, l3_dom_id);
+ cpumask_set_cpu(cpu, l3_mask);
+ }
+
+ bitmap_free(l3_dom_id);
+ return l3_mask;
+}
+
+/**
+ * resctrl_arch_update_nps() - Apply staged ctrl MSRs for NPS-scoped resources
+ * @mp: Parameters describing the MSR index range, resource and domain
+ * passed through to rdt_ctrl_update().
+ * @d: Control domain whose CPUs must see the MSR update.
+ *
+ * %RESCTRL_NPS_NODE resources program control MSRs per L3 complex, so one
+ * IPI per resctrl domain is not enough when the domain spans multiple L3s.
+ * Build a per-L3 representative mask with resctrl_get_l3_mask() and issue
+ * rdt_ctrl_update() via smp_call_function_many() on that mask.
+ *
+ * If the temporary cpumask or the scratch L3-id bitmap cannot be allocated,
+ * or the resulting per-L3 mask is empty, fall back to invoking
+ * smp_call_function_many() on the full domain CPU mask. This is
+ * conservative (more IPIs than strictly needed) but guarantees every L3 in
+ * the domain is covered.
+ */
+void resctrl_arch_update_nps(struct msr_param *mp, struct rdt_ctrl_domain *d)
+{
+ const struct cpumask *mask = &d->hdr.cpu_mask;
+ struct cpumask *new_mask;
+ cpumask_var_t l3_mask;
+ bool l3_alloc;
+
+ l3_alloc = zalloc_cpumask_var(&l3_mask, GFP_KERNEL);
+ if (l3_alloc) {
+ new_mask = resctrl_get_l3_mask(&d->hdr.cpu_mask, l3_mask);
+
+ if (new_mask && !cpumask_empty(new_mask))
+ mask = new_mask;
+ }
+
+ smp_call_function_many(mask, rdt_ctrl_update, mp, 1);
+
+ if (l3_alloc)
+ free_cpumask_var(l3_mask);
+}
+
int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
{
struct resctrl_staged_config *cfg;
@@ -76,8 +156,14 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
msr_param.high = max(msr_param.high, idx + 1);
}
}
- if (msr_param.res)
- smp_call_function_any(&d->hdr.cpu_mask, rdt_ctrl_update, &msr_param, 1);
+
+ if (msr_param.res) {
+ if (msr_param.res->ctrl_scope == RESCTRL_NPS_NODE)
+ resctrl_arch_update_nps(&msr_param, d);
+ else
+ smp_call_function_any(&d->hdr.cpu_mask,
+ rdt_ctrl_update, &msr_param, 1);
+ }
}
return 0;
diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h
index e3cfa0c10e92..902b98ce713d 100644
--- a/arch/x86/kernel/cpu/resctrl/internal.h
+++ b/arch/x86/kernel/cpu/resctrl/internal.h
@@ -223,6 +223,7 @@ union l3_qos_abmc_cfg {
};
void rdt_ctrl_update(void *arg);
+void resctrl_arch_update_nps(struct msr_param *mp, struct rdt_ctrl_domain *d);
int rdt_get_l3_mon_config(struct rdt_resource *r);
diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
index 885026468440..e29ab06cbe70 100644
--- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c
+++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
@@ -245,9 +245,12 @@ void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
msr_param.high = hw_res->num_closid;
/*
- * Disable resource control for this resource by setting all
- * CBMs in all ctrl_domains to the maximum mask value. Pick one CPU
- * from each domain to update the MSRs below.
+ * Disable resource control for this resource by setting all CBMs in
+ * all ctrl_domains to the maximum mask value. For non-NPS scopes pick
+ * one CPU from each domain to update the MSRs below; for
+ * %RESCTRL_NPS_NODE the MSRs are per-L3, so defer to
+ * resctrl_arch_update_nps() which issues the update on one CPU per
+ * distinct L3 in the domain.
*/
list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
hw_dom = resctrl_to_arch_ctrl_dom(d);
@@ -255,7 +258,11 @@ void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
for (i = 0; i < hw_res->num_closid; i++)
hw_dom->ctrl_val[i] = resctrl_get_default_ctrl(r);
msr_param.dom = d;
- smp_call_function_any(&d->hdr.cpu_mask, rdt_ctrl_update, &msr_param, 1);
+ if (msr_param.res->ctrl_scope == RESCTRL_NPS_NODE)
+ resctrl_arch_update_nps(&msr_param, d);
+ else
+ smp_call_function_any(&d->hdr.cpu_mask, rdt_ctrl_update,
+ &msr_param, 1);
}
return;
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 4/8] x86,fs/resctrl: Add the resource for Global Bandwidth Allocation
2026-04-24 1:41 [PATCH v2 0/8] x86/resctrl: Support for AMD Global (Slow) Memory Bandwidth Allocation Babu Moger
` (2 preceding siblings ...)
2026-04-24 1:41 ` [PATCH v2 3/8] x86/resctrl: Update control MSRs per L3 for NPS-scoped resources Babu Moger
@ 2026-04-24 1:41 ` Babu Moger
2026-04-24 1:41 ` [PATCH v2 5/8] fs/resctrl: Add the documentation for Global Memory " Babu Moger
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Babu Moger @ 2026-04-24 1:41 UTC (permalink / raw)
To: corbet, tony.luck, reinette.chatre, tglx, mingo, bp, dave.hansen
Cc: skhan, x86, Dave.Martin, james.morse, babu.moger, hpa, akpm,
rdunlap, dapeng1.mi, kees, elver, lirongqing, ebiggers, paulmck,
seanjc, pawan.kumar.gupta, nikunj, yazen.ghannam, peterz,
chang.seok.bae, kim.phillips, thomas.lendacky, naveen,
elena.reshetova, xin, linux-doc, linux-kernel, eranian,
peternewman
AMD PQoS Global Bandwidth Enforcement (GLBE) feature provides a mechanism
for software to specify bandwidth limits for groups of threads inside a
GLBE control domain. GLBE control domain is a set of participating QoS
domains that are grouped together for global bandwidth allocation.
Add the resource definition for GLBE in resctrl filesystem. Resource allows
users to configure and manage the global memory bandwidth allocation
settings for GLBE control domain. GLBE control domain is a set of
participating QoS domains that are grouped together for global bandwidth
allocation.
By default the GLBE control domain is aligned to system NPS (Nodes Per
Socket) configuration. However, MSR_IA32_GMBA_BW_BASE must be programmed
in L3 domains.
Signed-off-by: Babu Moger <babu.moger@amd.com>
---
v2: Updated the change log about NPS scope.
---
arch/x86/include/asm/msr-index.h | 1 +
arch/x86/kernel/cpu/resctrl/core.c | 46 ++++++++++++++++++++++++++++--
fs/resctrl/ctrlmondata.c | 5 ++--
fs/resctrl/rdtgroup.c | 13 +++++++--
include/linux/resctrl.h | 1 +
5 files changed, 59 insertions(+), 7 deletions(-)
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index a14a0f43e04a..f3ff11ca03f2 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -1293,6 +1293,7 @@
#define MSR_IA32_L3_QOS_ABMC_CFG 0xc00003fd
#define MSR_IA32_L3_QOS_EXT_CFG 0xc00003ff
#define MSR_IA32_EVT_CFG_BASE 0xc0000400
+#define MSR_IA32_GMBA_BW_BASE 0xc0000600
/* AMD-V MSRs */
#define MSR_VM_CR 0xc0010114
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index 0f58f5e3b853..22114ff84bfa 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -91,6 +91,15 @@ struct rdt_hw_resource rdt_resources_all[RDT_NUM_RESOURCES] = {
.schema_fmt = RESCTRL_SCHEMA_RANGE,
},
},
+ [RDT_RESOURCE_GMBA] =
+ {
+ .r_resctrl = {
+ .name = "GMB",
+ .ctrl_scope = RESCTRL_NPS_NODE,
+ .ctrl_domains = ctrl_domain_init(RDT_RESOURCE_GMBA),
+ .schema_fmt = RESCTRL_SCHEMA_RANGE,
+ },
+ },
[RDT_RESOURCE_SMBA] =
{
.r_resctrl = {
@@ -239,10 +248,22 @@ static __init bool __rdt_get_mem_config_amd(struct rdt_resource *r)
u32 eax, ebx, ecx, edx, subleaf;
/*
- * Query CPUID_Fn80000020_EDX_x01 for MBA and
- * CPUID_Fn80000020_EDX_x02 for SMBA
+ * Query CPUID function 0x80000020 to obtain num_closid and max_bw values.
+ * Use subleaf 1 for MBA, subleaf 2 for SMBA, and subleaf 7 for GMBA.
*/
- subleaf = (r->rid == RDT_RESOURCE_SMBA) ? 2 : 1;
+ switch (r->rid) {
+ case RDT_RESOURCE_MBA:
+ subleaf = 1;
+ break;
+ case RDT_RESOURCE_SMBA:
+ subleaf = 2;
+ break;
+ case RDT_RESOURCE_GMBA:
+ subleaf = 7;
+ break;
+ default:
+ return false;
+ }
cpuid_count(0x80000020, subleaf, &eax, &ebx, &ecx, &edx);
hw_res->num_closid = edx + 1;
@@ -930,6 +951,19 @@ static __init bool get_mem_config(void)
return false;
}
+static __init bool get_gmem_config(void)
+{
+ struct rdt_hw_resource *hw_res = &rdt_resources_all[RDT_RESOURCE_GMBA];
+
+ if (!rdt_cpu_has(X86_FEATURE_GMBA))
+ return false;
+
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+ return __rdt_get_mem_config_amd(&hw_res->r_resctrl);
+
+ return false;
+}
+
static __init bool get_slow_mem_config(void)
{
struct rdt_hw_resource *hw_res = &rdt_resources_all[RDT_RESOURCE_SMBA];
@@ -975,6 +1009,9 @@ static __init bool get_rdt_alloc_resources(void)
if (get_mem_config())
ret = true;
+ if (get_gmem_config())
+ ret = true;
+
if (get_slow_mem_config())
ret = true;
@@ -1075,6 +1112,9 @@ static __init void rdt_init_res_defs_amd(void)
} else if (r->rid == RDT_RESOURCE_MBA) {
hw_res->msr_base = MSR_IA32_MBA_BW_BASE;
hw_res->msr_update = mba_wrmsr_amd;
+ } else if (r->rid == RDT_RESOURCE_GMBA) {
+ hw_res->msr_base = MSR_IA32_GMBA_BW_BASE;
+ hw_res->msr_update = mba_wrmsr_amd;
} else if (r->rid == RDT_RESOURCE_SMBA) {
hw_res->msr_base = MSR_IA32_SMBA_BW_BASE;
hw_res->msr_update = mba_wrmsr_amd;
diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c
index 9a7dfc48cb2e..22bbc5fa520d 100644
--- a/fs/resctrl/ctrlmondata.c
+++ b/fs/resctrl/ctrlmondata.c
@@ -246,8 +246,9 @@ static int parse_line(char *line, struct resctrl_schema *s,
return -EINVAL;
if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP &&
- (r->rid == RDT_RESOURCE_MBA || r->rid == RDT_RESOURCE_SMBA)) {
- rdt_last_cmd_puts("Cannot pseudo-lock MBA resource\n");
+ (r->rid == RDT_RESOURCE_MBA || r->rid == RDT_RESOURCE_GMBA ||
+ r->rid == RDT_RESOURCE_SMBA)) {
+ rdt_last_cmd_puts("Cannot pseudo-lock MBA/SMBA/GMBA resource\n");
return -EINVAL;
}
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 5dfdaa6f9d8f..cc14c04314fe 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -1412,7 +1412,8 @@ static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp)
list_for_each_entry(s, &resctrl_schema_all, list) {
r = s->res;
- if (r->rid == RDT_RESOURCE_MBA || r->rid == RDT_RESOURCE_SMBA)
+ if (r->rid == RDT_RESOURCE_MBA || r->rid == RDT_RESOURCE_GMBA ||
+ r->rid == RDT_RESOURCE_SMBA)
continue;
has_cache = true;
list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
@@ -1617,6 +1618,7 @@ static int rdtgroup_size_show(struct kernfs_open_file *of,
closid,
type);
if (r->rid == RDT_RESOURCE_MBA ||
+ r->rid == RDT_RESOURCE_GMBA ||
r->rid == RDT_RESOURCE_SMBA)
size = ctrl;
else
@@ -2170,13 +2172,18 @@ static struct rftype *rdtgroup_get_rftype_by_name(const char *name)
static void thread_throttle_mode_init(void)
{
enum membw_throttle_mode throttle_mode = THREAD_THROTTLE_UNDEFINED;
- struct rdt_resource *r_mba, *r_smba;
+ struct rdt_resource *r_mba, *r_gmba, *r_smba;
r_mba = resctrl_arch_get_resource(RDT_RESOURCE_MBA);
if (r_mba->alloc_capable &&
r_mba->membw.throttle_mode != THREAD_THROTTLE_UNDEFINED)
throttle_mode = r_mba->membw.throttle_mode;
+ r_gmba = resctrl_arch_get_resource(RDT_RESOURCE_GMBA);
+ if (r_gmba->alloc_capable &&
+ r_gmba->membw.throttle_mode != THREAD_THROTTLE_UNDEFINED)
+ throttle_mode = r_gmba->membw.throttle_mode;
+
r_smba = resctrl_arch_get_resource(RDT_RESOURCE_SMBA);
if (r_smba->alloc_capable &&
r_smba->membw.throttle_mode != THREAD_THROTTLE_UNDEFINED)
@@ -2396,6 +2403,7 @@ static unsigned long fflags_from_resource(struct rdt_resource *r)
case RDT_RESOURCE_L2:
return RFTYPE_RES_CACHE;
case RDT_RESOURCE_MBA:
+ case RDT_RESOURCE_GMBA:
case RDT_RESOURCE_SMBA:
return RFTYPE_RES_MB;
case RDT_RESOURCE_PERF_PKG:
@@ -3649,6 +3657,7 @@ static int rdtgroup_init_alloc(struct rdtgroup *rdtgrp)
list_for_each_entry(s, &resctrl_schema_all, list) {
r = s->res;
if (r->rid == RDT_RESOURCE_MBA ||
+ r->rid == RDT_RESOURCE_GMBA ||
r->rid == RDT_RESOURCE_SMBA) {
rdtgroup_init_mba(r, rdtgrp->closid);
if (is_mba_sc(r))
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 80290ded0b82..ed09ed2e0477 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -52,6 +52,7 @@ enum resctrl_res_level {
RDT_RESOURCE_L3,
RDT_RESOURCE_L2,
RDT_RESOURCE_MBA,
+ RDT_RESOURCE_GMBA,
RDT_RESOURCE_SMBA,
RDT_RESOURCE_PERF_PKG,
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 5/8] fs/resctrl: Add the documentation for Global Memory Bandwidth Allocation
2026-04-24 1:41 [PATCH v2 0/8] x86/resctrl: Support for AMD Global (Slow) Memory Bandwidth Allocation Babu Moger
` (3 preceding siblings ...)
2026-04-24 1:41 ` [PATCH v2 4/8] x86,fs/resctrl: Add the resource for Global Bandwidth Allocation Babu Moger
@ 2026-04-24 1:41 ` Babu Moger
2026-04-24 1:41 ` [PATCH v2 6/8] x86,fs/resctrl: Add support for Global Slow " Babu Moger
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Babu Moger @ 2026-04-24 1:41 UTC (permalink / raw)
To: corbet, tony.luck, reinette.chatre, tglx, mingo, bp, dave.hansen
Cc: skhan, x86, Dave.Martin, james.morse, babu.moger, hpa, akpm,
rdunlap, dapeng1.mi, kees, elver, lirongqing, ebiggers, paulmck,
seanjc, pawan.kumar.gupta, nikunj, yazen.ghannam, peterz,
chang.seok.bae, kim.phillips, thomas.lendacky, naveen,
elena.reshetova, xin, linux-doc, linux-kernel, eranian,
peternewman
GMBA (added to resctrl by the earlier patches in this series) is a new DRAM
bandwidth allocation resource that applies limits across multiple QoS (L3)
domains rather than per-L3 like MBA. Each GMBA control domain is aligned to
the system's NPS (Nodes Per Socket) configuration. In the schemata file the
resource is exposed under the label "GMB" (not "GMBA", to match resctrl's
short-label convention) with values in multiples of 1 GB/s.
Document GMBA in Documentation/filesystems/resctrl.rst:
- Add GMBA to the resctrl feature table at the top of the file.
- Add a "Global Memory Bandwidth Allocation (GMBA)" section describing the
resource, its control domain and the schemata syntax/unit.
- Add a "Reading/writing the schemata file (on AMD systems) with GMBA
feature" section with a self-consistent worked example.
Signed-off-by: Babu Moger <babu.moger@amd.com>
---
v2: Describe GMBA's distinguishing characteristics (NPS-aligned control
domain, per-L3 span, DRAM target).
Added examples to update GMB schemata.
---
Documentation/filesystems/resctrl.rst | 39 +++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/Documentation/filesystems/resctrl.rst b/Documentation/filesystems/resctrl.rst
index b003bed339fd..901d059800fa 100644
--- a/Documentation/filesystems/resctrl.rst
+++ b/Documentation/filesystems/resctrl.rst
@@ -28,6 +28,7 @@ SMBA (Slow Memory Bandwidth Allocation) ""
BMEC (Bandwidth Monitoring Event Configuration) ""
ABMC (Assignable Bandwidth Monitoring Counters) ""
SDCIAE (Smart Data Cache Injection Allocation Enforcement) ""
+GMBA (Global Memory Bandwidth Allocation) ""
=============================================================== ================================
Historically, new features were made visible by default in /proc/cpuinfo. This
@@ -964,6 +965,23 @@ Memory bandwidth domain is L3 cache.
MB:<cache_id0>=bw_MiBps0;<cache_id1>=bw_MiBps1;...
+Global Memory Bandwidth Allocation (GMBA)
+-----------------------------------------
+
+AMD hardware supports Global Memory Bandwidth Allocation (GMBA). GMBA
+provides a mechanism for software to specify bandwidth limits for groups
+of threads that span multiple QoS (L3) domains. Each such collection of
+QoS domains is called a GMBA control domain and is aligned to the system's
+NPS (Nodes Per Socket) configuration. NPS is a BIOS-level setting on AMD
+processors that selects how many NUMA (Non-Uniform Memory Access) nodes
+each CPU socket is divided into.
+
+The bandwidth domain for GMBA is the GMBA control domain. GMBA is exposed
+in the schemata file under the resource label ``GMB``, with values
+expressed in multiples of 1 GB/s::
+
+ GMB:<domain_id0>=bw_GBps0;<domain_id1>=bw_GBps1;...
+
Slow Memory Bandwidth Allocation (SMBA)
---------------------------------------
AMD hardware supports Slow Memory Bandwidth Allocation (SMBA).
@@ -1018,6 +1036,27 @@ For example, to allocate 2GB/s limit on the first cache id:
MB:0=2048;1= 16;2=2048;3=2048
L3:0=ffff;1=ffff;2=ffff;3=ffff
+Reading/writing the schemata file (on AMD systems) with GMBA feature
+--------------------------------------------------------------------
+Reading the schemata file shows the current bandwidth limit on every
+GMBA control domain. Values are in multiples of 1 GB/s.
+
+For example, to set an 8 GB/s limit on GMBA control domain 0, leaving
+control domain 1 at its previous limit:
+
+::
+
+ # cat schemata
+ GMB:0=4096;1=4096
+ MB:0=8192;1=8192;2=8192;3=8192
+ L3:0=ffff;1=ffff;2=ffff;3=ffff
+
+ # echo "GMB:0=8" > schemata
+ # cat schemata
+ GMB:0= 8;1=4096
+ MB:0=8192;1=8192;2=8192;3=8192
+ L3:0=ffff;1=ffff;2=ffff;3=ffff
+
Reading/writing the schemata file (on AMD systems) with SMBA feature
--------------------------------------------------------------------
Reading and writing the schemata file is the same as without SMBA in
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 6/8] x86,fs/resctrl: Add support for Global Slow Memory Bandwidth Allocation
2026-04-24 1:41 [PATCH v2 0/8] x86/resctrl: Support for AMD Global (Slow) Memory Bandwidth Allocation Babu Moger
` (4 preceding siblings ...)
2026-04-24 1:41 ` [PATCH v2 5/8] fs/resctrl: Add the documentation for Global Memory " Babu Moger
@ 2026-04-24 1:41 ` Babu Moger
2026-04-24 1:41 ` [PATCH v2 7/8] x86,fs/resctrl: Add the resource " Babu Moger
2026-04-24 1:41 ` [PATCH v2 8/8] fs/resctrl: Add the documentation " Babu Moger
7 siblings, 0 replies; 9+ messages in thread
From: Babu Moger @ 2026-04-24 1:41 UTC (permalink / raw)
To: corbet, tony.luck, reinette.chatre, tglx, mingo, bp, dave.hansen
Cc: skhan, x86, Dave.Martin, james.morse, babu.moger, hpa, akpm,
rdunlap, dapeng1.mi, kees, elver, lirongqing, ebiggers, paulmck,
seanjc, pawan.kumar.gupta, nikunj, yazen.ghannam, peterz,
chang.seok.bae, kim.phillips, thomas.lendacky, naveen,
elena.reshetova, xin, linux-doc, linux-kernel, eranian,
peternewman
AMD PQoS Global Slow Memory Bandwidth Enforcement (GLSBE) is an extension
to GLBE that lets software specify slow-memory bandwidth limits for groups
of threads that span multiple QoS domains. GLSBE operates within the same
GLBE control domains defined by GLBE.
Like GLBE, the GLSBE control domain is by default aligned to the system's
NPS (Nodes Per Socket) configuration, a BIOS-level setting on AMD
processors that determines how many NUMA (Non-Uniform Memory Access) nodes
each CPU socket is divided into.
Support for GLSBE is indicated by CPUID leaf 0x80000020, ECX=0, EBX bit 8.
When this bit is set to 1, the platform supports GLSBE.
Because AMD Slow Memory Bandwidth Enforcement is exposed to resctrl as
SMBA, Global Slow Memory Bandwidth Enforcement is exposed as GSMBA to keep
the naming consistent.
Add following changes to support GLSBE:
- Add X86_FEATURE_GSMBA and its scattered-CPUID entry
(0x80000020 EBX[8]).
- Add RDT_FLAG_GSMBA and the corresponding rdt_options entry so the
existing rdt= kernel parameter accepts "gsmba".
The GLSBE feature is documented in:
AMD64 Zen6 Platform Quality of Service (PQOS) Extensions,
Publication # 69193 Revision 1.00, Issue Date March 2026
available at https://bugzilla.kernel.org/show_bug.cgi?id=206537
Signed-off-by: Babu Moger <babu.moger@amd.com>
---
v2: Clarify that the GLSBE control domain is aligned to NPS and that NPS
is configured via the BIOS setup utility.
---
Documentation/admin-guide/kernel-parameters.txt | 2 +-
arch/x86/include/asm/cpufeatures.h | 1 +
arch/x86/kernel/cpu/resctrl/core.c | 2 ++
arch/x86/kernel/cpu/scattered.c | 1 +
4 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index f23cad453f17..03c89f90da84 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -6452,7 +6452,7 @@ Kernel parameters
rdt= [HW,X86,RDT]
Turn on/off individual RDT features. List is:
cmt, mbmtotal, mbmlocal, l3cat, l3cdp, l2cat, l2cdp,
- mba, gmba, smba, bmec, abmc, sdciae, energy[:guid],
+ mba, gmba, smba, gsmba, bmec, abmc, sdciae, energy[:guid],
perf[:guid].
E.g. to turn on cmt and turn off mba use:
rdt=cmt,!mba
diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index 356f7a11d47c..947935fee7c5 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -516,6 +516,7 @@
*/
#define X86_FEATURE_X2AVIC_EXT (21*32+20) /* AMD SVM x2AVIC support for 4k vCPUs */
#define X86_FEATURE_GMBA (21*32+21) /* Global Memory Bandwidth Allocation */
+#define X86_FEATURE_GSMBA (21*32+22) /* Global Slow Memory Bandwidth Enforcement */
/*
* BUG word(s)
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index 22114ff84bfa..667ff3eb57f5 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -838,6 +838,7 @@ enum {
RDT_FLAG_MBA,
RDT_FLAG_GMBA,
RDT_FLAG_SMBA,
+ RDT_FLAG_GSMBA,
RDT_FLAG_BMEC,
RDT_FLAG_ABMC,
RDT_FLAG_SDCIAE,
@@ -866,6 +867,7 @@ static struct rdt_options rdt_options[] __ro_after_init = {
RDT_OPT(RDT_FLAG_MBA, "mba", X86_FEATURE_MBA),
RDT_OPT(RDT_FLAG_GMBA, "gmba", X86_FEATURE_GMBA),
RDT_OPT(RDT_FLAG_SMBA, "smba", X86_FEATURE_SMBA),
+ RDT_OPT(RDT_FLAG_GSMBA, "gsmba", X86_FEATURE_GSMBA),
RDT_OPT(RDT_FLAG_BMEC, "bmec", X86_FEATURE_BMEC),
RDT_OPT(RDT_FLAG_ABMC, "abmc", X86_FEATURE_ABMC),
RDT_OPT(RDT_FLAG_SDCIAE, "sdciae", X86_FEATURE_SDCIAE),
diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c
index 077cf452c257..7a57453a3dcb 100644
--- a/arch/x86/kernel/cpu/scattered.c
+++ b/arch/x86/kernel/cpu/scattered.c
@@ -61,6 +61,7 @@ static const struct cpuid_bit cpuid_bits[] = {
{ X86_FEATURE_ABMC, CPUID_EBX, 5, 0x80000020, 0 },
{ X86_FEATURE_SDCIAE, CPUID_EBX, 6, 0x80000020, 0 },
{ X86_FEATURE_GMBA, CPUID_EBX, 7, 0x80000020, 0 },
+ { X86_FEATURE_GSMBA, CPUID_EBX, 8, 0x80000020, 0 },
{ X86_FEATURE_TSA_SQ_NO, CPUID_ECX, 1, 0x80000021, 0 },
{ X86_FEATURE_TSA_L1_NO, CPUID_ECX, 2, 0x80000021, 0 },
{ X86_FEATURE_AMD_WORKLOAD_CLASS, CPUID_EAX, 22, 0x80000021, 0 },
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 7/8] x86,fs/resctrl: Add the resource for Global Slow Memory Bandwidth Allocation
2026-04-24 1:41 [PATCH v2 0/8] x86/resctrl: Support for AMD Global (Slow) Memory Bandwidth Allocation Babu Moger
` (5 preceding siblings ...)
2026-04-24 1:41 ` [PATCH v2 6/8] x86,fs/resctrl: Add support for Global Slow " Babu Moger
@ 2026-04-24 1:41 ` Babu Moger
2026-04-24 1:41 ` [PATCH v2 8/8] fs/resctrl: Add the documentation " Babu Moger
7 siblings, 0 replies; 9+ messages in thread
From: Babu Moger @ 2026-04-24 1:41 UTC (permalink / raw)
To: corbet, tony.luck, reinette.chatre, tglx, mingo, bp, dave.hansen
Cc: skhan, x86, Dave.Martin, james.morse, babu.moger, hpa, akpm,
rdunlap, dapeng1.mi, kees, elver, lirongqing, ebiggers, paulmck,
seanjc, pawan.kumar.gupta, nikunj, yazen.ghannam, peterz,
chang.seok.bae, kim.phillips, thomas.lendacky, naveen,
elena.reshetova, xin, linux-doc, linux-kernel, eranian,
peternewman
AMD PQoS Global Slow Memory Bandwidth Enforcement (GLSBE) lets software
specify slow-memory (CXL.memory) bandwidth limits for groups of threads
inside a GLBE control domain. A GLBE control domain is a set of QoS (L3)
domains that are grouped together for global bandwidth allocation; GLSBE
reuses those same control domains.
Add the resource definition for GLSBE in the resctrl filesystem so
administrators can configure and manage slow-memory bandwidth at GLSBE
control domain granularity:
The GLSBE control domain is aligned to the system's NPS (Nodes Per Socket)
configuration. Because RDT_RESOURCE_GSMBA uses the RESCTRL_NPS_NODE scope,
updates routed through resctrl_arch_update_domains() already flow into
resctrl_arch_update_nps(), which programs MSR_IA32_GSMBA_BW_BASE on one CPU
per L3 within the domain.
The schemata identifier is named GSMBA (Global Slow Memory Bandwidth
Allocation) to mirror SMBA; the architecturally documented name GLSBE is
used only in CPUID references.
Signed-off-by: Babu Moger <babu.moger@amd.com>
---
v2: Rewrite commit log to describe GSMBA and NPS scope.
---
arch/x86/include/asm/msr-index.h | 1 +
arch/x86/kernel/cpu/resctrl/core.c | 31 ++++++++++++++++++++++++++++++
fs/resctrl/ctrlmondata.c | 4 ++--
fs/resctrl/rdtgroup.c | 16 +++++++++++----
include/linux/resctrl.h | 1 +
5 files changed, 47 insertions(+), 6 deletions(-)
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index f3ff11ca03f2..83e042caa080 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -1294,6 +1294,7 @@
#define MSR_IA32_L3_QOS_EXT_CFG 0xc00003ff
#define MSR_IA32_EVT_CFG_BASE 0xc0000400
#define MSR_IA32_GMBA_BW_BASE 0xc0000600
+#define MSR_IA32_GSMBA_BW_BASE 0xc0000680
/* AMD-V MSRs */
#define MSR_VM_CR 0xc0010114
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index 667ff3eb57f5..9a78a59f1929 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -109,6 +109,15 @@ struct rdt_hw_resource rdt_resources_all[RDT_NUM_RESOURCES] = {
.schema_fmt = RESCTRL_SCHEMA_RANGE,
},
},
+ [RDT_RESOURCE_GSMBA] =
+ {
+ .r_resctrl = {
+ .name = "GSMBA",
+ .ctrl_scope = RESCTRL_NPS_NODE,
+ .ctrl_domains = ctrl_domain_init(RDT_RESOURCE_GSMBA),
+ .schema_fmt = RESCTRL_SCHEMA_RANGE,
+ },
+ },
[RDT_RESOURCE_PERF_PKG] =
{
.r_resctrl = {
@@ -261,6 +270,9 @@ static __init bool __rdt_get_mem_config_amd(struct rdt_resource *r)
case RDT_RESOURCE_GMBA:
subleaf = 7;
break;
+ case RDT_RESOURCE_GSMBA:
+ subleaf = 8;
+ break;
default:
return false;
}
@@ -979,6 +991,19 @@ static __init bool get_slow_mem_config(void)
return false;
}
+static __init bool get_gslow_mem_config(void)
+{
+ struct rdt_hw_resource *hw_res = &rdt_resources_all[RDT_RESOURCE_GSMBA];
+
+ if (!rdt_cpu_has(X86_FEATURE_GSMBA))
+ return false;
+
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+ return __rdt_get_mem_config_amd(&hw_res->r_resctrl);
+
+ return false;
+}
+
static __init bool get_rdt_alloc_resources(void)
{
struct rdt_resource *r;
@@ -1017,6 +1042,9 @@ static __init bool get_rdt_alloc_resources(void)
if (get_slow_mem_config())
ret = true;
+ if (get_gslow_mem_config())
+ ret = true;
+
return ret;
}
@@ -1120,6 +1148,9 @@ static __init void rdt_init_res_defs_amd(void)
} else if (r->rid == RDT_RESOURCE_SMBA) {
hw_res->msr_base = MSR_IA32_SMBA_BW_BASE;
hw_res->msr_update = mba_wrmsr_amd;
+ } else if (r->rid == RDT_RESOURCE_GSMBA) {
+ hw_res->msr_base = MSR_IA32_GSMBA_BW_BASE;
+ hw_res->msr_update = mba_wrmsr_amd;
}
}
}
diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c
index 22bbc5fa520d..217055aaf5c7 100644
--- a/fs/resctrl/ctrlmondata.c
+++ b/fs/resctrl/ctrlmondata.c
@@ -247,8 +247,8 @@ static int parse_line(char *line, struct resctrl_schema *s,
if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP &&
(r->rid == RDT_RESOURCE_MBA || r->rid == RDT_RESOURCE_GMBA ||
- r->rid == RDT_RESOURCE_SMBA)) {
- rdt_last_cmd_puts("Cannot pseudo-lock MBA/SMBA/GMBA resource\n");
+ r->rid == RDT_RESOURCE_SMBA || r->rid == RDT_RESOURCE_GSMBA)) {
+ rdt_last_cmd_puts("Cannot pseudo-lock MBA/SMBA/GMBA/GSMBA resource\n");
return -EINVAL;
}
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index cc14c04314fe..761cc9cff4db 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -1413,7 +1413,7 @@ static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp)
list_for_each_entry(s, &resctrl_schema_all, list) {
r = s->res;
if (r->rid == RDT_RESOURCE_MBA || r->rid == RDT_RESOURCE_GMBA ||
- r->rid == RDT_RESOURCE_SMBA)
+ r->rid == RDT_RESOURCE_SMBA || r->rid == RDT_RESOURCE_GSMBA)
continue;
has_cache = true;
list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
@@ -1619,7 +1619,8 @@ static int rdtgroup_size_show(struct kernfs_open_file *of,
type);
if (r->rid == RDT_RESOURCE_MBA ||
r->rid == RDT_RESOURCE_GMBA ||
- r->rid == RDT_RESOURCE_SMBA)
+ r->rid == RDT_RESOURCE_SMBA ||
+ r->rid == RDT_RESOURCE_GSMBA)
size = ctrl;
else
size = rdtgroup_cbm_to_size(r, d, ctrl);
@@ -2172,7 +2173,7 @@ static struct rftype *rdtgroup_get_rftype_by_name(const char *name)
static void thread_throttle_mode_init(void)
{
enum membw_throttle_mode throttle_mode = THREAD_THROTTLE_UNDEFINED;
- struct rdt_resource *r_mba, *r_gmba, *r_smba;
+ struct rdt_resource *r_mba, *r_gmba, *r_smba, *r_gsmba;
r_mba = resctrl_arch_get_resource(RDT_RESOURCE_MBA);
if (r_mba->alloc_capable &&
@@ -2189,6 +2190,11 @@ static void thread_throttle_mode_init(void)
r_smba->membw.throttle_mode != THREAD_THROTTLE_UNDEFINED)
throttle_mode = r_smba->membw.throttle_mode;
+ r_gsmba = resctrl_arch_get_resource(RDT_RESOURCE_GSMBA);
+ if (r_gsmba->alloc_capable &&
+ r_gsmba->membw.throttle_mode != THREAD_THROTTLE_UNDEFINED)
+ throttle_mode = r_gsmba->membw.throttle_mode;
+
if (throttle_mode == THREAD_THROTTLE_UNDEFINED)
return;
@@ -2405,6 +2411,7 @@ static unsigned long fflags_from_resource(struct rdt_resource *r)
case RDT_RESOURCE_MBA:
case RDT_RESOURCE_GMBA:
case RDT_RESOURCE_SMBA:
+ case RDT_RESOURCE_GSMBA:
return RFTYPE_RES_MB;
case RDT_RESOURCE_PERF_PKG:
return RFTYPE_RES_PERF_PKG;
@@ -3658,7 +3665,8 @@ static int rdtgroup_init_alloc(struct rdtgroup *rdtgrp)
r = s->res;
if (r->rid == RDT_RESOURCE_MBA ||
r->rid == RDT_RESOURCE_GMBA ||
- r->rid == RDT_RESOURCE_SMBA) {
+ r->rid == RDT_RESOURCE_SMBA ||
+ r->rid == RDT_RESOURCE_GSMBA) {
rdtgroup_init_mba(r, rdtgrp->closid);
if (is_mba_sc(r))
continue;
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index ed09ed2e0477..cd374f0d31db 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -54,6 +54,7 @@ enum resctrl_res_level {
RDT_RESOURCE_MBA,
RDT_RESOURCE_GMBA,
RDT_RESOURCE_SMBA,
+ RDT_RESOURCE_GSMBA,
RDT_RESOURCE_PERF_PKG,
/* Must be the last */
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 8/8] fs/resctrl: Add the documentation for Global Slow Memory Bandwidth Allocation
2026-04-24 1:41 [PATCH v2 0/8] x86/resctrl: Support for AMD Global (Slow) Memory Bandwidth Allocation Babu Moger
` (6 preceding siblings ...)
2026-04-24 1:41 ` [PATCH v2 7/8] x86,fs/resctrl: Add the resource " Babu Moger
@ 2026-04-24 1:41 ` Babu Moger
7 siblings, 0 replies; 9+ messages in thread
From: Babu Moger @ 2026-04-24 1:41 UTC (permalink / raw)
To: corbet, tony.luck, reinette.chatre, tglx, mingo, bp, dave.hansen
Cc: skhan, x86, Dave.Martin, james.morse, babu.moger, hpa, akpm,
rdunlap, dapeng1.mi, kees, elver, lirongqing, ebiggers, paulmck,
seanjc, pawan.kumar.gupta, nikunj, yazen.ghannam, peterz,
chang.seok.bae, kim.phillips, thomas.lendacky, naveen,
elena.reshetova, xin, linux-doc, linux-kernel, eranian,
peternewman
AMD Global Slow Memory Bandwidth Allocation (GSMBA) is the slow-memory
(CXL.memory) counterpart of GMBA. Like GMBA it applies bandwidth limits to
groups of threads that span multiple QoS (L3) domains, using the same GMBA
control domains that are aligned to the system's NPS (Nodes Per Socket)
configuration. GSMBA is exposed in the schemata file under the resource
label "GSMBA", with values in multiples of 1 GB/s.
Document GSMBA in Documentation/filesystems/resctrl.rst:
- Add GSMBA to the resctrl feature table at the top of the file.
- Add a "Global Slow Memory Bandwidth Allocation (GSMBA)" section
describing the resource, its bandwidth domain and the schemata syntax and
unit.
- Add a "Reading/writing the schemata file (on AMD systems) with GSMBA
feature" section with a worked example.
Signed-off-by: Babu Moger <babu.moger@amd.com>
---
v2: Updated the documentation with clarity and format issues.
Improved changelog.
---
Documentation/filesystems/resctrl.rst | 42 +++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/Documentation/filesystems/resctrl.rst b/Documentation/filesystems/resctrl.rst
index 901d059800fa..a1c5aa45f5fe 100644
--- a/Documentation/filesystems/resctrl.rst
+++ b/Documentation/filesystems/resctrl.rst
@@ -29,6 +29,7 @@ BMEC (Bandwidth Monitoring Event Configuration) ""
ABMC (Assignable Bandwidth Monitoring Counters) ""
SDCIAE (Smart Data Cache Injection Allocation Enforcement) ""
GMBA (Global Memory Bandwidth Allocation) ""
+GSMBA (Global Slow Memory Bandwidth Allocation) ""
=============================================================== ================================
Historically, new features were made visible by default in /proc/cpuinfo. This
@@ -1001,6 +1002,22 @@ is formatted as:
SMBA:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;...
+Global Slow Memory Bandwidth Allocation (GSMBA)
+-----------------------------------------------
+
+AMD hardware supports Global Slow Memory Bandwidth Allocation (GSMBA).
+GSMBA provides a mechanism for software to specify slow-memory bandwidth
+limits for groups of threads that span multiple QoS (L3) domains. Each
+such collection of QoS domains is called a GSMBA control domain. GSMBA
+operates similarly to GMBA, but targets slow memory (CXL.memory) instead
+of DRAM; it reuses the same NPS-aligned control domains as GMBA.
+
+The bandwidth domain for GSMBA is the GSMBA control domain. GSMBA is
+exposed in the schemata file under the resource label ``GSMBA``, with
+values expressed in multiples of 1 GB/s::
+
+ GSMBA:<domain_id0>=bw_GBps0;<domain_id1>=bw_GBps1;...
+
Reading/writing the schemata file
---------------------------------
Reading the schemata file will show the state of all resources
@@ -1077,6 +1094,31 @@ For example, to allocate 8GB/s limit on the first cache id:
MB:0=2048;1=2048;2=2048;3=2048
L3:0=ffff;1=ffff;2=ffff;3=ffff
+Reading/writing the schemata file (on AMD systems) with GSMBA feature
+---------------------------------------------------------------------
+Reading the schemata file shows the current bandwidth limit on every
+GSMBA control domain. Values are in multiples of 1 GB/s.
+
+For example, to set an 8 GB/s limit on GSMBA control domain 0, leaving
+control domain 1 at its previous limit:
+
+::
+
+ # cat schemata
+ GSMBA:0=4096;1=4096
+ SMBA:0=8192;1=8192;2=8192;3=8192
+ GMB:0=4096;1=4096
+ MB:0=8192;1=8192;2=8192;3=8192
+ L3:0=ffff;1=ffff;2=ffff;3=ffff
+
+ # echo "GSMBA:0=8" > schemata
+ # cat schemata
+ GSMBA:0= 8;1=4096
+ SMBA:0=8192;1=8192;2=8192;3=8192
+ GMB:0=4096;1=4096
+ MB:0=8192;1=8192;2=8192;3=8192
+ L3:0=ffff;1=ffff;2=ffff;3=ffff
+
Cache Pseudo-Locking
====================
CAT enables a user to specify the amount of cache space that an
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-04-24 1:43 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-24 1:41 [PATCH v2 0/8] x86/resctrl: Support for AMD Global (Slow) Memory Bandwidth Allocation Babu Moger
2026-04-24 1:41 ` [PATCH v2 1/8] x86,fs/resctrl: Add support for Global Bandwidth Enforcement (GLBE) Babu Moger
2026-04-24 1:41 ` [PATCH v2 2/8] x86/resctrl: Add RESCTRL_NPS_NODE scope for AMD NPS-aligned domains Babu Moger
2026-04-24 1:41 ` [PATCH v2 3/8] x86/resctrl: Update control MSRs per L3 for NPS-scoped resources Babu Moger
2026-04-24 1:41 ` [PATCH v2 4/8] x86,fs/resctrl: Add the resource for Global Bandwidth Allocation Babu Moger
2026-04-24 1:41 ` [PATCH v2 5/8] fs/resctrl: Add the documentation for Global Memory " Babu Moger
2026-04-24 1:41 ` [PATCH v2 6/8] x86,fs/resctrl: Add support for Global Slow " Babu Moger
2026-04-24 1:41 ` [PATCH v2 7/8] x86,fs/resctrl: Add the resource " Babu Moger
2026-04-24 1:41 ` [PATCH v2 8/8] fs/resctrl: Add the documentation " Babu Moger
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox