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
This commit is contained in:
Martin Stein 2017-08-24 13:30:22 +02:00 committed by Christian Helmuth
parent d9073a1848
commit 7f29eff75a
2 changed files with 15 additions and 6 deletions

View File

@ -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>(
Divide_configuration::Divide_value::MAX);
/* Enable LAPIC timer in one-shot mode */
write<Tmr_lvt::Vector>(Board::TIMER_VECTOR_KERNEL);
write<Tmr_lvt::Delivery>(0);
write<Tmr_lvt::Mask>(0);
write<Tmr_lvt::Timer_mode>(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<Divide_configuration::Divide_value>(div);
/* Calculate timer frequency */
ticks_per_ms = pit_calc_timer_freq();
}
}

View File

@ -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 */