From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 5C4CEE9461F for ; Mon, 9 Feb 2026 22:41:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type:Cc:To:From: Subject:Message-ID:References:Mime-Version:In-Reply-To:Date:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=TTgLU/vlu0rEnv4svs9zdi9v/ds5aA8zfTq/qKcEnmk=; b=KdRwHEDzmrweV/lpAGU9vsDTH6 3bPyW6aQN35tsIPR+cACOTH71xY2vzG9sMWGrE3VcrFVWKx7rJzNhTUwDMv8B9NeqDEXbf45sNN8T ZSbl5qQZOL8VimzgkpfY2tuQlafw6iOSYqCEt+FuYVm0eDRleow6tn/Zg6mG5ZsfXZOum094szIQW JOyDVtaQvnBAksOvsj+GE1LhbZapM2itwaRfDzVTYp0ZvthJ4CqrjF4VR6TqlP4A4FjJKJrufD9cA XlJHTOswBIn4sf1G5IYe5OE4HDgHA3jUpBPKXgv93+eaex2CO7gA6cC4o0skWmUz6Q/2o9Lu7PyZW 6z9BZ0+Q==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) id 1vpZwP-0000000G7eK-0LVH; Mon, 09 Feb 2026 22:41:13 +0000 Received: from mail-ot1-x34a.google.com ([2607:f8b0:4864:20::34a]) by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) id 1vpZwB-0000000G7Op-29JJ for linux-arm-kernel@lists.infradead.org; Mon, 09 Feb 2026 22:41:04 +0000 Received: by mail-ot1-x34a.google.com with SMTP id 46e09a7af769-7cfd69f74e2so10619197a34.1 for ; Mon, 09 Feb 2026 14:40:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1770676858; x=1771281658; darn=lists.infradead.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=TTgLU/vlu0rEnv4svs9zdi9v/ds5aA8zfTq/qKcEnmk=; b=JhtutCHl+XZuunClW+iVwgv/y21WBdFjFuJRzyMmFE3DdGNJHSfT70ClQg/XG7biLs ikIz/fwipXarSw3Gy6lfmi5kriVmutkivMrF9v3kFTQLoWH0C9qR8wOWTYePVJJifMLU +zAxUqokbVairAzbxPotqw0U36pM0Mpcan/cR0R3KluKlyht3qJfXwr29YK5o35R9gOd o2pArpIQMS96gTLz41Mb/9xFTZrHHNcEXkeUvJf3GU0mZTBJcmrELESkcFfZHnsOEqIo dWIcwl0Z+WnyzRaU91+xk156zz/ibX+MhUta2w0Lr/2E95P1fbFJ/EJX79bAymh5Zsrl B4qg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770676858; x=1771281658; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=TTgLU/vlu0rEnv4svs9zdi9v/ds5aA8zfTq/qKcEnmk=; b=seY0zfa0QLju7TzGhq4kwRR8npU2/DHwUgtxwBT67jG34acJM/9SF7cXrOD3zSWBnK kmuGTcoA8m2WRH1vQC014slouSJGcOJdH3o96pOD19EoFYfn5Yh4qnBak8bCpgukIic6 3LTzhwKDfLLNtWMSSD75IzBuWd4z/PDUNbLypVfbVkLhwmWEYBwOeGM8aSGlSZ3xME2L 8KqbOIbgjLmsXw9vnqE7a9825Xb24Yy6yG/PjZSrlFMdkgv7HxmHIl81xAZKE4PzRaEj mXBTHOX7+aECF2f2E5QcEC7wqGjVpUmzaXtxOhW3xhbYURzo8hG8i3fTUXmGINR5ecS4 c6wQ== X-Forwarded-Encrypted: i=1; AJvYcCWEBlzP8tT0ZlD9h4TL7H7ow25FvX2O18yPNaL7mPwlmb2HcE77/rlcm+HldVwgy4iGjnD5Bu8poPTckkKrxHFM@lists.infradead.org X-Gm-Message-State: AOJu0YxJSAPd0gzVzR66lxEqFXF7kjZXr2AqNl1/svOSDcxit92YLX6a C0ZLQWVoR6UgofnOTitqf/pJdlEhxkULTf3S1ju0TU6YfFa7TTyTted2hbf7rBhHDtg8ScE3YsP 9GSYaJp7d9wPoD9OgLyO2+6IxTQ== X-Received: from iorw25.prod.google.com ([2002:a5d:8459:0:b0:957:5e45:b59b]) (user=coltonlewis job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6820:806:b0:662:fb1b:ff9e with SMTP id 006d021491bc7-66d0c94e605mr6655176eaf.69.1770676857913; Mon, 09 Feb 2026 14:40:57 -0800 (PST) Date: Mon, 9 Feb 2026 22:14:08 +0000 In-Reply-To: <20260209221414.2169465-1-coltonlewis@google.com> Mime-Version: 1.0 References: <20260209221414.2169465-1-coltonlewis@google.com> X-Mailer: git-send-email 2.53.0.rc2.204.g2597b5adb4-goog Message-ID: <20260209221414.2169465-14-coltonlewis@google.com> Subject: [PATCH v6 13/19] KVM: arm64: Implement lazy PMU context swaps From: Colton Lewis To: kvm@vger.kernel.org Cc: Alexandru Elisei , Paolo Bonzini , Jonathan Corbet , Russell King , Catalin Marinas , Will Deacon , Marc Zyngier , Oliver Upton , Mingwei Zhang , Joey Gouly , Suzuki K Poulose , Zenghui Yu , Mark Rutland , Shuah Khan , Ganapatrao Kulkarni , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, linux-perf-users@vger.kernel.org, linux-kselftest@vger.kernel.org, Colton Lewis Content-Type: text/plain; charset="UTF-8" X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20260209_144059_560777_B0CCB381 X-CRM114-Status: GOOD ( 19.74 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Since many guests will never touch the PMU, they need not pay the cost of context swapping those registers. Use an enum to implement a simple state machine for PMU register access. The PMU is either free or guest owned. We only need to context swap if the PMU registers are guest owned. The PMU initially starts as free and only transitions to guest owned if a guest has touched the PMU registers. Signed-off-by: Colton Lewis --- arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/include/asm/kvm_types.h | 6 +++++- arch/arm64/kvm/debug.c | 2 +- arch/arm64/kvm/hyp/vhe/switch.c | 2 ++ arch/arm64/kvm/pmu-direct.c | 26 ++++++++++++++++++++++++-- include/kvm/arm_pmu.h | 5 +++++ 6 files changed, 38 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 8e09865490a9f..41577ede0254f 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -1377,6 +1377,7 @@ static inline bool kvm_system_needs_idmapped_vectors(void) return cpus_have_final_cap(ARM64_SPECTRE_V3A); } +void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu); void kvm_init_host_debug_data(void); void kvm_debug_init_vhe(void); void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu); diff --git a/arch/arm64/include/asm/kvm_types.h b/arch/arm64/include/asm/kvm_types.h index 9a126b9e2d7c9..4e39cbc80aa0b 100644 --- a/arch/arm64/include/asm/kvm_types.h +++ b/arch/arm64/include/asm/kvm_types.h @@ -4,5 +4,9 @@ #define KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE 40 -#endif /* _ASM_ARM64_KVM_TYPES_H */ +enum vcpu_pmu_register_access { + VCPU_PMU_ACCESS_FREE, + VCPU_PMU_ACCESS_GUEST_OWNED, +}; +#endif /* _ASM_ARM64_KVM_TYPES_H */ diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index 0ab89c91e19cb..c2cf6b308ec60 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -34,7 +34,7 @@ static int cpu_has_spe(u64 dfr0) * - Self-hosted Trace Filter controls (MDCR_EL2_TTRF) * - Self-hosted Trace (MDCR_EL2_TTRF/MDCR_EL2_E2TB) */ -static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu) +void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu) { int hpmn = kvm_pmu_hpmn(vcpu); diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c index 154da70146d98..b374308e786d7 100644 --- a/arch/arm64/kvm/hyp/vhe/switch.c +++ b/arch/arm64/kvm/hyp/vhe/switch.c @@ -524,6 +524,8 @@ static bool kvm_hyp_handle_pmu_regs(struct kvm_vcpu *vcpu) val = vcpu_get_reg(vcpu, rt); nr_cnt = vcpu->kvm->arch.nr_pmu_counters; + kvm_pmu_set_physical_access(vcpu); + switch (sysreg) { case SYS_PMCR_EL0: mask = ARMV8_PMU_PMCR_MASK; diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c index 4bcacc55c507f..11fae54cd6534 100644 --- a/arch/arm64/kvm/pmu-direct.c +++ b/arch/arm64/kvm/pmu-direct.c @@ -72,10 +72,30 @@ bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu) u8 hpmn = vcpu->kvm->arch.nr_pmu_counters; return kvm_vcpu_pmu_is_partitioned(vcpu) && + vcpu->arch.pmu.access == VCPU_PMU_ACCESS_GUEST_OWNED && cpus_have_final_cap(ARM64_HAS_FGT) && (hpmn != 0 || cpus_have_final_cap(ARM64_HAS_HPMN0)); } +/** + * kvm_pmu_set_physical_access() + * @vcpu: Pointer to vcpu struct + * + * Reconfigure the guest for physical access of PMU hardware if + * allowed. This means reconfiguring mdcr_el2 and loading the vCPU + * state onto hardware. + * + */ + +void kvm_pmu_set_physical_access(struct kvm_vcpu *vcpu) +{ + if (kvm_vcpu_pmu_is_partitioned(vcpu) + && vcpu->arch.pmu.access == VCPU_PMU_ACCESS_FREE) { + vcpu->arch.pmu.access = VCPU_PMU_ACCESS_GUEST_OWNED; + kvm_arm_setup_mdcr_el2(vcpu); + } +} + /** * kvm_pmu_host_counter_mask() - Compute bitmask of host-reserved counters * @pmu: Pointer to arm_pmu struct @@ -232,7 +252,8 @@ void kvm_pmu_load(struct kvm_vcpu *vcpu) * If we aren't guest-owned then we know the guest isn't using * the PMU anyway, so no need to bother with the swap. */ - if (!kvm_vcpu_pmu_is_partitioned(vcpu)) + if (!kvm_vcpu_pmu_is_partitioned(vcpu) || + vcpu->arch.pmu.access != VCPU_PMU_ACCESS_GUEST_OWNED) return; preempt_disable(); @@ -302,7 +323,8 @@ void kvm_pmu_put(struct kvm_vcpu *vcpu) * accessing the PMU anyway, so no need to bother with the * swap. */ - if (!kvm_vcpu_pmu_is_partitioned(vcpu)) + if (!kvm_vcpu_pmu_is_partitioned(vcpu) || + vcpu->arch.pmu.access != VCPU_PMU_ACCESS_GUEST_OWNED) return; preempt_disable(); diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h index 93ccda941aa46..82665d54258df 100644 --- a/include/kvm/arm_pmu.h +++ b/include/kvm/arm_pmu.h @@ -7,6 +7,7 @@ #ifndef __ASM_ARM_KVM_PMU_H #define __ASM_ARM_KVM_PMU_H +#include #include #include #include @@ -40,6 +41,7 @@ struct kvm_pmu { int irq_num; bool created; bool irq_level; + enum vcpu_pmu_register_access access; }; struct arm_pmu_entry { @@ -103,6 +105,8 @@ u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu); 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); + #if !defined(__KVM_NVHE_HYPERVISOR__) bool kvm_vcpu_pmu_is_partitioned(struct kvm_vcpu *vcpu); bool kvm_vcpu_pmu_use_fgt(struct kvm_vcpu *vcpu); @@ -177,6 +181,7 @@ static inline u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu) } static inline void kvm_pmu_load(struct kvm_vcpu *vcpu) {} static inline void kvm_pmu_put(struct kvm_vcpu *vcpu) {} +static inline void kvm_pmu_set_physical_access(struct kvm_vcpu *vcpu) {} static inline void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val) {} static inline void kvm_pmu_set_counter_value_user(struct kvm_vcpu *vcpu, -- 2.53.0.rc2.204.g2597b5adb4-goog