aboutsummaryrefslogtreecommitdiff
path: root/target-ppc
diff options
context:
space:
mode:
authorAlexey Kardashevskiy <aik@ozlabs.ru>2014-05-23 12:26:50 +1000
committerAlexander Graf <agraf@suse.de>2014-06-16 13:24:37 +0200
commit8dfa3a5e85eca94a93b1495136f49c5776fd5ada (patch)
tree7726147b23a12b6653e98e5b4d86ec52205f679b /target-ppc
parentaf354f19a9b6a655eac1c49b66d3be021e7ed3d9 (diff)
target-ppc: Add "compat" CPU option
PowerISA defines a compatibility mode for server POWERPC CPUs which is supported by the PCR special register which is hypervisor privileged. To support this mode for guests, SPAPR defines a set of virtual PVRs, one per PowerISA spec version. When a hypervisor needs a guest to work in a compatibility mode, it puts a virtual PVR value into @cpu-version property of a CPU node. This introduces a "compat" CPU option which defines maximal compatibility mode enabled. The supported modes are power6/power7/power8. This does not change the existing behaviour, new property will be used by next patches. Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'target-ppc')
-rw-r--r--target-ppc/cpu-models.h10
-rw-r--r--target-ppc/cpu-qom.h2
-rw-r--r--target-ppc/translate_init.c75
3 files changed, 87 insertions, 0 deletions
diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h
index 9a003b43b4..db75896012 100644
--- a/target-ppc/cpu-models.h
+++ b/target-ppc/cpu-models.h
@@ -595,6 +595,16 @@ enum {
CPU_POWERPC_PA6T = 0x00900000,
};
+/* Logical PVR definitions for sPAPR */
+enum {
+ CPU_POWERPC_LOGICAL_2_04 = 0x0F000001,
+ CPU_POWERPC_LOGICAL_2_05 = 0x0F000002,
+ CPU_POWERPC_LOGICAL_2_06 = 0x0F000003,
+ CPU_POWERPC_LOGICAL_2_06_PLUS = 0x0F100003,
+ CPU_POWERPC_LOGICAL_2_07 = 0x0F000004,
+ CPU_POWERPC_LOGICAL_2_08 = 0x0F000005,
+};
+
/* System version register (used on MPC 8xxx) */
enum {
POWERPC_SVR_NONE = 0x00000000,
diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h
index 046ea0effa..533de8fbd7 100644
--- a/target-ppc/cpu-qom.h
+++ b/target-ppc/cpu-qom.h
@@ -83,6 +83,7 @@ typedef struct PowerPCCPUClass {
* PowerPCCPU:
* @env: #CPUPPCState
* @cpu_dt_id: CPU index used in the device tree. KVM uses this index too
+ * @max_compat: Maximal supported logical PVR from the command line
*
* A PowerPC CPU.
*/
@@ -93,6 +94,7 @@ struct PowerPCCPU {
CPUPPCState env;
int cpu_dt_id;
+ uint32_t max_compat;
};
static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 16ecada688..2e273dcf62 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -28,6 +28,8 @@
#include "mmu-hash32.h"
#include "mmu-hash64.h"
#include "qemu/error-report.h"
+#include "qapi/visitor.h"
+#include "hw/qdev-properties.h"
//#define PPC_DUMP_CPU
//#define PPC_DEBUG_SPR
@@ -7680,6 +7682,76 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
pcc->l1_icache_size = 0x10000;
}
+static void powerpc_get_compat(Object *obj, Visitor *v,
+ void *opaque, const char *name, Error **errp)
+{
+ char *value = (char *)"";
+ Property *prop = opaque;
+ uint32_t *max_compat = qdev_get_prop_ptr(DEVICE(obj), prop);
+
+ switch (*max_compat) {
+ case CPU_POWERPC_LOGICAL_2_05:
+ value = (char *)"power6";
+ break;
+ case CPU_POWERPC_LOGICAL_2_06:
+ value = (char *)"power7";
+ break;
+ case CPU_POWERPC_LOGICAL_2_07:
+ value = (char *)"power8";
+ break;
+ case 0:
+ break;
+ default:
+ error_setg(errp, "Internal error: compat is set to %x",
+ max_compat ? *max_compat : -1);
+ break;
+ }
+
+ visit_type_str(v, &value, name, errp);
+}
+
+static void powerpc_set_compat(Object *obj, Visitor *v,
+ void *opaque, const char *name, Error **errp)
+{
+ Error *error = NULL;
+ char *value = NULL;
+ Property *prop = opaque;
+ uint32_t *max_compat = qdev_get_prop_ptr(DEVICE(obj), prop);
+
+ visit_type_str(v, &value, name, &error);
+ if (error) {
+ error_propagate(errp, error);
+ return;
+ }
+
+ if (strcmp(value, "power6") == 0) {
+ *max_compat = CPU_POWERPC_LOGICAL_2_05;
+ } else if (strcmp(value, "power7") == 0) {
+ *max_compat = CPU_POWERPC_LOGICAL_2_06;
+ } else if (strcmp(value, "power8") == 0) {
+ *max_compat = CPU_POWERPC_LOGICAL_2_07;
+ } else {
+ error_setg(errp, "Invalid compatibility mode \"%s\"", value);
+ }
+
+ g_free(value);
+}
+
+static PropertyInfo powerpc_compat_propinfo = {
+ .name = "str",
+ .legacy_name = "powerpc-server-compat",
+ .get = powerpc_get_compat,
+ .set = powerpc_set_compat,
+};
+
+#define DEFINE_PROP_POWERPC_COMPAT(_n, _s, _f) \
+ DEFINE_PROP(_n, _s, _f, powerpc_compat_propinfo, uint32_t)
+
+static Property powerpc_servercpu_properties[] = {
+ DEFINE_PROP_POWERPC_COMPAT("compat", PowerPCCPU, max_compat),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void init_proc_POWER7 (CPUPPCState *env)
{
gen_spr_ne_601(env);
@@ -7766,6 +7838,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
dc->fw_name = "PowerPC,POWER7";
dc->desc = "POWER7";
+ dc->props = powerpc_servercpu_properties;
pcc->pvr = CPU_POWERPC_POWER7_BASE;
pcc->pvr_mask = CPU_POWERPC_POWER7_MASK;
pcc->init_proc = init_proc_POWER7;
@@ -7825,6 +7898,7 @@ POWERPC_FAMILY(POWER7P)(ObjectClass *oc, void *data)
dc->fw_name = "PowerPC,POWER7+";
dc->desc = "POWER7+";
+ dc->props = powerpc_servercpu_properties;
pcc->pvr = CPU_POWERPC_POWER7P_BASE;
pcc->pvr_mask = CPU_POWERPC_POWER7P_MASK;
pcc->init_proc = init_proc_POWER7;
@@ -7896,6 +7970,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
dc->fw_name = "PowerPC,POWER8";
dc->desc = "POWER8";
+ dc->props = powerpc_servercpu_properties;
pcc->pvr = CPU_POWERPC_POWER8_BASE;
pcc->pvr_mask = CPU_POWERPC_POWER8_MASK;
pcc->init_proc = init_proc_POWER8;