#include "system/address-spaces.h"
#include "qom/object.h"
#include "qemu/lockable.h"
+#include "qemu/seqlock.h"
#include "trace.h"
struct hpet_fw_config hpet_fw_cfg = {.count = UINT8_MAX};
MemoryRegion iomem;
uint64_t hpet_offset;
bool hpet_offset_saved;
+ QemuSeqLock state_version;
qemu_irq irqs[HPET_NUM_IRQ_ROUTES];
uint32_t flags;
uint8_t rtc_irq_level;
trace_hpet_ram_read(addr);
addr &= ~4;
- QEMU_LOCK_GUARD(&s->lock);
if (addr == HPET_COUNTER) {
- if (hpet_enabled(s)) {
- cur_tick = hpet_get_ticks(s);
- } else {
- cur_tick = s->hpet_counter;
- }
+ unsigned version;
+
+ /*
+ * Write update is rare, so busywait here is unlikely to happen
+ */
+ do {
+ version = seqlock_read_begin(&s->state_version);
+ if (unlikely(!hpet_enabled(s))) {
+ cur_tick = s->hpet_counter;
+ } else {
+ cur_tick = hpet_get_ticks(s);
+ }
+ } while (seqlock_read_retry(&s->state_version, version));
trace_hpet_ram_read_reading_counter(addr & 4, cur_tick);
return cur_tick >> shift;
}
+ QEMU_LOCK_GUARD(&s->lock);
/*address range of all global regs*/
if (addr <= 0xff) {
switch (addr) {
old_val = s->config;
new_val = deposit64(old_val, shift, len, value);
new_val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
+ seqlock_write_begin(&s->state_version);
s->config = new_val;
if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
/* Enable main counter and interrupt generation. */
hpet_del_timer(&s->timer[i]);
}
}
+ seqlock_write_end(&s->state_version);
+
/* i8254 and RTC output pins are disabled
* when HPET is in legacy mode */
if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
HPETState *s = HPET(obj);
qemu_mutex_init(&s->lock);
+ seqlock_init(&s->state_version);
/* HPET Area */
memory_region_init_io(&s->iomem, obj, &hpet_ram_ops, s, "hpet", HPET_LEN);
memory_region_enable_lockless_io(&s->iomem);