Skip to content

Commit d5616ba

Browse files
Stephane EranianPeter Zijlstra
authored andcommitted
perf/x86/amd: Add idle hooks for branch sampling
On AMD Fam19h Zen3, the branch sampling (BRS) feature must be disabled before entering low power and re-enabled (if was active) when returning from low power. Otherwise, the NMI interrupt may be held up for too long and cause problems. Stopping BRS will cause the NMI to be delivered if it was held up. Define a perf_amd_brs_lopwr_cb() callback to stop/restart BRS. The callback is protected by a jump label which is enabled only when AMD BRS is detected. In all other cases, the callback is never called. Signed-off-by: Stephane Eranian <[email protected]> [peterz: static_call() and build fixes] Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 2a606a1 commit d5616ba

File tree

4 files changed

+61
-0
lines changed

4 files changed

+61
-0
lines changed

arch/x86/events/amd/brs.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* Contributed by Stephane Eranian <[email protected]>
88
*/
99
#include <linux/kernel.h>
10+
#include <linux/jump_label.h>
1011
#include <asm/msr.h>
1112
#include <asm/cpufeature.h>
1213

@@ -329,3 +330,35 @@ void amd_pmu_brs_sched_task(struct perf_event_context *ctx, bool sched_in)
329330
if (sched_in)
330331
amd_brs_poison_buffer();
331332
}
333+
334+
/*
335+
* called from ACPI processor_idle.c or acpi_pad.c
336+
* with interrupts disabled
337+
*/
338+
void perf_amd_brs_lopwr_cb(bool lopwr_in)
339+
{
340+
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
341+
union amd_debug_extn_cfg cfg;
342+
343+
/*
344+
* on mwait in, we may end up in non C0 state.
345+
* we must disable branch sampling to avoid holding the NMI
346+
* for too long. We disable it in hardware but we
347+
* keep the state in cpuc, so we can re-enable.
348+
*
349+
* The hardware will deliver the NMI if needed when brsmen cleared
350+
*/
351+
if (cpuc->brs_active) {
352+
cfg.val = get_debug_extn_cfg();
353+
cfg.brsmen = !lopwr_in;
354+
set_debug_extn_cfg(cfg.val);
355+
}
356+
}
357+
358+
DEFINE_STATIC_CALL_NULL(perf_lopwr_cb, perf_amd_brs_lopwr_cb);
359+
EXPORT_STATIC_CALL_TRAMP_GPL(perf_lopwr_cb);
360+
361+
void __init amd_brs_lopwr_init(void)
362+
{
363+
static_call_update(perf_lopwr_cb, perf_amd_brs_lopwr_cb);
364+
}

arch/x86/events/amd/core.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22
#include <linux/perf_event.h>
3+
#include <linux/jump_label.h>
34
#include <linux/export.h>
45
#include <linux/types.h>
56
#include <linux/init.h>
@@ -1225,6 +1226,9 @@ static int __init amd_core_pmu_init(void)
12251226
/*
12261227
* put_event_constraints callback same as Fam17h, set above
12271228
*/
1229+
1230+
/* branch sampling must be stopped when entering low power */
1231+
amd_brs_lopwr_init();
12281232
}
12291233

12301234
x86_pmu.attr_update = amd_attr_update;

arch/x86/events/perf_event.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,7 @@ void amd_brs_enable(void);
12261226
void amd_brs_enable_all(void);
12271227
void amd_brs_disable_all(void);
12281228
void amd_brs_drain(void);
1229+
void amd_brs_lopwr_init(void);
12291230
void amd_brs_disable_all(void);
12301231
int amd_brs_setup_filter(struct perf_event *event);
12311232
void amd_brs_reset(void);

arch/x86/include/asm/perf_event.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#ifndef _ASM_X86_PERF_EVENT_H
33
#define _ASM_X86_PERF_EVENT_H
44

5+
#include <linux/static_call.h>
6+
57
/*
68
* Performance event hw details:
79
*/
@@ -513,6 +515,27 @@ static inline void intel_pt_handle_vmx(int on)
513515
#if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD)
514516
extern void amd_pmu_enable_virt(void);
515517
extern void amd_pmu_disable_virt(void);
518+
519+
#if defined(CONFIG_PERF_EVENTS_AMD_BRS)
520+
521+
#define PERF_NEEDS_LOPWR_CB 1
522+
523+
/*
524+
* architectural low power callback impacts
525+
* drivers/acpi/processor_idle.c
526+
* drivers/acpi/acpi_pad.c
527+
*/
528+
extern void perf_amd_brs_lopwr_cb(bool lopwr_in);
529+
530+
DECLARE_STATIC_CALL(perf_lopwr_cb, perf_amd_brs_lopwr_cb);
531+
532+
static inline void perf_lopwr_cb(bool lopwr_in)
533+
{
534+
static_call_mod(perf_lopwr_cb)(lopwr_in);
535+
}
536+
537+
#endif /* PERF_NEEDS_LOPWR_CB */
538+
516539
#else
517540
static inline void amd_pmu_enable_virt(void) { }
518541
static inline void amd_pmu_disable_virt(void) { }

0 commit comments

Comments
 (0)