perf/x86/amd/uncore: Add group validation

The amd_uncore driver currently does not validate event groups and
allows creation of groups with more events than the number of available
hardware counters. Because of this, pmu->event_init() succeeds but
counter assignment fails later in pmu->add() which returns -EBUSY once
all counters are exhausted.

Address this by introducing group validation in the pmu->event_init()
path. Since the uncore PMUs have no per-event constraints and all
counters of a PMU are interchangeable, validation is reduced to just
counting the group members that target a PMU and ensuring that they fit
within the available set of counters.

Fixes: c43ca5091a ("perf/x86/amd: Add support for AMD NB and L2I "uncore" counters")
Signed-off-by: Sandipan Das <sandipan.das@amd.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://patch.msgid.link/750877d66e208603c3047f13eed6399625d43969.1782884387.git.sandipan.das@amd.com
This commit is contained in:
Sandipan Das 2026-07-01 11:12:00 +05:30 committed by Ingo Molnar
parent d7ebbae57d
commit edda9051e2

View File

@ -265,6 +265,29 @@ static void amd_uncore_del(struct perf_event *event, int flags)
hwc->idx = -1;
}
static bool amd_uncore_group_valid(struct perf_event *event)
{
struct amd_uncore_pmu *pmu = event_to_amd_uncore_pmu(event);
struct perf_event *leader = event->group_leader;
struct perf_event *sibling;
int counters = 0;
if (leader->pmu == event->pmu)
counters++;
for_each_sibling_event(sibling, leader) {
if (sibling->pmu == event->pmu &&
sibling->state > PERF_EVENT_STATE_OFF)
counters++;
}
/*
* When pmu->event_init() is called, the event is yet to be linked to
* its leader's sibling list, so it is counted separately
*/
return (counters + 1) <= pmu->num_counters;
}
static int amd_uncore_event_init(struct perf_event *event)
{
struct amd_uncore_pmu *pmu;
@ -282,6 +305,14 @@ static int amd_uncore_event_init(struct perf_event *event)
if (!ctx)
return -ENODEV;
/*
* Ensure that all events in a group can be scheduled together so that
* a failure can be reported at perf_event_open() time rather than
* silently at pmu->add() time when no free counter is found
*/
if (event->group_leader != event && !amd_uncore_group_valid(event))
return -EINVAL;
/*
* NB and Last level cache counters (MSRs) are shared across all cores
* that share the same NB / Last level cache. On family 16h and below,