From patchwork Fri Apr 1 04:15:33 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Gibson X-Patchwork-Id: 89193 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 7782CB6F82 for ; Fri, 1 Apr 2011 16:22:11 +1100 (EST) Received: from localhost ([127.0.0.1]:60783 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Q5WS0-0006cr-FT for incoming@patchwork.ozlabs.org; Fri, 01 Apr 2011 00:59:12 -0400 Received: from [140.186.70.92] (port=39995 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Q5VmF-0007CJ-PC for qemu-devel@nongnu.org; Fri, 01 Apr 2011 00:16:08 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Q5Vm6-0001Uq-N8 for qemu-devel@nongnu.org; Fri, 01 Apr 2011 00:16:03 -0400 Received: from ozlabs.org ([203.10.76.45]:35014) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Q5Vm6-0001R3-3i for qemu-devel@nongnu.org; Fri, 01 Apr 2011 00:15:54 -0400 Received: by ozlabs.org (Postfix, from userid 1007) id 8E00B1007EC; Fri, 1 Apr 2011 15:15:44 +1100 (EST) From: David Gibson To: agraf@suse.de, qemu-devel@nongnu.org Date: Fri, 1 Apr 2011 15:15:33 +1100 Message-Id: <1301631334-30795-27-git-send-email-david@gibson.dropbear.id.au> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1301631334-30795-1-git-send-email-david@gibson.dropbear.id.au> References: <1301631334-30795-1-git-send-email-david@gibson.dropbear.id.au> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 203.10.76.45 Cc: paulus@samba.org, anton@samba.org Subject: [Qemu-devel] [PATCH 26/27] Implement PAPR VPA functions for pSeries shared processor partitions X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Shared-processor partitions are those where a CPU is time-sliced between partitions, rather than being permanently dedicated to a single partition. qemu emulated partitions, since they are just scheduled with the qemu user process, behave mostly like shared processor partitions. In order to better support shared processor partitions (splpar), PAPR defines the "VPA" (Virtual Processor Area), a shared memory communication channel between the hypervisor and partitions. There are also two additional shared memory communication areas for specialized purposes associated with the VPA. A VPA is not essential for operating an splpar, though it can be necessary for obtaining accurate performance measurements in the presence of runtime partition switching. Most importantly, however, the VPA is a prerequisite for PAPR's H_CEDE, hypercall, which allows a partition OS to give up it's shared processor timeslices to other partitions when idle. This patch implements the VPA and H_CEDE hypercalls in qemu. We don't implement any of the more advanced statistics which can be communicated through the VPA. However, this is enough to make normal pSeries kernels do an effective power-save idle on an emulated pSeries, significantly reducing the host load of a qemu emulated pSeries running an idle guest OS. Signed-off-by: David Gibson --- hw/spapr.c | 2 +- hw/spapr_hcall.c | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ target-ppc/cpu.h | 7 ++ 3 files changed, 200 insertions(+), 1 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index 3bffaab..8767686 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -68,7 +68,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt" - "\0hcall-tce\0hcall-vio"; + "\0hcall-tce\0hcall-vio\0hcall-splpar"; uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; int i; char *modelname; diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index a47a97b..f88e1d2 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -4,6 +4,8 @@ #include "sysemu.h" #include "qemu-char.h" #include "exec-all.h" +#include "exec.h" +#include "helper_regs.h" #include "hw/spapr.h" #define HPTES_PER_GROUP 8 @@ -255,6 +257,192 @@ static target_ulong h_set_dabr(CPUState *env, sPAPREnvironment *spapr, return H_HARDWARE; } +#define FLAGS_REGISTER_VPA 0x0000200000000000ULL +#define FLAGS_REGISTER_DTL 0x0000400000000000ULL +#define FLAGS_REGISTER_SLBSHADOW 0x0000600000000000ULL +#define FLAGS_DEREGISTER_VPA 0x0000a00000000000ULL +#define FLAGS_DEREGISTER_DTL 0x0000c00000000000ULL +#define FLAGS_DEREGISTER_SLBSHADOW 0x0000e00000000000ULL + +#define VPA_MIN_SIZE 640 +#define VPA_SIZE_OFFSET 0x4 +#define VPA_SHARED_PROC_OFFSET 0x9 +#define VPA_SHARED_PROC_VAL 0x2 + +static target_ulong register_vpa(CPUState *env, target_ulong vpa) +{ + uint16_t size; + uint8_t tmp; + + if (vpa == 0) { + hcall_dprintf("Can't cope with registering a VPA at logical 0\n"); + return H_HARDWARE; + } + + if (vpa % env->dcache_line_size) { + return H_PARAMETER; + } + /* FIXME: bounds check the address */ + + size = lduw_phys(vpa + 0x4); + + if (size < VPA_MIN_SIZE) { + return H_PARAMETER; + } + + /* VPA is not allowed to cross a page boundary */ + if ((vpa / 4096) != ((vpa + size - 1) / 4096)) { + return H_PARAMETER; + } + + env->vpa = vpa; + + tmp = ldub_phys(env->vpa + VPA_SHARED_PROC_OFFSET); + tmp |= VPA_SHARED_PROC_VAL; + stb_phys(env->vpa + VPA_SHARED_PROC_OFFSET, tmp); + + return H_SUCCESS; +} + +static target_ulong deregister_vpa(CPUState *env, target_ulong vpa) +{ + if (env->slb_shadow) { + return H_RESOURCE; + } + + if (env->dispatch_trace_log) { + return H_RESOURCE; + } + + env->vpa = 0; + return H_SUCCESS; +} + +static target_ulong register_slb_shadow(CPUState *env, target_ulong addr) +{ + uint32_t size; + + if (addr == 0) { + hcall_dprintf("Can't cope with SLB shadow at logical 0\n"); + return H_HARDWARE; + } + + size = ldl_phys(addr + 0x4); + if (size < 0x8) { + return H_PARAMETER; + } + + if ((addr / 4096) != ((addr + size - 1) / 4096)) { + return H_PARAMETER; + } + + if (!env->vpa) { + return H_RESOURCE; + } + + env->slb_shadow = addr; + + return H_SUCCESS; +} + +static target_ulong deregister_slb_shadow(CPUState *env, target_ulong addr) +{ + env->slb_shadow = 0; + return H_SUCCESS; +} + +static target_ulong register_dtl(CPUState *env, target_ulong addr) +{ + uint32_t size; + + if (addr == 0) { + hcall_dprintf("Can't cope with DTL at logical 0\n"); + return H_HARDWARE; + } + + size = ldl_phys(addr + 0x4); + + if (size < 48) { + return H_PARAMETER; + } + + if (!env->vpa) { + return H_RESOURCE; + } + + env->dispatch_trace_log = addr; + env->dtl_size = size; + + return H_SUCCESS; +} + +static target_ulong deregister_dtl(CPUState *emv, target_ulong addr) +{ + env->dispatch_trace_log = 0; + env->dtl_size = 0; + + return H_SUCCESS; +} + +static target_ulong h_register_vpa(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong flags = args[0]; + target_ulong procno = args[1]; + target_ulong vpa = args[2]; + target_ulong ret = H_PARAMETER; + CPUState *tenv; + + for (tenv = first_cpu; tenv; tenv = tenv->next_cpu) { + if (tenv->cpu_index == procno) { + break; + } + } + + if (!tenv) { + return H_PARAMETER; + } + + switch (flags) { + case FLAGS_REGISTER_VPA: + ret = register_vpa(tenv, vpa); + break; + + case FLAGS_DEREGISTER_VPA: + ret = deregister_vpa(tenv, vpa); + break; + + case FLAGS_REGISTER_SLBSHADOW: + ret = register_slb_shadow(tenv, vpa); + break; + + case FLAGS_DEREGISTER_SLBSHADOW: + ret = deregister_slb_shadow(tenv, vpa); + break; + + case FLAGS_REGISTER_DTL: + ret = register_dtl(tenv, vpa); + break; + + case FLAGS_DEREGISTER_DTL: + ret = deregister_dtl(tenv, vpa); + break; + } + + return ret; +} + +static target_ulong h_cede(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + env->msr |= (1ULL << MSR_EE); + hreg_compute_hflags(env); + if (!cpu_has_work(env)) { + env->halted = 1; + } + return H_SUCCESS; +} + static target_ulong h_rtas(CPUState *env, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { @@ -327,6 +515,10 @@ static void hypercall_init(void) /* hcall-dabr */ spapr_register_hypercall(H_SET_DABR, h_set_dabr); + /* hcall-splpar */ + spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa); + spapr_register_hypercall(H_CEDE, h_cede); + /* qemu/KVM-PPC specific hcalls */ spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas); } diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index b4c2555..04b1259 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -721,6 +721,13 @@ struct CPUPPCState { uint32_t flags; uint64_t insns_flags; +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) + target_phys_addr_t vpa; + target_phys_addr_t slb_shadow; + target_phys_addr_t dispatch_trace_log; + uint32_t dtl_size; +#endif /* TARGET_PPC64 */ + int error_code; uint32_t pending_interrupts; #if !defined(CONFIG_USER_ONLY)