-rtc_nanotime_t rtc_nanotime_info = {0,0,0,0,1,0};
-
-static uint64_t rtc_decrementer_min;
-static uint64_t rtc_decrementer_max;
-
-static uint64_t
-deadline_to_decrementer(
- uint64_t deadline,
- uint64_t now)
-{
- uint64_t delta;
-
- if (deadline <= now)
- return rtc_decrementer_min;
- else {
- delta = deadline - now;
- return MIN(MAX(rtc_decrementer_min,delta),rtc_decrementer_max);
- }
-}
-
-static inline uint64_t
-_absolutetime_to_tsc(uint64_t ns)
-{
- uint32_t generation;
- uint64_t tsc;
-
- do {
- generation = rtc_nanotime_info.generation;
- tsc = tmrCvt(ns - rtc_nanotime_info.ns_base, tscFCvtn2t)
- + rtc_nanotime_info.tsc_base;
- } while (generation == 0 ||
- generation != rtc_nanotime_info.generation);
-
- return tsc;
-}
-
-/*
- * Regular local APIC timer case:
- */
-static void
-rtc_lapic_config_timer(void)
-{
- lapic_config_timer(TRUE, one_shot, divide_by_1);
-}
-static uint64_t
-rtc_lapic_set_timer(uint64_t deadline, uint64_t now)
-{
- uint64_t count;
- uint64_t set = 0;
-
- if (deadline > 0) {
- /*
- * Convert delta to bus ticks
- * - time now is not relevant
- */
- count = deadline_to_decrementer(deadline, now);
- set = now + count;
- lapic_set_timer_fast((uint32_t) tmrCvt(count, busFCvtn2t));
- } else {
- lapic_set_timer(FALSE, one_shot, divide_by_1, 0);
- }
- return set;
-}
-
-/*
- * TSC-deadline timer case:
- */
-static void
-rtc_lapic_config_tsc_deadline_timer(void)
-{
- lapic_config_tsc_deadline_timer();
-}
-static uint64_t
-rtc_lapic_set_tsc_deadline_timer(uint64_t deadline, uint64_t now)
-{
- uint64_t set = 0;
-
- if (deadline > 0) {
- /*
- * Convert to TSC
- */
- set = now + deadline_to_decrementer(deadline, now);
- lapic_set_tsc_deadline_timer(_absolutetime_to_tsc(set));
- } else {
- lapic_set_tsc_deadline_timer(0);
- }
- return set;
-}
-
-/*
- * Definitions for timer operations table
- */
-typedef struct {
- void (*config)(void);
- uint64_t (*set) (uint64_t, uint64_t);
-} rtc_timer_t;
-
-rtc_timer_t rtc_timer_lapic = {
- rtc_lapic_config_timer,
- rtc_lapic_set_timer
-};
-
-rtc_timer_t rtc_timer_tsc_deadline = {
- rtc_lapic_config_tsc_deadline_timer,
- rtc_lapic_set_tsc_deadline_timer
-};
-
-rtc_timer_t *rtc_timer = &rtc_timer_lapic; /* defaults to LAPIC timer */
-
-/*
- * rtc_timer_init() is called at startup on the boot processor only.
- */
-static void
-rtc_timer_init(void)
-{
- int TSC_deadline_timer = 0;
-
- /* See whether we can use the local apic in TSC-deadline mode */
- if ((cpuid_features() & CPUID_FEATURE_TSCTMR)) {
- TSC_deadline_timer = 1;
- PE_parse_boot_argn("TSC_deadline_timer", &TSC_deadline_timer,
- sizeof(TSC_deadline_timer));
- printf("TSC Deadline Timer supported %s enabled\n",
- TSC_deadline_timer ? "and" : "but not");
- }
-
- if (TSC_deadline_timer) {
- rtc_timer = &rtc_timer_tsc_deadline;
- rtc_decrementer_max = UINT64_MAX; /* effectively none */
- /*
- * The min could be as low as 1nsec,
- * but we're being conservative for now and making it the same
- * as for the local apic timer.
- */
- rtc_decrementer_min = 1*NSEC_PER_USEC; /* 1 usec */
- } else {
- /*
- * Compute the longest interval using LAPIC timer.
- */
- rtc_decrementer_max = tmrCvt(0x7fffffffULL, busFCvtt2n);
- kprintf("maxDec: %lld\n", rtc_decrementer_max);
- rtc_decrementer_min = 1*NSEC_PER_USEC; /* 1 usec */
- }
-
- /* Point LAPIC interrupts to hardclock() */
- lapic_set_timer_func((i386_intr_func_t) rtclock_intr);
-}
-
-static inline uint64_t
-rtc_timer_set(uint64_t deadline, uint64_t now)
-{
- return rtc_timer->set(deadline, now);
-}
-