x86: events: Do not return bogus capabilities if PMU is broken
If the PMU is broken due to firmware issues, check_hw_exists() will return false but perf_get_x86_pmu_capability() will still return data from x86_pmu. Likewise if some of the hotplug callbacks cannot be installed the contents of x86_pmu will not be reverted. Handle the failure in both cases by clearing x86_pmu if init_hw_perf_events() or reverts to software events only. Co-developed-by: Like Xu <likexu@tencent.com> Signed-off-by: Like Xu <likexu@tencent.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
92d80178a3
commit
916e3a4f95
|
@ -2103,14 +2103,15 @@ static int __init init_hw_perf_events(void)
|
||||||
}
|
}
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
pr_cont("no PMU driver, software events only.\n");
|
pr_cont("no PMU driver, software events only.\n");
|
||||||
return 0;
|
err = 0;
|
||||||
|
goto out_bad_pmu;
|
||||||
}
|
}
|
||||||
|
|
||||||
pmu_check_apic();
|
pmu_check_apic();
|
||||||
|
|
||||||
/* sanity check that the hardware exists or is emulated */
|
/* sanity check that the hardware exists or is emulated */
|
||||||
if (!check_hw_exists(&pmu, x86_pmu.num_counters, x86_pmu.num_counters_fixed))
|
if (!check_hw_exists(&pmu, x86_pmu.num_counters, x86_pmu.num_counters_fixed))
|
||||||
return 0;
|
goto out_bad_pmu;
|
||||||
|
|
||||||
pr_cont("%s PMU driver.\n", x86_pmu.name);
|
pr_cont("%s PMU driver.\n", x86_pmu.name);
|
||||||
|
|
||||||
|
@ -2219,6 +2220,8 @@ static int __init init_hw_perf_events(void)
|
||||||
cpuhp_remove_state(CPUHP_AP_PERF_X86_STARTING);
|
cpuhp_remove_state(CPUHP_AP_PERF_X86_STARTING);
|
||||||
out:
|
out:
|
||||||
cpuhp_remove_state(CPUHP_PERF_X86_PREPARE);
|
cpuhp_remove_state(CPUHP_PERF_X86_PREPARE);
|
||||||
|
out_bad_pmu:
|
||||||
|
memset(&x86_pmu, 0, sizeof(x86_pmu));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
early_initcall(init_hw_perf_events);
|
early_initcall(init_hw_perf_events);
|
||||||
|
@ -2990,6 +2993,11 @@ unsigned long perf_misc_flags(struct pt_regs *regs)
|
||||||
|
|
||||||
void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap)
|
void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap)
|
||||||
{
|
{
|
||||||
|
if (!x86_pmu_initialized()) {
|
||||||
|
memset(cap, 0, sizeof(*cap));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
cap->version = x86_pmu.version;
|
cap->version = x86_pmu.version;
|
||||||
/*
|
/*
|
||||||
* KVM doesn't support the hybrid PMU yet.
|
* KVM doesn't support the hybrid PMU yet.
|
||||||
|
|
Loading…
Reference in New Issue