7a3408
From 487347db121ea526b8bd8c90fef223b57b058530 Mon Sep 17 00:00:00 2001
7a3408
Message-Id: <487347db121ea526b8bd8c90fef223b57b058530@dist-git>
7a3408
From: Andrea Bolognani <abologna@redhat.com>
7a3408
Date: Fri, 21 Aug 2015 16:36:02 -0700
7a3408
Subject: [PATCH] cpu: Better support for ppc64 compatibility modes
7a3408
7a3408
Not all combinations of host CPU models and compatibility modes
7a3408
are valid, so we need to make sure we don't try to do something
7a3408
that QEMU will reject.
7a3408
7a3408
Moreover, we need to apply a different logic to guests using
7a3408
host-model and host-passthrough modes when testing them for host
7a3408
compatibility.
7a3408
7a3408
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1251927
7a3408
(cherry picked from commit 2f913162ed615faa7227d7366b39fa59b23f233d)
7a3408
7a3408
Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1251927
7a3408
7a3408
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
7a3408
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
7a3408
---
7a3408
 src/cpu/cpu_ppc64.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++--
7a3408
 1 file changed, 86 insertions(+), 3 deletions(-)
7a3408
7a3408
diff --git a/src/cpu/cpu_ppc64.c b/src/cpu/cpu_ppc64.c
7a3408
index 72b8fa0..a72cc32 100644
7a3408
--- a/src/cpu/cpu_ppc64.c
7a3408
+++ b/src/cpu/cpu_ppc64.c
7a3408
@@ -84,6 +84,53 @@ ppc64ConvertLegacyCPUDef(const virCPUDef *legacy)
7a3408
     return cpu;
7a3408
 }
7a3408
 
7a3408
+/* Some hosts can run guests in compatibility mode, but not all
7a3408
+ * host CPUs support this and not all combinations are valid.
7a3408
+ * This function performs the necessary checks */
7a3408
+static virCPUCompareResult
7a3408
+ppc64CheckCompatibilityMode(const char *host_model,
7a3408
+                            const char *compat_mode)
7a3408
+{
7a3408
+    int host;
7a3408
+    int compat;
7a3408
+    char *tmp;
7a3408
+    virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR;
7a3408
+
7a3408
+    if (!compat_mode)
7a3408
+        return VIR_CPU_COMPARE_IDENTICAL;
7a3408
+
7a3408
+    /* Valid host CPUs: POWER6, POWER7, POWER8 */
7a3408
+    if (!STRPREFIX(host_model, "POWER") ||
7a3408
+        !(tmp = (char *) host_model + strlen("POWER")) ||
7a3408
+        virStrToLong_i(tmp, NULL, 10, &host) < 0 ||
7a3408
+        host < 6 || host > 8) {
7a3408
+        virReportError(VIR_ERR_INTERNAL_ERROR,
7a3408
+                       "%s",
7a3408
+                       _("Host CPU does not support compatibility modes"));
7a3408
+        goto out;
7a3408
+    }
7a3408
+
7a3408
+    /* Valid compatibility modes: power6, power7, power8 */
7a3408
+    if (!STRPREFIX(compat_mode, "power") ||
7a3408
+        !(tmp = (char *) compat_mode + strlen("power")) ||
7a3408
+        virStrToLong_i(tmp, NULL, 10, &compat) < 0 ||
7a3408
+        compat < 6 || compat > 8) {
7a3408
+        virReportError(VIR_ERR_INTERNAL_ERROR,
7a3408
+                       _("Unknown compatibility mode %s"),
7a3408
+                       compat_mode);
7a3408
+        goto out;
7a3408
+    }
7a3408
+
7a3408
+    /* Version check */
7a3408
+    if (compat > host)
7a3408
+        ret = VIR_CPU_COMPARE_INCOMPATIBLE;
7a3408
+    else
7a3408
+        ret = VIR_CPU_COMPARE_IDENTICAL;
7a3408
+
7a3408
+ out:
7a3408
+    return ret;
7a3408
+}
7a3408
+
7a3408
 static void
7a3408
 ppc64DataFree(virCPUppc64Data *data)
7a3408
 {
7a3408
@@ -509,11 +556,47 @@ ppc64Compute(virCPUDefPtr host,
7a3408
         goto cleanup;
7a3408
     }
7a3408
 
7a3408
-    if (!(map = ppc64LoadMap()) ||
7a3408
-        !(host_model = ppc64ModelFromCPU(host, map)) ||
7a3408
-        !(guest_model = ppc64ModelFromCPU(cpu, map)))
7a3408
+    if (!(map = ppc64LoadMap()))
7a3408
         goto cleanup;
7a3408
 
7a3408
+    /* Host CPU information */
7a3408
+    if (!(host_model = ppc64ModelFromCPU(host, map)))
7a3408
+        goto cleanup;
7a3408
+
7a3408
+    if (cpu->type == VIR_CPU_TYPE_GUEST) {
7a3408
+        /* Guest CPU information */
7a3408
+        virCPUCompareResult tmp;
7a3408
+        switch (cpu->mode) {
7a3408
+        case VIR_CPU_MODE_HOST_MODEL:
7a3408
+            /* host-model only:
7a3408
+             * we need to take compatibility modes into account */
7a3408
+            tmp = ppc64CheckCompatibilityMode(host->model, cpu->model);
7a3408
+            if (tmp != VIR_CPU_COMPARE_IDENTICAL) {
7a3408
+                ret = tmp;
7a3408
+                goto cleanup;
7a3408
+            }
7a3408
+            /* fallthrough */
7a3408
+
7a3408
+        case VIR_CPU_MODE_HOST_PASSTHROUGH:
7a3408
+            /* host-model and host-passthrough:
7a3408
+             * the guest CPU is the same as the host */
7a3408
+            if (!(guest_model = ppc64ModelCopy(host_model)))
7a3408
+                goto cleanup;
7a3408
+            break;
7a3408
+
7a3408
+        case VIR_CPU_MODE_CUSTOM:
7a3408
+            /* custom:
7a3408
+             * look up guest CPU information */
7a3408
+            if (!(guest_model = ppc64ModelFromCPU(cpu, map)))
7a3408
+                goto cleanup;
7a3408
+            break;
7a3408
+        }
7a3408
+    } else {
7a3408
+        /* Other host CPU information */
7a3408
+        if (!(guest_model = ppc64ModelFromCPU(cpu, map)))
7a3408
+            goto cleanup;
7a3408
+    }
7a3408
+
7a3408
     if (STRNEQ(guest_model->name, host_model->name)) {
7a3408
         VIR_DEBUG("host CPU model does not match required CPU model %s",
7a3408
                   guest_model->name);
7a3408
-- 
7a3408
2.5.0
7a3408