mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-09-17 09:41:09 +02:00
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()
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/* event isn't installed as a sibling yet. */
|
||||
if (event != leader) {
|
||||
if (intel_set_branch_counter_constr(event, &num))
|
||||
return -EINVAL;
|
||||
if (branch_sample_counters(sibling)) {
|
||||
num++;
|
||||
sibling->hw.dyn_constraint &= x86_pmu.lbr_counters;
|
||||
}
|
||||
}
|
||||
|
||||
if (num > fls(x86_pmu.lbr_counters))
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user