X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/48b4a227035048fdebcd32532deb7a857c6199ac..b26d3165c52589d1f8de37bf0df27ad96f460f47:/lunaix-os/kernel/time/timer.c diff --git a/lunaix-os/kernel/time/timer.c b/lunaix-os/kernel/time/timer.c index 42a9ac2..61f6d41 100644 --- a/lunaix-os/kernel/time/timer.c +++ b/lunaix-os/kernel/time/timer.c @@ -1,25 +1,29 @@ /** * @file timer.c * @author Lunaixsky - * @brief A simple timer implementation based on APIC with adjustable frequency and subscribable "timerlets" + * @brief A simple timer implementation based on APIC with adjustable frequency + * and subscribable "timerlets" * @version 0.1 * @date 2022-03-12 - * + * * @copyright Copyright (c) 2022 - * + * */ -#include +#include #include #include -#include +#include +#include +#include +#include #include #include #include -#include -#define LVT_ENTRY_TIMER(vector, mode) (LVT_DELIVERY_FIXED | mode | vector) +#include +#define LVT_ENTRY_TIMER(vector, mode) (LVT_DELIVERY_FIXED | mode | vector) LOG_MODULE("TIMER"); @@ -36,30 +40,31 @@ static volatile struct lx_timer_context* timer_ctx = NULL; // Don't optimize them! Took me an half hour to figure that out... -static volatile uint32_t rtc_counter = 0; -static volatile uint8_t apic_timer_done = 0; +static volatile u32_t rtc_counter = 0; +static volatile u8_t apic_timer_done = 0; -static volatile uint32_t sched_ticks = 0; -static volatile uint32_t sched_ticks_counter = 0; +static volatile u32_t sched_ticks = 0; +static volatile u32_t sched_ticks_counter = 0; + +static struct cake_pile* timer_pile; #define APIC_CALIBRATION_CONST 0x100000 void timer_init_context() { + timer_pile = cake_new_pile("timer", sizeof(struct lx_timer), 1, 0); timer_ctx = - (struct lx_timer_context*)lxmalloc(sizeof(struct lx_timer_context)); + (struct lx_timer_context*)valloc(sizeof(struct lx_timer_context)); assert_msg(timer_ctx, "Fail to initialize timer contex"); - timer_ctx->active_timers = - (struct lx_timer*)lxmalloc(sizeof(struct lx_timer)); - llist_init_head(timer_ctx->active_timers); - + timer_ctx->active_timers = (struct lx_timer*)cake_grab(timer_pile); + llist_init_head(&timer_ctx->active_timers->link); } void -timer_init(uint32_t frequency) +timer_init(u32_t frequency) { timer_init_context(); @@ -67,10 +72,20 @@ timer_init(uint32_t frequency) // Setup APIC timer + // Remap the IRQ 8 (rtc timer's vector) to RTC_TIMER_IV in ioapic + // (Remarks IRQ 8 is pin INTIN8) + // See IBM PC/AT Technical Reference 1-10 for old RTC IRQ + // See Intel's Multiprocessor Specification for IRQ - IOAPIC INTIN + // mapping config. + + // grab ourselves these irq numbers + u32_t iv_rtc = isrm_bindirq(PC_AT_IRQ_RTC, temp_intr_routine_rtc_tick); + u32_t iv_timer = isrm_ivexalloc(temp_intr_routine_apic_timer); + // Setup a one-shot timer, we will use this to measure the bus speed. So we // can then calibrate apic timer to work at *nearly* accurate hz apic_write_reg(APIC_TIMER_LVT, - LVT_ENTRY_TIMER(APIC_TIMER_IV, LVT_TIMER_ONESHOT)); + LVT_ENTRY_TIMER(iv_timer, LVT_TIMER_ONESHOT)); // Set divider to 64 apic_write_reg(APIC_TIMER_DCR, APIC_TIMER_DIV64); @@ -79,13 +94,13 @@ timer_init(uint32_t frequency) Timer calibration process - measure the APIC timer base frequency step 1: setup a temporary isr for RTC timer which trigger at each tick - (1024Hz) - step 2: setup a temporary isr for #APIC_TIMER_IV - step 3: setup the divider, APIC_TIMER_DCR - step 4: Startup RTC timer - step 5: Write a large value, v, to APIC_TIMER_ICR to start APIC timer (this must be - followed immediately after step 4) - step 6: issue a write to EOI and clean up. + (1024Hz) + step 2: setup a temporary isr for #APIC_TIMER_IV + step 3: setup the divider, APIC_TIMER_DCR + step 4: Startup RTC timer + step 5: Write a large value, v, to APIC_TIMER_ICR to start APIC timer + (this must be followed immediately after step 4) step 6: issue a write to + EOI and clean up. When the APIC ICR counting down to 0 #APIC_TIMER_IV triggered, save the rtc timer's counter, k, and disable RTC timer immediately (although the @@ -98,19 +113,16 @@ timer_init(uint32_t frequency) */ - #ifdef __LUNAIXOS_DEBUG__ +#ifdef __LUNAIXOS_DEBUG__ if (frequency < 1000) { kprintf(KWARN "Frequency too low. Millisecond timer might be dodgy."); } - #endif +#endif timer_ctx->base_frequency = 0; rtc_counter = 0; apic_timer_done = 0; - intr_subscribe(APIC_TIMER_IV, temp_intr_routine_apic_timer); - intr_subscribe(RTC_TIMER_IV, temp_intr_routine_rtc_tick); - rtc_enable_timer(); // start RTC timer apic_write_reg(APIC_TIMER_ICR, APIC_CALIBRATION_CONST); // start APIC timer @@ -119,21 +131,21 @@ timer_init(uint32_t frequency) wait_until(apic_timer_done); - assert_msg(timer_ctx->base_frequency, "Fail to initialize timer (NOFREQ)"); - kprintf(KINFO "Base frequency: %u Hz\n", timer_ctx->base_frequency); + kprintf( + KINFO "hw: %u Hz; os: %u Hz\n", timer_ctx->base_frequency, frequency); timer_ctx->running_frequency = frequency; timer_ctx->tphz = timer_ctx->base_frequency / frequency; // cleanup - intr_unsubscribe(APIC_TIMER_IV, temp_intr_routine_apic_timer); - intr_unsubscribe(RTC_TIMER_IV, temp_intr_routine_rtc_tick); + isrm_ivfree(iv_timer); + isrm_ivfree(iv_rtc); - apic_write_reg(APIC_TIMER_LVT, - LVT_ENTRY_TIMER(APIC_TIMER_IV, LVT_TIMER_PERIODIC)); - intr_subscribe(APIC_TIMER_IV, timer_update); + apic_write_reg( + APIC_TIMER_LVT, + LVT_ENTRY_TIMER(isrm_ivexalloc(timer_update), LVT_TIMER_PERIODIC)); apic_write_reg(APIC_TIMER_ICR, timer_ctx->tphz); @@ -141,24 +153,35 @@ timer_init(uint32_t frequency) sched_ticks_counter = 0; } -int -timer_run_second(uint32_t second, void (*callback)(void*), void* payload, uint8_t flags) +struct lx_timer* +timer_run_second(u32_t second, + void (*callback)(void*), + void* payload, + u8_t flags) { - return timer_run(second * timer_ctx->running_frequency, callback, payload, flags); + return timer_run( + second * timer_ctx->running_frequency, callback, payload, flags); } -int -timer_run_ms(uint32_t millisecond, void (*callback)(void*), void* payload, uint8_t flags) +struct lx_timer* +timer_run_ms(u32_t millisecond, + void (*callback)(void*), + void* payload, + u8_t flags) { - return timer_run(timer_ctx->running_frequency / 1000 * millisecond, callback, payload, flags); + return timer_run(timer_ctx->running_frequency / 1000 * millisecond, + callback, + payload, + flags); } -int -timer_run(ticks_t ticks, void (*callback)(void*), void* payload, uint8_t flags) +struct lx_timer* +timer_run(ticks_t ticks, void (*callback)(void*), void* payload, u8_t flags) { - struct lx_timer* timer = (struct lx_timer*)lxmalloc(sizeof(struct lx_timer)); + struct lx_timer* timer = (struct lx_timer*)cake_grab(timer_pile); - if (!timer) return 0; + if (!timer) + return NULL; timer->callback = callback; timer->counter = ticks; @@ -166,9 +189,9 @@ timer_run(ticks_t ticks, void (*callback)(void*), void* payload, uint8_t flags) timer->payload = payload; timer->flags = flags; - llist_append(timer_ctx->active_timers, &timer->link); + llist_append(&timer_ctx->active_timers->link, &timer->link); - return 1; + return timer; } static void @@ -179,20 +202,20 @@ timer_update(const isr_param* param) llist_for_each(pos, n, &timer_list_head->link, link) { - if (--pos->counter) { + if (--(pos->counter)) { continue; } pos->callback ? pos->callback(pos->payload) : 1; - if (pos->flags & TIMER_MODE_PERIODIC) { + if ((pos->flags & TIMER_MODE_PERIODIC)) { pos->counter = pos->deadline; } else { llist_delete(&pos->link); - lxfree(pos); + cake_release(timer_pile, pos); } } - + sched_ticks_counter++; if (sched_ticks_counter >= sched_ticks) { @@ -221,7 +244,8 @@ temp_intr_routine_apic_timer(const isr_param* param) rtc_disable_timer(); } -struct lx_timer_context* -timer_context() { - return timer_ctx; +struct lx_timer_context* +timer_context() +{ + return (struct lx_timer_context*)timer_ctx; } \ No newline at end of file