b38b0f
From 4949ead0219a44a8419ac6726f219aafd0f91137 Mon Sep 17 00:00:00 2001
b38b0f
From: Cornelia Huck <cohuck@redhat.com>
b38b0f
Date: Wed, 17 Apr 2019 13:57:40 +0100
b38b0f
Subject: [PATCH 23/24] s390x: refactor reset/reipl handling
b38b0f
b38b0f
RH-Author: Cornelia Huck <cohuck@redhat.com>
b38b0f
Message-id: <20190417135741.25297-24-cohuck@redhat.com>
b38b0f
Patchwork-id: 85802
b38b0f
O-Subject: [RHEL-8.1.0 qemu-kvm PATCH v2 23/24] s390x: refactor reset/reipl handling
b38b0f
Bugzilla: 1699070
b38b0f
RH-Acked-by: David Hildenbrand <david@redhat.com>
b38b0f
RH-Acked-by: Thomas Huth <thuth@redhat.com>
b38b0f
RH-Acked-by: Jens Freimann <jfreimann@redhat.com>
b38b0f
b38b0f
From: David Hildenbrand <david@redhat.com>
b38b0f
b38b0f
Calling pause_all_vcpus()/resume_all_vcpus() from a VCPU thread might
b38b0f
not be the best idea. As pause_all_vcpus() temporarily drops the qemu
b38b0f
mutex, two parallel calls to pause_all_vcpus() can be active at a time,
b38b0f
resulting in a deadlock. (either by two VCPUs or by the main thread and a
b38b0f
VCPU)
b38b0f
b38b0f
Let's handle it via the main loop instead, as suggested by Paolo. If we
b38b0f
would have two parallel reset requests by two different VCPUs at the
b38b0f
same time, the last one would win.
b38b0f
b38b0f
We use the existing ipl device to handle it. The nice side effect is
b38b0f
that we can get rid of reipl_requested.
b38b0f
b38b0f
This change implies that all reset handling now goes via the common
b38b0f
path, so "no-reboot" handling is now active for all kinds of reboots.
b38b0f
b38b0f
Let's execute any CPU initialization code on the target CPU using
b38b0f
run_on_cpu.
b38b0f
b38b0f
Signed-off-by: David Hildenbrand <david@redhat.com>
b38b0f
Message-Id: <20180424101859.10239-1-david@redhat.com>
b38b0f
Acked-by: Thomas Huth <thuth@redhat.com>
b38b0f
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
b38b0f
(cherry picked from commit a30fb811cbe940020a498d2cdac9326cac38b4d9)
b38b0f
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
b38b0f
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
b38b0f
---
b38b0f
 hw/s390x/ipl.c                     | 43 +++++++++++++++++++++++----
b38b0f
 hw/s390x/ipl.h                     | 16 ++++++++--
b38b0f
 hw/s390x/s390-virtio-ccw.c         | 51 ++++++++++++++++++++++++++-----
b38b0f
 include/hw/s390x/s390-virtio-ccw.h |  2 --
b38b0f
 target/s390x/cpu.h                 | 26 ++++++++++++++++
b38b0f
 target/s390x/diag.c                | 61 +++-----------------------------------
b38b0f
 target/s390x/internal.h            |  6 ----
b38b0f
 target/s390x/kvm.c                 |  2 +-
b38b0f
 8 files changed, 127 insertions(+), 80 deletions(-)
b38b0f
b38b0f
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
b38b0f
index 10038ec..ee6701e 100644
b38b0f
--- a/hw/s390x/ipl.c
b38b0f
+++ b/hw/s390x/ipl.c
b38b0f
@@ -26,6 +26,7 @@
b38b0f
 #include "qemu/config-file.h"
b38b0f
 #include "qemu/cutils.h"
b38b0f
 #include "qemu/option.h"
b38b0f
+#include "exec/exec-all.h"
b38b0f
 
b38b0f
 #define KERN_IMAGE_START                0x010000UL
b38b0f
 #define LINUX_MAGIC_ADDR                0x010008UL
b38b0f
@@ -511,12 +512,20 @@ IplParameterBlock *s390_ipl_get_iplb(void)
b38b0f
     return &ipl->iplb;
b38b0f
 }
b38b0f
 
b38b0f
-void s390_reipl_request(void)
b38b0f
+void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type)
b38b0f
 {
b38b0f
     S390IPLState *ipl = get_ipl_device();
b38b0f
 
b38b0f
-    ipl->reipl_requested = true;
b38b0f
-    if (ipl->iplb_valid &&
b38b0f
+    if (reset_type == S390_RESET_EXTERNAL || reset_type == S390_RESET_REIPL) {
b38b0f
+        /* use CPU 0 for full resets */
b38b0f
+        ipl->reset_cpu_index = 0;
b38b0f
+    } else {
b38b0f
+        ipl->reset_cpu_index = cs->cpu_index;
b38b0f
+    }
b38b0f
+    ipl->reset_type = reset_type;
b38b0f
+
b38b0f
+    if (reset_type == S390_RESET_REIPL &&
b38b0f
+        ipl->iplb_valid &&
b38b0f
         !ipl->netboot &&
b38b0f
         ipl->iplb.pbt == S390_IPL_TYPE_CCW &&
b38b0f
         is_virtio_scsi_device(&ipl->iplb)) {
b38b0f
@@ -533,6 +542,31 @@ void s390_reipl_request(void)
b38b0f
         }
b38b0f
     }
b38b0f
     qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
b38b0f
+    /* as this is triggered by a CPU, make sure to exit the loop */
b38b0f
+    if (tcg_enabled()) {
b38b0f
+        cpu_loop_exit(cs);
b38b0f
+    }
b38b0f
+}
b38b0f
+
b38b0f
+void s390_ipl_get_reset_request(CPUState **cs, enum s390_reset *reset_type)
b38b0f
+{
b38b0f
+    S390IPLState *ipl = get_ipl_device();
b38b0f
+
b38b0f
+    *cs = qemu_get_cpu(ipl->reset_cpu_index);
b38b0f
+    if (!*cs) {
b38b0f
+        /* use any CPU */
b38b0f
+        *cs = first_cpu;
b38b0f
+    }
b38b0f
+    *reset_type = ipl->reset_type;
b38b0f
+}
b38b0f
+
b38b0f
+void s390_ipl_clear_reset_request(void)
b38b0f
+{
b38b0f
+    S390IPLState *ipl = get_ipl_device();
b38b0f
+
b38b0f
+    ipl->reset_type = S390_RESET_EXTERNAL;
b38b0f
+    /* use CPU 0 for full resets */
b38b0f
+    ipl->reset_cpu_index = 0;
b38b0f
 }
b38b0f
 
b38b0f
 static void s390_ipl_prepare_qipl(S390CPU *cpu)
b38b0f
@@ -579,11 +613,10 @@ static void s390_ipl_reset(DeviceState *dev)
b38b0f
 {
b38b0f
     S390IPLState *ipl = S390_IPL(dev);
b38b0f
 
b38b0f
-    if (!ipl->reipl_requested) {
b38b0f
+    if (ipl->reset_type != S390_RESET_REIPL) {
b38b0f
         ipl->iplb_valid = false;
b38b0f
         memset(&ipl->iplb, 0, sizeof(IplParameterBlock));
b38b0f
     }
b38b0f
-    ipl->reipl_requested = false;
b38b0f
 }
b38b0f
 
b38b0f
 static void s390_ipl_class_init(ObjectClass *klass, void *data)
b38b0f
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
b38b0f
index 0570d0a..4e87b89 100644
b38b0f
--- a/hw/s390x/ipl.h
b38b0f
+++ b/hw/s390x/ipl.h
b38b0f
@@ -87,7 +87,17 @@ int s390_ipl_set_loadparm(uint8_t *loadparm);
b38b0f
 void s390_ipl_update_diag308(IplParameterBlock *iplb);
b38b0f
 void s390_ipl_prepare_cpu(S390CPU *cpu);
b38b0f
 IplParameterBlock *s390_ipl_get_iplb(void);
b38b0f
-void s390_reipl_request(void);
b38b0f
+
b38b0f
+enum s390_reset {
b38b0f
+    /* default is a reset not triggered by a CPU e.g. issued by QMP */
b38b0f
+    S390_RESET_EXTERNAL = 0,
b38b0f
+    S390_RESET_REIPL,
b38b0f
+    S390_RESET_MODIFIED_CLEAR,
b38b0f
+    S390_RESET_LOAD_NORMAL,
b38b0f
+};
b38b0f
+void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type);
b38b0f
+void s390_ipl_get_reset_request(CPUState **cs, enum s390_reset *reset_type);
b38b0f
+void s390_ipl_clear_reset_request(void);
b38b0f
 
b38b0f
 #define QIPL_ADDRESS  0xcc
b38b0f
 
b38b0f
@@ -129,9 +139,11 @@ struct S390IPLState {
b38b0f
     bool enforce_bios;
b38b0f
     IplParameterBlock iplb;
b38b0f
     bool iplb_valid;
b38b0f
-    bool reipl_requested;
b38b0f
     bool netboot;
b38b0f
     QemuIplParameters qipl;
b38b0f
+    /* reset related properties don't have to be migrated or reset */
b38b0f
+    enum s390_reset reset_type;
b38b0f
+    int reset_cpu_index;
b38b0f
 
b38b0f
     /*< public >*/
b38b0f
     char *kernel;
b38b0f
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
b38b0f
index 8f93edc..ba90e4f 100644
b38b0f
--- a/hw/s390x/s390-virtio-ccw.c
b38b0f
+++ b/hw/s390x/s390-virtio-ccw.c
b38b0f
@@ -95,7 +95,7 @@ static const char *const reset_dev_types[] = {
b38b0f
     "diag288",
b38b0f
 };
b38b0f
 
b38b0f
-void subsystem_reset(void)
b38b0f
+static void subsystem_reset(void)
b38b0f
 {
b38b0f
     DeviceState *dev;
b38b0f
     int i;
b38b0f
@@ -317,17 +317,54 @@ static void s390_cpu_plug(HotplugHandler *hotplug_dev,
b38b0f
     }
b38b0f
 }
b38b0f
 
b38b0f
+static inline void s390_do_cpu_ipl(CPUState *cs, run_on_cpu_data arg)
b38b0f
+{
b38b0f
+    S390CPU *cpu = S390_CPU(cs);
b38b0f
+
b38b0f
+    s390_ipl_prepare_cpu(cpu);
b38b0f
+    s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
b38b0f
+}
b38b0f
+
b38b0f
 static void s390_machine_reset(void)
b38b0f
 {
b38b0f
-    S390CPU *ipl_cpu = S390_CPU(qemu_get_cpu(0));
b38b0f
+    enum s390_reset reset_type;
b38b0f
+    CPUState *cs, *t;
b38b0f
 
b38b0f
+    /* get the reset parameters, reset them once done */
b38b0f
+    s390_ipl_get_reset_request(&cs, &reset_type);
b38b0f
+
b38b0f
+    /* all CPUs are paused and synchronized at this point */
b38b0f
     s390_cmma_reset();
b38b0f
-    qemu_devices_reset();
b38b0f
-    s390_crypto_reset();
b38b0f
 
b38b0f
-    /* all cpus are stopped - configure and start the ipl cpu only */
b38b0f
-    s390_ipl_prepare_cpu(ipl_cpu);
b38b0f
-    s390_cpu_set_state(S390_CPU_STATE_OPERATING, ipl_cpu);
b38b0f
+    switch (reset_type) {
b38b0f
+    case S390_RESET_EXTERNAL:
b38b0f
+    case S390_RESET_REIPL:
b38b0f
+        qemu_devices_reset();
b38b0f
+        s390_crypto_reset();
b38b0f
+
b38b0f
+        /* configure and start the ipl CPU only */
b38b0f
+        run_on_cpu(cs, s390_do_cpu_ipl, RUN_ON_CPU_NULL);
b38b0f
+        break;
b38b0f
+    case S390_RESET_MODIFIED_CLEAR:
b38b0f
+        CPU_FOREACH(t) {
b38b0f
+            run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
b38b0f
+        }
b38b0f
+        subsystem_reset();
b38b0f
+        s390_crypto_reset();
b38b0f
+        run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
b38b0f
+        break;
b38b0f
+    case S390_RESET_LOAD_NORMAL:
b38b0f
+        CPU_FOREACH(t) {
b38b0f
+            run_on_cpu(t, s390_do_cpu_reset, RUN_ON_CPU_NULL);
b38b0f
+        }
b38b0f
+        subsystem_reset();
b38b0f
+        run_on_cpu(cs, s390_do_cpu_initial_reset, RUN_ON_CPU_NULL);
b38b0f
+        run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
b38b0f
+        break;
b38b0f
+    default:
b38b0f
+        g_assert_not_reached();
b38b0f
+    }
b38b0f
+    s390_ipl_clear_reset_request();
b38b0f
 }
b38b0f
 
b38b0f
 static void s390_machine_device_plug(HotplugHandler *hotplug_dev,
b38b0f
diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h
b38b0f
index ac896e3..ab88d49 100644
b38b0f
--- a/include/hw/s390x/s390-virtio-ccw.h
b38b0f
+++ b/include/hw/s390x/s390-virtio-ccw.h
b38b0f
@@ -53,6 +53,4 @@ bool cpu_model_allowed(void);
b38b0f
  */
b38b0f
 bool css_migration_enabled(void);
b38b0f
 
b38b0f
-void subsystem_reset(void);
b38b0f
-
b38b0f
 #endif
b38b0f
diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
b38b0f
index 6500f42..21b2f21 100644
b38b0f
--- a/target/s390x/cpu.h
b38b0f
+++ b/target/s390x/cpu.h
b38b0f
@@ -687,6 +687,32 @@ static inline uint64_t s390_build_validity_mcic(void)
b38b0f
     return mcic;
b38b0f
 }
b38b0f
 
b38b0f
+static inline void s390_do_cpu_full_reset(CPUState *cs, run_on_cpu_data arg)
b38b0f
+{
b38b0f
+    cpu_reset(cs);
b38b0f
+}
b38b0f
+
b38b0f
+static inline void s390_do_cpu_reset(CPUState *cs, run_on_cpu_data arg)
b38b0f
+{
b38b0f
+    S390CPUClass *scc = S390_CPU_GET_CLASS(cs);
b38b0f
+
b38b0f
+    scc->cpu_reset(cs);
b38b0f
+}
b38b0f
+
b38b0f
+static inline void s390_do_cpu_initial_reset(CPUState *cs, run_on_cpu_data arg)
b38b0f
+{
b38b0f
+    S390CPUClass *scc = S390_CPU_GET_CLASS(cs);
b38b0f
+
b38b0f
+    scc->initial_cpu_reset(cs);
b38b0f
+}
b38b0f
+
b38b0f
+static inline void s390_do_cpu_load_normal(CPUState *cs, run_on_cpu_data arg)
b38b0f
+{
b38b0f
+    S390CPUClass *scc = S390_CPU_GET_CLASS(cs);
b38b0f
+
b38b0f
+    scc->load_normal(cs);
b38b0f
+}
b38b0f
+
b38b0f
 
b38b0f
 /* cpu.c */
b38b0f
 void s390_crypto_reset(void);
b38b0f
diff --git a/target/s390x/diag.c b/target/s390x/diag.c
b38b0f
index 50b58df..b5d5f8e 100644
b38b0f
--- a/target/s390x/diag.c
b38b0f
+++ b/target/s390x/diag.c
b38b0f
@@ -22,51 +22,6 @@
b38b0f
 #include "hw/s390x/ipl.h"
b38b0f
 #include "hw/s390x/s390-virtio-ccw.h"
b38b0f
 
b38b0f
-static int modified_clear_reset(S390CPU *cpu)
b38b0f
-{
b38b0f
-    S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
b38b0f
-    CPUState *t;
b38b0f
-
b38b0f
-    pause_all_vcpus();
b38b0f
-    cpu_synchronize_all_states();
b38b0f
-    CPU_FOREACH(t) {
b38b0f
-        run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
b38b0f
-    }
b38b0f
-    s390_cmma_reset();
b38b0f
-    subsystem_reset();
b38b0f
-    s390_crypto_reset();
b38b0f
-    scc->load_normal(CPU(cpu));
b38b0f
-    cpu_synchronize_all_post_reset();
b38b0f
-    resume_all_vcpus();
b38b0f
-    return 0;
b38b0f
-}
b38b0f
-
b38b0f
-static inline void s390_do_cpu_reset(CPUState *cs, run_on_cpu_data arg)
b38b0f
-{
b38b0f
-    S390CPUClass *scc = S390_CPU_GET_CLASS(cs);
b38b0f
-
b38b0f
-    scc->cpu_reset(cs);
b38b0f
-}
b38b0f
-
b38b0f
-static int load_normal_reset(S390CPU *cpu)
b38b0f
-{
b38b0f
-    S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
b38b0f
-    CPUState *t;
b38b0f
-
b38b0f
-    pause_all_vcpus();
b38b0f
-    cpu_synchronize_all_states();
b38b0f
-    CPU_FOREACH(t) {
b38b0f
-        run_on_cpu(t, s390_do_cpu_reset, RUN_ON_CPU_NULL);
b38b0f
-    }
b38b0f
-    s390_cmma_reset();
b38b0f
-    subsystem_reset();
b38b0f
-    scc->initial_cpu_reset(CPU(cpu));
b38b0f
-    scc->load_normal(CPU(cpu));
b38b0f
-    cpu_synchronize_all_post_reset();
b38b0f
-    resume_all_vcpus();
b38b0f
-    return 0;
b38b0f
-}
b38b0f
-
b38b0f
 int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
b38b0f
 {
b38b0f
     uint64_t func = env->regs[r1];
b38b0f
@@ -101,6 +56,7 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
b38b0f
 
b38b0f
 void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
b38b0f
 {
b38b0f
+    CPUState *cs = CPU(s390_env_get_cpu(env));
b38b0f
     uint64_t addr =  env->regs[r1];
b38b0f
     uint64_t subcode = env->regs[r3];
b38b0f
     IplParameterBlock *iplb;
b38b0f
@@ -117,22 +73,13 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
b38b0f
 
b38b0f
     switch (subcode) {
b38b0f
     case 0:
b38b0f
-        modified_clear_reset(s390_env_get_cpu(env));
b38b0f
-        if (tcg_enabled()) {
b38b0f
-            cpu_loop_exit(CPU(s390_env_get_cpu(env)));
b38b0f
-        }
b38b0f
+        s390_ipl_reset_request(cs, S390_RESET_MODIFIED_CLEAR);
b38b0f
         break;
b38b0f
     case 1:
b38b0f
-        load_normal_reset(s390_env_get_cpu(env));
b38b0f
-        if (tcg_enabled()) {
b38b0f
-            cpu_loop_exit(CPU(s390_env_get_cpu(env)));
b38b0f
-        }
b38b0f
+        s390_ipl_reset_request(cs, S390_RESET_LOAD_NORMAL);
b38b0f
         break;
b38b0f
     case 3:
b38b0f
-        s390_reipl_request();
b38b0f
-        if (tcg_enabled()) {
b38b0f
-            cpu_loop_exit(CPU(s390_env_get_cpu(env)));
b38b0f
-        }
b38b0f
+        s390_ipl_reset_request(cs, S390_RESET_REIPL);
b38b0f
         break;
b38b0f
     case 5:
b38b0f
         if ((r1 & 1) || (addr & 0x0fffULL)) {
b38b0f
diff --git a/target/s390x/internal.h b/target/s390x/internal.h
b38b0f
index 61a509d..f2a771e 100644
b38b0f
--- a/target/s390x/internal.h
b38b0f
+++ b/target/s390x/internal.h
b38b0f
@@ -258,12 +258,6 @@ static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb,
b38b0f
 /* Base/displacement are at the same locations. */
b38b0f
 #define decode_basedisp_rs decode_basedisp_s
b38b0f
 
b38b0f
-static inline void s390_do_cpu_full_reset(CPUState *cs, run_on_cpu_data arg)
b38b0f
-{
b38b0f
-    cpu_reset(cs);
b38b0f
-}
b38b0f
-
b38b0f
-
b38b0f
 /* arch_dump.c */
b38b0f
 int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
b38b0f
                               int cpuid, void *opaque);
b38b0f
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
b38b0f
index 1cf117b..114502d 100644
b38b0f
--- a/target/s390x/kvm.c
b38b0f
+++ b/target/s390x/kvm.c
b38b0f
@@ -1826,7 +1826,7 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
b38b0f
             ret = handle_intercept(cpu);
b38b0f
             break;
b38b0f
         case KVM_EXIT_S390_RESET:
b38b0f
-            s390_reipl_request();
b38b0f
+            s390_ipl_reset_request(cs, S390_RESET_REIPL);
b38b0f
             break;
b38b0f
         case KVM_EXIT_S390_TSCH:
b38b0f
             ret = handle_tsch(cpu);
b38b0f
-- 
b38b0f
1.8.3.1
b38b0f