s390x/watchdog: introduce diag288 watchdog device
authorXu Wang <gesaint@linux.vnet.ibm.com>
Thu, 5 Feb 2015 10:28:32 +0000 (18:28 +0800)
committerChristian Borntraeger <borntraeger@de.ibm.com>
Thu, 11 Jun 2015 15:45:49 +0000 (17:45 +0200)
This patch introduces a new diag288 watchdog device that will, just like
other watchdogs, monitor a guest and take corresponding actions when it
detects that the guest is not responding.

diag288 is s390x specific. The wiring to s390x KVM will be done in
separate patches.

Signed-off-by: Xu Wang <gesaint@linux.vnet.ibm.com>
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
[split out qemu-option.hx base changes]

default-configs/s390x-softmmu.mak
hw/watchdog/Makefile.objs
hw/watchdog/wdt_diag288.c [new file with mode: 0644]
include/hw/watchdog/wdt_diag288.h [new file with mode: 0644]
qemu-options.hx

index f9e13f1..36e15de 100644 (file)
@@ -4,3 +4,4 @@ CONFIG_VIRTIO=y
 CONFIG_SCLPCONSOLE=y
 CONFIG_S390_FLIC=y
 CONFIG_S390_FLIC_KVM=$(CONFIG_KVM)
+CONFIG_WDT_DIAG288=y
index 4b0374a..72e3ffd 100644 (file)
@@ -1,3 +1,4 @@
 common-obj-y += watchdog.o
 common-obj-$(CONFIG_WDT_IB6300ESB) += wdt_i6300esb.o
 common-obj-$(CONFIG_WDT_IB700) += wdt_ib700.o
+common-obj-$(CONFIG_WDT_DIAG288) += wdt_diag288.o
diff --git a/hw/watchdog/wdt_diag288.c b/hw/watchdog/wdt_diag288.c
new file mode 100644 (file)
index 0000000..351b5a8
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * watchdog device diag288 support
+ *
+ * Copyright IBM, Corp. 2015
+ *
+ * Authors:
+ *  Xu Wang <gesaint@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version.  See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "sysemu/watchdog.h"
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "hw/watchdog/wdt_diag288.h"
+
+static WatchdogTimerModel model = {
+    .wdt_name = TYPE_WDT_DIAG288,
+    .wdt_description = "diag288 device for s390x platform",
+};
+
+static void wdt_diag288_reset(DeviceState *dev)
+{
+    DIAG288State *diag288 = DIAG288(dev);
+
+    diag288->enabled = false;
+    timer_del(diag288->timer);
+}
+
+static void diag288_timer_expired(void *dev)
+{
+    qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n");
+    watchdog_perform_action();
+    wdt_diag288_reset(dev);
+}
+
+static int wdt_diag288_handle_timer(DIAG288State *diag288,
+                                     uint64_t func, uint64_t timeout)
+{
+    switch (func) {
+    case WDT_DIAG288_INIT:
+        diag288->enabled = true;
+        /* fall through */
+    case WDT_DIAG288_CHANGE:
+        if (!diag288->enabled) {
+            return -1;
+        }
+        timer_mod(diag288->timer,
+                  qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+                  timeout * get_ticks_per_sec());
+        break;
+    case WDT_DIAG288_CANCEL:
+        if (!diag288->enabled) {
+            return -1;
+        }
+        diag288->enabled = false;
+        timer_del(diag288->timer);
+        break;
+    default:
+        return -1;
+    }
+
+    return 0;
+}
+
+static void wdt_diag288_realize(DeviceState *dev, Error **errp)
+{
+    DIAG288State *diag288 = DIAG288(dev);
+
+    diag288->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, diag288_timer_expired,
+                                  dev);
+}
+
+static void wdt_diag288_unrealize(DeviceState *dev, Error **errp)
+{
+    DIAG288State *diag288 = DIAG288(dev);
+
+    timer_del(diag288->timer);
+    timer_free(diag288->timer);
+}
+
+static void wdt_diag288_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    DIAG288Class *diag288 = DIAG288_CLASS(klass);
+
+    dc->realize = wdt_diag288_realize;
+    dc->unrealize = wdt_diag288_unrealize;
+    dc->reset = wdt_diag288_reset;
+    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+    diag288->handle_timer = wdt_diag288_handle_timer;
+}
+
+static const TypeInfo wdt_diag288_info = {
+    .class_init = wdt_diag288_class_init,
+    .parent = TYPE_DEVICE,
+    .name  = TYPE_WDT_DIAG288,
+    .instance_size  = sizeof(DIAG288State),
+    .class_size = sizeof(DIAG288Class),
+};
+
+static void wdt_diag288_register_types(void)
+{
+    watchdog_add_model(&model);
+    type_register_static(&wdt_diag288_info);
+}
+
+type_init(wdt_diag288_register_types)
diff --git a/include/hw/watchdog/wdt_diag288.h b/include/hw/watchdog/wdt_diag288.h
new file mode 100644 (file)
index 0000000..7f3fd45
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef WDT_DIAG288_H
+#define WDT_DIAG288_H
+
+#include "hw/qdev.h"
+
+#define TYPE_WDT_DIAG288 "diag288"
+#define DIAG288(obj) \
+    OBJECT_CHECK(DIAG288State, (obj), TYPE_WDT_DIAG288)
+#define DIAG288_CLASS(klass) \
+    OBJECT_CLASS_CHECK(DIAG288Class, (klass), TYPE_WDT_DIAG288)
+#define DIAG288_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(DIAG288Class, (obj), TYPE_WDT_DIAG288)
+
+#define WDT_DIAG288_INIT      0
+#define WDT_DIAG288_CHANGE    1
+#define WDT_DIAG288_CANCEL    2
+
+typedef struct DIAG288State {
+    /*< private >*/
+    DeviceState parent_obj;
+    QEMUTimer *timer;
+    bool enabled;
+
+    /*< public >*/
+} DIAG288State;
+
+typedef struct DIAG288Class {
+    /*< private >*/
+    DeviceClass parent_class;
+
+    /*< public >*/
+    int (*handle_timer)(DIAG288State *dev,
+                        uint64_t func, uint64_t timeout);
+} DIAG288Class;
+
+#endif  /* WDT_DIAG288_H */
index a295c0f..d31fe35 100644 (file)
@@ -3174,6 +3174,9 @@ iBASE 700 is a very simple ISA watchdog with a single timer.
 @item i6300esb
 Intel 6300ESB I/O controller hub is a much more featureful PCI-based
 dual-timer watchdog.
+@item diag288
+A virtual watchdog for s390x backed by the diagnose 288 hypercall
+(currently KVM only).
 @end table
 ETEXI