qemu/hw/watchdog/wdt_ib700.c
<<
>>
Prefs
   1/*
   2 * Virtual hardware watchdog.
   3 *
   4 * Copyright (C) 2009 Red Hat Inc.
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * as published by the Free Software Foundation; either version 2
   9 * of the License, or (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
  18 *
  19 * By Richard W.M. Jones (rjones@redhat.com).
  20 */
  21
  22#include "qemu/osdep.h"
  23#include "qemu/module.h"
  24#include "qemu/timer.h"
  25#include "sysemu/watchdog.h"
  26#include "hw/isa/isa.h"
  27#include "migration/vmstate.h"
  28#include "qom/object.h"
  29
  30/*#define IB700_DEBUG 1*/
  31
  32#ifdef IB700_DEBUG
  33#define ib700_debug(fs,...)                                     \
  34    fprintf(stderr,"ib700: %s: "fs,__func__,##__VA_ARGS__)
  35#else
  36#define ib700_debug(fs,...)
  37#endif
  38
  39#define TYPE_IB700 "ib700"
  40typedef struct IB700state IB700State;
  41DECLARE_INSTANCE_CHECKER(IB700State, IB700,
  42                         TYPE_IB700)
  43
  44struct IB700state {
  45    ISADevice parent_obj;
  46
  47    QEMUTimer *timer;
  48
  49    PortioList port_list;
  50};
  51
  52/* This is the timer.  We use a global here because the watchdog
  53 * code ensures there is only one watchdog (it is located at a fixed,
  54 * unchangeable IO port, so there could only ever be one anyway).
  55 */
  56
  57/* A write to this register enables the timer. */
  58static void ib700_write_enable_reg(void *vp, uint32_t addr, uint32_t data)
  59{
  60    IB700State *s = vp;
  61    static int time_map[] = {
  62        30, 28, 26, 24, 22, 20, 18, 16,
  63        14, 12, 10,  8,  6,  4,  2,  0
  64    };
  65    int64_t timeout;
  66
  67    ib700_debug("addr = %x, data = %x\n", addr, data);
  68
  69    timeout = (int64_t) time_map[data & 0xF] * NANOSECONDS_PER_SECOND;
  70    timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + timeout);
  71}
  72
  73/* A write (of any value) to this register disables the timer. */
  74static void ib700_write_disable_reg(void *vp, uint32_t addr, uint32_t data)
  75{
  76    IB700State *s = vp;
  77
  78    ib700_debug("addr = %x, data = %x\n", addr, data);
  79
  80    timer_del(s->timer);
  81}
  82
  83/* This is called when the watchdog expires. */
  84static void ib700_timer_expired(void *vp)
  85{
  86    IB700State *s = vp;
  87
  88    ib700_debug("watchdog expired\n");
  89
  90    watchdog_perform_action();
  91    timer_del(s->timer);
  92}
  93
  94static const VMStateDescription vmstate_ib700 = {
  95    .name = "ib700_wdt",
  96    .version_id = 0,
  97    .minimum_version_id = 0,
  98    .fields = (VMStateField[]) {
  99        VMSTATE_TIMER_PTR(timer, IB700State),
 100        VMSTATE_END_OF_LIST()
 101    }
 102};
 103
 104static const MemoryRegionPortio wdt_portio_list[] = {
 105    { 0x441, 2, 1, .write = ib700_write_disable_reg, },
 106    { 0x443, 2, 1, .write = ib700_write_enable_reg, },
 107    PORTIO_END_OF_LIST(),
 108};
 109
 110static void wdt_ib700_realize(DeviceState *dev, Error **errp)
 111{
 112    IB700State *s = IB700(dev);
 113
 114    ib700_debug("watchdog init\n");
 115
 116    s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ib700_timer_expired, s);
 117
 118    portio_list_init(&s->port_list, OBJECT(s), wdt_portio_list, s, "ib700");
 119    portio_list_add(&s->port_list, isa_address_space_io(&s->parent_obj), 0);
 120}
 121
 122static void wdt_ib700_reset(DeviceState *dev)
 123{
 124    IB700State *s = IB700(dev);
 125
 126    ib700_debug("watchdog reset\n");
 127
 128    timer_del(s->timer);
 129}
 130
 131static WatchdogTimerModel model = {
 132    .wdt_name = "ib700",
 133    .wdt_description = "iBASE 700",
 134};
 135
 136static void wdt_ib700_class_init(ObjectClass *klass, void *data)
 137{
 138    DeviceClass *dc = DEVICE_CLASS(klass);
 139
 140    dc->realize = wdt_ib700_realize;
 141    dc->reset = wdt_ib700_reset;
 142    dc->vmsd = &vmstate_ib700;
 143    set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
 144    dc->desc = "iBASE 700";
 145}
 146
 147static const TypeInfo wdt_ib700_info = {
 148    .name          = TYPE_IB700,
 149    .parent        = TYPE_ISA_DEVICE,
 150    .instance_size = sizeof(IB700State),
 151    .class_init    = wdt_ib700_class_init,
 152};
 153
 154static void wdt_ib700_register_types(void)
 155{
 156    watchdog_add_model(&model);
 157    type_register_static(&wdt_ib700_info);
 158}
 159
 160type_init(wdt_ib700_register_types)
 161