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