1 /* 2 * Generic watchdog device model for SBSA 3 * 4 * The watchdog device has been implemented as revision 1 variant of 5 * the ARM SBSA specification v6.0 6 * (https://developer.arm.com/documentation/den0029/d?lang=en) 7 * 8 * Copyright Linaro.org 2020 9 * 10 * Authors: 11 * Shashi Mallela <shashi.mallela@linaro.org> 12 * 13 * This work is licensed under the terms of the GNU GPL, version 2 or (at your 14 * option) any later version. See the COPYING file in the top-level directory. 15 * 16 */ 17 18 #include "qemu/osdep.h" 19 #include "sysemu/reset.h" 20 #include "sysemu/watchdog.h" 21 #include "hw/watchdog/sbsa_gwdt.h" 22 #include "qemu/timer.h" 23 #include "migration/vmstate.h" 24 #include "qemu/log.h" 25 #include "qemu/module.h" 26 27 static const VMStateDescription vmstate_sbsa_gwdt = { 28 .name = "sbsa-gwdt", 29 .version_id = 1, 30 .minimum_version_id = 1, 31 .fields = (VMStateField[]) { 32 VMSTATE_TIMER_PTR(timer, SBSA_GWDTState), 33 VMSTATE_UINT32(wcs, SBSA_GWDTState), 34 VMSTATE_UINT32(worl, SBSA_GWDTState), 35 VMSTATE_UINT32(woru, SBSA_GWDTState), 36 VMSTATE_UINT32(wcvl, SBSA_GWDTState), 37 VMSTATE_UINT32(wcvu, SBSA_GWDTState), 38 VMSTATE_END_OF_LIST() 39 } 40 }; 41 42 typedef enum WdtRefreshType { 43 EXPLICIT_REFRESH = 0, 44 TIMEOUT_REFRESH = 1, 45 } WdtRefreshType; 46 47 static uint64_t sbsa_gwdt_rread(void *opaque, hwaddr addr, unsigned int size) 48 { 49 SBSA_GWDTState *s = SBSA_GWDT(opaque); 50 uint32_t ret = 0; 51 52 switch (addr) { 53 case SBSA_GWDT_WRR: 54 /* watch refresh read has no effect and returns 0 */ 55 ret = 0; 56 break; 57 case SBSA_GWDT_W_IIDR: 58 ret = s->id; 59 break; 60 default: 61 qemu_log_mask(LOG_GUEST_ERROR, "bad address in refresh frame read :" 62 " 0x%x\n", (int)addr); 63 } 64 return ret; 65 } 66 67 static uint64_t sbsa_gwdt_read(void *opaque, hwaddr addr, unsigned int size) 68 { 69 SBSA_GWDTState *s = SBSA_GWDT(opaque); 70 uint32_t ret = 0; 71 72 switch (addr) { 73 case SBSA_GWDT_WCS: 74 ret = s->wcs; 75 break; 76 case SBSA_GWDT_WOR: 77 ret = s->worl; 78 break; 79 case SBSA_GWDT_WORU: 80 ret = s->woru; 81 break; 82 case SBSA_GWDT_WCV: 83 ret = s->wcvl; 84 break; 85 case SBSA_GWDT_WCVU: 86 ret = s->wcvu; 87 break; 88 case SBSA_GWDT_W_IIDR: 89 ret = s->id; 90 break; 91 default: 92 qemu_log_mask(LOG_GUEST_ERROR, "bad address in control frame read :" 93 " 0x%x\n", (int)addr); 94 } 95 return ret; 96 } 97 98 static void sbsa_gwdt_update_timer(SBSA_GWDTState *s, WdtRefreshType rtype) 99 { 100 uint64_t timeout = 0; 101 102 timer_del(s->timer); 103 104 if (s->wcs & SBSA_GWDT_WCS_EN) { 105 /* 106 * Extract the upper 16 bits from woru & 32 bits from worl 107 * registers to construct the 48 bit offset value 108 */ 109 timeout = s->woru; 110 timeout <<= 32; 111 timeout |= s->worl; 112 timeout = muldiv64(timeout, NANOSECONDS_PER_SECOND, SBSA_TIMER_FREQ); 113 timeout += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 114 115 if ((rtype == EXPLICIT_REFRESH) || ((rtype == TIMEOUT_REFRESH) && 116 (!(s->wcs & SBSA_GWDT_WCS_WS0)))) { 117 /* store the current timeout value into compare registers */ 118 s->wcvu = timeout >> 32; 119 s->wcvl = timeout; 120 } 121 timer_mod(s->timer, timeout); 122 } 123 } 124 125 static void sbsa_gwdt_rwrite(void *opaque, hwaddr offset, uint64_t data, 126 unsigned size) { 127 SBSA_GWDTState *s = SBSA_GWDT(opaque); 128 129 if (offset == SBSA_GWDT_WRR) { 130 s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1); 131 132 sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH); 133 } else { 134 qemu_log_mask(LOG_GUEST_ERROR, "bad address in refresh frame write :" 135 " 0x%x\n", (int)offset); 136 } 137 } 138 139 static void sbsa_gwdt_write(void *opaque, hwaddr offset, uint64_t data, 140 unsigned size) { 141 SBSA_GWDTState *s = SBSA_GWDT(opaque); 142 143 switch (offset) { 144 case SBSA_GWDT_WCS: 145 s->wcs = data & SBSA_GWDT_WCS_EN; 146 qemu_set_irq(s->irq, 0); 147 sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH); 148 break; 149 150 case SBSA_GWDT_WOR: 151 s->worl = data; 152 s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1); 153 qemu_set_irq(s->irq, 0); 154 sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH); 155 break; 156 157 case SBSA_GWDT_WORU: 158 s->woru = data & SBSA_GWDT_WOR_MASK; 159 s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1); 160 qemu_set_irq(s->irq, 0); 161 sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH); 162 break; 163 164 case SBSA_GWDT_WCV: 165 s->wcvl = data; 166 break; 167 168 case SBSA_GWDT_WCVU: 169 s->wcvu = data; 170 break; 171 172 default: 173 qemu_log_mask(LOG_GUEST_ERROR, "bad address in control frame write :" 174 " 0x%x\n", (int)offset); 175 } 176 return; 177 } 178 179 static void wdt_sbsa_gwdt_reset(DeviceState *dev) 180 { 181 SBSA_GWDTState *s = SBSA_GWDT(dev); 182 183 timer_del(s->timer); 184 185 s->wcs = 0; 186 s->wcvl = 0; 187 s->wcvu = 0; 188 s->worl = 0; 189 s->woru = 0; 190 s->id = SBSA_GWDT_ID; 191 } 192 193 static void sbsa_gwdt_timer_sysinterrupt(void *opaque) 194 { 195 SBSA_GWDTState *s = SBSA_GWDT(opaque); 196 197 if (!(s->wcs & SBSA_GWDT_WCS_WS0)) { 198 s->wcs |= SBSA_GWDT_WCS_WS0; 199 sbsa_gwdt_update_timer(s, TIMEOUT_REFRESH); 200 qemu_set_irq(s->irq, 1); 201 } else { 202 s->wcs |= SBSA_GWDT_WCS_WS1; 203 qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n"); 204 /* 205 * Reset the watchdog only if the guest gets notified about 206 * expiry. watchdog_perform_action() may temporarily relinquish 207 * the BQL; reset before triggering the action to avoid races with 208 * sbsa_gwdt instructions. 209 */ 210 switch (get_watchdog_action()) { 211 case WATCHDOG_ACTION_DEBUG: 212 case WATCHDOG_ACTION_NONE: 213 case WATCHDOG_ACTION_PAUSE: 214 break; 215 default: 216 wdt_sbsa_gwdt_reset(DEVICE(s)); 217 } 218 watchdog_perform_action(); 219 } 220 } 221 222 static const MemoryRegionOps sbsa_gwdt_rops = { 223 .read = sbsa_gwdt_rread, 224 .write = sbsa_gwdt_rwrite, 225 .endianness = DEVICE_LITTLE_ENDIAN, 226 .valid.min_access_size = 4, 227 .valid.max_access_size = 4, 228 .valid.unaligned = false, 229 }; 230 231 static const MemoryRegionOps sbsa_gwdt_ops = { 232 .read = sbsa_gwdt_read, 233 .write = sbsa_gwdt_write, 234 .endianness = DEVICE_LITTLE_ENDIAN, 235 .valid.min_access_size = 4, 236 .valid.max_access_size = 4, 237 .valid.unaligned = false, 238 }; 239 240 static void wdt_sbsa_gwdt_realize(DeviceState *dev, Error **errp) 241 { 242 SBSA_GWDTState *s = SBSA_GWDT(dev); 243 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 244 245 memory_region_init_io(&s->rmmio, OBJECT(dev), 246 &sbsa_gwdt_rops, s, 247 "sbsa_gwdt.refresh", 248 SBSA_GWDT_RMMIO_SIZE); 249 250 memory_region_init_io(&s->cmmio, OBJECT(dev), 251 &sbsa_gwdt_ops, s, 252 "sbsa_gwdt.control", 253 SBSA_GWDT_CMMIO_SIZE); 254 255 sysbus_init_mmio(sbd, &s->rmmio); 256 sysbus_init_mmio(sbd, &s->cmmio); 257 258 sysbus_init_irq(sbd, &s->irq); 259 260 s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sbsa_gwdt_timer_sysinterrupt, 261 dev); 262 } 263 264 static void wdt_sbsa_gwdt_class_init(ObjectClass *klass, void *data) 265 { 266 DeviceClass *dc = DEVICE_CLASS(klass); 267 268 dc->realize = wdt_sbsa_gwdt_realize; 269 dc->reset = wdt_sbsa_gwdt_reset; 270 dc->hotpluggable = false; 271 set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories); 272 dc->vmsd = &vmstate_sbsa_gwdt; 273 dc->desc = "SBSA-compliant generic watchdog device"; 274 } 275 276 static const TypeInfo wdt_sbsa_gwdt_info = { 277 .class_init = wdt_sbsa_gwdt_class_init, 278 .parent = TYPE_SYS_BUS_DEVICE, 279 .name = TYPE_WDT_SBSA, 280 .instance_size = sizeof(SBSA_GWDTState), 281 }; 282 283 static void wdt_sbsa_gwdt_register_types(void) 284 { 285 type_register_static(&wdt_sbsa_gwdt_info); 286 } 287 288 type_init(wdt_sbsa_gwdt_register_types) 289