X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/34f6af4f61e0eec9c96113e07f140b609b4113c8..f89517343bf062d299d54408eea2f9387bfefb6d:/lunaix-os/arch/x86/hal/apic_timer.c diff --git a/lunaix-os/arch/x86/hal/apic_timer.c b/lunaix-os/arch/x86/hal/apic_timer.c index eae4c3f..178928c 100644 --- a/lunaix-os/arch/x86/hal/apic_timer.c +++ b/lunaix-os/arch/x86/hal/apic_timer.c @@ -1,85 +1,57 @@ #include "apic_timer.h" #include +#include #include #include -#include #include #include #include "asm/soc/apic.h" -LOG_MODULE("APIC_TIMER") +LOG_MODULE("timer(apic)") #define LVT_ENTRY_TIMER(vector, mode) (LVT_DELIVERY_FIXED | mode | vector) #define APIC_BASETICKS 0x100000 -// Don't optimize them! Took me an half hour to figure that out... - -static volatile u8_t apic_timer_done = 0; -static volatile ticks_t base_freq = 0; -static volatile ticks_t systicks = 0; - -static timer_tick_cb tick_cb = NULL; - -static void -temp_intr_routine_apic_timer(const struct hart_state* state) -{ - apic_timer_done = 1; -} - static void -apic_timer_tick_isr(const struct hart_state* state) +apic_timer_count_stop(irq_t irq, const struct hart_state* state) { - systicks++; + struct hwtimer_pot* pot; - if (likely((ptr_t)tick_cb)) { - tick_cb(); - } + pot = irq_payload(irq, struct hwtimer_pot); + pot->systick_raw = (ticks_t)-1; } -static int -apic_timer_check(struct hwtimer* hwt) +static void +apic_timer_tick_isr(irq_t irq, const struct hart_state* state) { - // TODO check whether apic timer is supported - return 1; -} + struct hwtimer_pot* pot; -static ticks_t -apic_get_systicks() -{ - return systicks; -} + pot = irq_payload(irq, struct hwtimer_pot); + pot->systick_raw++; -static ticks_t -apic_get_base_freq() -{ - return base_freq; + if (likely(__ptr(pot->callback))) { + pot->callback(); + } } -void -apic_timer_init(struct hwtimer* timer, u32_t hertz, timer_tick_cb timer_cb) +static void +__apic_timer_calibrate(struct hwtimer_pot* pot, u32_t hertz) { - ticks_t frequency = hertz; - tick_cb = timer_cb; + irq_t irq; + ticks_t base_freq = 0; cpu_disable_interrupt(); - // 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_timer = isrm_ivexalloc(temp_intr_routine_apic_timer); + irq = irq_declare_direct(apic_timer_count_stop); + irq_set_payload(irq, pot); + irq_assign(irq_get_default_domain(), irq, NULL); // 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(iv_timer, LVT_TIMER_ONESHOT)); + LVT_ENTRY_TIMER(irq->vector, LVT_TIMER_ONESHOT)); // Set divider to 64 apic_write_reg(APIC_TIMER_DCR, APIC_TIMER_DIV64); @@ -107,55 +79,56 @@ apic_timer_init(struct hwtimer* timer, u32_t hertz, timer_tick_cb timer_cb) */ -#ifdef __LUNAIXOS_DEBUG__ - if (frequency < 1000) { - WARN("Frequency too low. Millisecond timer might be dodgy."); - } -#endif - - apic_timer_done = 0; - - sysrtc->cls_mask(sysrtc); + sysrtc->ops->set_proactive(sysrtc, true); apic_write_reg(APIC_TIMER_ICR, APIC_BASETICKS); // start APIC timer - // enable interrupt, just for our RTC start ticking! + pot->systick_raw = 0; cpu_enable_interrupt(); - wait_until(apic_timer_done); + wait_until(!(pot->systick_raw + 1)); cpu_disable_interrupt(); - sysrtc->set_mask(sysrtc); - - base_freq = sysrtc->get_counts(sysrtc); + sysrtc->ops->set_proactive(sysrtc, false); + + base_freq = sysrtc->live; base_freq = APIC_BASETICKS / base_freq * sysrtc->base_freq; + pot->base_freq = base_freq; + pot->systick_raw = 0; assert_msg(base_freq, "Fail to initialize timer (NOFREQ)"); + INFO("hw: %u Hz; os: %u Hz", base_freq, hertz); - kprintf("hw: %u Hz; os: %u Hz", base_freq, frequency); - - // cleanup - isrm_ivfree(iv_timer); - - ticks_t tphz = base_freq / frequency; - timer->base_freq = base_freq; - apic_write_reg(APIC_TIMER_ICR, tphz); + irq_set_servant(irq, apic_timer_tick_isr); + apic_write_reg(APIC_TIMER_ICR, base_freq / hertz); apic_write_reg( - APIC_TIMER_LVT, - LVT_ENTRY_TIMER(isrm_ivexalloc(apic_timer_tick_isr), LVT_TIMER_PERIODIC)); + APIC_TIMER_LVT, + LVT_ENTRY_TIMER(irq->vector, LVT_TIMER_PERIODIC)); } -struct hwtimer* -apic_hwtimer_context() +static struct hwtimer_pot_ops potops = { + .calibrate = __apic_timer_calibrate, +}; + +static int +__apic_timer_load(struct device_def* def) { - static struct hwtimer apic_hwt = { - .name = "apic_timer", - .class = DEVCLASSV(DEVIF_SOC, DEVFN_TIME, DEV_TIMER, DEV_TIMER_APIC), - .init = apic_timer_init, - .supported = apic_timer_check, - .systicks = apic_get_systicks - }; - - return &apic_hwt; + struct device* timer; + + timer = device_allocsys(NULL, NULL); + + hwtimer_attach_potens(timer, HWTIMER_MAX_PRECEDENCE, &potops); + register_device_var(timer, &def->class, "apic-timer"); + return 0; } + + +static struct device_def x86_apic_timer = +{ + def_device_class(INTEL, TIME, TIMER_APIC), + def_device_name("Intel APIC Timer"), + + def_on_load(__apic_timer_load) +}; +EXPORT_DEVICE(apic_timer, &x86_apic_timer, load_sysconf);