Commit 916e3a4f authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

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: default avatarLike Xu <likexu@tencent.com>
Signed-off-by: default avatarLike Xu <likexu@tencent.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 92d80178
Loading
Loading
Loading
Loading
+10 −2
Original line number Diff line number Diff line
@@ -2103,14 +2103,15 @@ static int __init init_hw_perf_events(void)
	}
	if (err != 0) {
		pr_cont("no PMU driver, software events only.\n");
		return 0;
		err = 0;
		goto out_bad_pmu;
	}

	pmu_check_apic();

	/* sanity check that the hardware exists or is emulated */
	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);

@@ -2219,6 +2220,8 @@ static int __init init_hw_perf_events(void)
	cpuhp_remove_state(CPUHP_AP_PERF_X86_STARTING);
out:
	cpuhp_remove_state(CPUHP_PERF_X86_PREPARE);
out_bad_pmu:
	memset(&x86_pmu, 0, sizeof(x86_pmu));
	return err;
}
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)
{
	if (!x86_pmu_initialized()) {
		memset(cap, 0, sizeof(*cap));
		return;
	}

	cap->version		= x86_pmu.version;
	/*
	 * KVM doesn't support the hybrid PMU yet.