Blame SOURCES/kvm-PPC-KVM-Support-machine-option-to-set-VSMT-mode.patch

4a2fec
From cdb93019369dff9f8a3ab19df18f24a5ba508698 Mon Sep 17 00:00:00 2001
4a2fec
From: Sam Bobroff <sbobroff@redhat.com>
4a2fec
Date: Fri, 6 Oct 2017 06:04:59 +0200
4a2fec
Subject: [PATCH 13/34] PPC: KVM: Support machine option to set VSMT mode
4a2fec
4a2fec
RH-Author: Sam Bobroff <sbobroff@redhat.com>
4a2fec
Message-id: <1507269899-22908-1-git-send-email-sbobroff@redhat.com>
4a2fec
Patchwork-id: 76834
4a2fec
O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH] PPC: KVM: Support machine option to set VSMT mode
4a2fec
Bugzilla: 1479178
4a2fec
RH-Acked-by: David Gibson <dgibson@redhat.com>
4a2fec
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
4a2fec
RH-Acked-by: Thomas Huth <thuth@redhat.com>
4a2fec
4a2fec
From: Sam Bobroff <sam.bobroff@au1.ibm.com>
4a2fec
4a2fec
KVM now allows writing to KVM_CAP_PPC_SMT which has previously been
4a2fec
read only. Doing so causes KVM to act, for that VM, as if the host's
4a2fec
SMT mode was the given value. This is particularly important on Power
4a2fec
9 systems because their default value is 1, but they are able to
4a2fec
support values up to 8.
4a2fec
4a2fec
This patch introduces a way to control this capability via a new
4a2fec
machine property called VSMT ("Virtual SMT"). If the value is not set
4a2fec
on the command line a default is chosen that is, when possible,
4a2fec
compatible with legacy systems.
4a2fec
4a2fec
Note that the intialization of KVM_CAP_PPC_SMT has changed slightly
4a2fec
because it has changed (in KVM) from a global capability to a
4a2fec
VM-specific one. This won't cause a problem on older KVMs because VM
4a2fec
capabilities fall back to global ones.
4a2fec
4a2fec
Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com>
4a2fec
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
4a2fec
(cherry picked from commit fa98fbfcdfcb980b4a690b8bc93ab597935087b1)
4a2fec
4a2fec
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1479178
4a2fec
Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=14187630
4a2fec
Testing: Start QEMU using "--machine pseries,vsmt=4".
4a2fec
Signed-off-by: Sam Bobroff <sbobroff@redhat.com>
4a2fec
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
4a2fec
---
4a2fec
 hw/ppc/spapr.c              | 75 +++++++++++++++++++++++++++++++++++++++++++++
4a2fec
 include/hw/ppc/spapr.h      |  1 +
4a2fec
 target/ppc/kvm.c            | 39 ++++++++++++++++++++++-
4a2fec
 target/ppc/kvm_ppc.h        | 12 ++++++++
4a2fec
 target/ppc/translate_init.c | 14 ---------
4a2fec
 5 files changed, 126 insertions(+), 15 deletions(-)
4a2fec
4a2fec
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
4a2fec
index d3db051..30b2c5b 100644
4a2fec
--- a/hw/ppc/spapr.c
4a2fec
+++ b/hw/ppc/spapr.c
4a2fec
@@ -26,6 +26,7 @@
4a2fec
  */
4a2fec
 #include "qemu/osdep.h"
4a2fec
 #include "qapi/error.h"
4a2fec
+#include "qapi/visitor.h"
4a2fec
 #include "sysemu/sysemu.h"
4a2fec
 #include "sysemu/numa.h"
4a2fec
 #include "hw/hw.h"
4a2fec
@@ -2166,6 +2167,61 @@ static void spapr_init_cpus(sPAPRMachineState *spapr)
4a2fec
     g_free(type);
4a2fec
 }
4a2fec
 
4a2fec
+static void spapr_set_vsmt_mode(sPAPRMachineState *spapr, Error **errp)
4a2fec
+{
4a2fec
+    Error *local_err = NULL;
4a2fec
+    bool vsmt_user = !!spapr->vsmt;
4a2fec
+    int kvm_smt = kvmppc_smt_threads();
4a2fec
+    int ret;
4a2fec
+
4a2fec
+    if (!kvm_enabled() && (smp_threads > 1)) {
4a2fec
+        error_setg(&local_err, "TCG cannot support more than 1 thread/core "
4a2fec
+                     "on a pseries machine");
4a2fec
+        goto out;
4a2fec
+    }
4a2fec
+    if (!is_power_of_2(smp_threads)) {
4a2fec
+        error_setg(&local_err, "Cannot support %d threads/core on a pseries "
4a2fec
+                     "machine because it must be a power of 2", smp_threads);
4a2fec
+        goto out;
4a2fec
+    }
4a2fec
+
4a2fec
+    /* Detemine the VSMT mode to use: */
4a2fec
+    if (vsmt_user) {
4a2fec
+        if (spapr->vsmt < smp_threads) {
4a2fec
+            error_setg(&local_err, "Cannot support VSMT mode %d"
4a2fec
+                         " because it must be >= threads/core (%d)",
4a2fec
+                         spapr->vsmt, smp_threads);
4a2fec
+            goto out;
4a2fec
+        }
4a2fec
+        /* In this case, spapr->vsmt has been set by the command line */
4a2fec
+    } else {
4a2fec
+        /* Choose a VSMT mode that may be higher than necessary but is
4a2fec
+         * likely to be compatible with hosts that don't have VSMT. */
4a2fec
+        spapr->vsmt = MAX(kvm_smt, smp_threads);
4a2fec
+    }
4a2fec
+
4a2fec
+    /* KVM: If necessary, set the SMT mode: */
4a2fec
+    if (kvm_enabled() && (spapr->vsmt != kvm_smt)) {
4a2fec
+        ret = kvmppc_set_smt_threads(spapr->vsmt);
4a2fec
+        if (ret) {
4a2fec
+            error_setg(&local_err,
4a2fec
+                       "Failed to set KVM's VSMT mode to %d (errno %d)",
4a2fec
+                       spapr->vsmt, ret);
4a2fec
+            if (!vsmt_user) {
4a2fec
+                error_append_hint(&local_err, "On PPC, a VM with %d threads/"
4a2fec
+                             "core on a host with %d threads/core requires "
4a2fec
+                             " the use of VSMT mode %d.\n",
4a2fec
+                             smp_threads, kvm_smt, spapr->vsmt);
4a2fec
+            }
4a2fec
+            kvmppc_hint_smt_possible(&local_err);
4a2fec
+            goto out;
4a2fec
+        }
4a2fec
+    }
4a2fec
+    /* else TCG: nothing to do currently */
4a2fec
+out:
4a2fec
+    error_propagate(errp, local_err);
4a2fec
+}
4a2fec
+
4a2fec
 /* pSeries LPAR / sPAPR hardware init */
4a2fec
 static void ppc_spapr_init(MachineState *machine)
4a2fec
 {
4a2fec
@@ -2298,6 +2354,8 @@ static void ppc_spapr_init(MachineState *machine)
4a2fec
 
4a2fec
     spapr_cpu_parse_features(spapr);
4a2fec
 
4a2fec
+    spapr_set_vsmt_mode(spapr, &error_fatal);
4a2fec
+
4a2fec
     spapr_init_cpus(spapr);
4a2fec
 
4a2fec
     if (kvm_enabled()) {
4a2fec
@@ -2682,6 +2740,18 @@ static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp)
4a2fec
     }
4a2fec
 }
4a2fec
 
4a2fec
+static void spapr_get_vsmt(Object *obj, Visitor *v, const char *name,
4a2fec
+                                   void *opaque, Error **errp)
4a2fec
+{
4a2fec
+    visit_type_uint32(v, name, (uint32_t *)opaque, errp);
4a2fec
+}
4a2fec
+
4a2fec
+static void spapr_set_vsmt(Object *obj, Visitor *v, const char *name,
4a2fec
+                                   void *opaque, Error **errp)
4a2fec
+{
4a2fec
+    visit_type_uint32(v, name, (uint32_t *)opaque, errp);
4a2fec
+}
4a2fec
+
4a2fec
 static void spapr_machine_initfn(Object *obj)
4a2fec
 {
4a2fec
     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
4a2fec
@@ -2712,6 +2782,11 @@ static void spapr_machine_initfn(Object *obj)
4a2fec
     object_property_set_description(obj, "resize-hpt",
4a2fec
                                     "Resizing of the Hash Page Table (enabled, disabled, required)",
4a2fec
                                     NULL);
4a2fec
+    object_property_add(obj, "vsmt", "uint32", spapr_get_vsmt,
4a2fec
+                        spapr_set_vsmt, NULL, &spapr->vsmt, &error_abort);
4a2fec
+    object_property_set_description(obj, "vsmt",
4a2fec
+                                    "Virtual SMT: KVM behaves as if this were"
4a2fec
+                                    " the host's SMT mode", &error_abort);
4a2fec
 }
4a2fec
 
4a2fec
 static void spapr_machine_finalizefn(Object *obj)
4a2fec
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
4a2fec
index 5d161ec..3d0d206 100644
4a2fec
--- a/include/hw/ppc/spapr.h
4a2fec
+++ b/include/hw/ppc/spapr.h
4a2fec
@@ -99,6 +99,7 @@ struct sPAPRMachineState {
4a2fec
     uint64_t rtc_offset; /* Now used only during incoming migration */
4a2fec
     struct PPCTimebase tb;
4a2fec
     bool has_graphics;
4a2fec
+    uint32_t vsmt;       /* Virtual SMT mode (KVM's "core stride") */
4a2fec
 
4a2fec
     Notifier epow_notifier;
4a2fec
     QTAILQ_HEAD(, sPAPREventLogEntry) pending_events;
4a2fec
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
4a2fec
index f31c67e..ce7e2ec 100644
4a2fec
--- a/target/ppc/kvm.c
4a2fec
+++ b/target/ppc/kvm.c
4a2fec
@@ -74,6 +74,7 @@ static int cap_interrupt_level = false;
4a2fec
 static int cap_segstate;
4a2fec
 static int cap_booke_sregs;
4a2fec
 static int cap_ppc_smt;
4a2fec
+static int cap_ppc_smt_possible;
4a2fec
 static int cap_ppc_rma;
4a2fec
 static int cap_spapr_tce;
4a2fec
 static int cap_spapr_tce_64;
4a2fec
@@ -130,7 +131,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
4a2fec
     cap_interrupt_level = kvm_check_extension(s, KVM_CAP_PPC_IRQ_LEVEL);
4a2fec
     cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE);
4a2fec
     cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS);
4a2fec
-    cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT);
4a2fec
+    cap_ppc_smt_possible = kvm_check_extension(s, KVM_CAP_PPC_SMT_POSSIBLE);
4a2fec
     cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA);
4a2fec
     cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE);
4a2fec
     cap_spapr_tce_64 = kvm_check_extension(s, KVM_CAP_SPAPR_TCE_64);
4a2fec
@@ -144,6 +145,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
4a2fec
      * only activated after this by kvmppc_set_papr() */
4a2fec
     cap_htab_fd = kvm_check_extension(s, KVM_CAP_PPC_HTAB_FD);
4a2fec
     cap_fixup_hcalls = kvm_check_extension(s, KVM_CAP_PPC_FIXUP_HCALL);
4a2fec
+    cap_ppc_smt = kvm_vm_check_extension(s, KVM_CAP_PPC_SMT);
4a2fec
     cap_htm = kvm_vm_check_extension(s, KVM_CAP_PPC_HTM);
4a2fec
     cap_mmu_radix = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_RADIX);
4a2fec
     cap_mmu_hash_v3 = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_HASH_V3);
4a2fec
@@ -2134,6 +2136,41 @@ int kvmppc_smt_threads(void)
4a2fec
     return cap_ppc_smt ? cap_ppc_smt : 1;
4a2fec
 }
4a2fec
 
4a2fec
+int kvmppc_set_smt_threads(int smt)
4a2fec
+{
4a2fec
+    int ret;
4a2fec
+
4a2fec
+    ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_PPC_SMT, 0, smt, 0);
4a2fec
+    if (!ret) {
4a2fec
+        cap_ppc_smt = smt;
4a2fec
+    }
4a2fec
+    return ret;
4a2fec
+}
4a2fec
+
4a2fec
+void kvmppc_hint_smt_possible(Error **errp)
4a2fec
+{
4a2fec
+    int i;
4a2fec
+    GString *g;
4a2fec
+    char *s;
4a2fec
+
4a2fec
+    assert(kvm_enabled());
4a2fec
+    if (cap_ppc_smt_possible) {
4a2fec
+        g = g_string_new("Available VSMT modes:");
4a2fec
+        for (i = 63; i >= 0; i--) {
4a2fec
+            if ((1UL << i) & cap_ppc_smt_possible) {
4a2fec
+                g_string_append_printf(g, " %lu", (1UL << i));
4a2fec
+            }
4a2fec
+        }
4a2fec
+        s = g_string_free(g, false);
4a2fec
+        error_append_hint(errp, "%s.\n", s);
4a2fec
+        g_free(s);
4a2fec
+    } else {
4a2fec
+        error_append_hint(errp,
4a2fec
+                          "This KVM seems to be too old to support VSMT.\n");
4a2fec
+    }
4a2fec
+}
4a2fec
+
4a2fec
+
4a2fec
 #ifdef TARGET_PPC64
4a2fec
 off_t kvmppc_alloc_rma(void **rma)
4a2fec
 {
4a2fec
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
4a2fec
index 381afe6..e6711fc 100644
4a2fec
--- a/target/ppc/kvm_ppc.h
4a2fec
+++ b/target/ppc/kvm_ppc.h
4a2fec
@@ -29,6 +29,8 @@ void kvmppc_set_papr(PowerPCCPU *cpu);
4a2fec
 int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr);
4a2fec
 void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy);
4a2fec
 int kvmppc_smt_threads(void);
4a2fec
+void kvmppc_hint_smt_possible(Error **errp);
4a2fec
+int kvmppc_set_smt_threads(int smt);
4a2fec
 int kvmppc_clear_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits);
4a2fec
 int kvmppc_or_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits);
4a2fec
 int kvmppc_set_tcr(PowerPCCPU *cpu);
4a2fec
@@ -148,6 +150,16 @@ static inline int kvmppc_smt_threads(void)
4a2fec
     return 1;
4a2fec
 }
4a2fec
 
4a2fec
+static inline void kvmppc_hint_smt_possible(Error **errp)
4a2fec
+{
4a2fec
+    return;
4a2fec
+}
4a2fec
+
4a2fec
+static inline int kvmppc_set_smt_threads(int smt)
4a2fec
+{
4a2fec
+    return 0;
4a2fec
+}
4a2fec
+
4a2fec
 static inline int kvmppc_or_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits)
4a2fec
 {
4a2fec
     return 0;
4a2fec
diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c
4a2fec
index 8fb407e..371bbae 100644
4a2fec
--- a/target/ppc/translate_init.c
4a2fec
+++ b/target/ppc/translate_init.c
4a2fec
@@ -9817,20 +9817,6 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp)
4a2fec
     int max_smt = kvmppc_smt_threads();
4a2fec
 #endif
4a2fec
 
4a2fec
-#if !defined(CONFIG_USER_ONLY)
4a2fec
-    if (smp_threads > max_smt) {
4a2fec
-        error_setg(errp, "Cannot support more than %d threads on PPC with %s",
4a2fec
-                   max_smt, kvm_enabled() ? "KVM" : "TCG");
4a2fec
-        return;
4a2fec
-    }
4a2fec
-    if (!is_power_of_2(smp_threads)) {
4a2fec
-        error_setg(errp, "Cannot support %d threads on PPC with %s, "
4a2fec
-                   "threads count must be a power of 2.",
4a2fec
-                   smp_threads, kvm_enabled() ? "KVM" : "TCG");
4a2fec
-        return;
4a2fec
-    }
4a2fec
-#endif
4a2fec
-
4a2fec
     cpu_exec_realizefn(cs, &local_err);
4a2fec
     if (local_err != NULL) {
4a2fec
         error_propagate(errp, local_err);
4a2fec
-- 
4a2fec
1.8.3.1
4a2fec