aboutsummaryrefslogtreecommitdiff
path: root/target/ppc
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2017-07-12 17:56:55 +1000
committerDavid Gibson <david@gibson.dropbear.id.au>2017-07-17 15:07:05 +1000
commitb55d295e3ec98e46f5b39d50e4a3a9725b4289b3 (patch)
treea9fadf3a3abae4c1e018f3b3aaca9ca9ceea59fc /target/ppc
parent2772cf6be90e39919d0557ba3c57a77313ca9edf (diff)
downloadqemu-b55d295e3ec98e46f5b39d50e4a3a9725b4289b3.zip
qemu-b55d295e3ec98e46f5b39d50e4a3a9725b4289b3.tar.gz
qemu-b55d295e3ec98e46f5b39d50e4a3a9725b4289b3.tar.bz2
pseries: Allow HPT resizing with KVM
So far, qemu implements the PAPR Hash Page Table (HPT) resizing extension with TCG. The same implementation will work with KVM PR, but we don't currently allow that. For KVM HV we can only implement resizing with the assistance of the host kernel, which needs a new capability and ioctl()s. This patch adds support for testing the new KVM capability and implementing the resize in terms of KVM facilities when necessary. If we're running on a kernel which doesn't have the new capability flag at all, we fall back to testing for PR vs. HV KVM using the same hack that we already use in a number of places for older kernels. Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'target/ppc')
-rw-r--r--target/ppc/kvm.c67
-rw-r--r--target/ppc/kvm_ppc.h21
2 files changed, 86 insertions, 2 deletions
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 8bafd1e..8571379 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -89,6 +89,7 @@ static int cap_fixup_hcalls;
static int cap_htm; /* Hardware transactional memory support */
static int cap_mmu_radix;
static int cap_mmu_hash_v3;
+static int cap_resize_hpt;
static uint32_t debug_inst_opcode;
@@ -145,6 +146,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
cap_htm = kvm_vm_check_extension(s, KVM_CAP_PPC_HTM);
cap_mmu_radix = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_RADIX);
cap_mmu_hash_v3 = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_HASH_V3);
+ cap_resize_hpt = kvm_vm_check_extension(s, KVM_CAP_SPAPR_RESIZE_HPT);
if (!cap_interrupt_level) {
fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the "
@@ -2714,11 +2716,72 @@ int kvmppc_enable_hwrng(void)
void kvmppc_check_papr_resize_hpt(Error **errp)
{
if (!kvm_enabled()) {
- return;
+ return; /* No KVM, we're good */
+ }
+
+ if (cap_resize_hpt) {
+ return; /* Kernel has explicit support, we're good */
}
- /* TODO: Check for resize-capable KVM implementations */
+ /* Otherwise fallback on looking for PR KVM */
+ if (kvmppc_is_pr(kvm_state)) {
+ return;
+ }
error_setg(errp,
"Hash page table resizing not available with this KVM version");
}
+
+int kvmppc_resize_hpt_prepare(PowerPCCPU *cpu, target_ulong flags, int shift)
+{
+ CPUState *cs = CPU(cpu);
+ struct kvm_ppc_resize_hpt rhpt = {
+ .flags = flags,
+ .shift = shift,
+ };
+
+ if (!cap_resize_hpt) {
+ return -ENOSYS;
+ }
+
+ return kvm_vm_ioctl(cs->kvm_state, KVM_PPC_RESIZE_HPT_PREPARE, &rhpt);
+}
+
+int kvmppc_resize_hpt_commit(PowerPCCPU *cpu, target_ulong flags, int shift)
+{
+ CPUState *cs = CPU(cpu);
+ struct kvm_ppc_resize_hpt rhpt = {
+ .flags = flags,
+ .shift = shift,
+ };
+
+ if (!cap_resize_hpt) {
+ return -ENOSYS;
+ }
+
+ return kvm_vm_ioctl(cs->kvm_state, KVM_PPC_RESIZE_HPT_COMMIT, &rhpt);
+}
+
+static void kvmppc_pivot_hpt_cpu(CPUState *cs, run_on_cpu_data arg)
+{
+ target_ulong sdr1 = arg.target_ptr;
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+
+ /* This is just for the benefit of PR KVM */
+ cpu_synchronize_state(cs);
+ env->spr[SPR_SDR1] = sdr1;
+ if (kvmppc_put_books_sregs(cpu) < 0) {
+ error_report("Unable to update SDR1 in KVM");
+ exit(1);
+ }
+}
+
+void kvmppc_update_sdr1(target_ulong sdr1)
+{
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ run_on_cpu(cs, kvmppc_pivot_hpt_cpu, RUN_ON_CPU_TARGET_PTR(sdr1));
+ }
+}
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index 9be706c..6bc6fb3 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -64,6 +64,9 @@ int kvmppc_enable_hwrng(void);
int kvmppc_put_books_sregs(PowerPCCPU *cpu);
PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
void kvmppc_check_papr_resize_hpt(Error **errp);
+int kvmppc_resize_hpt_prepare(PowerPCCPU *cpu, target_ulong flags, int shift);
+int kvmppc_resize_hpt_commit(PowerPCCPU *cpu, target_ulong flags, int shift);
+void kvmppc_update_sdr1(target_ulong sdr1);
bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path);
@@ -302,6 +305,24 @@ static inline void kvmppc_check_papr_resize_hpt(Error **errp)
{
return;
}
+
+static inline int kvmppc_resize_hpt_prepare(PowerPCCPU *cpu,
+ target_ulong flags, int shift)
+{
+ return -ENOSYS;
+}
+
+static inline int kvmppc_resize_hpt_commit(PowerPCCPU *cpu,
+ target_ulong flags, int shift)
+{
+ return -ENOSYS;
+}
+
+static inline void kvmppc_update_sdr1(target_ulong sdr1)
+{
+ abort();
+}
+
#endif
#ifndef CONFIG_KVM