162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2015 Linaro Ltd.
462306a36Sopenharmony_ci * Author: Shannon Zhao <shannon.zhao@linaro.org>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#ifndef __ASM_ARM_KVM_PMU_H
862306a36Sopenharmony_ci#define __ASM_ARM_KVM_PMU_H
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/perf_event.h>
1162306a36Sopenharmony_ci#include <linux/perf/arm_pmuv3.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define ARMV8_PMU_CYCLE_IDX		(ARMV8_PMU_MAX_COUNTERS - 1)
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_HW_PERF_EVENTS) && IS_ENABLED(CONFIG_KVM)
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistruct kvm_pmc {
1862306a36Sopenharmony_ci	u8 idx;	/* index into the pmu->pmc array */
1962306a36Sopenharmony_ci	struct perf_event *perf_event;
2062306a36Sopenharmony_ci};
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistruct kvm_pmu_events {
2362306a36Sopenharmony_ci	u32 events_host;
2462306a36Sopenharmony_ci	u32 events_guest;
2562306a36Sopenharmony_ci};
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistruct kvm_pmu {
2862306a36Sopenharmony_ci	struct irq_work overflow_work;
2962306a36Sopenharmony_ci	struct kvm_pmu_events events;
3062306a36Sopenharmony_ci	struct kvm_pmc pmc[ARMV8_PMU_MAX_COUNTERS];
3162306a36Sopenharmony_ci	int irq_num;
3262306a36Sopenharmony_ci	bool created;
3362306a36Sopenharmony_ci	bool irq_level;
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistruct arm_pmu_entry {
3762306a36Sopenharmony_ci	struct list_head entry;
3862306a36Sopenharmony_ci	struct arm_pmu *arm_pmu;
3962306a36Sopenharmony_ci};
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ciDECLARE_STATIC_KEY_FALSE(kvm_arm_pmu_available);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic __always_inline bool kvm_arm_support_pmu_v3(void)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	return static_branch_likely(&kvm_arm_pmu_available);
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define kvm_arm_pmu_irq_initialized(v)	((v)->arch.pmu.irq_num >= VGIC_NR_SGIS)
4962306a36Sopenharmony_ciu64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
5062306a36Sopenharmony_civoid kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val);
5162306a36Sopenharmony_ciu64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu);
5262306a36Sopenharmony_ciu64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1);
5362306a36Sopenharmony_civoid kvm_pmu_vcpu_init(struct kvm_vcpu *vcpu);
5462306a36Sopenharmony_civoid kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu);
5562306a36Sopenharmony_civoid kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu);
5662306a36Sopenharmony_civoid kvm_pmu_disable_counter_mask(struct kvm_vcpu *vcpu, u64 val);
5762306a36Sopenharmony_civoid kvm_pmu_enable_counter_mask(struct kvm_vcpu *vcpu, u64 val);
5862306a36Sopenharmony_civoid kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
5962306a36Sopenharmony_civoid kvm_pmu_sync_hwstate(struct kvm_vcpu *vcpu);
6062306a36Sopenharmony_cibool kvm_pmu_should_notify_user(struct kvm_vcpu *vcpu);
6162306a36Sopenharmony_civoid kvm_pmu_update_run(struct kvm_vcpu *vcpu);
6262306a36Sopenharmony_civoid kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val);
6362306a36Sopenharmony_civoid kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val);
6462306a36Sopenharmony_civoid kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
6562306a36Sopenharmony_ci				    u64 select_idx);
6662306a36Sopenharmony_ciint kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu,
6762306a36Sopenharmony_ci			    struct kvm_device_attr *attr);
6862306a36Sopenharmony_ciint kvm_arm_pmu_v3_get_attr(struct kvm_vcpu *vcpu,
6962306a36Sopenharmony_ci			    struct kvm_device_attr *attr);
7062306a36Sopenharmony_ciint kvm_arm_pmu_v3_has_attr(struct kvm_vcpu *vcpu,
7162306a36Sopenharmony_ci			    struct kvm_device_attr *attr);
7262306a36Sopenharmony_ciint kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistruct kvm_pmu_events *kvm_get_pmu_events(void);
7562306a36Sopenharmony_civoid kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu);
7662306a36Sopenharmony_civoid kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu);
7762306a36Sopenharmony_civoid kvm_vcpu_pmu_resync_el0(void);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci#define kvm_vcpu_has_pmu(vcpu)					\
8062306a36Sopenharmony_ci	(test_bit(KVM_ARM_VCPU_PMU_V3, (vcpu)->arch.features))
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/*
8362306a36Sopenharmony_ci * Updates the vcpu's view of the pmu events for this cpu.
8462306a36Sopenharmony_ci * Must be called before every vcpu run after disabling interrupts, to ensure
8562306a36Sopenharmony_ci * that an interrupt cannot fire and update the structure.
8662306a36Sopenharmony_ci */
8762306a36Sopenharmony_ci#define kvm_pmu_update_vcpu_events(vcpu)				\
8862306a36Sopenharmony_ci	do {								\
8962306a36Sopenharmony_ci		if (!has_vhe() && kvm_vcpu_has_pmu(vcpu))		\
9062306a36Sopenharmony_ci			vcpu->arch.pmu.events = *kvm_get_pmu_events();	\
9162306a36Sopenharmony_ci	} while (0)
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/*
9462306a36Sopenharmony_ci * Evaluates as true when emulating PMUv3p5, and false otherwise.
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_ci#define kvm_pmu_is_3p5(vcpu) ({						\
9762306a36Sopenharmony_ci	u64 val = IDREG(vcpu->kvm, SYS_ID_AA64DFR0_EL1);		\
9862306a36Sopenharmony_ci	u8 pmuver = SYS_FIELD_GET(ID_AA64DFR0_EL1, PMUVer, val);	\
9962306a36Sopenharmony_ci									\
10062306a36Sopenharmony_ci	pmuver >= ID_AA64DFR0_EL1_PMUVer_V3P5;				\
10162306a36Sopenharmony_ci})
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ciu8 kvm_arm_pmu_get_pmuver_limit(void);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#else
10662306a36Sopenharmony_cistruct kvm_pmu {
10762306a36Sopenharmony_ci};
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic inline bool kvm_arm_support_pmu_v3(void)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	return false;
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define kvm_arm_pmu_irq_initialized(v)	(false)
11562306a36Sopenharmony_cistatic inline u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu,
11662306a36Sopenharmony_ci					    u64 select_idx)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	return 0;
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_cistatic inline void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu,
12162306a36Sopenharmony_ci					     u64 select_idx, u64 val) {}
12262306a36Sopenharmony_cistatic inline u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	return 0;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_cistatic inline void kvm_pmu_vcpu_init(struct kvm_vcpu *vcpu) {}
12762306a36Sopenharmony_cistatic inline void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu) {}
12862306a36Sopenharmony_cistatic inline void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu) {}
12962306a36Sopenharmony_cistatic inline void kvm_pmu_disable_counter_mask(struct kvm_vcpu *vcpu, u64 val) {}
13062306a36Sopenharmony_cistatic inline void kvm_pmu_enable_counter_mask(struct kvm_vcpu *vcpu, u64 val) {}
13162306a36Sopenharmony_cistatic inline void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
13262306a36Sopenharmony_cistatic inline void kvm_pmu_sync_hwstate(struct kvm_vcpu *vcpu) {}
13362306a36Sopenharmony_cistatic inline bool kvm_pmu_should_notify_user(struct kvm_vcpu *vcpu)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	return false;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_cistatic inline void kvm_pmu_update_run(struct kvm_vcpu *vcpu) {}
13862306a36Sopenharmony_cistatic inline void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) {}
13962306a36Sopenharmony_cistatic inline void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val) {}
14062306a36Sopenharmony_cistatic inline void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu,
14162306a36Sopenharmony_ci						  u64 data, u64 select_idx) {}
14262306a36Sopenharmony_cistatic inline int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu,
14362306a36Sopenharmony_ci					  struct kvm_device_attr *attr)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	return -ENXIO;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_cistatic inline int kvm_arm_pmu_v3_get_attr(struct kvm_vcpu *vcpu,
14862306a36Sopenharmony_ci					  struct kvm_device_attr *attr)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	return -ENXIO;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_cistatic inline int kvm_arm_pmu_v3_has_attr(struct kvm_vcpu *vcpu,
15362306a36Sopenharmony_ci					  struct kvm_device_attr *attr)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	return -ENXIO;
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_cistatic inline int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	return 0;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_cistatic inline u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	return 0;
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci#define kvm_vcpu_has_pmu(vcpu)		({ false; })
16762306a36Sopenharmony_ci#define kvm_pmu_is_3p5(vcpu)		({ false; })
16862306a36Sopenharmony_cistatic inline void kvm_pmu_update_vcpu_events(struct kvm_vcpu *vcpu) {}
16962306a36Sopenharmony_cistatic inline void kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu) {}
17062306a36Sopenharmony_cistatic inline void kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu) {}
17162306a36Sopenharmony_cistatic inline u8 kvm_arm_pmu_get_pmuver_limit(void)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	return 0;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_cistatic inline void kvm_vcpu_pmu_resync_el0(void) {}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci#endif
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci#endif
180