diff --git a/repos/os/src/drivers/timer/epit/time_source.cc b/repos/os/src/drivers/timer/epit/time_source.cc index ea48d9bee..1137efa59 100644 --- a/repos/os/src/drivers/timer/epit/time_source.cc +++ b/repos/os/src/drivers/timer/epit/time_source.cc @@ -23,57 +23,33 @@ using namespace Genode; void Timer::Time_source::schedule_timeout(Genode::Microseconds duration, Timeout_handler &handler) { - /* on duration 0 trigger directly at function end and set max timeout */ - unsigned long const us = duration.value ? duration.value - : max_timeout().value; - unsigned long const ticks = (1ULL * us * TICKS_PER_MS) / 1000; - + unsigned long const ticks = (1ULL * duration.value * TICKS_PER_MS) / 1000; _handler = &handler; _timer_irq.ack_irq(); - - /* wait until ongoing reset operations are finished */ - while (read()) ; + _cleared_ticks = 0; /* disable timer */ write(0); - /* clear interrupt */ + /* clear interrupt and install timeout */ write(1); - - /* configure timer for a one-shot */ write(Cr::prepare_one_shot()); - write(ticks); - write(0); + write(Cnt::MAX - ticks); /* start timer */ write(1); - - /* trigger for a timeout 0 immediately the signal */ - if (!duration.value) { - Signal_transmitter(_signal_handler).submit(); - } } Duration Timer::Time_source::curr_time() { - /* read timer status */ - unsigned long diff_ticks = 0; - Lr::access_t const max_value = read(); - Cnt::access_t cnt = read(); - bool const wrapped = read(); - - /* determine how many ticks have passed */ - if (_irq && wrapped) { - cnt = read(); - diff_ticks += max_value; - } - diff_ticks += max_value - cnt; - unsigned long const diff_us = timer_ticks_to_us(diff_ticks, TICKS_PER_MS); + unsigned long const uncleared_ticks = Cnt::MAX - read() - _cleared_ticks; + unsigned long const uncleared_us = timer_ticks_to_us(uncleared_ticks, TICKS_PER_MS); /* update time only on IRQs and if rate is under 1000 per second */ - if (_irq || diff_us > 1000) { - _curr_time.add(Genode::Microseconds(diff_us)); + if (_irq || uncleared_us > 1000) { + _curr_time.add(Genode::Microseconds(uncleared_us)); + _cleared_ticks += uncleared_ticks; } return _curr_time; } diff --git a/repos/os/src/drivers/timer/epit/time_source.h b/repos/os/src/drivers/timer/epit/time_source.h index b7dbd03c2..fa26a3725 100644 --- a/repos/os/src/drivers/timer/epit/time_source.h +++ b/repos/os/src/drivers/timer/epit/time_source.h @@ -39,7 +39,6 @@ class Timer::Time_source : public Genode::Attached_mmio, struct En : Bitfield<0, 1> { }; struct En_mod : Bitfield<1, 1> { enum { RELOAD = 1 }; }; struct Oci_en : Bitfield<2, 1> { }; - struct Rld : Bitfield<3, 1> { enum { RELOAD_FROM_LR = 1 }; }; struct Swr : Bitfield<16, 1> { }; struct Clk_src : Bitfield<24, 2> { enum { HIGH_FREQ_REF_CLK = 2 }; }; @@ -48,20 +47,19 @@ class Timer::Time_source : public Genode::Attached_mmio, access_t cr = 0; En_mod::set(cr, En_mod::RELOAD); Oci_en::set(cr, 1); - Rld::set(cr, Rld::RELOAD_FROM_LR); Clk_src::set(cr, Clk_src::HIGH_FREQ_REF_CLK); return cr; } }; struct Sr : Register<0x4, 32> { struct Ocif : Bitfield<0, 1> { }; }; - struct Lr : Register<0x8, 32> { }; struct Cmpr : Register<0xc, 32> { }; - struct Cnt : Register<0x10, 32> { }; + struct Cnt : Register<0x10, 32> { enum { MAX = ~(access_t)0 }; }; Genode::Irq_connection _timer_irq; - Genode::Duration _curr_time { Genode::Microseconds(0) }; - Genode::Microseconds const _max_timeout { Genode::timer_ticks_to_us(~0U, TICKS_PER_MS) }; + Genode::Duration _curr_time { Genode::Microseconds(0) }; + Genode::Microseconds const _max_timeout { Genode::timer_ticks_to_us(Cnt::MAX / 2, TICKS_PER_MS) }; + unsigned long _cleared_ticks { 0 }; public: diff --git a/repos/os/src/drivers/timer/epit/wand_quad/timer.cc b/repos/os/src/drivers/timer/epit/wand_quad/timer.cc index f3aeade44..337ade6ce 100644 --- a/repos/os/src/drivers/timer/epit/wand_quad/timer.cc +++ b/repos/os/src/drivers/timer/epit/wand_quad/timer.cc @@ -29,4 +29,5 @@ Timer::Time_source::Time_source(Env &env) _timer_irq(env, Wand_quad::EPIT_2_IRQ) { _timer_irq.sigh(_signal_handler); + while (read()) ; }