forked from Minki/linux
6b5b368fcc
We currently find out about the presence of a HW PMU (or the handling of that PMU by perf, which amounts to the same thing) in a fairly roundabout way, by checking the number of counters available to perf. That's good enough for now, but we will soon need to find about about that on paths where perf is out of reach (in the world switch). Instead, let's turn kvm_arm_support_pmu_v3() into a static key. Signed-off-by: Marc Zyngier <maz@kernel.org> Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com> Link: https://lore.kernel.org/r/20210209114844.3278746-2-maz@kernel.org Message-Id: <20210305185254.3730990-5-maz@kernel.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
68 lines
1.3 KiB
C
68 lines
1.3 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Based on the x86 implementation.
|
|
*
|
|
* Copyright (C) 2012 ARM Ltd.
|
|
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
|
*/
|
|
|
|
#include <linux/perf_event.h>
|
|
#include <linux/kvm_host.h>
|
|
|
|
#include <asm/kvm_emulate.h>
|
|
|
|
DEFINE_STATIC_KEY_FALSE(kvm_arm_pmu_available);
|
|
|
|
static int kvm_is_in_guest(void)
|
|
{
|
|
return kvm_get_running_vcpu() != NULL;
|
|
}
|
|
|
|
static int kvm_is_user_mode(void)
|
|
{
|
|
struct kvm_vcpu *vcpu;
|
|
|
|
vcpu = kvm_get_running_vcpu();
|
|
|
|
if (vcpu)
|
|
return !vcpu_mode_priv(vcpu);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static unsigned long kvm_get_guest_ip(void)
|
|
{
|
|
struct kvm_vcpu *vcpu;
|
|
|
|
vcpu = kvm_get_running_vcpu();
|
|
|
|
if (vcpu)
|
|
return *vcpu_pc(vcpu);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct perf_guest_info_callbacks kvm_guest_cbs = {
|
|
.is_in_guest = kvm_is_in_guest,
|
|
.is_user_mode = kvm_is_user_mode,
|
|
.get_guest_ip = kvm_get_guest_ip,
|
|
};
|
|
|
|
int kvm_perf_init(void)
|
|
{
|
|
/*
|
|
* Check if HW_PERF_EVENTS are supported by checking the number of
|
|
* hardware performance counters. This could ensure the presence of
|
|
* a physical PMU and CONFIG_PERF_EVENT is selected.
|
|
*/
|
|
if (IS_ENABLED(CONFIG_ARM_PMU) && perf_num_counters() > 0)
|
|
static_branch_enable(&kvm_arm_pmu_available);
|
|
|
|
return perf_register_guest_info_callbacks(&kvm_guest_cbs);
|
|
}
|
|
|
|
int kvm_perf_teardown(void)
|
|
{
|
|
return perf_unregister_guest_info_callbacks(&kvm_guest_cbs);
|
|
}
|