From 7f29eff75a12927e5261856eb12ddb8a8a066e33 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Thu, 24 Aug 2017 13:30:22 +0200 Subject: [PATCH] hw lapic: find best frequency dynamically Some x86 machines do have a LAPIC speed < 1000 ticks per millisecond when configured to use the maximum divider (as it was always the case). But we need microseconds precision for the timeout framework. Thus, reduce the divider dynamically until the frequency fullfills our requirements. Ref #2400 --- repos/base-hw/src/core/spec/x86_64/timer.cc | 19 +++++++++++++------ .../src/core/spec/x86_64/timer_driver.h | 2 ++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/repos/base-hw/src/core/spec/x86_64/timer.cc b/repos/base-hw/src/core/spec/x86_64/timer.cc index b75b25b5c..fe008d633 100644 --- a/repos/base-hw/src/core/spec/x86_64/timer.cc +++ b/repos/base-hw/src/core/spec/x86_64/timer.cc @@ -56,18 +56,25 @@ uint32_t Timer_driver::pit_calc_timer_freq(void) Timer_driver::Timer_driver(unsigned) : Mmio(Platform::mmio_to_virt(Hw::Cpu_memory_map::MMIO_LAPIC_BASE)) { - write( - Divide_configuration::Divide_value::MAX); - /* Enable LAPIC timer in one-shot mode */ write(Board::TIMER_VECTOR_KERNEL); write(0); write(0); write(0); - /* Calculate timer frequency */ - ticks_per_ms = pit_calc_timer_freq(); - assert(ticks_per_ms >= TIMER_MIN_TICKS_PER_MS); + /* calibrate LAPIC frequency to fullfill our requirements */ + for (Divide_configuration::access_t div = Divide_configuration::Divide_value::MAX; + div && ticks_per_ms < TIMER_MIN_TICKS_PER_MS; div--) + { + if (!div){ + error("Failed to calibrate timer frequency"); + throw Calibration_failed(); + } + write(div); + + /* Calculate timer frequency */ + ticks_per_ms = pit_calc_timer_freq(); + } } diff --git a/repos/base-hw/src/core/spec/x86_64/timer_driver.h b/repos/base-hw/src/core/spec/x86_64/timer_driver.h index ac95fd0de..6b9dbca77 100644 --- a/repos/base-hw/src/core/spec/x86_64/timer_driver.h +++ b/repos/base-hw/src/core/spec/x86_64/timer_driver.h @@ -63,6 +63,8 @@ struct Kernel::Timer_driver : Genode::Mmio }; }; + struct Calibration_failed : Genode::Exception { }; + Genode::uint32_t ticks_per_ms = 0; /* Measure LAPIC timer frequency using PIT channel 2 */