On Fri, Jun 20, 2025 at 10:13:07PM +0000, Colton Lewis wrote:
For PMUv3, the register field MDCR_EL2.HPMN partitiones the PMU counters into two ranges where counters 0..HPMN-1 are accessible by EL1 and, if allowed, EL0 while counters HPMN..N are only accessible by EL2.
Create module parameters partition_pmu and reserved_guest_counters to reserve a number of counters for the guest. These numbers are set at boot because the perf subsystem assumes the number of counters will not change after the PMU is probed.
Introduce the function armv8pmu_partition() to modify the PMU driver's cntr_mask of available counters to exclude the counters being reserved for the guest and record reserved_guest_counters as the maximum allowable value for HPMN.
Due to the difficulty this feature would create for the driver running at EL1 on the host, partitioning is only allowed in VHE mode. Working on nVHE mode would require a hypercall for every counter access in the driver because the counters reserved for the host by HPMN are only accessible to EL2.
Signed-off-by: Colton Lewis coltonlewis@google.com
arch/arm/include/asm/arm_pmuv3.h | 10 ++++ arch/arm64/include/asm/arm_pmuv3.h | 5 ++ drivers/perf/arm_pmuv3.c | 95 +++++++++++++++++++++++++++++- include/linux/perf/arm_pmu.h | 1 + 4 files changed, 109 insertions(+), 2 deletions(-)
diff --git a/arch/arm/include/asm/arm_pmuv3.h b/arch/arm/include/asm/arm_pmuv3.h index 2ec0e5e83fc9..9dc43242538c 100644 --- a/arch/arm/include/asm/arm_pmuv3.h +++ b/arch/arm/include/asm/arm_pmuv3.h @@ -228,6 +228,11 @@ static inline bool kvm_set_pmuserenr(u64 val) static inline void kvm_vcpu_pmu_resync_el0(void) {} +static inline bool has_vhe(void) +{
- return false;
+}
This has nothing to do with PMUv3, I'm a bit surprised to see you're touching 32-bit ARM. Can you just gate the whole partitioning thing on arm64?
+static bool partition_pmu __read_mostly; +static u8 reserved_guest_counters __read_mostly;
+module_param(partition_pmu, bool, 0); +MODULE_PARM_DESC(partition_pmu,
"Partition the PMU into host and guest VM counters [y/n]");
+module_param(reserved_guest_counters, byte, 0); +MODULE_PARM_DESC(reserved_guest_counters,
"How many counters to reserve for guest VMs [0-$NR_COUNTERS]");
This is confusing and not what we discussed offline.
Please use a single parameter that describes the number of counters used by the *host*. This affects the *host* PMU driver, KVM can discover (and use) the leftovers.
If the single module parameter goes unspecified the user did not ask for PMU partitioning.
+/**
- armv8pmu_reservation_is_valid() - Determine if reservation is allowed
- @guest_counters: Number of host counters to reserve
- Determine if the number of host counters in the argument is
- allowed. It is allowed if it will produce a valid value for
- register field MDCR_EL2.HPMN.
- Return: True if reservation allowed, false otherwise
- */
+static bool armv8pmu_reservation_is_valid(u8 guest_counters) +{
- return guest_counters <= armv8pmu_pmcr_n_read();
+}
+/**
- armv8pmu_partition_supported() - Determine if partitioning is possible
- Partitioning is only supported in VHE mode (with PMUv3, assumed
- since we are in the PMUv3 driver)
- Return: True if partitioning is possible, false otherwise
- */
+static bool armv8pmu_partition_supported(void) +{
- return has_vhe();
+}
+/**
- armv8pmu_partition() - Partition the PMU
- @pmu: Pointer to pmu being partitioned
- @guest_counters: Number of host counters to reserve
- Partition the given PMU by taking a number of host counters to
- reserve and, if it is a valid reservation, recording the
- corresponding HPMN value in the hpmn field of the PMU and clearing
- the guest-reserved counters from the counter mask.
- Passing 0 for @guest_counters has the effect of disabling partitioning.
- Return: 0 on success, -ERROR otherwise
- */
+static int armv8pmu_partition(struct arm_pmu *pmu, u8 guest_counters) +{
- u8 nr_counters;
- u8 hpmn;
- if (!armv8pmu_reservation_is_valid(guest_counters))
return -EINVAL;
- nr_counters = armv8pmu_pmcr_n_read();
- hpmn = guest_counters;
- pmu->hpmn_max = hpmn;
I'm not sure the host driver needs this for anything, KVM just needs to know what's potentially in use by the host.
- /* Inform host driver of available counters */
... said the driver to itself :)
Thanks, Oliver