Commit ebfd9b7a authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'perf-urgent-2026-03-22' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf fixes from Ingo Molnar:

 - Fix a PMU driver crash on AMD EPYC systems, caused by
   a race condition in x86_pmu_enable()

 - Fix a possible counter-initialization bug in x86_pmu_enable()

 - Fix a counter inheritance bug in inherit_event() and
   __perf_event_read()

 - Fix an Intel PMU driver branch constraints handling bug
   found by UBSAN

 - Fix the Intel PMU driver's new Off-Module Response (OMR)
   support code for Diamond Rapids / Nova lake, to fix a snoop
   information parsing bug

* tag 'perf-urgent-2026-03-22' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  perf/x86/intel: Fix OMR snoop information parsing issues
  perf/x86/intel: Add missing branch counters constraint apply
  perf: Make sure to use pmu_ctx->pmu for groups
  x86/perf: Make sure to program the counter value for stopped events on migration
  perf/x86: Move event pointer setup earlier in x86_pmu_enable()
parents dea622e1 e7fcc545
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -1372,14 +1372,17 @@ static void x86_pmu_enable(struct pmu *pmu)
			else if (i < n_running)
				continue;

			if (hwc->state & PERF_HES_ARCH)
			cpuc->events[hwc->idx] = event;

			if (hwc->state & PERF_HES_ARCH) {
				static_call(x86_pmu_set_period)(event);
				continue;
			}

			/*
			 * if cpuc->enabled = 0, then no wrmsr as
			 * per x86_pmu_enable_event()
			 */
			cpuc->events[hwc->idx] = event;
			x86_pmu_start(event, PERF_EF_RELOAD);
		}
		cpuc->n_added = 0;
+21 −10
Original line number Diff line number Diff line
@@ -4628,6 +4628,19 @@ static inline void intel_pmu_set_acr_caused_constr(struct perf_event *event,
		event->hw.dyn_constraint &= hybrid(event->pmu, acr_cause_mask64);
}

static inline int intel_set_branch_counter_constr(struct perf_event *event,
						  int *num)
{
	if (branch_sample_call_stack(event))
		return -EINVAL;
	if (branch_sample_counters(event)) {
		(*num)++;
		event->hw.dyn_constraint &= x86_pmu.lbr_counters;
	}

	return 0;
}

static int intel_pmu_hw_config(struct perf_event *event)
{
	int ret = x86_pmu_hw_config(event);
@@ -4698,21 +4711,19 @@ static int intel_pmu_hw_config(struct perf_event *event)
		 * group, which requires the extra space to store the counters.
		 */
		leader = event->group_leader;
		if (branch_sample_call_stack(leader))
		if (intel_set_branch_counter_constr(leader, &num))
			return -EINVAL;
		if (branch_sample_counters(leader)) {
			num++;
			leader->hw.dyn_constraint &= x86_pmu.lbr_counters;
		}
		leader->hw.flags |= PERF_X86_EVENT_BRANCH_COUNTERS;

		for_each_sibling_event(sibling, leader) {
			if (branch_sample_call_stack(sibling))
			if (intel_set_branch_counter_constr(sibling, &num))
				return -EINVAL;
			if (branch_sample_counters(sibling)) {
				num++;
				sibling->hw.dyn_constraint &= x86_pmu.lbr_counters;
		}

		/* event isn't installed as a sibling yet. */
		if (event != leader) {
			if (intel_set_branch_counter_constr(event, &num))
				return -EINVAL;
		}

		if (num > fls(x86_pmu.lbr_counters))
+7 −4
Original line number Diff line number Diff line
@@ -345,12 +345,12 @@ static u64 parse_omr_data_source(u8 dse)
	if (omr.omr_remote)
		val |= REM;

	val |= omr.omr_hitm ? P(SNOOP, HITM) : P(SNOOP, HIT);

	if (omr.omr_source == 0x2) {
		u8 snoop = omr.omr_snoop | omr.omr_promoted;
		u8 snoop = omr.omr_snoop | (omr.omr_promoted << 1);

		if (snoop == 0x0)
		if (omr.omr_hitm)
			val |= P(SNOOP, HITM);
		else if (snoop == 0x0)
			val |= P(SNOOP, NA);
		else if (snoop == 0x1)
			val |= P(SNOOP, MISS);
@@ -359,7 +359,10 @@ static u64 parse_omr_data_source(u8 dse)
		else if (snoop == 0x3)
			val |= P(SNOOP, NONE);
	} else if (omr.omr_source > 0x2 && omr.omr_source < 0x7) {
		val |= omr.omr_hitm ? P(SNOOP, HITM) : P(SNOOP, HIT);
		val |= omr.omr_snoop ? P(SNOOPX, FWD) : 0;
	} else {
		val |= P(SNOOP, NONE);
	}

	return val;
+8 −11
Original line number Diff line number Diff line
@@ -4813,7 +4813,7 @@ static void __perf_event_read(void *info)
	struct perf_event *sub, *event = data->event;
	struct perf_event_context *ctx = event->ctx;
	struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
	struct pmu *pmu = event->pmu;
	struct pmu *pmu;

	/*
	 * If this is a task context, we need to check whether it is
@@ -4825,7 +4825,7 @@ static void __perf_event_read(void *info)
	if (ctx->task && cpuctx->task_ctx != ctx)
		return;

	raw_spin_lock(&ctx->lock);
	guard(raw_spinlock)(&ctx->lock);
	ctx_time_update_event(ctx, event);

	perf_event_update_time(event);
@@ -4833,25 +4833,22 @@ static void __perf_event_read(void *info)
		perf_event_update_sibling_time(event);

	if (event->state != PERF_EVENT_STATE_ACTIVE)
		goto unlock;
		return;

	if (!data->group) {
		pmu->read(event);
		perf_pmu_read(event);
		data->ret = 0;
		goto unlock;
		return;
	}

	pmu = event->pmu_ctx->pmu;
	pmu->start_txn(pmu, PERF_PMU_TXN_READ);

	pmu->read(event);

	perf_pmu_read(event);
	for_each_sibling_event(sub, event)
		perf_pmu_read(sub);

	data->ret = pmu->commit_txn(pmu);

unlock:
	raw_spin_unlock(&ctx->lock);
}

static inline u64 perf_event_count(struct perf_event *event, bool self)
@@ -14744,7 +14741,7 @@ inherit_event(struct perf_event *parent_event,
	get_ctx(child_ctx);
	child_event->ctx = child_ctx;

	pmu_ctx = find_get_pmu_context(child_event->pmu, child_ctx, child_event);
	pmu_ctx = find_get_pmu_context(parent_event->pmu_ctx->pmu, child_ctx, child_event);
	if (IS_ERR(pmu_ctx)) {
		free_event(child_event);
		return ERR_CAST(pmu_ctx);