[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