From b3d87dd88a9497f9c778be14880ab389e640da56 Mon Sep 17 00:00:00 2001
From: Alexey Kardashevskiy <aik@ozlabs.ru>
Date: Fri, 4 Jul 2014 00:48:55 +1000
Subject: [PATCH] target-ppc: Add pvr_match() callback

So far it was enough to have a base PVR value and mask per CPU
family such as POWER7 or POWER8. However there CPUs which are
completely architecturally compatible but have different PVRs such
as POWER7/POWER7+ and POWER8/POWER8E. For these CPUs, top 16 bits
are CPU family and low 16 bits are the version. The families have
PVR base values different enough so defining a mask which
would cover both (or potentially more) CPUs within the family is
not possible.

This adds a pvr_match() callback to PowerPCCPUClass. The default
handler simply compares PVR defined in the class.

This implements ppc_pvr_match_power7/ppc_pvr_match_power8 callbacks
for POWER7/8 families. These check for POWER7/POWER7+ and POWER8/POWER8E.

This changes ppc_cpu_compare_class_pvr_mask() not to check masks but
use the pvr_match() callback.

Since all server CPUs use the same mask, this defines one mask
value - CPU_POWERPC_POWER_SERVER_MASK - which is used everywhere now.
This removes other mask definitions.

This removes pvr_mask from PowerPCCPUClass as it is not used anymore.
This removes pvr initialization for POWER7/8 families as it is not used
to find the class, the pvr_match() callback is used instead.

Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Signed-off-by: Alexander Graf <agraf@suse.de>
(cherry picked from commit 22168903f3e108528d19afa3d1f227c06d2ee5ec)
Signed-off-by: Alexander Graf <agraf@suse.de>
---
 target-ppc/cpu-models.c     |  1 -
 target-ppc/cpu-models.h     |  6 +-----
 target-ppc/cpu-qom.h        |  2 +-
 target-ppc/translate_init.c | 49 ++++++++++++++++++++++++++++++++-------------
 4 files changed, 37 insertions(+), 21 deletions(-)

diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c
index 05d088a..24ee80a 100644
--- a/target-ppc/cpu-models.c
+++ b/target-ppc/cpu-models.c
@@ -44,7 +44,6 @@
         PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);                       \
                                                                             \
         pcc->pvr          = _pvr;                                           \
-        pcc->pvr_mask     = CPU_POWERPC_DEFAULT_MASK;                       \
         pcc->svr          = _svr;                                           \
         dc->desc          = _desc;                                          \
     }                                                                       \
diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h
index c39d03a..290a759 100644
--- a/target-ppc/cpu-models.h
+++ b/target-ppc/cpu-models.h
@@ -39,7 +39,6 @@ extern PowerPCCPUAlias ppc_cpu_aliases[];
 /*****************************************************************************/
 /* PVR definitions for most known PowerPC                                    */
 enum {
-    CPU_POWERPC_DEFAULT_MASK       = 0xFFFFFFFF,
     /* PowerPC 401 family */
     /* Generic PowerPC 401 */
 #define CPU_POWERPC_401              CPU_POWERPC_401G2
@@ -553,17 +552,14 @@ enum {
     CPU_POWERPC_POWER6             = 0x003E0000,
     CPU_POWERPC_POWER6_5           = 0x0F000001, /* POWER6 in POWER5 mode */
     CPU_POWERPC_POWER6A            = 0x0F000002,
+    CPU_POWERPC_POWER_SERVER_MASK  = 0xFFFF0000,
     CPU_POWERPC_POWER7_BASE        = 0x003F0000,
-    CPU_POWERPC_POWER7_MASK        = 0xFFFF0000,
     CPU_POWERPC_POWER7_v23         = 0x003F0203,
     CPU_POWERPC_POWER7P_BASE       = 0x004A0000,
-    CPU_POWERPC_POWER7P_MASK       = 0xFFFF0000,
     CPU_POWERPC_POWER7P_v21        = 0x004A0201,
     CPU_POWERPC_POWER8E_BASE       = 0x004B0000,
-    CPU_POWERPC_POWER8E_MASK       = 0xFFFF0000,
     CPU_POWERPC_POWER8E_v10        = 0x004B0100,
     CPU_POWERPC_POWER8_BASE        = 0x004D0000,
-    CPU_POWERPC_POWER8_MASK        = 0xFFFF0000,
     CPU_POWERPC_POWER8_v10         = 0x004D0100,
     CPU_POWERPC_970                = 0x00390202,
     CPU_POWERPC_970FX_v10          = 0x00391100,
diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h
index 13c7031..4ae3a5e 100644
--- a/target-ppc/cpu-qom.h
+++ b/target-ppc/cpu-qom.h
@@ -56,7 +56,7 @@ typedef struct PowerPCCPUClass {
     void (*parent_reset)(CPUState *cpu);
 
     uint32_t pvr;
-    uint32_t pvr_mask;
+    bool (*pvr_match)(struct PowerPCCPUClass *pcc, uint32_t pvr);
     uint64_t pcr_mask;
     uint32_t svr;
     uint64_t insns_flags;
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 86ce3d3..ce63e60 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -7149,6 +7149,17 @@ static void init_proc_POWER7 (CPUPPCState *env)
                  0x00000000);
 }
 
+static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr)
+{
+    if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER7P_BASE) {
+        return true;
+    }
+    if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER7_BASE) {
+        return true;
+    }
+    return false;
+}
+
 POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
@@ -7157,8 +7168,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->pvr_match = ppc_pvr_match_power7;
     pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06;
     pcc->init_proc = init_proc_POWER7;
     pcc->check_pow = check_pow_nocheck;
@@ -7203,8 +7213,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->pvr_match = ppc_pvr_match_power7;
     pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06;
     pcc->init_proc = init_proc_POWER7;
     pcc->check_pow = check_pow_nocheck;
@@ -7253,6 +7262,17 @@ static void init_proc_POWER8(CPUPPCState *env)
                  0x00000000);
 }
 
+static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr)
+{
+    if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER8E_BASE) {
+        return true;
+    }
+    if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER8_BASE) {
+        return true;
+    }
+    return false;
+}
+
 POWERPC_FAMILY(POWER8E)(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
@@ -7261,8 +7281,7 @@ POWERPC_FAMILY(POWER8E)(ObjectClass *oc, void *data)
     dc->fw_name = "PowerPC,POWER8";
     dc->desc = "POWER8E";
     dc->props = powerpc_servercpu_properties;
-    pcc->pvr = CPU_POWERPC_POWER8E_BASE;
-    pcc->pvr_mask = CPU_POWERPC_POWER8E_MASK;
+    pcc->pvr_match = ppc_pvr_match_power8;
     pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06;
     pcc->init_proc = init_proc_POWER8;
     pcc->check_pow = check_pow_nocheck;
@@ -7304,13 +7323,10 @@ POWERPC_FAMILY(POWER8E)(ObjectClass *oc, void *data)
 POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
-    PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
 
     ppc_POWER8E_cpu_family_class_init(oc, data);
 
     dc->desc = "POWER8";
-    pcc->pvr = CPU_POWERPC_POWER8_BASE;
-    pcc->pvr_mask = CPU_POWERPC_POWER8_MASK;
 }
 #endif /* defined (TARGET_PPC64) */
 
@@ -8293,7 +8309,6 @@ static gint ppc_cpu_compare_class_pvr_mask(gconstpointer a, gconstpointer b)
     ObjectClass *oc = (ObjectClass *)a;
     uint32_t pvr = *(uint32_t *)b;
     PowerPCCPUClass *pcc = (PowerPCCPUClass *)a;
-    gint ret;
 
     /* -cpu host does a PVR lookup during construction */
     if (unlikely(strcmp(object_class_get_name(oc),
@@ -8305,9 +8320,11 @@ static gint ppc_cpu_compare_class_pvr_mask(gconstpointer a, gconstpointer b)
         return -1;
     }
 
-    ret = (((pcc->pvr & pcc->pvr_mask) == (pvr & pcc->pvr_mask)) ? 0 : -1);
+    if (pcc->pvr_match(pcc, pvr)) {
+        return 0;
+    }
 
-    return ret;
+    return -1;
 }
 
 PowerPCCPUClass *ppc_cpu_class_by_pvr_mask(uint32_t pvr)
@@ -8697,6 +8714,11 @@ static void ppc_cpu_initfn(Object *obj)
     }
 }
 
+static bool ppc_pvr_match_default(PowerPCCPUClass *pcc, uint32_t pvr)
+{
+    return pcc->pvr == pvr;
+}
+
 static void ppc_cpu_class_init(ObjectClass *oc, void *data)
 {
     PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -8704,8 +8726,7 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
     DeviceClass *dc = DEVICE_CLASS(oc);
 
     pcc->parent_realize = dc->realize;
-    pcc->pvr = CPU_POWERPC_DEFAULT_MASK;
-    pcc->pvr_mask = CPU_POWERPC_DEFAULT_MASK;
+    pcc->pvr_match = ppc_pvr_match_default;
     pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_always;
     dc->realize = ppc_cpu_realizefn;
     dc->unrealize = ppc_cpu_unrealizefn;
