/* * Test harness for verifying ACPI timer behaviour. * Boot with debug.acpi.timer_test set to invoke this. */ static void acpi_timer_boot_test(void) { uint32_t u1, u2, u3; u1 = acpi_timer_read(); u2 = acpi_timer_read(); u3 = acpi_timer_read(); device_printf(acpi_timer_dev, "timer test in progress, reboot to quit.\n"); for (;;) { /* * The failure case is where u3 > u1, but u2 does not fall between * the two, ie. it contains garbage. */ if (u3 > u1) { if (u2 < u1 || u2 > u3) device_printf(acpi_timer_dev, "timer is not monotonic: 0x%08x,0x%08x,0x%08x\n", u1, u2, u3); } u1 = u2; u2 = u3; u3 = acpi_timer_read(); } }
static void acpi_timer_suspend_handler(struct timecounter *newtc) { struct timecounter *tc; /* Deregister existing resume event handler. */ if (acpi_timer_eh != NULL) { EVENTHANDLER_DEREGISTER(power_resume, acpi_timer_eh); acpi_timer_eh = NULL; } if ((timecounter->tc_flags & TC_FLAGS_SUSPEND_SAFE) != 0) { /* * If we are using a suspend safe timecounter, don't * save/restore it across suspend/resume. */ return; } KASSERT(newtc == &acpi_timer_timecounter, ("acpi_timer_suspend_handler: wrong timecounter")); tc = timecounter; if (tc != newtc) { if (bootverbose) device_printf(acpi_timer_dev, "switching timecounter, %s -> %s\n", tc->tc_name, newtc->tc_name); (void)acpi_timer_read(); (void)acpi_timer_read(); timecounter = newtc; acpi_timer_eh = EVENTHANDLER_REGISTER(power_resume, acpi_timer_resume_handler, tc, EVENTHANDLER_PRI_LAST); } }
static int acpi_timer_test() { uint32_t last, this; int min, max, n, delta; register_t s; min = 10000000; max = 0; /* Test the timer with interrupts disabled to get accurate results. */ s = intr_disable(); last = acpi_timer_read(); for (n = 0; n < N; n++) { this = acpi_timer_read(); delta = acpi_TimerDelta(this, last); if (delta > max) max = delta; else if (delta < min) min = delta; last = this; } intr_restore(s); if (max - min > 2) n = 0; else if (min < 0 || max == 0) n = 0; else n = 1; if (bootverbose) printf(" %d/%d", n, max-min); return (n); }
static int acpi_timer_test(void) { uint32_t last, this; int min, max, n, delta; register_t s; min = 10000000; max = 0; /* Test the timer with interrupts disabled to get accurate results. */ #if defined(__i386__) s = read_eflags(); #elif defined(__x86_64__) s = read_rflags(); #else #error "no read_eflags" #endif cpu_disable_intr(); last = acpi_timer_read(); for (n = 0; n < 2000; n++) { this = acpi_timer_read(); delta = acpi_TimerDelta(this, last); if (delta > max) max = delta; else if (delta < min) min = delta; last = this; } #if defined(__i386__) write_eflags(s); #elif defined(__x86_64__) write_rflags(s); #else #error "no read_eflags" #endif if (max - min > 2) n = 0; else if (min < 0 || max == 0) n = 0; else n = 1; if (bootverbose) { kprintf("ACPI timer looks %s min = %d, max = %d, width = %d\n", n ? "GOOD" : "BAD ", min, max, max - min); } return (n); }
/* * Fetch current time value from hardware that may not correctly * latch the counter. We need to read until we have three monotonic * samples and then use the middle one, otherwise we are not protected * against the fact that the bits can be wrong in two directions. If * we only cared about monosity, two reads would be enough. */ static u_int acpi_timer_get_timecount_safe(struct timecounter *tc) { u_int u1, u2, u3; u2 = acpi_timer_read(); u3 = acpi_timer_read(); do { u1 = u2; u2 = u3; u3 = acpi_timer_read(); } while (u1 > u2 || u2 > u3); return (u2); }
static int acpi_timer_test() { uint32_t last, this; int delta, max, max2, min, n; register_t s; min = INT32_MAX; max = max2 = 0; /* Test the timer with interrupts disabled to get accurate results. */ s = intr_disable(); last = acpi_timer_read(); for (n = 0; n < N; n++) { this = acpi_timer_read(); delta = acpi_TimerDelta(this, last); if (delta > max) { max2 = max; max = delta; } else if (delta > max2) max2 = delta; if (delta < min) min = delta; last = this; } intr_restore(s); delta = max2 - min; if ((max - min > 8 || delta > 3) && vm_guest == VM_GUEST_NO) n = 0; else if (min < 0 || max == 0 || max2 == 0) n = 0; else n = 1; if (bootverbose) printf(" %d/%d", n, delta); return (n); }
/* * Fetch current time value from reliable hardware. * * The cputimer interface requires a 32 bit return value. If the ACPI timer * is only 24 bits then we have to keep track of the upper 8 bits on our * own. * * XXX we could probably get away with using a per-cpu field for this and * just use interrupt disablement instead of clock_lock. */ static sysclock_t acpi_timer_get_timecount24(void) { sysclock_t counter; clock_lock(); counter = acpi_timer_read(); if (counter < acpi_last_counter) acpi_cputimer.base += 0x01000000; acpi_last_counter = counter; counter += acpi_cputimer.base; clock_unlock(); return (counter); }
/* * Fetch current time value from hardware that may not correctly * latch the counter. We need to read until we have three monotonic * samples and then use the middle one, otherwise we are not protected * against the fact that the bits can be wrong in two directions. If * we only cared about monosity, two reads would be enough. */ static sysclock_t acpi_timer_get_timecount_safe(void) { u_int u1, u2, u3; if (acpi_counter_mask != 0xffffffff) clock_lock(); u2 = acpi_timer_read(); u3 = acpi_timer_read(); do { u1 = u2; u2 = u3; u3 = acpi_timer_read(); } while (u1 > u2 || u2 > u3); if (acpi_counter_mask != 0xffffffff) { if (u2 < acpi_last_counter) acpi_cputimer.base += 0x01000000; acpi_last_counter = u2; clock_unlock(); } return (u2 + acpi_cputimer.base); }
static sysclock_t acpi_timer_get_timecount(void) { return (acpi_timer_read() + acpi_cputimer.base); }
/* * Fetch current time value from reliable hardware. */ static u_int acpi_timer_get_timecount(struct timecounter *tc) { return (acpi_timer_read()); }