mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-27 05:55:18 +07:00
688c50aa72
As we are about to be lazy with saving and restoring the timer registers, we prepare by moving all possible timer configuration logic out of the hyp code. All virtual timer registers can be programmed from EL1 and since the arch timer is always a level triggered interrupt we can safely do this with interrupts disabled in the host kernel on the way to the guest without taking vtimer interrupts in the host kernel (yet). The downside is that the cntvoff register can only be programmed from hyp mode, so we jump into hyp mode and back to program it. This is also safe, because the host kernel doesn't use the virtual timer in the KVM code. It may add a little performance performance penalty, but only until following commits where we move this operation to vcpu load/put. Signed-off-by: Christoffer Dall <cdall@linaro.org> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
69 lines
1.8 KiB
C
69 lines
1.8 KiB
C
/*
|
|
* Copyright (C) 2012-2015 - ARM Ltd
|
|
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <clocksource/arm_arch_timer.h>
|
|
#include <linux/compiler.h>
|
|
#include <linux/kvm_host.h>
|
|
|
|
#include <asm/kvm_hyp.h>
|
|
|
|
void __hyp_text __kvm_timer_set_cntvoff(u32 cntvoff_low, u32 cntvoff_high)
|
|
{
|
|
u64 cntvoff = (u64)cntvoff_high << 32 | cntvoff_low;
|
|
write_sysreg(cntvoff, cntvoff_el2);
|
|
}
|
|
|
|
void __hyp_text enable_el1_phys_timer_access(void)
|
|
{
|
|
u64 val;
|
|
|
|
/* Allow physical timer/counter access for the host */
|
|
val = read_sysreg(cnthctl_el2);
|
|
val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
|
|
write_sysreg(val, cnthctl_el2);
|
|
}
|
|
|
|
void __hyp_text disable_el1_phys_timer_access(void)
|
|
{
|
|
u64 val;
|
|
|
|
/*
|
|
* Disallow physical timer access for the guest
|
|
* Physical counter access is allowed
|
|
*/
|
|
val = read_sysreg(cnthctl_el2);
|
|
val &= ~CNTHCTL_EL1PCEN;
|
|
val |= CNTHCTL_EL1PCTEN;
|
|
write_sysreg(val, cnthctl_el2);
|
|
}
|
|
|
|
void __hyp_text __timer_disable_traps(struct kvm_vcpu *vcpu)
|
|
{
|
|
/*
|
|
* We don't need to do this for VHE since the host kernel runs in EL2
|
|
* with HCR_EL2.TGE ==1, which makes those bits have no impact.
|
|
*/
|
|
if (!has_vhe())
|
|
enable_el1_phys_timer_access();
|
|
}
|
|
|
|
void __hyp_text __timer_enable_traps(struct kvm_vcpu *vcpu)
|
|
{
|
|
if (!has_vhe())
|
|
disable_el1_phys_timer_access();
|
|
}
|