/** * Detects the local APIC reference bus clock. The only sure-fire way to do * this is to depend on some other absolute timing source. This function uses * the CPU's cycle counter and the previously detected CPU clock frequency. * * NOTE: This assumes that the CPU's clock frequency has already been detected. * (i.e., cpu_info[cpu_id()].arch.tsc_khz has been initialized. */ unsigned int __init lapic_calibrate_timer(void) { const unsigned int tick_count = 100000000; cycles_t tsc_start, tsc_now; uint32_t apic_start, apic_now; unsigned int apic_Hz; /* Start the APIC counter running for calibration */ lapic_set_timer_count(4000000000); apic_start = apic_read(APIC_TMCCT); tsc_start = get_cycles_sync(); /* Spin until enough ticks for a meaningful result have elapsed */ do { apic_now = apic_read(APIC_TMCCT); tsc_now = get_cycles_sync(); } while ( ((tsc_now - tsc_start) < tick_count) && ((apic_start - apic_now) < tick_count) ); apic_Hz = (apic_start - apic_now) * 1000L * cpu_info[this_cpu].arch.tsc_khz / (tsc_now - tsc_start); lapic_stop_timer(); return (apic_Hz / 1000); }
PUBLIC int init_local_timer(unsigned freq) { #ifdef USE_APIC /* if we know the address, lapic is enabled and we should use it */ if (lapic_addr) { unsigned cpu = cpuid; tsc_per_ms[cpu] = div64u(cpu_get_freq(cpu), 1000); lapic_set_timer_one_shot(1000000/system_hz); } else { BOOT_VERBOSE(printf("Initiating legacy i8253 timer\n")); #else { #endif init_8253A_timer(freq); estimate_cpu_freq(); /* always only 1 cpu in the system */ tsc_per_ms[0] = div64u(cpu_get_freq(0), 1000); } return 0; } PUBLIC void stop_local_timer(void) { #ifdef USE_APIC if (lapic_addr) { lapic_stop_timer(); apic_eoi(); } else #endif { stop_8253A_timer(); } } PUBLIC void restart_local_timer(void) { #ifdef USE_APIC if (lapic_addr) { lapic_restart_timer(); } #endif } PUBLIC int register_local_timer_handler(const irq_handler_t handler) { #ifdef USE_APIC if (lapic_addr) { /* Using APIC, it is configured in apic_idt_init() */ BOOT_VERBOSE(printf("Using LAPIC timer as tick source\n")); } else #endif { /* Using PIC, Initialize the CLOCK's interrupt hook. */ pic_timer_hook.proc_nr_e = NONE; pic_timer_hook.irq = CLOCK_IRQ; put_irq_handler(&pic_timer_hook, CLOCK_IRQ, handler); } return 0; } PUBLIC void cycles_accounting_init(void) { #ifdef CONFIG_SMP unsigned cpu = cpuid; #endif read_tsc_64(get_cpu_var_ptr(cpu, tsc_ctr_switch)); make_zero64(get_cpu_var(cpu, cpu_last_tsc)); make_zero64(get_cpu_var(cpu, cpu_last_idle)); }