* [PATCH] perf/amd/ibs: Clear stale IBS_{FETCH|OP}_CTL in perf_ibs_start() with CTL2[Dis]
@ 2026-10-07 23:48 Jim Mattson
0 siblings, 0 replies; only message in thread
From: Jim Mattson @ 2026-10-07 23:48 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar
Cc: Jim Mattson, Ravi Bangoria, Manali Shukla, Sandipan Das,
Namhyung Kim, Arnaldo Carvalho de Melo, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
James Clark, Thomas Gleixner, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Yosry Ahmed, linux-perf-users, linux-kernel
Commit 1b044ff3c17e ("perf/amd/ibs: Avoid race between event add and
NMI") makes perf_ibs_start() reset IBS_{FETCH|OP}_CTL before it sets
IBS_STARTED. Thus, an NMI from another source that arrives before the
event is enabled finds Val=0 and does not process a stale sample or
enable the event too early.
The reset is a call to perf_ibs_disable_event() with config=0. A later
commit changed perf_ibs_disable_event():
commit efa5700ec0da ("perf/amd/ibs: Support IBS_{FETCH|OP}_CTL2[Dis] to eliminate RMW race")
When IBS_CAPS_DIS is set, the function now writes only
IBS_{FETCH|OP}_CTL2 and returns. It does not write IBS_{FETCH|OP}_CTL.
On hardware with IBS_CAPS_DIS, the reset does nothing, and the race is
possible again: CTL still holds the previous sample, with Val=1, when
IBS_STARTED is set.
Clear IBS_{FETCH|OP}_CTL explicitly when IBS_CAPS_DIS is set, as
perf_ibs_disable_event() did before CTL2 support. Everything in CTL is
stale at this point, so it does not matter if this write discards a
Val that the hardware sets late.
Fixes: efa5700ec0da ("perf/amd/ibs: Support IBS_{FETCH|OP}_CTL2[Dis] to eliminate RMW race")
Assisted-by: LLM
Signed-off-by: Jim Mattson <jmattson@google.com>
---
I reproduced the race on hardware with IBS_CAPS_DIS. To make the window
wider, I added a debug-only udelay() between set_bit(IBS_STARTED) and
perf_ibs_enable_event() in perf_ibs_start(). A throttled ibs_op event
gave about 1000 perf_ibs_start() calls per second, and a cycles event
gave NMIs from the core PMU. In 60 seconds:
- Without this patch, IBS_OP_CTL[Val] was 1 at every
perf_ibs_start() call (60003 of 60003). The IBS op NMI handler took
the stale sample and re-enabled the event during the window 17
times.
- With this patch, the handler never took a sample during the window.
Without the udelay(), the window is only a few instructions long.
A related question for AMD: with IBS_CAPS_DIS, perf_ibs_stop() now
leaves IBS_{FETCH|OP}_CTL[En]=1. APM vol. 2, section 15.38, says that
IbsFetchEn and IbsOpEn must be 0 at VMRUN of an SEV-ES or SEV-SNP
guest with IBS virtualization enabled, and should be 0 for other
guests. Can the hardware set CTL[Val] or change CTL in any other way
after CTL2[Dis] is set to 1? If not, perf_ibs_stop() can safely clear
CTL[En] with a read-modify-write after it sets CTL2[Dis].
arch/x86/events/amd/ibs.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c
index 3531f9c23b8c..3a5475006b59 100644
--- a/arch/x86/events/amd/ibs.c
+++ b/arch/x86/events/amd/ibs.c
@@ -580,8 +580,15 @@ static void perf_ibs_start(struct perf_event *event, int flags)
* Doing so prevents a race condition in which an NMI due to other
* source might accidentally activate the event before we enable
* it ourselves.
+ *
+ * With IBS_CAPS_DIS, perf_ibs_disable_event() only sets CTL2[Dis]
+ * and leaves the previous sample in CTL, so clear CTL explicitly.
+ * Anything in CTL is stale, so it does not matter if this write
+ * discards a late Val.
*/
perf_ibs_disable_event(perf_ibs, hwc, 0);
+ if (ibs_caps & IBS_CAPS_DIS)
+ wrmsrq(hwc->config_base, 0);
/*
* Set STARTED before enabling the hardware, such that a subsequent NMI
--
2.56.0.385.gd3acb90ef8-goog
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-07 23:48 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-07 23:48 [PATCH] perf/amd/ibs: Clear stale IBS_{FETCH|OP}_CTL in perf_ibs_start() with CTL2[Dis] Jim Mattson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®