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