[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-ppc] [PATCH for-2.10 5/5] pseries: Allow HPT resizing with KVM
From: |
David Gibson |
Subject: |
Re: [Qemu-ppc] [PATCH for-2.10 5/5] pseries: Allow HPT resizing with KVM |
Date: |
Fri, 10 Mar 2017 12:15:27 +1100 |
User-agent: |
Mutt/1.7.1 (2016-10-04) |
On Fri, Mar 10, 2017 at 12:13:28PM +1100, David Gibson wrote:
> 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.
>
> NOTE: This patch updates the linux-headers tree with the define for the
> new capability and ioctl()s. Since the corresponding kernel changes aren't
> yet upstream this is a temporary hack to be replaced by a proper headers
> update before merge.
The paragraph above is no longer accurate - the defines are in the
mainline kernel, and have even already been pulled into the qemu
tree. I'll drop this chunk when I commit.
>
> Signed-off-by: David Gibson <address@hidden>
> ---
> hw/ppc/spapr_hcall.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++---
> target/ppc/kvm.c | 67
> ++++++++++++++++++++++++++++++++++++++++++++++++++--
> target/ppc/kvm_ppc.h | 21 ++++++++++++++++
> 3 files changed, 148 insertions(+), 5 deletions(-)
>
> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> index ee1b7fa..f66bc4f 100644
> --- a/hw/ppc/spapr_hcall.c
> +++ b/hw/ppc/spapr_hcall.c
> @@ -457,6 +457,44 @@ static ram_addr_t get_current_ram_size(void)
> return size;
> }
>
> +/* Convert a return code from the KVM ioctl()s implementing resize HPT
> + * into a PAPR hypercall return code */
> +static target_ulong resize_hpt_convert_rc(int ret)
> +{
> + if (ret >= 100000) {
> + return H_LONG_BUSY_ORDER_100_SEC;
> + } else if (ret >= 10000) {
> + return H_LONG_BUSY_ORDER_10_SEC;
> + } else if (ret >= 1000) {
> + return H_LONG_BUSY_ORDER_1_SEC;
> + } else if (ret >= 100) {
> + return H_LONG_BUSY_ORDER_100_MSEC;
> + } else if (ret >= 10) {
> + return H_LONG_BUSY_ORDER_10_MSEC;
> + } else if (ret > 0) {
> + return H_LONG_BUSY_ORDER_1_MSEC;
> + }
> +
> + switch (ret) {
> + case 0:
> + return H_SUCCESS;
> + case -EPERM:
> + return H_AUTHORITY;
> + case -EINVAL:
> + return H_PARAMETER;
> + case -ENXIO:
> + return H_CLOSED;
> + case -ENOSPC:
> + return H_PTEG_FULL;
> + case -EBUSY:
> + return H_BUSY;
> + case -ENOMEM:
> + return H_NO_MEM;
> + default:
> + return H_HARDWARE;
> + }
> +}
> +
> static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu,
> sPAPRMachineState *spapr,
> target_ulong opcode,
> @@ -465,6 +503,7 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu,
> target_ulong flags = args[0];
> int shift = args[1];
> sPAPRPendingHPT *pending = spapr->pending_hpt;
> + int rc;
>
> if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) {
> return H_AUTHORITY;
> @@ -487,6 +526,11 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu,
> return H_RESOURCE;
> }
>
> + rc = kvmppc_resize_hpt_prepare(cpu, flags, shift);
> + if (rc != -ENOSYS) {
> + return resize_hpt_convert_rc(rc);
> + }
> +
> if (pending) {
> /* something already in progress */
> if (pending->shift == shift) {
> @@ -682,6 +726,11 @@ static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu,
>
> trace_spapr_h_resize_hpt_commit(flags, shift);
>
> + rc = kvmppc_resize_hpt_commit(cpu, flags, shift);
> + if (rc != -ENOSYS) {
> + return resize_hpt_convert_rc(rc);
> + }
> +
> if (flags != 0) {
> return H_PARAMETER;
> }
> @@ -700,12 +749,17 @@ static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu,
> rc = rehash_hpt(cpu, spapr->htab, HTAB_SIZE(spapr),
> pending->hpt, newsize);
> if (rc == H_SUCCESS) {
> - CPUState *cs;
> -
> qemu_vfree(spapr->htab);
> spapr->htab = pending->hpt;
> spapr->htab_shift = pending->shift;
>
> + if (kvm_enabled()) {
> + /* For KVM PR, update the HPT pointer */
> + target_ulong sdr1 = (target_ulong)(uintptr_t)spapr->htab
> + | (spapr->htab_shift - 18);
> + kvmppc_update_sdr1(sdr1);
> + }
> +
> pending->hpt = NULL; /* so it's not free()d */
> }
>
> @@ -1373,7 +1427,12 @@ static target_ulong
> h_client_architecture_support(PowerPCCPU *cpu,
> * entered into the existing HPT */
> spapr_reallocate_hpt(spapr, maxshift, &error_fatal);
> CPU_FOREACH(cs) {
> - run_on_cpu(cs, pivot_hpt, RUN_ON_CPU_HOST_PTR(spapr));
> + if (kvm_enabled()) {
> + /* For KVM PR, update the HPT pointer */
> + target_ulong sdr1 = (target_ulong)(uintptr_t)spapr->htab
> + | (spapr->htab_shift - 18);
> + kvmppc_update_sdr1(sdr1);
> + }
> }
> }
> }
> diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
> index 97591d2..bff04ff 100644
> --- a/target/ppc/kvm.c
> +++ b/target/ppc/kvm.c
> @@ -84,6 +84,7 @@ static int cap_papr;
> static int cap_htab_fd;
> static int cap_fixup_hcalls;
> static int cap_htm; /* Hardware transactional memory support */
> +static int cap_resize_hpt;
>
> static uint32_t debug_inst_opcode;
>
> @@ -137,6 +138,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
> cap_htab_fd = kvm_check_extension(s, KVM_CAP_PPC_HTAB_FD);
> cap_fixup_hcalls = kvm_check_extension(s, KVM_CAP_PPC_FIXUP_HCALL);
> cap_htm = kvm_vm_check_extension(s, KVM_CAP_PPC_HTM);
> + 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
> "
> @@ -2603,10 +2605,71 @@ 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 cd3b234..493ff2e 100644
> --- a/target/ppc/kvm_ppc.h
> +++ b/target/ppc/kvm_ppc.h
> @@ -57,6 +57,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(char *obj_path);
>
> @@ -272,6 +275,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
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
signature.asc
Description: PGP signature
- [Qemu-ppc] [PATCH for-2.10 0/5] HPT resizing for PAPR guests, David Gibson, 2017/03/09
- [Qemu-ppc] [PATCH for-2.10 1/5] pseries: Stubs for HPT resizing, David Gibson, 2017/03/09
- [Qemu-ppc] [PATCH for-2.10 3/5] pseries: Enable HPT resizing for 2.10, David Gibson, 2017/03/09
- [Qemu-ppc] [PATCH for-2.10 2/5] pseries: Implement HPT resizing, David Gibson, 2017/03/09
- [Qemu-ppc] [PATCH for-2.10 4/5] pseries: Use smaller default hash page tables when guest can resize, David Gibson, 2017/03/09
- [Qemu-ppc] [PATCH for-2.10 5/5] pseries: Allow HPT resizing with KVM, David Gibson, 2017/03/09
- Re: [Qemu-ppc] [PATCH for-2.10 5/5] pseries: Allow HPT resizing with KVM,
David Gibson <=