Miscellaneous perf fixes:
- 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
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-----BEGIN PGP SIGNATURE-----
iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAmm/ptcRHG1pbmdvQGtl
cm5lbC5vcmcACgkQEnMQ0APhK1i8yBAAsbAbTzyJOxiE29beCiW3r9V4ELtrSlpG
syUtZ4Y1cozK1w6/8S2oWHJkuWa+ToO6bn9rKxNemWIrnsxe5B4iKfeNWRFTz24g
41xTXaxUB9c7vBgv4BDvr/ykkYGQybkn0Bf/U5rufzvIlst9bx7zKVAnIT9Qws37
UTMY96XGYY5HNzGSZbQkpQ4cs8n72U+00OBHMTWtH8NJT+fRmaM312Q8F6wNKgH2
YtaAjwb55BU5+hQUz5YN96xQGYaoj0s8UtOk4a3tS/t0F8mOodDVTxzMdHKToQmD
SbscGvfC+bg5zjoYGFEU+cXoBMkkZlBPqZdLVQAGEy3YZT+JIdmyJhn9FD6HVuVw
OzyG9VuY+TxOFrFQdMs3Xfa0vZ7AO1c90HB08P4T7nWaMioR1iFAF31MSVEMXuzd
ZROHplWNIqDeOzmerXgZq4JWy3Bpaam8fH1B5/qN450oAxaym3lCOoCZidJYgy3g
CVBF/6BO7DlpKiy9lXknRscItwIiRmZ9Xr+sOmOMQRGqQkC6Ykk/Hj2sA1qKPuQ5
ruRqqaL9cznttAoJR2jZ0Ijyu7usgxB/y066nR1zXKdvEdNcntaic+QybHxbQoYx
kyYNoR1dg+AWLb5juT68abkP4trZ8EUa7Q29OX1SzTk+0U7M0fO3/rq9gt71HiHR
WSjRDQPfWrI=
=jp5H
-----END PGP SIGNATURE-----
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:
commit
ebfd9b7af2
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue