Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "drivers/timer/hpet: Extend qemu workaround" #32790

Merged
merged 1 commit into from
Mar 2, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 19 additions & 41 deletions drivers/timer/hpet.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,41 +41,18 @@ DEVICE_MMIO_TOPLEVEL_STATIC(hpet_regs, DT_DRV_INST(0));

#define MIN_DELAY 1000

/* The clock on Qemu in SMP has been observed going backwards. This
* enables a workaround that forces the clock to be monotonic.
*/
#if defined(CONFIG_SMP) && defined(CONFIG_QEMU_TARGET)
#define GLITCHY_EMU
#endif

static struct k_spinlock lock;
static unsigned int max_ticks;
static unsigned int cyc_per_tick;
static unsigned int last_count;

#ifdef GLITCHY_EMU
volatile static int32_t last_counter;
#endif

static ALWAYS_INLINE uint32_t counter(void)
{
int32_t now = MAIN_COUNTER_REG;
#ifdef GLITCHY_EMU
if ((now - last_counter) < 0) {
now = last_counter + 1;
}
last_counter = now;
#endif
return now;
}

static void hpet_isr(const void *arg)
{
ARG_UNUSED(arg);

k_spinlock_key_t key = k_spin_lock(&lock);

uint32_t now = counter();
uint32_t now = MAIN_COUNTER_REG;

#if ((DT_INST_IRQ(0, sense) & IRQ_TYPE_LEVEL) == IRQ_TYPE_LEVEL)
/*
Expand All @@ -86,6 +63,19 @@ static void hpet_isr(const void *arg)
INTR_STATUS_REG = TIMER0_INT_STS;
#endif

if (IS_ENABLED(CONFIG_SMP) &&
IS_ENABLED(CONFIG_QEMU_TARGET)) {
/* Qemu in SMP mode has observed the clock going
* "backwards" relative to interrupts already received
* on the other CPU, despite the HPET being
* theoretically a global device.
*/
int32_t diff = (int32_t)(now - last_count);

if (last_count && diff < 0) {
now = last_count;
}
}
uint32_t dticks = (now - last_count) / cyc_per_tick;

last_count += dticks * cyc_per_tick;
Expand Down Expand Up @@ -148,14 +138,10 @@ int z_clock_driver_init(const struct device *device)
TIMER0_CONF_REG |= TCONF_MODE32;

max_ticks = (0x7fffffff - cyc_per_tick) / cyc_per_tick;
last_count = counter();
#ifdef GLITCHY_EMU
last_counter = last_count;
max_ticks -= 20;
#endif
last_count = MAIN_COUNTER_REG;

TIMER0_CONF_REG |= TCONF_INT_ENABLE;
TIMER0_COMPARATOR_REG = counter() + cyc_per_tick;
TIMER0_COMPARATOR_REG = MAIN_COUNTER_REG + cyc_per_tick;

return 0;
}
Expand All @@ -182,7 +168,7 @@ void z_clock_set_timeout(int32_t ticks, bool idle)
ticks = CLAMP(ticks - 1, 0, (int32_t)max_ticks);

k_spinlock_key_t key = k_spin_lock(&lock);
uint32_t now = counter(), cyc, adj;
uint32_t now = MAIN_COUNTER_REG, cyc, adj;
uint32_t max_cyc = max_ticks * cyc_per_tick;

/* Round up to next tick boundary. */
Expand Down Expand Up @@ -212,23 +198,15 @@ uint32_t z_clock_elapsed(void)
}

k_spinlock_key_t key = k_spin_lock(&lock);
uint32_t ret = (counter() - last_count) / cyc_per_tick;
uint32_t ret = (MAIN_COUNTER_REG - last_count) / cyc_per_tick;

k_spin_unlock(&lock, key);
return ret;
}

uint32_t z_timer_cycle_get_32(void)
{
#ifdef GLITCHY_EMU
k_spinlock_key_t key = k_spin_lock(&lock);
uint32_t ret = counter();

k_spin_unlock(&lock, key);
return ret;
#else
return counter();
#endif
return MAIN_COUNTER_REG;
}

void z_clock_idle_exit(void)
Expand Down