AMD event select 0xFFF (Merge) is the hardware control encoding used by Large Increment per Cycle (LIPC) pairs. When written into an odd counter's PerfCtl it turns that counter into the upper 16 bits of a 64-bit merged accumulator; any subsequent arming write (-(2^47-1)) is silently truncated to its low 16 bits, while hwc->prev_count retains the full value. This is particularly problematic with a KVM guest, which will program the Merge encoding into its own odd vPMC as a normal part of scheduling a LIPC event. KVM intercepts that write and faithfully forwards it to the host as a raw event carrying the Merge encoding, where it is accepted as an ordinary countable event. Once a counter's PerfCtl holds the Merge encoding, every later user of that counter gets a first delta inflated by 2^47 Reject Merge (AMD_MERGE_EVENT) in amd_core_hw_config() so it cannot be submitted as a user-visible event. The pair mechanism programs it itself via x86_pmu.perf_ctr_pair_en; nothing else should do so. Fixes: 5738891229a2 ("perf/x86/amd: Add support for Large Increment per Cycle Events") Reported-by: Yao Zhou Signed-off-by: Luka Absandze --- arch/x86/events/amd/core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/x86/events/amd/core.c b/arch/x86/events/amd/core.c index 49b6b8fce566..cb655c751e5b 100644 --- a/arch/x86/events/amd/core.c +++ b/arch/x86/events/amd/core.c @@ -380,8 +380,12 @@ static int amd_core_hw_config(struct perf_event *event) else if (event->attr.exclude_guest) event->hw.config |= AMD64_EVENTSEL_HOSTONLY; - if ((x86_pmu.flags & PMU_FL_PAIR) && amd_is_pair_event_code(&event->hw)) - event->hw.flags |= PERF_X86_EVENT_PAIR; + if (x86_pmu.flags & PMU_FL_PAIR) { + if ((event->hw.config & AMD64_EVENTSEL_EVENT) == AMD_MERGE_EVENT) + return -EINVAL; + if (amd_is_pair_event_code(&event->hw)) + event->hw.flags |= PERF_X86_EVENT_PAIR; + } if (has_branch_stack(event)) return static_call(amd_pmu_branch_hw_config)(event); -- 2.47.3