Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0 2 : : /* 3 : : * 8253/PIT functions 4 : : * 5 : : */ 6 : : #include <linux/clockchips.h> 7 : : #include <linux/init.h> 8 : : #include <linux/timex.h> 9 : : #include <linux/i8253.h> 10 : : 11 : : #include <asm/apic.h> 12 : : #include <asm/hpet.h> 13 : : #include <asm/time.h> 14 : : #include <asm/smp.h> 15 : : 16 : : /* 17 : : * HPET replaces the PIT, when enabled. So we need to know, which of 18 : : * the two timers is used 19 : : */ 20 : : struct clock_event_device *global_clock_event; 21 : : 22 : : /* 23 : : * Modern chipsets can disable the PIT clock which makes it unusable. It 24 : : * would be possible to enable the clock but the registers are chipset 25 : : * specific and not discoverable. Avoid the whack a mole game. 26 : : * 27 : : * These platforms have discoverable TSC/CPU frequencies but this also 28 : : * requires to know the local APIC timer frequency as it normally is 29 : : * calibrated against the PIT interrupt. 30 : : */ 31 : 0 : static bool __init use_pit(void) 32 : : { 33 [ # # ]: 0 : if (!IS_ENABLED(CONFIG_X86_TSC) || !boot_cpu_has(X86_FEATURE_TSC)) 34 : : return true; 35 : : 36 : : /* This also returns true when APIC is disabled */ 37 : 0 : return apic_needs_pit(); 38 : : } 39 : : 40 : 0 : bool __init pit_timer_init(void) 41 : : { 42 [ # # ]: 0 : if (!use_pit()) 43 : : return false; 44 : : 45 : 0 : clockevent_i8253_init(true); 46 : 0 : global_clock_event = &i8253_clockevent; 47 : 0 : return true; 48 : : } 49 : : 50 : : #ifndef CONFIG_X86_64 51 : : static int __init init_pit_clocksource(void) 52 : : { 53 : : /* 54 : : * Several reasons not to register PIT as a clocksource: 55 : : * 56 : : * - On SMP PIT does not scale due to i8253_lock 57 : : * - when HPET is enabled 58 : : * - when local APIC timer is active (PIT is switched off) 59 : : */ 60 : : if (num_possible_cpus() > 1 || is_hpet_enabled() || 61 : : !clockevent_state_periodic(&i8253_clockevent)) 62 : : return 0; 63 : : 64 : : return clocksource_i8253_init(); 65 : : } 66 : : arch_initcall(init_pit_clocksource); 67 : : #endif /* !CONFIG_X86_64 */