qemu/hw/watchdog/wdt_diag288.c
<<
>>
Prefs
   1/*
   2 * watchdog device diag288 support
   3 *
   4 * Copyright IBM, Corp. 2015
   5 *
   6 * Authors:
   7 *  Xu Wang <gesaint@linux.vnet.ibm.com>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or (at your
  10 * option) any later version.  See the COPYING file in the top-level directory.
  11 *
  12 */
  13
  14#include "qemu/osdep.h"
  15#include "sysemu/watchdog.h"
  16#include "hw/sysbus.h"
  17#include "qemu/timer.h"
  18#include "hw/watchdog/wdt_diag288.h"
  19#include "qemu/log.h"
  20
  21static WatchdogTimerModel model = {
  22    .wdt_name = TYPE_WDT_DIAG288,
  23    .wdt_description = "diag288 device for s390x platform",
  24};
  25
  26static const VMStateDescription vmstate_diag288 = {
  27    .name = "vmstate_diag288",
  28    .version_id = 0,
  29    .minimum_version_id = 0,
  30    .fields = (VMStateField[]) {
  31        VMSTATE_TIMER_PTR(timer, DIAG288State),
  32        VMSTATE_BOOL(enabled, DIAG288State),
  33        VMSTATE_END_OF_LIST()
  34    }
  35};
  36
  37static void wdt_diag288_reset(DeviceState *dev)
  38{
  39    DIAG288State *diag288 = DIAG288(dev);
  40
  41    diag288->enabled = false;
  42    timer_del(diag288->timer);
  43}
  44
  45static void diag288_reset(void *opaque)
  46{
  47    DeviceState *diag288 = opaque;
  48
  49    wdt_diag288_reset(diag288);
  50}
  51
  52static void diag288_timer_expired(void *dev)
  53{
  54    qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n");
  55    /* Reset the watchdog only if the guest gets notified about
  56     * expiry. watchdog_perform_action() may temporarily relinquish
  57     * the BQL; reset before triggering the action to avoid races with
  58     * diag288 instructions. */
  59    switch (get_watchdog_action()) {
  60    case WATCHDOG_ACTION_DEBUG:
  61    case WATCHDOG_ACTION_NONE:
  62    case WATCHDOG_ACTION_PAUSE:
  63        break;
  64    default:
  65        wdt_diag288_reset(dev);
  66    }
  67    watchdog_perform_action();
  68}
  69
  70static int wdt_diag288_handle_timer(DIAG288State *diag288,
  71                                     uint64_t func, uint64_t timeout)
  72{
  73    switch (func) {
  74    case WDT_DIAG288_INIT:
  75        diag288->enabled = true;
  76        /* fall through */
  77    case WDT_DIAG288_CHANGE:
  78        if (!diag288->enabled) {
  79            return -1;
  80        }
  81        timer_mod(diag288->timer,
  82                  qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
  83                  timeout * NANOSECONDS_PER_SECOND);
  84        break;
  85    case WDT_DIAG288_CANCEL:
  86        if (!diag288->enabled) {
  87            return -1;
  88        }
  89        diag288->enabled = false;
  90        timer_del(diag288->timer);
  91        break;
  92    default:
  93        return -1;
  94    }
  95
  96    return 0;
  97}
  98
  99static void wdt_diag288_realize(DeviceState *dev, Error **errp)
 100{
 101    DIAG288State *diag288 = DIAG288(dev);
 102
 103    qemu_register_reset(diag288_reset, diag288);
 104    diag288->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, diag288_timer_expired,
 105                                  dev);
 106}
 107
 108static void wdt_diag288_unrealize(DeviceState *dev, Error **errp)
 109{
 110    DIAG288State *diag288 = DIAG288(dev);
 111
 112    timer_del(diag288->timer);
 113    timer_free(diag288->timer);
 114}
 115
 116static void wdt_diag288_class_init(ObjectClass *klass, void *data)
 117{
 118    DeviceClass *dc = DEVICE_CLASS(klass);
 119    DIAG288Class *diag288 = DIAG288_CLASS(klass);
 120
 121    dc->realize = wdt_diag288_realize;
 122    dc->unrealize = wdt_diag288_unrealize;
 123    dc->reset = wdt_diag288_reset;
 124    dc->hotpluggable = false;
 125    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
 126    dc->vmsd = &vmstate_diag288;
 127    diag288->handle_timer = wdt_diag288_handle_timer;
 128}
 129
 130static const TypeInfo wdt_diag288_info = {
 131    .class_init = wdt_diag288_class_init,
 132    .parent = TYPE_DEVICE,
 133    .name  = TYPE_WDT_DIAG288,
 134    .instance_size  = sizeof(DIAG288State),
 135    .class_size = sizeof(DIAG288Class),
 136};
 137
 138static void wdt_diag288_register_types(void)
 139{
 140    watchdog_add_model(&model);
 141    type_register_static(&wdt_diag288_info);
 142}
 143
 144type_init(wdt_diag288_register_types)
 145