Skip to content

Commit 4d20deb

Browse files
rananta468oupton
authored andcommitted
KVM: arm64: PMU: Set PMCR_EL0.N for vCPU based on the associated PMU
The number of PMU event counters is indicated in PMCR_EL0.N. For a vCPU with PMUv3 configured, the value is set to the same value as the current PE on every vCPU reset. Unless the vCPU is pinned to PEs that has the PMU associated to the guest from the initial vCPU reset, the value might be different from the PMU's PMCR_EL0.N on heterogeneous PMU systems. Fix this by setting the vCPU's PMCR_EL0.N to the PMU's PMCR_EL0.N value. Track the PMCR_EL0.N per guest, as only one PMU can be set for the guest (PMCR_EL0.N must be the same for all vCPUs of the guest), and it is convenient for updating the value. To achieve this, the patch introduces a helper, kvm_arm_pmu_get_max_counters(), that reads the maximum number of counters from the arm_pmu associated to the VM. Make the function global as upcoming patches will be interested to know the value while setting the PMCR.N of the guest from userspace. KVM does not yet support userspace modifying PMCR_EL0.N. The following patch will add support for that. Reviewed-by: Sebastian Ott <[email protected]> Co-developed-by: Marc Zyngier <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Signed-off-by: Reiji Watanabe <[email protected]> Signed-off-by: Raghavendra Rao Ananta <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Oliver Upton <[email protected]>
1 parent 57fc267 commit 4d20deb

File tree

4 files changed

+43
-15
lines changed

4 files changed

+43
-15
lines changed

arch/arm64/include/asm/kvm_host.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,9 @@ struct kvm_arch {
257257

258258
cpumask_var_t supported_cpus;
259259

260+
/* PMCR_EL0.N value for the guest */
261+
u8 pmcr_n;
262+
260263
/* Hypercall features firmware registers' descriptor */
261264
struct kvm_smccc_features smccc_feat;
262265
struct maple_tree smccc_filter;

arch/arm64/kvm/pmu-emul.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -873,11 +873,27 @@ static bool pmu_irq_is_valid(struct kvm *kvm, int irq)
873873
return true;
874874
}
875875

876+
/**
877+
* kvm_arm_pmu_get_max_counters - Return the max number of PMU counters.
878+
* @kvm: The kvm pointer
879+
*/
880+
u8 kvm_arm_pmu_get_max_counters(struct kvm *kvm)
881+
{
882+
struct arm_pmu *arm_pmu = kvm->arch.arm_pmu;
883+
884+
/*
885+
* The arm_pmu->num_events considers the cycle counter as well.
886+
* Ignore that and return only the general-purpose counters.
887+
*/
888+
return arm_pmu->num_events - 1;
889+
}
890+
876891
static void kvm_arm_set_pmu(struct kvm *kvm, struct arm_pmu *arm_pmu)
877892
{
878893
lockdep_assert_held(&kvm->arch.config_lock);
879894

880895
kvm->arch.arm_pmu = arm_pmu;
896+
kvm->arch.pmcr_n = kvm_arm_pmu_get_max_counters(kvm);
881897
}
882898

883899
/**
@@ -1091,5 +1107,8 @@ u8 kvm_arm_pmu_get_pmuver_limit(void)
10911107
*/
10921108
u64 kvm_vcpu_read_pmcr(struct kvm_vcpu *vcpu)
10931109
{
1094-
return __vcpu_sys_reg(vcpu, PMCR_EL0);
1110+
u64 pmcr = __vcpu_sys_reg(vcpu, PMCR_EL0) &
1111+
~(ARMV8_PMU_PMCR_N_MASK << ARMV8_PMU_PMCR_N_SHIFT);
1112+
1113+
return pmcr | ((u64)vcpu->kvm->arch.pmcr_n << ARMV8_PMU_PMCR_N_SHIFT);
10951114
}

arch/arm64/kvm/sys_regs.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -721,12 +721,7 @@ static u64 reset_pmu_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
721721
{
722722
u64 n, mask = BIT(ARMV8_PMU_CYCLE_IDX);
723723

724-
/* No PMU available, any PMU reg may UNDEF... */
725-
if (!kvm_arm_support_pmu_v3())
726-
return 0;
727-
728-
n = read_sysreg(pmcr_el0) >> ARMV8_PMU_PMCR_N_SHIFT;
729-
n &= ARMV8_PMU_PMCR_N_MASK;
724+
n = vcpu->kvm->arch.pmcr_n;
730725
if (n)
731726
mask |= GENMASK(n - 1, 0);
732727

@@ -762,17 +757,15 @@ static u64 reset_pmselr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
762757

763758
static u64 reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
764759
{
765-
u64 pmcr;
760+
u64 pmcr = 0;
766761

767-
/* No PMU available, PMCR_EL0 may UNDEF... */
768-
if (!kvm_arm_support_pmu_v3())
769-
return 0;
770-
771-
/* Only preserve PMCR_EL0.N, and reset the rest to 0 */
772-
pmcr = read_sysreg(pmcr_el0) & (ARMV8_PMU_PMCR_N_MASK << ARMV8_PMU_PMCR_N_SHIFT);
773762
if (!kvm_supports_32bit_el0())
774763
pmcr |= ARMV8_PMU_PMCR_LC;
775764

765+
/*
766+
* The value of PMCR.N field is included when the
767+
* vCPU register is read via kvm_vcpu_read_pmcr().
768+
*/
776769
__vcpu_sys_reg(vcpu, r->reg) = pmcr;
777770

778771
return __vcpu_sys_reg(vcpu, r->reg);
@@ -1103,6 +1096,13 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
11031096
return true;
11041097
}
11051098

1099+
static int get_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
1100+
u64 *val)
1101+
{
1102+
*val = kvm_vcpu_read_pmcr(vcpu);
1103+
return 0;
1104+
}
1105+
11061106
/* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
11071107
#define DBG_BCR_BVR_WCR_WVR_EL1(n) \
11081108
{ SYS_DESC(SYS_DBGBVRn_EL1(n)), \
@@ -2167,7 +2167,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
21672167
{ SYS_DESC(SYS_SVCR), undef_access },
21682168

21692169
{ PMU_SYS_REG(PMCR_EL0), .access = access_pmcr,
2170-
.reset = reset_pmcr, .reg = PMCR_EL0 },
2170+
.reset = reset_pmcr, .reg = PMCR_EL0, .get_user = get_pmcr },
21712171
{ PMU_SYS_REG(PMCNTENSET_EL0),
21722172
.access = access_pmcnten, .reg = PMCNTENSET_EL0 },
21732173
{ PMU_SYS_REG(PMCNTENCLR_EL0),

include/kvm/arm_pmu.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ void kvm_vcpu_pmu_resync_el0(void);
102102

103103
u8 kvm_arm_pmu_get_pmuver_limit(void);
104104
int kvm_arm_set_default_pmu(struct kvm *kvm);
105+
u8 kvm_arm_pmu_get_max_counters(struct kvm *kvm);
105106

106107
u64 kvm_vcpu_read_pmcr(struct kvm_vcpu *vcpu);
107108
#else
@@ -181,6 +182,11 @@ static inline int kvm_arm_set_default_pmu(struct kvm *kvm)
181182
return -ENODEV;
182183
}
183184

185+
static inline u8 kvm_arm_pmu_get_max_counters(struct kvm *kvm)
186+
{
187+
return 0;
188+
}
189+
184190
static inline u64 kvm_vcpu_read_pmcr(struct kvm_vcpu *vcpu)
185191
{
186192
return 0;

0 commit comments

Comments
 (0)