diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 5286ad3fa0f4..0409ac9e7b31 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -6539,20 +6539,56 @@ static bool kvmppc_hash_v3_possible(void) return true; } +static int kvmppc_map_compat_capabilities(u32 cpu_version, + unsigned long *capabilities) +{ + switch (cpu_version) { + case PVR_ARCH_31_P11: + *capabilities |= KVM_PPC_COMPAT_CAP_POWER11; + fallthrough; + case PVR_ARCH_31: + *capabilities |= KVM_PPC_COMPAT_CAP_POWER10; + fallthrough; + case PVR_ARCH_300: + *capabilities |= KVM_PPC_COMPAT_CAP_POWER9; + break; + default: + return -EINVAL; + } + + return 0; +} static int kvmppc_get_compat_caps(struct kvm_ppc_compat_caps *host_caps) { + struct device_node *np; unsigned long capabilities = 0; long rc = -EINVAL; + u32 cpu_version = 0; if (kvmhv_on_pseries()) { if (kvmhv_is_nestedv2()) { WARN_ON_ONCE(!nested_capabilities); capabilities = nested_capabilities; rc = 0; + } else { + for_each_node_by_type(np, "cpu") { + if (!of_property_read_u32(np, "cpu-version", + &cpu_version)) { + of_node_put(np); + break; + } + } + if (!cpu_version) + return -EINVAL; + rc = kvmppc_map_compat_capabilities(cpu_version, + &capabilities); } } + if (rc < 0) + return rc; + host_caps->compat_capabilities = capabilities & KVM_PPC_COMPAT_BITMASK; return rc;