On Thu, Aug 29, 2013 at 3:46 AM, Li Zhang <zhlcindy@gmail.com> wrote:
From: Li Zhang <zhlcindy@linux.vnet.ibm.com>

On Power platform, Power7+ can support Power7 guest.
It needs to define XML configuration to specify guest's CPU model.

For exmaple:
  <cpu match='exact'>
    <model>POWER7+_v2.1</model>
    <vendor>IBM</vendor>
  </cpu>

Signed-off-by: Li Zhang <zhlcindy@linux.vnet.ibm.com>
---
 src/cpu/cpu_powerpc.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 164 insertions(+), 2 deletions(-)

diff --git a/src/cpu/cpu_powerpc.c b/src/cpu/cpu_powerpc.c
index 647a8a1..84fa3f7 100644
--- a/src/cpu/cpu_powerpc.c
+++ b/src/cpu/cpu_powerpc.c
@@ -99,6 +99,23 @@ ppcModelFindPVR(const struct ppc_map *map,
     return NULL;
 }

+static struct ppc_model *
+ppcModelCopy(const struct ppc_model *model)
+{
+    struct ppc_model *copy;
+
+    if (VIR_ALLOC(copy) < 0 ||
+        VIR_STRDUP(copy->name, model->name) < 0) {
+        ppcModelFree(copy);
+        return NULL;
+    }
+
+    copy->data.pvr = model->data.pvr;
+    copy->vendor = model->vendor;
+
+    return copy;
+}
+
 static struct ppc_vendor *
 ppcVendorFind(const struct ppc_map *map,
               const char *name)
@@ -126,6 +143,29 @@ ppcVendorFree(struct ppc_vendor *vendor)
     VIR_FREE(vendor);
 }

+static struct ppc_model *
+ppcModelFromCPU(const virCPUDefPtr cpu,
+                const struct ppc_map *map)
+{
+    struct ppc_model *model = NULL;
+
+    if ((model = ppcModelFind(map, cpu->model)) == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Unknown CPU model %s"), cpu->model);
+        goto error;
+    }
+
+    if ((model = ppcModelCopy(model)) == NULL)
+        goto error;
+
+    return model;
+
+error:
+    ppcModelFree(model);
+    return NULL;
+}
+
+
 static int
 ppcVendorLoad(xmlXPathContextPtr ctxt,
               struct ppc_map *map)
@@ -288,6 +328,112 @@ error:
     return NULL;
 }

+static virCPUDataPtr
+ppcMakeCPUData(virArch arch, struct cpuPPCData *data)
+{
+    virCPUDataPtr cpuData;
+
+    if (VIR_ALLOC(cpuData) < 0)
+        return NULL;
+
+    cpuData->arch = arch;
+    cpuData->data.ppc = *data;
+    data = NULL;
+
+    return cpuData;
+}
+
+static virCPUCompareResult
+ppcCompute(virCPUDefPtr host,
+             const virCPUDefPtr cpu,
+             virCPUDataPtr *guestData,
+             char **message)
+
+{
+    struct ppc_map *map = NULL;
+    struct ppc_model *host_model = NULL;
+    struct ppc_model *guest_model = NULL;
+
+    int ret = 0;
+    virArch arch;
+    size_t i;
+
+    if (cpu->arch != VIR_ARCH_NONE) {
+        bool found = false;
+
+        for (i = 0; i < ARRAY_CARDINALITY(archs); i++) {
+            if (archs[i] == cpu->arch) {
+                found = true;
+                break;
+            }
+        }
+
+        if (!found) {
+            VIR_DEBUG("CPU arch %s does not match host arch",
+                      virArchToString(cpu->arch));
+            if (message &&
+                virAsprintf(message,
+                            _("CPU arch %s does not match host arch"),
+                            virArchToString(cpu->arch)) < 0)
+                goto error;
+            return VIR_CPU_COMPARE_INCOMPATIBLE;
+        }
+        arch = cpu->arch;
+    } else {
+        arch = host->arch;
+    }
+
+   if (cpu->vendor &&
+        (!host->vendor || STRNEQ(cpu->vendor, host->vendor))) {
+        VIR_DEBUG("host CPU vendor does not match required CPU vendor %s",
+                  cpu->vendor);
+        if (message &&
+            virAsprintf(message,
+                        _("host CPU vendor does not match required "
+                          "CPU vendor %s"),
+                        cpu->vendor) < 0)
+            goto error;
+        return VIR_CPU_COMPARE_INCOMPATIBLE;
+    }

Could this beginning part of ppcCompute() not go into some common function in cpu_generic.c? It just looks entirely copied and pasted from cpu_x86.c from x86Compute()
 
+
+    if (!(map = ppcLoadMap()) ||
+        !(host_model = ppcModelFromCPU(host, map)) ||
+        !(guest_model = ppcModelFromCPU(cpu, map)))
+        goto error;
+
+    if (guestData != NULL) {
+        if (cpu->type == VIR_CPU_TYPE_GUEST &&
+            cpu->match == VIR_CPU_MATCH_STRICT &&
+            STRNEQ(guest_model->name, host_model->name)) {
+            VIR_DEBUG("host CPU model does not match required CPU model %s",
+                     guest_model->name);
+            if (message &&
+                virAsprintf(message,
+                            _("host CPU model does not match required "
+                            "CPU model %s"),
+                            guest_model->name) < 0)
+                goto error;
+            return VIR_CPU_COMPARE_INCOMPATIBLE;
+        }
+
+        if (!(*guestData = ppcMakeCPUData(arch, &guest_model->data)))
+            goto error;
+    }
+
+    ret = VIR_CPU_COMPARE_IDENTICAL;
+
+out:

I don't see this label used anywhere.
 
+   ppcMapFree(map);
+   ppcModelFree(host_model);
+   ppcModelFree(guest_model);
+   return ret;
+
+error:
+   ret = VIR_CPU_COMPARE_ERROR;
+   goto out;
+
+}
+
 static virCPUCompareResult
 ppcCompare(virCPUDefPtr host,
            virCPUDefPtr cpu)
@@ -369,6 +515,15 @@ ppcNodeData(void)
 }
 #endif

+static virCPUCompareResult
+ppcGuestData(virCPUDefPtr host,
+             virCPUDefPtr guest,
+             virCPUDataPtr *data,
+             char **message)
+{
+    return ppcCompute(host, guest, data, message);
+}
+
 static int
 ppcUpdate(virCPUDefPtr guest ATTRIBUTE_UNUSED,
           const virCPUDefPtr host ATTRIBUTE_UNUSED)
@@ -466,6 +621,13 @@ error:
     goto cleanup;
 }

+static int
+ppcHasFeature(const virCPUDataPtr data ATTRIBUTE_UNUSED,
+                         const char *name ATTRIBUTE_UNUSED)
+{
+    return 0;
+}
+

I'm really curious about this addition. I'm assuming you are hitting a check from qemu_command.c and I'm wondering which one because it likely seems that we need to fix that rather than just providing this dummy stub. That or this was left in and isn't really necessary.
 
 struct cpuArchDriver cpuDriverPowerPC = {
     .name = "ppc64",
     .arch = archs,
@@ -479,8 +641,8 @@ struct cpuArchDriver cpuDriverPowerPC = {
 #else
     .nodeData   = NULL,
 #endif
-    .guestData  = NULL,
+    .guestData  = ppcGuestData,
     .baseline   = ppcBaseline,
     .update     = ppcUpdate,
-    .hasFeature = NULL,
+    .hasFeature = ppcHasFeature,
 };
--
1.8.1.4


I don't have PPC however so I can't actually test the code. But I did add a few comments above.

--
Doug Goldstein