virt inclusion category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/8610 -------------------------------------------------------------------- When LPI is enabled, a CPU may enter power-down mode. During this transition, dvmbm ctrl register is reset to 0 after the cpu was down, which leads to functional breakdown. At this mode, the kernel invokes a notifier during CPU suspend, and the CPU enters the CPU_PM_ENTER state. KVM has registered a handler for this state. To prevent the loss of configuration, the DVM broadcast management control register (SYS_LSUDVM_CTRL_EL2) must be saved on CPU suspend and restored on CPU resume. Fixes: e85b97c7e2b4 ("KVM: arm64: Probe and configure DVMBM capability on HiSi CPUs") Signed-off-by: Tian Zheng <zhengtian10@huawei.com> Reviewed-by: Yanan Wang <wangyanan55@huawei.com> Reviewed-by: Zenghui Yu <yuzenghui@huawei.com> --- arch/arm64/kvm/arm.c | 4 ++++ arch/arm64/kvm/hisilicon/hisi_virt.c | 19 +++++++++++++++++++ arch/arm64/kvm/hisilicon/hisi_virt.h | 4 ++++ 3 files changed, 27 insertions(+) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index e59152ad5c4a..f349f22b9dec 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -2424,6 +2424,8 @@ static int hyp_init_cpu_pm_notifier(struct notifier_block *self, */ switch (cmd) { case CPU_PM_ENTER: + kvm_save_dvmbm_ctrl_el2(); + if (__this_cpu_read(kvm_hyp_initialized)) /* * don't update kvm_hyp_initialized here @@ -2439,6 +2441,8 @@ static int hyp_init_cpu_pm_notifier(struct notifier_block *self, /* The hyp was enabled before suspend. */ cpu_hyp_reinit(); + kvm_restore_dvmbm_ctrl_el2(); + return NOTIFY_OK; default: diff --git a/arch/arm64/kvm/hisilicon/hisi_virt.c b/arch/arm64/kvm/hisilicon/hisi_virt.c index 5731d337b228..d5a8a6d66dbc 100644 --- a/arch/arm64/kvm/hisilicon/hisi_virt.c +++ b/arch/arm64/kvm/hisilicon/hisi_virt.c @@ -13,6 +13,7 @@ static enum hisi_cpu_type cpu_type = UNKNOWN_HI_TYPE; static bool dvmbm_enabled; +static DEFINE_PER_CPU(u64, kvm_dvmbm_ctrl_el2_val); #ifdef CONFIG_ARM64_HISI_IPIV static bool ipiv_enabled; @@ -162,6 +163,24 @@ static void hardware_disable_dvmbm(void *data) write_sysreg_s(val, SYS_LSUDVM_CTRL_EL2); } +void kvm_save_dvmbm_ctrl_el2(void) +{ + if (!kvm_dvmbm_support) + return; + + __this_cpu_write(kvm_dvmbm_ctrl_el2_val, + read_sysreg_s(SYS_LSUDVM_CTRL_EL2)); +} + +void kvm_restore_dvmbm_ctrl_el2(void) +{ + if (!kvm_dvmbm_support) + return; + + write_sysreg_s(__this_cpu_read(kvm_dvmbm_ctrl_el2_val), + SYS_LSUDVM_CTRL_EL2); +} + #ifdef CONFIG_ARM64_HISI_IPIV static int __init early_ipiv_enable(char *buf) { diff --git a/arch/arm64/kvm/hisilicon/hisi_virt.h b/arch/arm64/kvm/hisilicon/hisi_virt.h index 180618e42cbc..e0fca8236197 100644 --- a/arch/arm64/kvm/hisilicon/hisi_virt.h +++ b/arch/arm64/kvm/hisilicon/hisi_virt.h @@ -94,6 +94,8 @@ enum hisi_cpu_type { void probe_hisi_cpu_type(void); bool hisi_ncsnp_supported(void); bool hisi_dvmbm_supported(void); +void kvm_save_dvmbm_ctrl_el2(void); +void kvm_restore_dvmbm_ctrl_el2(void); #ifdef CONFIG_ARM64_HISI_IPIV bool hisi_ipiv_supported(void); bool hisi_ipiv_supported_per_vm(struct kvm *kvm); @@ -119,6 +121,8 @@ static inline bool hisi_dvmbm_supported(void) { return false; } +static inline void kvm_save_dvmbm_ctrl_el2(void) {} +static inline void kvm_restore_dvmbm_ctrl_el2(void) {} #ifdef CONFIG_ARM64_HISI_IPIV static inline bool hisi_ipiv_supported(void) { -- 2.33.0