[Patch v3 1/4] perf/x86/intel: Improve validation and configuration of ACR masks

Dapeng Mi
2026-04-27T09:00:16Z

Currently there are several issues on the user space ACR mask validation
and configuration.
- The validation for user space ACR mask (attr.config2) is incomplete,
e.g., the ACR mask could include the index which belongs to another
ACR events group, but it's not validated.
- An early return on an invalid ACR mask caused all subsequent ACR groups
to be skipped.
- The stale hardware ACR mask (hw.config1) is not cleared before setting
new hardware ACR mask.

The following changes address all of the above issues.
- Calculate the indices bitmap for each ACR events group. Any bits in
the user-space mask not present in the group's bitmap are now dropped.
- Instead of an early return on invalid bits, drop only the invalid
portions and continue iterating through all ACR events to ensure full
configuration.
- Explicitly clear the stale hardware ACR mask for each event prior to
writing the new configuration.

Cc: stable@vger.kernel.org
Fixes: ec980e4facef ("perf/x86/intel: Support auto counter reload")
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
---

v3: new patch.

arch/x86/events/intel/core.c | 32 +++++++++++++++++++++++++-------
1 file changed, 25 insertions(+), 7 deletions(-)

diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 4768236c054b..1a2c268018a2 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -3332,23 +3332,41 @@ static void intel_pmu_enable_event(struct perf_event *event)
static void intel_pmu_acr_late_setup(struct cpu_hw_events *cpuc)
{
struct perf_event *event, *leader;
- int i, j, idx;
+ int i, j, k, bit, idx;
+ u64 group_mask;

for (i = 0; i < cpuc->n_events; i++) {
leader = cpuc->event_list[i];
if (!is_acr_event_group(leader))
continue;

- /* The ACR events must be contiguous. */
+ /* Find the last event of the ACR group. */
for (j = i; j < cpuc->n_events; j++) {
event = cpuc->event_list[j];
if (event->group_leader != leader->group_leader)
break;
- for_each_set_bit(idx, (unsigned long *)&event->attr.config2, X86_PMC_IDX_MAX) {
- if (i + idx >= cpuc->n_events ||
- !is_acr_event_group(cpuc->event_list[i + idx]))
- return;
- __set_bit(cpuc->assign[i + idx], (unsigned long *)&event->hw.config1);
+ }
+
+ /* Figure out the group indices bitmap. */
+ group_mask = 0;
+ for (k = i; k < j; k++)
+ group_mask |= BIT_ULL(cpuc->assign[k]);
+
+ /*
+ * Translate the user-space ACR mask (attr.config2) into the physical
+ * counter bitmask (hw.config1) for each ACR event in the group.
+ * NOTE: ACR event contiguity is guaranteed by intel_pmu_hw_config().
+ */
+ for (k = i; k < j; k++) {
+ event = cpuc->event_list[k];
+ event->hw.config1 = 0;
+ for_each_set_bit(bit, (unsigned long *)&event->attr.config2, X86_PMC_IDX_MAX) {
+ idx = i + bit;
+ if (idx >= cpuc->n_events ||
+ !(BIT_ULL(cpuc->assign[idx]) & group_mask) ||
+ !is_acr_event_group(cpuc->event_list[idx]))
+ continue;
+ __set_bit(cpuc->assign[idx], (unsigned long *)&event->hw.config1);
}
}
i = j - 1;
--
2.34.1