[PATCH v6 16/19] KVM: arm64: Add vCPU device attr to partition the PMU
Colton Lewis
coltonlewis at google.com
Thu Mar 12 15:13:40 PDT 2026
Thanks James for the review.
James Clark <james.clark at linaro.org> writes:
> On 09/02/2026 10:14 pm, Colton Lewis wrote:
>> Add a new PMU device attr to enable the partitioned PMU for a given
>> VM. This capability can be set when the PMU is initially configured
>> before the vCPU starts running and is allowed where PMUv3 and VHE are
>> supported and the host driver was configured with
>> arm_pmuv3.reserved_host_counters.
>> The enabled capability is tracked by the new flag
>> KVM_ARCH_FLAG_PARTITIONED_PMU_ENABLED.
> Typo, should be: KVM_ARCH_FLAG_PARTITION_PMU_ENABLED. Or maybe the
> #define should be fixed.
Stale commit message. I will fix.
> I couldn't see if this was discussed before, but what's the reason to
> not use the guest partition by default and make this flag control
> reverting back to use the non passed through PMU?
> Seems like if you already have to enable it by creating a partition on
> the host, then you more than likely want your guests to use it. And it's
> lower overhead so it's "better". Right now it's two things that you have
> to set at the same time to do one thing.
> Or does having to set it on the host go away with the dynamic approach
> here [1]?
Yes, the plan is to have it go away on the host with a dynamic approach.
> [1]: https://lore.kernel.org/kvmarm/aWjlfl85vSd6sMwT@willie-the-truck/
>> Signed-off-by: Colton Lewis <coltonlewis at google.com>
>> ---
>> arch/arm64/include/asm/kvm_host.h | 2 ++
>> arch/arm64/include/uapi/asm/kvm.h | 2 ++
>> arch/arm64/kvm/pmu-direct.c | 35 ++++++++++++++++++++++++++++---
>> arch/arm64/kvm/pmu.c | 14 +++++++++++++
>> include/kvm/arm_pmu.h | 9 ++++++++
>> 5 files changed, 59 insertions(+), 3 deletions(-)
>> diff --git a/arch/arm64/include/asm/kvm_host.h
>> b/arch/arm64/include/asm/kvm_host.h
>> index 41577ede0254f..f0b0a5edc7252 100644
>> --- a/arch/arm64/include/asm/kvm_host.h
>> +++ b/arch/arm64/include/asm/kvm_host.h
>> @@ -353,6 +353,8 @@ struct kvm_arch {
>> #define KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS 10
>> /* Unhandled SEAs are taken to userspace */
>> #define KVM_ARCH_FLAG_EXIT_SEA 11
>> + /* Partitioned PMU Enabled */
>> +#define KVM_ARCH_FLAG_PARTITION_PMU_ENABLED 12
>> unsigned long flags;
>> /* VM-wide vCPU feature set */
>> diff --git a/arch/arm64/include/uapi/asm/kvm.h
>> b/arch/arm64/include/uapi/asm/kvm.h
>> index a792a599b9d68..3e0b7619f781d 100644
>> --- a/arch/arm64/include/uapi/asm/kvm.h
>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>> @@ -436,6 +436,8 @@ enum {
>> #define KVM_ARM_VCPU_PMU_V3_FILTER 2
>> #define KVM_ARM_VCPU_PMU_V3_SET_PMU 3
>> #define KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS 4
>> +#define KVM_ARM_VCPU_PMU_V3_ENABLE_PARTITION 5
>> +
>> #define KVM_ARM_VCPU_TIMER_CTRL 1
>> #define KVM_ARM_VCPU_TIMER_IRQ_VTIMER 0
>> #define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1
>> diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
>> index 6ebb59d2aa0e7..1dbf50b8891f6 100644
>> --- a/arch/arm64/kvm/pmu-direct.c
>> +++ b/arch/arm64/kvm/pmu-direct.c
>> @@ -44,8 +44,8 @@ bool kvm_pmu_is_partitioned(struct arm_pmu *pmu)
>> }
>> /**
>> - * kvm_vcpu_pmu_is_partitioned() - Determine if given VCPU has a
>> partitioned PMU
>> - * @vcpu: Pointer to kvm_vcpu struct
>> + * kvm_pmu_is_partitioned() - Determine if given VCPU has a partitioned
>> PMU
>> + * @kvm: Pointer to kvm_vcpu struct
>> *
>> * Determine if given VCPU has a partitioned PMU by extracting that
>> * field and passing it to :c:func:`kvm_pmu_is_partitioned`
>> @@ -55,7 +55,36 @@ bool kvm_pmu_is_partitioned(struct arm_pmu *pmu)
>> bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu)
>> {
>> return kvm_pmu_is_partitioned(vcpu->kvm->arch.arm_pmu) &&
>> - false;
>> + test_bit(KVM_ARCH_FLAG_PARTITION_PMU_ENABLED, &vcpu->kvm->arch.flags);
>> +}
>> +
>> +/**
>> + * has_kvm_pmu_partition_support() - If we can enable/disable partition
>> + *
>> + * Return: true if allowed, false otherwise.
>> + */
>> +bool has_kvm_pmu_partition_support(void)
>> +{
>> + return has_host_pmu_partition_support() &&
>> + kvm_supports_guest_pmuv3() &&
>> + armv8pmu_max_guest_counters > -1;
>> +}
>> +
>> +/**
>> + * kvm_pmu_partition_enable() - Enable/disable partition flag
>> + * @kvm: Pointer to vcpu
>> + * @enable: Whether to enable or disable
>> + *
>> + * If we want to enable the partition, the guest is free to grab
>> + * hardware by accessing PMU registers. Otherwise, the host maintains
>> + * control.
>> + */
>> +void kvm_pmu_partition_enable(struct kvm *kvm, bool enable)
>> +{
>> + if (enable)
>> + set_bit(KVM_ARCH_FLAG_PARTITION_PMU_ENABLED, &kvm->arch.flags);
>> + else
>> + clear_bit(KVM_ARCH_FLAG_PARTITION_PMU_ENABLED, &kvm->arch.flags);
>> }
>> /**
>> diff --git a/arch/arm64/kvm/pmu.c b/arch/arm64/kvm/pmu.c
>> index 72d5b7cb3d93e..cdf51f24fdaf3 100644
>> --- a/arch/arm64/kvm/pmu.c
>> +++ b/arch/arm64/kvm/pmu.c
>> @@ -759,6 +759,19 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu,
>> struct kvm_device_attr *attr)
>> return kvm_arm_pmu_v3_set_nr_counters(vcpu, n);
>> }
>> + case KVM_ARM_VCPU_PMU_V3_ENABLE_PARTITION: {
>> + unsigned int __user *uaddr = (unsigned int __user *)(long)attr->addr;
>> + bool enable;
>> +
>> + if (get_user(enable, uaddr))
>> + return -EFAULT;
>> +
>> + if (!has_kvm_pmu_partition_support())
>> + return -EPERM;
>> +
>> + kvm_pmu_partition_enable(kvm, enable);
>> + return 0;
>> + }
>> case KVM_ARM_VCPU_PMU_V3_INIT:
>> return kvm_arm_pmu_v3_init(vcpu);
>> }
>> @@ -798,6 +811,7 @@ int kvm_arm_pmu_v3_has_attr(struct kvm_vcpu *vcpu,
>> struct kvm_device_attr *attr)
>> case KVM_ARM_VCPU_PMU_V3_FILTER:
>> case KVM_ARM_VCPU_PMU_V3_SET_PMU:
>> case KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS:
>> + case KVM_ARM_VCPU_PMU_V3_ENABLE_PARTITION:
>> if (kvm_vcpu_has_pmu(vcpu))
>> return 0;
>> }
>> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
>> index 93586691a2790..ff898370fa63f 100644
>> --- a/include/kvm/arm_pmu.h
>> +++ b/include/kvm/arm_pmu.h
>> @@ -109,6 +109,8 @@ void kvm_pmu_load(struct kvm_vcpu *vcpu);
>> void kvm_pmu_put(struct kvm_vcpu *vcpu);
>> void kvm_pmu_set_physical_access(struct kvm_vcpu *vcpu);
>> +bool has_kvm_pmu_partition_support(void);
>> +void kvm_pmu_partition_enable(struct kvm *kvm, bool enable);
>> #if !defined(__KVM_NVHE_HYPERVISOR__)
>> bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu);
>> @@ -311,6 +313,13 @@ static inline void
>> kvm_pmu_host_counters_enable(void) {}
>> static inline void kvm_pmu_host_counters_disable(void) {}
>> static inline void kvm_pmu_handle_guest_irq(struct arm_pmu *pmu, u64
>> pmovsr) {}
>> +static inline bool has_kvm_pmu_partition_support(void)
>> +{
>> + return false;
>> +}
>> +
>> +static inline void kvm_pmu_partition_enable(struct kvm *kvm, bool
>> enable) {}
>> +
>> #endif
>> #endif
More information about the linux-arm-kernel
mailing list