311 lines
12 KiB
Diff
311 lines
12 KiB
Diff
From 3c806e795bf954e4dc28b75887a89095815325ed Mon Sep 17 00:00:00 2001
|
|
From: Andrew Lukoshko <alukoshko@almalinux.org>
|
|
Date: Sat, 17 May 2025 08:48:11 +0000
|
|
Subject: [PATCH] =?UTF-8?q?Bring=20back=20KVM=20support=20for=20PPC=C2=A7?=
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Backport of the following upstream commits:
|
|
524ab50336b1190547ceb8074260a1fbebfee0be
|
|
93b71801a8274cd9511557faf04365a5de487197
|
|
f771b55731fc82b1e8e9ef123f6f1b8d8c92bc63
|
|
---
|
|
Documentation/virt/kvm/api.rst | 14 ++++++++++++++
|
|
arch/powerpc/include/asm/kvm_ppc.h | 4 ----
|
|
arch/powerpc/include/asm/setup.h | 2 ++
|
|
arch/powerpc/kvm/book3s.c | 6 ++----
|
|
arch/powerpc/kvm/book3s_64_vio_hv.c | 2 +-
|
|
arch/powerpc/kvm/book3s_hv.c | 12 +++---------
|
|
arch/powerpc/kvm/book3s_pr.c | 2 --
|
|
arch/powerpc/kvm/booke.c | 2 --
|
|
arch/powerpc/kvm/powerpc.c | 21 +++++++++++++++++++--
|
|
arch/powerpc/platforms/pseries/setup.c | 13 ++++++++++++-
|
|
10 files changed, 53 insertions(+), 25 deletions(-)
|
|
|
|
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
|
|
index 9f2f130c6..64aca1034 100644
|
|
--- a/Documentation/virt/kvm/api.rst
|
|
+++ b/Documentation/virt/kvm/api.rst
|
|
@@ -7735,6 +7735,20 @@ indicated by the fd to the VM this is called on.
|
|
This is intended to support intra-host migration of VMs between userspace VMMs,
|
|
upgrading the VMM process without interrupting the guest.
|
|
|
|
+7.30 KVM_CAP_PPC_AIL_MODE_3
|
|
+-------------------------------
|
|
+
|
|
+:Capability: KVM_CAP_PPC_AIL_MODE_3
|
|
+:Architectures: ppc
|
|
+:Type: vm
|
|
+
|
|
+This capability indicates that the kernel supports the mode 3 setting for the
|
|
+"Address Translation Mode on Interrupt" aka "Alternate Interrupt Location"
|
|
+resource that is controlled with the H_SET_MODE hypercall.
|
|
+
|
|
+This capability allows a guest kernel to use a better-performance mode for
|
|
+handling interrupts and system calls.
|
|
+
|
|
7.31 KVM_CAP_DISABLE_QUIRKS2
|
|
----------------------------
|
|
|
|
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
|
|
index 254a41648..e16491011 100644
|
|
--- a/arch/powerpc/include/asm/kvm_ppc.h
|
|
+++ b/arch/powerpc/include/asm/kvm_ppc.h
|
|
@@ -199,12 +199,10 @@ extern void kvmppc_core_destroy_vm(struct kvm *kvm);
|
|
extern void kvmppc_core_free_memslot(struct kvm *kvm,
|
|
struct kvm_memory_slot *slot);
|
|
extern int kvmppc_core_prepare_memory_region(struct kvm *kvm,
|
|
- const struct kvm_userspace_memory_region *mem,
|
|
const struct kvm_memory_slot *old,
|
|
struct kvm_memory_slot *new,
|
|
enum kvm_mr_change change);
|
|
extern void kvmppc_core_commit_memory_region(struct kvm *kvm,
|
|
- const struct kvm_userspace_memory_region *mem,
|
|
struct kvm_memory_slot *old,
|
|
const struct kvm_memory_slot *new,
|
|
enum kvm_mr_change change);
|
|
@@ -274,12 +272,10 @@ struct kvmppc_ops {
|
|
int (*get_dirty_log)(struct kvm *kvm, struct kvm_dirty_log *log);
|
|
void (*flush_memslot)(struct kvm *kvm, struct kvm_memory_slot *memslot);
|
|
int (*prepare_memory_region)(struct kvm *kvm,
|
|
- const struct kvm_userspace_memory_region *mem,
|
|
const struct kvm_memory_slot *old,
|
|
struct kvm_memory_slot *new,
|
|
enum kvm_mr_change change);
|
|
void (*commit_memory_region)(struct kvm *kvm,
|
|
- const struct kvm_userspace_memory_region *mem,
|
|
struct kvm_memory_slot *old,
|
|
const struct kvm_memory_slot *new,
|
|
enum kvm_mr_change change);
|
|
diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h
|
|
index 31f315223..1868e4a07 100644
|
|
--- a/arch/powerpc/include/asm/setup.h
|
|
+++ b/arch/powerpc/include/asm/setup.h
|
|
@@ -27,11 +27,13 @@ void setup_panic(void);
|
|
#define ARCH_PANIC_TIMEOUT 180
|
|
|
|
#ifdef CONFIG_PPC_PSERIES
|
|
+extern bool pseries_reloc_on_exception(void);
|
|
extern bool pseries_enable_reloc_on_exc(void);
|
|
extern void pseries_disable_reloc_on_exc(void);
|
|
extern void pseries_big_endian_exceptions(void);
|
|
extern void pseries_little_endian_exceptions(void);
|
|
#else
|
|
+static inline bool pseries_reloc_on_exception(void) { return false; }
|
|
static inline bool pseries_enable_reloc_on_exc(void) { return false; }
|
|
static inline void pseries_disable_reloc_on_exc(void) {}
|
|
static inline void pseries_big_endian_exceptions(void) {}
|
|
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
|
|
index 64fd4b3ea..cb7b5f365 100644
|
|
--- a/arch/powerpc/kvm/book3s.c
|
|
+++ b/arch/powerpc/kvm/book3s.c
|
|
@@ -847,21 +847,19 @@ void kvmppc_core_flush_memslot(struct kvm *kvm, struct kvm_memory_slot *memslot)
|
|
}
|
|
|
|
int kvmppc_core_prepare_memory_region(struct kvm *kvm,
|
|
- const struct kvm_userspace_memory_region *mem,
|
|
const struct kvm_memory_slot *old,
|
|
struct kvm_memory_slot *new,
|
|
enum kvm_mr_change change)
|
|
{
|
|
- return kvm->arch.kvm_ops->prepare_memory_region(kvm, mem, old, new, change);
|
|
+ return kvm->arch.kvm_ops->prepare_memory_region(kvm, old, new, change);
|
|
}
|
|
|
|
void kvmppc_core_commit_memory_region(struct kvm *kvm,
|
|
- const struct kvm_userspace_memory_region *mem,
|
|
struct kvm_memory_slot *old,
|
|
const struct kvm_memory_slot *new,
|
|
enum kvm_mr_change change)
|
|
{
|
|
- kvm->arch.kvm_ops->commit_memory_region(kvm, mem, old, new, change);
|
|
+ kvm->arch.kvm_ops->commit_memory_region(kvm, old, new, change);
|
|
}
|
|
|
|
bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
|
|
diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c
|
|
index f38dfe195..16e5872a1 100644
|
|
--- a/arch/powerpc/kvm/book3s_64_vio_hv.c
|
|
+++ b/arch/powerpc/kvm/book3s_64_vio_hv.c
|
|
@@ -488,7 +488,7 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu,
|
|
/*
|
|
* used to check for invalidations in progress
|
|
*/
|
|
- mmu_seq = kvm->mmu_notifier_seq;
|
|
+ mmu_seq = kvm->mmu_invalidate_seq;
|
|
smp_rmb();
|
|
|
|
stt = kvmppc_find_table(vcpu->kvm, liobn);
|
|
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
|
|
index 5b2530818..f6ce07b4b 100644
|
|
--- a/arch/powerpc/kvm/book3s_hv.c
|
|
+++ b/arch/powerpc/kvm/book3s_hv.c
|
|
@@ -4777,15 +4777,12 @@ static void kvmppc_core_free_memslot_hv(struct kvm_memory_slot *slot)
|
|
}
|
|
|
|
static int kvmppc_core_prepare_memory_region_hv(struct kvm *kvm,
|
|
- const struct kvm_userspace_memory_region *mem,
|
|
const struct kvm_memory_slot *old,
|
|
struct kvm_memory_slot *new,
|
|
enum kvm_mr_change change)
|
|
{
|
|
- unsigned long npages = mem->memory_size >> PAGE_SHIFT;
|
|
-
|
|
if (change == KVM_MR_CREATE) {
|
|
- new->arch.rmap = vzalloc(array_size(npages,
|
|
+ new->arch.rmap = vzalloc(array_size(new->npages,
|
|
sizeof(*new->arch.rmap)));
|
|
if (!new->arch.rmap)
|
|
return -ENOMEM;
|
|
@@ -4797,20 +4794,17 @@ static int kvmppc_core_prepare_memory_region_hv(struct kvm *kvm,
|
|
}
|
|
|
|
static void kvmppc_core_commit_memory_region_hv(struct kvm *kvm,
|
|
- const struct kvm_userspace_memory_region *mem,
|
|
struct kvm_memory_slot *old,
|
|
const struct kvm_memory_slot *new,
|
|
enum kvm_mr_change change)
|
|
{
|
|
- unsigned long npages = mem->memory_size >> PAGE_SHIFT;
|
|
-
|
|
/*
|
|
- * If we are making a new memslot, it might make
|
|
+ * If we are creating or modifying a memslot, it might make
|
|
* some address that was previously cached as emulated
|
|
* MMIO be no longer emulated MMIO, so invalidate
|
|
* all the caches of emulated MMIO translations.
|
|
*/
|
|
- if (npages)
|
|
+ if (change != KVM_MR_DELETE)
|
|
atomic64_inc(&kvm->arch.mmio_update);
|
|
|
|
/*
|
|
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
|
|
index 48b48311a..6884c04f2 100644
|
|
--- a/arch/powerpc/kvm/book3s_pr.c
|
|
+++ b/arch/powerpc/kvm/book3s_pr.c
|
|
@@ -1892,7 +1892,6 @@ static void kvmppc_core_flush_memslot_pr(struct kvm *kvm,
|
|
}
|
|
|
|
static int kvmppc_core_prepare_memory_region_pr(struct kvm *kvm,
|
|
- const struct kvm_userspace_memory_region *mem,
|
|
const struct kvm_memory_slot *old,
|
|
struct kvm_memory_slot *new,
|
|
enum kvm_mr_change change)
|
|
@@ -1901,7 +1900,6 @@ static int kvmppc_core_prepare_memory_region_pr(struct kvm *kvm,
|
|
}
|
|
|
|
static void kvmppc_core_commit_memory_region_pr(struct kvm *kvm,
|
|
- const struct kvm_userspace_memory_region *mem,
|
|
struct kvm_memory_slot *old,
|
|
const struct kvm_memory_slot *new,
|
|
enum kvm_mr_change change)
|
|
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
|
|
index b06ca6646..6cf2db284 100644
|
|
--- a/arch/powerpc/kvm/booke.c
|
|
+++ b/arch/powerpc/kvm/booke.c
|
|
@@ -1806,7 +1806,6 @@ void kvmppc_core_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot)
|
|
}
|
|
|
|
int kvmppc_core_prepare_memory_region(struct kvm *kvm,
|
|
- const struct kvm_userspace_memory_region *mem,
|
|
const struct kvm_memory_slot *old,
|
|
struct kvm_memory_slot *new,
|
|
enum kvm_mr_change change)
|
|
@@ -1815,7 +1814,6 @@ int kvmppc_core_prepare_memory_region(struct kvm *kvm,
|
|
}
|
|
|
|
void kvmppc_core_commit_memory_region(struct kvm *kvm,
|
|
- const struct kvm_userspace_memory_region *mem,
|
|
struct kvm_memory_slot *old,
|
|
const struct kvm_memory_slot *new,
|
|
enum kvm_mr_change change)
|
|
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
|
|
index 818815e15..b89271923 100644
|
|
--- a/arch/powerpc/kvm/powerpc.c
|
|
+++ b/arch/powerpc/kvm/powerpc.c
|
|
@@ -662,6 +662,23 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
|
r = 1;
|
|
break;
|
|
#endif
|
|
+ case KVM_CAP_PPC_AIL_MODE_3:
|
|
+ r = 0;
|
|
+ /*
|
|
+ * KVM PR, POWER7, and some POWER9s don't support AIL=3 mode.
|
|
+ * The POWER9s can support it if the guest runs in hash mode,
|
|
+ * but QEMU doesn't necessarily query the capability in time.
|
|
+ */
|
|
+ if (hv_enabled) {
|
|
+ if (kvmhv_on_pseries()) {
|
|
+ if (pseries_reloc_on_exception())
|
|
+ r = 1;
|
|
+ } else if (cpu_has_feature(CPU_FTR_ARCH_207S) &&
|
|
+ !cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG)) {
|
|
+ r = 1;
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
default:
|
|
r = 0;
|
|
break;
|
|
@@ -686,7 +703,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
|
|
struct kvm_memory_slot *new,
|
|
enum kvm_mr_change change)
|
|
{
|
|
- return kvmppc_core_prepare_memory_region(kvm, mem, old, new, change);
|
|
+ return kvmppc_core_prepare_memory_region(kvm, old, new, change);
|
|
}
|
|
|
|
void kvm_arch_commit_memory_region(struct kvm *kvm,
|
|
@@ -694,7 +711,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
|
|
const struct kvm_memory_slot *new,
|
|
enum kvm_mr_change change)
|
|
{
|
|
- kvmppc_core_commit_memory_region(kvm, mem, old, new, change);
|
|
+ kvmppc_core_commit_memory_region(kvm, old, new, change);
|
|
}
|
|
|
|
void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
|
|
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
|
|
index f5c2718e2..1f7e535ab 100644
|
|
--- a/arch/powerpc/platforms/pseries/setup.c
|
|
+++ b/arch/powerpc/platforms/pseries/setup.c
|
|
@@ -367,6 +367,14 @@ static void pseries_lpar_idle(void)
|
|
pseries_idle_epilog();
|
|
}
|
|
|
|
+static bool pseries_reloc_on_exception_enabled;
|
|
+
|
|
+bool pseries_reloc_on_exception(void)
|
|
+{
|
|
+ return pseries_reloc_on_exception_enabled;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(pseries_reloc_on_exception);
|
|
+
|
|
/*
|
|
* Enable relocation on during exceptions. This has partition wide scope and
|
|
* may take a while to complete, if it takes longer than one second we will
|
|
@@ -391,6 +399,7 @@ bool pseries_enable_reloc_on_exc(void)
|
|
" on exceptions: %ld\n", rc);
|
|
return false;
|
|
}
|
|
+ pseries_reloc_on_exception_enabled = true;
|
|
return true;
|
|
}
|
|
|
|
@@ -418,7 +427,9 @@ void pseries_disable_reloc_on_exc(void)
|
|
break;
|
|
mdelay(get_longbusy_msecs(rc));
|
|
}
|
|
- if (rc != H_SUCCESS)
|
|
+ if (rc == H_SUCCESS)
|
|
+ pseries_reloc_on_exception_enabled = false;
|
|
+ else
|
|
pr_warn("Warning: Failed to disable relocation on exceptions: %ld\n",
|
|
rc);
|
|
}
|
|
--
|
|
2.43.5
|
|
|