[tip: perf/core] perf/x86/intel: Keep cap_user_rdpmc in sync with RDPMC user-disable state

From: tip-bot2 for Dapeng Mi

Date: Tue Jun 30 2026 - 05:15:49 EST


The following commit has been merged into the perf/core branch of tip:

Commit-ID: 503c7184ca6a5e1f5b53466621d94fa413f3bad9
Gitweb: https://git.kernel.org/tip/503c7184ca6a5e1f5b53466621d94fa413f3bad9
Author: Dapeng Mi <dapeng1.mi@xxxxxxxxxxxxxxx>
AuthorDate: Fri, 12 Jun 2026 17:01:08 +08:00
Committer: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
CommitterDate: Tue, 30 Jun 2026 10:57:05 +02:00

perf/x86/intel: Keep cap_user_rdpmc in sync with RDPMC user-disable state

After introducing the RDPMC user disable feature, user-space RDPMC may
return 0 instead of the actual event count. This creates an inconsistency
with cap_user_rdpmc, where cap_user_rdpmc is set, but user-space RDPMC
only returns 0.

To accurately represent the user-space RDPMC capability, update
cap_user_rdpmc (depending on PERF_EVENT_FLAG_USER_READ_CNT) according to
the RDPMC user disable state. If RDPMC user disable is enabled,
cap_user_rdpmc is updated to false eventually, allowing user-space
programs to fall back to the read() syscall to obtain the real event
count.

Because PERF_EVENT_FLAG_USER_READ_CNT is evaluated in
x86_pmu_event_init(), move intel_pmu_update_rdpmc_user_disable()
earlier into intel_pmu_hw_config(). This ensures that the user-disable
state is updated before updating PERF_EVENT_FLAG_USER_READ_CNT. Note that
since event->ctx is not yet assigned at this stage, use the
PERF_ATTACH_TASK flag to detect whether the event is task-attached.

While at it, fix the indentation of x86_pmu_has_rdpmc_user_disable()
to adhere to the kernel coding style.

Fixes: 59af95e028d4 ("perf/x86/intel: Add support for rdpmc user disable feature")
Signed-off-by: Dapeng Mi <dapeng1.mi@xxxxxxxxxxxxxxx>
Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx>
Link: https://patch.msgid.link/20260612090114.3188886-3-dapeng1.mi@xxxxxxxxxxxxxxx
---
arch/x86/events/core.c | 3 ++-
arch/x86/events/intel/core.c | 6 +++---
arch/x86/events/perf_event.h | 2 +-
3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index d1af33d..af0b67f 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -2539,7 +2539,8 @@ static int x86_pmu_event_init(struct perf_event *event)
}

if (READ_ONCE(x86_pmu.attr_rdpmc) &&
- !(event->hw.flags & PERF_X86_EVENT_LARGE_PEBS))
+ !(event->hw.flags & PERF_X86_EVENT_LARGE_PEBS) &&
+ !(event->hw.config & ARCH_PERFMON_EVENTSEL_RDPMC_USER_DISABLE))
event->hw.flags |= PERF_EVENT_FLAG_USER_READ_CNT;

return err;
diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 465c414..5116b15 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -3533,7 +3533,7 @@ static void intel_pmu_update_rdpmc_user_disable(struct perf_event *event)
*/
if (x86_pmu.attr_rdpmc == X86_USER_RDPMC_ALWAYS_ENABLE ||
(x86_pmu.attr_rdpmc == X86_USER_RDPMC_CONDITIONAL_ENABLE &&
- event->ctx->task))
+ (event->attach_state & PERF_ATTACH_TASK)))
event->hw.config &= ~ARCH_PERFMON_EVENTSEL_RDPMC_USER_DISABLE;
else
event->hw.config |= ARCH_PERFMON_EVENTSEL_RDPMC_USER_DISABLE;
@@ -3547,8 +3547,6 @@ static void intel_pmu_enable_event(struct perf_event *event)
struct hw_perf_event *hwc = &event->hw;
int idx = hwc->idx;

- intel_pmu_update_rdpmc_user_disable(event);
-
if (unlikely(event->attr.precise_ip))
static_call(x86_pmu_pebs_enable)(event);

@@ -5147,6 +5145,8 @@ static int intel_pmu_hw_config(struct perf_event *event)
leader->hw.flags |= PERF_X86_EVENT_ACR;
}

+ intel_pmu_update_rdpmc_user_disable(event);
+
if ((event->attr.type == PERF_TYPE_HARDWARE) ||
(event->attr.type == PERF_TYPE_HW_CACHE))
return 0;
diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
index 5902a29..a8afea8 100644
--- a/arch/x86/events/perf_event.h
+++ b/arch/x86/events/perf_event.h
@@ -1344,7 +1344,7 @@ static inline u64 x86_pmu_get_event_config(struct perf_event *event)
static inline bool x86_pmu_has_rdpmc_user_disable(struct pmu *pmu)
{
return !!(hybrid(pmu, config_mask) &
- ARCH_PERFMON_EVENTSEL_RDPMC_USER_DISABLE);
+ ARCH_PERFMON_EVENTSEL_RDPMC_USER_DISABLE);
}

extern struct event_constraint emptyconstraint;