From 41614e79fb75eb41c4afb8d014a896dfd2421909 Mon Sep 17 00:00:00 2001 From: sigsegv7 Date: Wed, 20 Sep 2023 03:04:17 -0400 Subject: kernel/amd64: Add stub LAPIC timer support Signed-off-by: sigsegv7 --- sys/arch/amd64/lapic.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) (limited to 'sys/arch/amd64') diff --git a/sys/arch/amd64/lapic.c b/sys/arch/amd64/lapic.c index 6a5ed9a..c020f19 100644 --- a/sys/arch/amd64/lapic.c +++ b/sys/arch/amd64/lapic.c @@ -31,11 +31,12 @@ #include #include #include -#include #include +#include #include #include #include +#include /* * Only calls KINFO if we are the BSP. @@ -52,7 +53,9 @@ __MODULE_NAME("lapic"); __KERNEL_META("$Vega$: lapic.c, Ian Marco Moffett, " "Local APIC driver"); + static void *lapic_base = NULL; +static struct timer lapic_timer = { 0 }; /* * Returns true if LAPIC is supported. @@ -98,6 +101,28 @@ lapic_writel(uint32_t reg, uint32_t val) mmio_write32(addr, val); } +/* + * Calibrates the Local APIC timer - Timer abstraction + */ +static size_t +lapic_timer_calibrate(void) +{ + size_t freq_hz; + + lapic_timer_init(&freq_hz); + return freq_hz; +} + +/* + * Stops the Local APIC timer - Timer abstraction + */ +static void +lapic_timer_stop(void) +{ + lapic_writel(LAPIC_INIT_CNT, 0); + lapic_writel(LAPIC_LVT_TMR, LAPIC_LVT_MASK); +} + /* * Set bits within a LAPIC register * without overwriting the whole thing. @@ -130,6 +155,42 @@ lapic_reg_clear(uint32_t reg, uint32_t value) lapic_writel(reg, old & ~(value)); } +void +lapic_timer_init(size_t *freq_out) +{ + uint32_t ticks_per_10ms; + size_t freq_hz; + const uint32_t MHZ_DIV = 1000000; + const uint32_t GHZ_DIV = 1000000000; + const uint32_t MAX_SAMPLES = 0xFFFFFFFF; + + lapic_writel(LAPIC_DCR, 3); /* Use divider 16 */ + lapic_writel(LAPIC_INIT_CNT, MAX_SAMPLES); /* Set the initial count */ + + hpet_msleep(10); /* Wait 10ms (10000 usec) */ + lapic_writel(LAPIC_LVT_TMR, LAPIC_LVT_MASK); /* Stop the timer w/ LVT mask bit */ + + /* Sanity check */ + if (freq_out == NULL) + panic("lapic_timer_init() freq_out NULL\n"); + + /* Calculate frequency in Hz */ + ticks_per_10ms = MAX_SAMPLES - lapic_readl(LAPIC_CUR_CNT); + freq_hz = ticks_per_10ms * 10000; /* 10000 since we waited 10ms */ + + /* Check if in MHz or GHz range */ + if (freq_hz >= GHZ_DIV) { + BSP_KINFO("BSP Local APIC Timer frequency: %d GHz\n", freq_hz / GHZ_DIV); + } else if (freq_hz >= MHZ_DIV) { + BSP_KINFO("BSP Local APIC Timer frequency: %d MHz\n", freq_hz / MHZ_DIV); + } else { + BSP_KINFO("BSP Local APIC Timer frequency: %d Hz\n", freq_hz); + } + + /* Divide by 10000 to get ticks */ + *freq_out = freq_hz; +} + void lapic_set_base(void *mmio_base) { @@ -164,4 +225,12 @@ lapic_init(void) BSP_KINFO("Enabled Local APIC for BSP\n"); lapic_writel(LAPIC_LDR, LAPIC_STARTUP_LID); + + /* Setup the timer descriptor */ + lapic_timer.name = "LAPIC_INTEGRATED_TIMER"; + lapic_timer.calibrate = lapic_timer_calibrate; + lapic_timer.stop = lapic_timer_stop; + + /* Register the timer for scheduler usage */ + register_timer(TIMER_SCHED, &lapic_timer); } -- cgit v1.2.3