162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2012-2015 - ARM Ltd
462306a36Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <clocksource/arm_arch_timer.h>
862306a36Sopenharmony_ci#include <linux/compiler.h>
962306a36Sopenharmony_ci#include <linux/kvm_host.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <asm/kvm_hyp.h>
1262306a36Sopenharmony_ci#include <asm/kvm_mmu.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_civoid __kvm_timer_set_cntvoff(u64 cntvoff)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	write_sysreg(cntvoff, cntvoff_el2);
1762306a36Sopenharmony_ci}
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*
2062306a36Sopenharmony_ci * Should only be called on non-VHE or hVHE setups.
2162306a36Sopenharmony_ci * VHE systems use EL2 timers and configure EL1 timers in kvm_timer_init_vhe().
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_civoid __timer_disable_traps(struct kvm_vcpu *vcpu)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	u64 val, shift = 0;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	if (has_hvhe())
2862306a36Sopenharmony_ci		shift = 10;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	/* Allow physical timer/counter access for the host */
3162306a36Sopenharmony_ci	val = read_sysreg(cnthctl_el2);
3262306a36Sopenharmony_ci	val |= (CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN) << shift;
3362306a36Sopenharmony_ci	write_sysreg(val, cnthctl_el2);
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/*
3762306a36Sopenharmony_ci * Should only be called on non-VHE or hVHE setups.
3862306a36Sopenharmony_ci * VHE systems use EL2 timers and configure EL1 timers in kvm_timer_init_vhe().
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_civoid __timer_enable_traps(struct kvm_vcpu *vcpu)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	u64 clr = 0, set = 0;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	/*
4562306a36Sopenharmony_ci	 * Disallow physical timer access for the guest
4662306a36Sopenharmony_ci	 * Physical counter access is allowed if no offset is enforced
4762306a36Sopenharmony_ci	 * or running protected (we don't offset anything in this case).
4862306a36Sopenharmony_ci	 */
4962306a36Sopenharmony_ci	clr = CNTHCTL_EL1PCEN;
5062306a36Sopenharmony_ci	if (is_protected_kvm_enabled() ||
5162306a36Sopenharmony_ci	    !kern_hyp_va(vcpu->kvm)->arch.timer_data.poffset)
5262306a36Sopenharmony_ci		set |= CNTHCTL_EL1PCTEN;
5362306a36Sopenharmony_ci	else
5462306a36Sopenharmony_ci		clr |= CNTHCTL_EL1PCTEN;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	if (has_hvhe()) {
5762306a36Sopenharmony_ci		clr <<= 10;
5862306a36Sopenharmony_ci		set <<= 10;
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	sysreg_clear_set(cnthctl_el2, clr, set);
6262306a36Sopenharmony_ci}
63