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-common.h" 23 #include "qemu/timer.h" 24 #include "sysemu/watchdog.h" 25 #include "hw/hw.h" 26 #include "hw/isa/isa.h" 27 #include "hw/i386/pc.h" 28 29 /*#define IB700_DEBUG 1*/ 30 31 #ifdef IB700_DEBUG 32 #define ib700_debug(fs,...) \ 33 fprintf(stderr,"ib700: %s: "fs,__func__,##__VA_ARGS__) 34 #else 35 #define ib700_debug(fs,...) 36 #endif 37 38 typedef struct IB700state { 39 ISADevice dev; 40 QEMUTimer *timer; 41 } IB700State; 42 43 /* This is the timer. We use a global here because the watchdog 44 * code ensures there is only one watchdog (it is located at a fixed, 45 * unchangeable IO port, so there could only ever be one anyway). 46 */ 47 48 /* A write to this register enables the timer. */ 49 static void ib700_write_enable_reg(void *vp, uint32_t addr, uint32_t data) 50 { 51 IB700State *s = vp; 52 static int time_map[] = { 53 30, 28, 26, 24, 22, 20, 18, 16, 54 14, 12, 10, 8, 6, 4, 2, 0 55 }; 56 int64_t timeout; 57 58 ib700_debug("addr = %x, data = %x\n", addr, data); 59 60 timeout = (int64_t) time_map[data & 0xF] * get_ticks_per_sec(); 61 qemu_mod_timer(s->timer, qemu_get_clock_ns (vm_clock) + timeout); 62 } 63 64 /* A write (of any value) to this register disables the timer. */ 65 static void ib700_write_disable_reg(void *vp, uint32_t addr, uint32_t data) 66 { 67 IB700State *s = vp; 68 69 ib700_debug("addr = %x, data = %x\n", addr, data); 70 71 qemu_del_timer(s->timer); 72 } 73 74 /* This is called when the watchdog expires. */ 75 static void ib700_timer_expired(void *vp) 76 { 77 IB700State *s = vp; 78 79 ib700_debug("watchdog expired\n"); 80 81 watchdog_perform_action(); 82 qemu_del_timer(s->timer); 83 } 84 85 static const VMStateDescription vmstate_ib700 = { 86 .name = "ib700_wdt", 87 .version_id = 0, 88 .minimum_version_id = 0, 89 .minimum_version_id_old = 0, 90 .fields = (VMStateField []) { 91 VMSTATE_TIMER(timer, IB700State), 92 VMSTATE_END_OF_LIST() 93 } 94 }; 95 96 static int wdt_ib700_init(ISADevice *dev) 97 { 98 IB700State *s = DO_UPCAST(IB700State, dev, dev); 99 100 ib700_debug("watchdog init\n"); 101 102 s->timer = qemu_new_timer_ns(vm_clock, ib700_timer_expired, s); 103 register_ioport_write(0x441, 2, 1, ib700_write_disable_reg, s); 104 register_ioport_write(0x443, 2, 1, ib700_write_enable_reg, s); 105 106 return 0; 107 } 108 109 static void wdt_ib700_reset(DeviceState *dev) 110 { 111 IB700State *s = DO_UPCAST(IB700State, dev.qdev, dev); 112 113 ib700_debug("watchdog reset\n"); 114 115 qemu_del_timer(s->timer); 116 } 117 118 static WatchdogTimerModel model = { 119 .wdt_name = "ib700", 120 .wdt_description = "iBASE 700", 121 }; 122 123 static void wdt_ib700_class_init(ObjectClass *klass, void *data) 124 { 125 DeviceClass *dc = DEVICE_CLASS(klass); 126 ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); 127 ic->init = wdt_ib700_init; 128 dc->reset = wdt_ib700_reset; 129 dc->vmsd = &vmstate_ib700; 130 } 131 132 static const TypeInfo wdt_ib700_info = { 133 .name = "ib700", 134 .parent = TYPE_ISA_DEVICE, 135 .instance_size = sizeof(IB700State), 136 .class_init = wdt_ib700_class_init, 137 }; 138 139 static void wdt_ib700_register_types(void) 140 { 141 watchdog_add_model(&model); 142 type_register_static(&wdt_ib700_info); 143 } 144 145 type_init(wdt_ib700_register_types) 146