1 /* 2 * General purpose implementation of a simple periodic countdown timer. 3 * 4 * Copyright (c) 2007 CodeSourcery. 5 * 6 * This code is licensed under the GNU LGPL. 7 */ 8 #include "qemu/osdep.h" 9 #include "hw/hw.h" 10 #include "qemu/timer.h" 11 #include "hw/ptimer.h" 12 #include "qemu/host-utils.h" 13 #include "sysemu/replay.h" 14 #include "sysemu/qtest.h" 15 16 #define DELTA_ADJUST 1 17 #define DELTA_NO_ADJUST -1 18 19 struct ptimer_state 20 { 21 uint8_t enabled; /* 0 = disabled, 1 = periodic, 2 = oneshot. */ 22 uint64_t limit; 23 uint64_t delta; 24 uint32_t period_frac; 25 int64_t period; 26 int64_t last_event; 27 int64_t next_event; 28 uint8_t policy_mask; 29 QEMUBH *bh; 30 QEMUTimer *timer; 31 }; 32 33 /* Use a bottom-half routine to avoid reentrancy issues. */ 34 static void ptimer_trigger(ptimer_state *s) 35 { 36 if (s->bh) { 37 replay_bh_schedule_event(s->bh); 38 } 39 } 40 41 static void ptimer_reload(ptimer_state *s, int delta_adjust) 42 { 43 uint32_t period_frac = s->period_frac; 44 uint64_t period = s->period; 45 uint64_t delta = s->delta; 46 47 if (delta == 0 && !(s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)) { 48 ptimer_trigger(s); 49 } 50 51 if (delta == 0) { 52 delta = s->delta = s->limit; 53 } 54 55 if (s->period == 0) { 56 if (!qtest_enabled()) { 57 fprintf(stderr, "Timer with period zero, disabling\n"); 58 } 59 timer_del(s->timer); 60 s->enabled = 0; 61 return; 62 } 63 64 if (s->policy_mask & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD) { 65 if (delta_adjust != DELTA_NO_ADJUST) { 66 delta += delta_adjust; 67 } 68 } 69 70 if (delta == 0 && (s->policy_mask & PTIMER_POLICY_CONTINUOUS_TRIGGER)) { 71 if (s->enabled == 1 && s->limit == 0) { 72 delta = 1; 73 } 74 } 75 76 if (delta == 0 && (s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)) { 77 if (delta_adjust != DELTA_NO_ADJUST) { 78 delta = 1; 79 } 80 } 81 82 if (delta == 0) { 83 if (!qtest_enabled()) { 84 fprintf(stderr, "Timer with delta zero, disabling\n"); 85 } 86 timer_del(s->timer); 87 s->enabled = 0; 88 return; 89 } 90 91 /* 92 * Artificially limit timeout rate to something 93 * achievable under QEMU. Otherwise, QEMU spends all 94 * its time generating timer interrupts, and there 95 * is no forward progress. 96 * About ten microseconds is the fastest that really works 97 * on the current generation of host machines. 98 */ 99 100 if (s->enabled == 1 && (delta * period < 10000) && !use_icount) { 101 period = 10000 / delta; 102 period_frac = 0; 103 } 104 105 s->last_event = s->next_event; 106 s->next_event = s->last_event + delta * period; 107 if (period_frac) { 108 s->next_event += ((int64_t)period_frac * delta) >> 32; 109 } 110 timer_mod(s->timer, s->next_event); 111 } 112 113 static void ptimer_tick(void *opaque) 114 { 115 ptimer_state *s = (ptimer_state *)opaque; 116 ptimer_trigger(s); 117 s->delta = 0; 118 if (s->enabled == 2) { 119 s->enabled = 0; 120 } else { 121 int delta_adjust = DELTA_ADJUST; 122 123 if (s->limit == 0) { 124 /* If a "continuous trigger" policy is not used and limit == 0, 125 we should error out. */ 126 delta_adjust = DELTA_NO_ADJUST; 127 } 128 129 ptimer_reload(s, delta_adjust); 130 } 131 } 132 133 uint64_t ptimer_get_count(ptimer_state *s) 134 { 135 uint64_t counter; 136 137 if (s->enabled && s->delta != 0) { 138 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 139 int64_t next = s->next_event; 140 int64_t last = s->last_event; 141 bool expired = (now - next >= 0); 142 bool oneshot = (s->enabled == 2); 143 144 /* Figure out the current counter value. */ 145 if (expired) { 146 /* Prevent timer underflowing if it should already have 147 triggered. */ 148 counter = 0; 149 } else { 150 uint64_t rem; 151 uint64_t div; 152 int clz1, clz2; 153 int shift; 154 uint32_t period_frac = s->period_frac; 155 uint64_t period = s->period; 156 157 if (!oneshot && (s->delta * period < 10000) && !use_icount) { 158 period = 10000 / s->delta; 159 period_frac = 0; 160 } 161 162 /* We need to divide time by period, where time is stored in 163 rem (64-bit integer) and period is stored in period/period_frac 164 (64.32 fixed point). 165 166 Doing full precision division is hard, so scale values and 167 do a 64-bit division. The result should be rounded down, 168 so that the rounding error never causes the timer to go 169 backwards. 170 */ 171 172 rem = next - now; 173 div = period; 174 175 clz1 = clz64(rem); 176 clz2 = clz64(div); 177 shift = clz1 < clz2 ? clz1 : clz2; 178 179 rem <<= shift; 180 div <<= shift; 181 if (shift >= 32) { 182 div |= ((uint64_t)period_frac << (shift - 32)); 183 } else { 184 if (shift != 0) 185 div |= (period_frac >> (32 - shift)); 186 /* Look at remaining bits of period_frac and round div up if 187 necessary. */ 188 if ((uint32_t)(period_frac << shift)) 189 div += 1; 190 } 191 counter = rem / div; 192 193 if (s->policy_mask & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD) { 194 /* Before wrapping around, timer should stay with counter = 0 195 for a one period. */ 196 if (!oneshot && s->delta == s->limit) { 197 if (now == last) { 198 /* Counter == delta here, check whether it was 199 adjusted and if it was, then right now it is 200 that "one period". */ 201 if (counter == s->limit + DELTA_ADJUST) { 202 return 0; 203 } 204 } else if (counter == s->limit) { 205 /* Since the counter is rounded down and now != last, 206 the counter == limit means that delta was adjusted 207 by +1 and right now it is that adjusted period. */ 208 return 0; 209 } 210 } 211 } 212 } 213 } else { 214 counter = s->delta; 215 } 216 return counter; 217 } 218 219 void ptimer_set_count(ptimer_state *s, uint64_t count) 220 { 221 s->delta = count; 222 if (s->enabled) { 223 s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 224 ptimer_reload(s, 0); 225 } 226 } 227 228 void ptimer_run(ptimer_state *s, int oneshot) 229 { 230 bool was_disabled = !s->enabled; 231 232 if (was_disabled && s->period == 0) { 233 if (!qtest_enabled()) { 234 fprintf(stderr, "Timer with period zero, disabling\n"); 235 } 236 return; 237 } 238 s->enabled = oneshot ? 2 : 1; 239 if (was_disabled) { 240 s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 241 ptimer_reload(s, 0); 242 } 243 } 244 245 /* Pause a timer. Note that this may cause it to "lose" time, even if it 246 is immediately restarted. */ 247 void ptimer_stop(ptimer_state *s) 248 { 249 if (!s->enabled) 250 return; 251 252 s->delta = ptimer_get_count(s); 253 timer_del(s->timer); 254 s->enabled = 0; 255 } 256 257 /* Set counter increment interval in nanoseconds. */ 258 void ptimer_set_period(ptimer_state *s, int64_t period) 259 { 260 s->delta = ptimer_get_count(s); 261 s->period = period; 262 s->period_frac = 0; 263 if (s->enabled) { 264 s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 265 ptimer_reload(s, 0); 266 } 267 } 268 269 /* Set counter frequency in Hz. */ 270 void ptimer_set_freq(ptimer_state *s, uint32_t freq) 271 { 272 s->delta = ptimer_get_count(s); 273 s->period = 1000000000ll / freq; 274 s->period_frac = (1000000000ll << 32) / freq; 275 if (s->enabled) { 276 s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 277 ptimer_reload(s, 0); 278 } 279 } 280 281 /* Set the initial countdown value. If reload is nonzero then also set 282 count = limit. */ 283 void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload) 284 { 285 s->limit = limit; 286 if (reload) 287 s->delta = limit; 288 if (s->enabled && reload) { 289 s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 290 ptimer_reload(s, 0); 291 } 292 } 293 294 uint64_t ptimer_get_limit(ptimer_state *s) 295 { 296 return s->limit; 297 } 298 299 const VMStateDescription vmstate_ptimer = { 300 .name = "ptimer", 301 .version_id = 1, 302 .minimum_version_id = 1, 303 .fields = (VMStateField[]) { 304 VMSTATE_UINT8(enabled, ptimer_state), 305 VMSTATE_UINT64(limit, ptimer_state), 306 VMSTATE_UINT64(delta, ptimer_state), 307 VMSTATE_UINT32(period_frac, ptimer_state), 308 VMSTATE_INT64(period, ptimer_state), 309 VMSTATE_INT64(last_event, ptimer_state), 310 VMSTATE_INT64(next_event, ptimer_state), 311 VMSTATE_TIMER_PTR(timer, ptimer_state), 312 VMSTATE_END_OF_LIST() 313 } 314 }; 315 316 ptimer_state *ptimer_init(QEMUBH *bh, uint8_t policy_mask) 317 { 318 ptimer_state *s; 319 320 s = (ptimer_state *)g_malloc0(sizeof(ptimer_state)); 321 s->bh = bh; 322 s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ptimer_tick, s); 323 s->policy_mask = policy_mask; 324 return s; 325 } 326