[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 26/27] Implement PAPR VPA functions for pSeries shar
From: |
David Gibson |
Subject: |
[Qemu-devel] [PATCH 26/27] Implement PAPR VPA functions for pSeries shared processor partitions |
Date: |
Wed, 23 Mar 2011 16:30:46 +1100 |
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 <address@hidden>
---
hw/spapr.c | 2 +-
hw/spapr_hcall.c | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
target-ppc/cpu.h | 5 ++
3 files changed, 198 insertions(+), 1 deletions(-)
diff --git a/hw/spapr.c b/hw/spapr.c
index 8585520..941f8a3 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -67,7 +67,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 02ccafd..6cc101d 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(sPAPREnvironment *spapr, target_ulong rtas_r3)
{
uint32_t token = ldl_phys(rtas_r3);
@@ -318,5 +506,9 @@ 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);
}
device_init(hypercall_init);
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index b4c2555..955d8af 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -721,6 +721,11 @@ struct CPUPPCState {
uint32_t flags;
uint64_t insns_flags;
+ target_phys_addr_t vpa;
+ target_phys_addr_t slb_shadow;
+ target_phys_addr_t dispatch_trace_log;
+ uint32_t dtl_size;
+
int error_code;
uint32_t pending_interrupts;
#if !defined(CONFIG_USER_ONLY)
--
1.7.1
- [Qemu-devel] [PATCH 19/27] Add PAPR H_VIO_SIGNAL hypercall and infrastructure for VIO interrupts, (continued)
- [Qemu-devel] [PATCH 19/27] Add PAPR H_VIO_SIGNAL hypercall and infrastructure for VIO interrupts, David Gibson, 2011/03/23
- [Qemu-devel] [PATCH 13/27] Start implementing pSeries logical partition machine, David Gibson, 2011/03/23
- [Qemu-devel] [PATCH 15/27] Virtual hash page table handling on pSeries machine, David Gibson, 2011/03/23
- [Qemu-devel] [PATCH 14/27] Implement the bus structure for PAPR virtual IO, David Gibson, 2011/03/23
- [Qemu-devel] [PATCH 18/27] Implement the PAPR (pSeries) virtualized interrupt controller (xics), David Gibson, 2011/03/23
- [Qemu-devel] [PATCH 20/27] Add (virtual) interrupt to PAPR virtual tty device, David Gibson, 2011/03/23
- [Qemu-devel] [PATCH 16/27] Implement hcall based RTAS for pSeries machines, David Gibson, 2011/03/23
- [Qemu-devel] [PATCH 22/27] Implement sPAPR Virtual LAN (ibmveth), David Gibson, 2011/03/23
- [Qemu-devel] [PATCH 23/27] Implement PAPR CRQ hypercalls, David Gibson, 2011/03/23
- [Qemu-devel] [PATCH 21/27] Implement TCE translation for sPAPR VIO, David Gibson, 2011/03/23
- [Qemu-devel] [PATCH 26/27] Implement PAPR VPA functions for pSeries shared processor partitions,
David Gibson <=
- [Qemu-devel] [PATCH 25/27] Add a PAPR TCE-bypass mechanism for the pSeries machine, David Gibson, 2011/03/23
- [Qemu-devel] [PATCH 24/27] Implement PAPR virtual SCSI interface (ibmvscsi), David Gibson, 2011/03/23
- Message not available
- [Qemu-devel] Re: [0/27] Implement emulation of pSeries logical partitions (v4), Alexander Graf, 2011/03/23
- [Qemu-devel] Re: [0/27] Implement emulation of pSeries logical partitions (v4), Alexander Graf, 2011/03/23