Skip to content

Commit 2edfd10

Browse files
committed
Merge tag 'x86_cache_for_v6.9_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull resource control updates from Borislav Petkov: - Rework different aspects of the resctrl code like adding arch-specific accessors and splitting the locking, in order to accomodate ARM's MPAM implementation of hw resource control and be able to use the same filesystem control interface like on x86. Work by James Morse - Improve the memory bandwidth throttling heuristic to handle workloads with not too regular load levels which end up penalized unnecessarily - Use CPUID to detect the memory bandwidth enforcement limit on AMD - The usual set of fixes * tag 'x86_cache_for_v6.9_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (30 commits) x86/resctrl: Remove lockdep annotation that triggers false positive x86/resctrl: Separate arch and fs resctrl locks x86/resctrl: Move domain helper migration into resctrl_offline_cpu() x86/resctrl: Add CPU offline callback for resctrl work x86/resctrl: Allow overflow/limbo handlers to be scheduled on any-but CPU x86/resctrl: Add CPU online callback for resctrl work x86/resctrl: Add helpers for system wide mon/alloc capable x86/resctrl: Make rdt_enable_key the arch's decision to switch x86/resctrl: Move alloc/mon static keys into helpers x86/resctrl: Make resctrl_mounted checks explicit x86/resctrl: Allow arch to allocate memory needed in resctrl_arch_rmid_read() x86/resctrl: Allow resctrl_arch_rmid_read() to sleep x86/resctrl: Queue mon_event_read() instead of sending an IPI x86/resctrl: Add cpumask_any_housekeeping() for limbo/overflow x86/resctrl: Move CLOSID/RMID matching and setting to use helpers x86/resctrl: Allocate the cleanest CLOSID by searching closid_num_dirty_rmid x86/resctrl: Use __set_bit()/__clear_bit() instead of open coding x86/resctrl: Track the number of dirty RMID a CLOSID has x86/resctrl: Allow RMID allocation to be scoped by CLOSID x86/resctrl: Access per-rmid structures by index ...
2 parents bfdb395 + c0d848f commit 2edfd10

File tree

9 files changed

+946
-339
lines changed

9 files changed

+946
-339
lines changed

arch/x86/include/asm/resctrl.h

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77
#include <linux/sched.h>
88
#include <linux/jump_label.h>
99

10+
/*
11+
* This value can never be a valid CLOSID, and is used when mapping a
12+
* (closid, rmid) pair to an index and back. On x86 only the RMID is
13+
* needed. The index is a software defined value.
14+
*/
15+
#define X86_RESCTRL_EMPTY_CLOSID ((u32)~0)
16+
1017
/**
1118
* struct resctrl_pqr_state - State cache for the PQR MSR
1219
* @cur_rmid: The cached Resource Monitoring ID
@@ -31,10 +38,47 @@ struct resctrl_pqr_state {
3138

3239
DECLARE_PER_CPU(struct resctrl_pqr_state, pqr_state);
3340

41+
extern bool rdt_alloc_capable;
42+
extern bool rdt_mon_capable;
43+
3444
DECLARE_STATIC_KEY_FALSE(rdt_enable_key);
3545
DECLARE_STATIC_KEY_FALSE(rdt_alloc_enable_key);
3646
DECLARE_STATIC_KEY_FALSE(rdt_mon_enable_key);
3747

48+
static inline bool resctrl_arch_alloc_capable(void)
49+
{
50+
return rdt_alloc_capable;
51+
}
52+
53+
static inline void resctrl_arch_enable_alloc(void)
54+
{
55+
static_branch_enable_cpuslocked(&rdt_alloc_enable_key);
56+
static_branch_inc_cpuslocked(&rdt_enable_key);
57+
}
58+
59+
static inline void resctrl_arch_disable_alloc(void)
60+
{
61+
static_branch_disable_cpuslocked(&rdt_alloc_enable_key);
62+
static_branch_dec_cpuslocked(&rdt_enable_key);
63+
}
64+
65+
static inline bool resctrl_arch_mon_capable(void)
66+
{
67+
return rdt_mon_capable;
68+
}
69+
70+
static inline void resctrl_arch_enable_mon(void)
71+
{
72+
static_branch_enable_cpuslocked(&rdt_mon_enable_key);
73+
static_branch_inc_cpuslocked(&rdt_enable_key);
74+
}
75+
76+
static inline void resctrl_arch_disable_mon(void)
77+
{
78+
static_branch_disable_cpuslocked(&rdt_mon_enable_key);
79+
static_branch_dec_cpuslocked(&rdt_enable_key);
80+
}
81+
3882
/*
3983
* __resctrl_sched_in() - Writes the task's CLOSid/RMID to IA32_PQR_MSR
4084
*
@@ -88,12 +132,58 @@ static inline unsigned int resctrl_arch_round_mon_val(unsigned int val)
88132
return val * scale;
89133
}
90134

135+
static inline void resctrl_arch_set_closid_rmid(struct task_struct *tsk,
136+
u32 closid, u32 rmid)
137+
{
138+
WRITE_ONCE(tsk->closid, closid);
139+
WRITE_ONCE(tsk->rmid, rmid);
140+
}
141+
142+
static inline bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid)
143+
{
144+
return READ_ONCE(tsk->closid) == closid;
145+
}
146+
147+
static inline bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 ignored,
148+
u32 rmid)
149+
{
150+
return READ_ONCE(tsk->rmid) == rmid;
151+
}
152+
91153
static inline void resctrl_sched_in(struct task_struct *tsk)
92154
{
93155
if (static_branch_likely(&rdt_enable_key))
94156
__resctrl_sched_in(tsk);
95157
}
96158

159+
static inline u32 resctrl_arch_system_num_rmid_idx(void)
160+
{
161+
/* RMID are independent numbers for x86. num_rmid_idx == num_rmid */
162+
return boot_cpu_data.x86_cache_max_rmid + 1;
163+
}
164+
165+
static inline void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid)
166+
{
167+
*rmid = idx;
168+
*closid = X86_RESCTRL_EMPTY_CLOSID;
169+
}
170+
171+
static inline u32 resctrl_arch_rmid_idx_encode(u32 ignored, u32 rmid)
172+
{
173+
return rmid;
174+
}
175+
176+
/* x86 can always read an rmid, nothing needs allocating */
177+
struct rdt_resource;
178+
static inline void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r, int evtid)
179+
{
180+
might_sleep();
181+
return NULL;
182+
};
183+
184+
static inline void resctrl_arch_mon_ctx_free(struct rdt_resource *r, int evtid,
185+
void *ctx) { };
186+
97187
void resctrl_cpu_detect(struct cpuinfo_x86 *c);
98188

99189
#else

arch/x86/kernel/cpu/resctrl/core.c

Lines changed: 52 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#define pr_fmt(fmt) "resctrl: " fmt
1818

19+
#include <linux/cpu.h>
1920
#include <linux/slab.h>
2021
#include <linux/err.h>
2122
#include <linux/cacheinfo.h>
@@ -25,8 +26,15 @@
2526
#include <asm/resctrl.h>
2627
#include "internal.h"
2728

28-
/* Mutex to protect rdtgroup access. */
29-
DEFINE_MUTEX(rdtgroup_mutex);
29+
/*
30+
* rdt_domain structures are kfree()d when their last CPU goes offline,
31+
* and allocated when the first CPU in a new domain comes online.
32+
* The rdt_resource's domain list is updated when this happens. Readers of
33+
* the domain list must either take cpus_read_lock(), or rely on an RCU
34+
* read-side critical section, to avoid observing concurrent modification.
35+
* All writers take this mutex:
36+
*/
37+
static DEFINE_MUTEX(domain_list_lock);
3038

3139
/*
3240
* The cached resctrl_pqr_state is strictly per CPU and can never be
@@ -136,15 +144,15 @@ static inline void cache_alloc_hsw_probe(void)
136144
{
137145
struct rdt_hw_resource *hw_res = &rdt_resources_all[RDT_RESOURCE_L3];
138146
struct rdt_resource *r = &hw_res->r_resctrl;
139-
u32 l, h, max_cbm = BIT_MASK(20) - 1;
147+
u64 max_cbm = BIT_ULL_MASK(20) - 1, l3_cbm_0;
140148

141-
if (wrmsr_safe(MSR_IA32_L3_CBM_BASE, max_cbm, 0))
149+
if (wrmsrl_safe(MSR_IA32_L3_CBM_BASE, max_cbm))
142150
return;
143151

144-
rdmsr(MSR_IA32_L3_CBM_BASE, l, h);
152+
rdmsrl(MSR_IA32_L3_CBM_BASE, l3_cbm_0);
145153

146154
/* If all the bits were set in MSR, return success */
147-
if (l != max_cbm)
155+
if (l3_cbm_0 != max_cbm)
148156
return;
149157

150158
hw_res->num_closid = 4;
@@ -231,19 +239,17 @@ static bool __get_mem_config_intel(struct rdt_resource *r)
231239
static bool __rdt_get_mem_config_amd(struct rdt_resource *r)
232240
{
233241
struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
234-
union cpuid_0x10_3_eax eax;
235-
union cpuid_0x10_x_edx edx;
236-
u32 ebx, ecx, subleaf;
242+
u32 eax, ebx, ecx, edx, subleaf;
237243

238244
/*
239245
* Query CPUID_Fn80000020_EDX_x01 for MBA and
240246
* CPUID_Fn80000020_EDX_x02 for SMBA
241247
*/
242248
subleaf = (r->rid == RDT_RESOURCE_SMBA) ? 2 : 1;
243249

244-
cpuid_count(0x80000020, subleaf, &eax.full, &ebx, &ecx, &edx.full);
245-
hw_res->num_closid = edx.split.cos_max + 1;
246-
r->default_ctrl = MAX_MBA_BW_AMD;
250+
cpuid_count(0x80000020, subleaf, &eax, &ebx, &ecx, &edx);
251+
hw_res->num_closid = edx + 1;
252+
r->default_ctrl = 1 << eax;
247253

248254
/* AMD does not use delay */
249255
r->membw.delay_linear = false;
@@ -512,6 +518,8 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r)
512518
struct rdt_domain *d;
513519
int err;
514520

521+
lockdep_assert_held(&domain_list_lock);
522+
515523
d = rdt_find_domain(r, id, &add_pos);
516524
if (IS_ERR(d)) {
517525
pr_warn("Couldn't find cache id for CPU %d\n", cpu);
@@ -545,11 +553,12 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r)
545553
return;
546554
}
547555

548-
list_add_tail(&d->list, add_pos);
556+
list_add_tail_rcu(&d->list, add_pos);
549557

550558
err = resctrl_online_domain(r, d);
551559
if (err) {
552-
list_del(&d->list);
560+
list_del_rcu(&d->list);
561+
synchronize_rcu();
553562
domain_free(hw_dom);
554563
}
555564
}
@@ -560,6 +569,8 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r)
560569
struct rdt_hw_domain *hw_dom;
561570
struct rdt_domain *d;
562571

572+
lockdep_assert_held(&domain_list_lock);
573+
563574
d = rdt_find_domain(r, id, NULL);
564575
if (IS_ERR_OR_NULL(d)) {
565576
pr_warn("Couldn't find cache id for CPU %d\n", cpu);
@@ -570,7 +581,8 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r)
570581
cpumask_clear_cpu(cpu, &d->cpu_mask);
571582
if (cpumask_empty(&d->cpu_mask)) {
572583
resctrl_offline_domain(r, d);
573-
list_del(&d->list);
584+
list_del_rcu(&d->list);
585+
synchronize_rcu();
574586

575587
/*
576588
* rdt_domain "d" is going to be freed below, so clear
@@ -582,73 +594,47 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r)
582594

583595
return;
584596
}
585-
586-
if (r == &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl) {
587-
if (is_mbm_enabled() && cpu == d->mbm_work_cpu) {
588-
cancel_delayed_work(&d->mbm_over);
589-
mbm_setup_overflow_handler(d, 0);
590-
}
591-
if (is_llc_occupancy_enabled() && cpu == d->cqm_work_cpu &&
592-
has_busy_rmid(r, d)) {
593-
cancel_delayed_work(&d->cqm_limbo);
594-
cqm_setup_limbo_handler(d, 0);
595-
}
596-
}
597597
}
598598

599599
static void clear_closid_rmid(int cpu)
600600
{
601601
struct resctrl_pqr_state *state = this_cpu_ptr(&pqr_state);
602602

603-
state->default_closid = 0;
604-
state->default_rmid = 0;
605-
state->cur_closid = 0;
606-
state->cur_rmid = 0;
607-
wrmsr(MSR_IA32_PQR_ASSOC, 0, 0);
603+
state->default_closid = RESCTRL_RESERVED_CLOSID;
604+
state->default_rmid = RESCTRL_RESERVED_RMID;
605+
state->cur_closid = RESCTRL_RESERVED_CLOSID;
606+
state->cur_rmid = RESCTRL_RESERVED_RMID;
607+
wrmsr(MSR_IA32_PQR_ASSOC, RESCTRL_RESERVED_RMID,
608+
RESCTRL_RESERVED_CLOSID);
608609
}
609610

610-
static int resctrl_online_cpu(unsigned int cpu)
611+
static int resctrl_arch_online_cpu(unsigned int cpu)
611612
{
612613
struct rdt_resource *r;
613614

614-
mutex_lock(&rdtgroup_mutex);
615+
mutex_lock(&domain_list_lock);
615616
for_each_capable_rdt_resource(r)
616617
domain_add_cpu(cpu, r);
617-
/* The cpu is set in default rdtgroup after online. */
618-
cpumask_set_cpu(cpu, &rdtgroup_default.cpu_mask);
618+
mutex_unlock(&domain_list_lock);
619+
619620
clear_closid_rmid(cpu);
620-
mutex_unlock(&rdtgroup_mutex);
621+
resctrl_online_cpu(cpu);
621622

622623
return 0;
623624
}
624625

625-
static void clear_childcpus(struct rdtgroup *r, unsigned int cpu)
626-
{
627-
struct rdtgroup *cr;
628-
629-
list_for_each_entry(cr, &r->mon.crdtgrp_list, mon.crdtgrp_list) {
630-
if (cpumask_test_and_clear_cpu(cpu, &cr->cpu_mask)) {
631-
break;
632-
}
633-
}
634-
}
635-
636-
static int resctrl_offline_cpu(unsigned int cpu)
626+
static int resctrl_arch_offline_cpu(unsigned int cpu)
637627
{
638-
struct rdtgroup *rdtgrp;
639628
struct rdt_resource *r;
640629

641-
mutex_lock(&rdtgroup_mutex);
630+
resctrl_offline_cpu(cpu);
631+
632+
mutex_lock(&domain_list_lock);
642633
for_each_capable_rdt_resource(r)
643634
domain_remove_cpu(cpu, r);
644-
list_for_each_entry(rdtgrp, &rdt_all_groups, rdtgroup_list) {
645-
if (cpumask_test_and_clear_cpu(cpu, &rdtgrp->cpu_mask)) {
646-
clear_childcpus(rdtgrp, cpu);
647-
break;
648-
}
649-
}
635+
mutex_unlock(&domain_list_lock);
636+
650637
clear_closid_rmid(cpu);
651-
mutex_unlock(&rdtgroup_mutex);
652638

653639
return 0;
654640
}
@@ -968,7 +954,8 @@ static int __init resctrl_late_init(void)
968954

969955
state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
970956
"x86/resctrl/cat:online:",
971-
resctrl_online_cpu, resctrl_offline_cpu);
957+
resctrl_arch_online_cpu,
958+
resctrl_arch_offline_cpu);
972959
if (state < 0)
973960
return state;
974961

@@ -992,8 +979,14 @@ late_initcall(resctrl_late_init);
992979

993980
static void __exit resctrl_exit(void)
994981
{
982+
struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
983+
995984
cpuhp_remove_state(rdt_online);
985+
996986
rdtgroup_exit();
987+
988+
if (r->mon_capable)
989+
rdt_put_mon_l3_config();
997990
}
998991

999992
__exitcall(resctrl_exit);

0 commit comments

Comments
 (0)