xref: /openbmc/linux/arch/x86/kernel/time.c (revision f91ca89e924eb287915522664a31afc71a49c05b)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
247926214SThomas Gleixner /*
347926214SThomas Gleixner  *  Copyright (c) 1991,1992,1995  Linus Torvalds
447926214SThomas Gleixner  *  Copyright (c) 1994  Alan Modra
547926214SThomas Gleixner  *  Copyright (c) 1995  Markus Kuhn
647926214SThomas Gleixner  *  Copyright (c) 1996  Ingo Molnar
747926214SThomas Gleixner  *  Copyright (c) 1998  Andrea Arcangeli
847926214SThomas Gleixner  *  Copyright (c) 2002,2006  Vojtech Pavlik
947926214SThomas Gleixner  *  Copyright (c) 2003  Andi Kleen
1047926214SThomas Gleixner  *
1147926214SThomas Gleixner  */
1247926214SThomas Gleixner 
132a21ad57SThomas Gleixner #include <linux/clocksource.h>
1447926214SThomas Gleixner #include <linux/clockchips.h>
1547926214SThomas Gleixner #include <linux/interrupt.h>
16447ae316SNicolai Stange #include <linux/irq.h>
17334955efSRalf Baechle #include <linux/i8253.h>
1847926214SThomas Gleixner #include <linux/time.h>
1969c60c88SPaul Gortmaker #include <linux/export.h>
2047926214SThomas Gleixner 
2147926214SThomas Gleixner #include <asm/vsyscall.h>
2247926214SThomas Gleixner #include <asm/x86_init.h>
2347926214SThomas Gleixner #include <asm/i8259.h>
2447926214SThomas Gleixner #include <asm/timer.h>
2547926214SThomas Gleixner #include <asm/hpet.h>
2647926214SThomas Gleixner #include <asm/time.h>
2747926214SThomas Gleixner 
profile_pc(struct pt_regs * regs)2847926214SThomas Gleixner unsigned long profile_pc(struct pt_regs *regs)
2947926214SThomas Gleixner {
30*16222bebSLinus Torvalds 	return instruction_pointer(regs);
3147926214SThomas Gleixner }
3247926214SThomas Gleixner EXPORT_SYMBOL(profile_pc);
3347926214SThomas Gleixner 
3447926214SThomas Gleixner /*
3547926214SThomas Gleixner  * Default timer interrupt handler for PIT/HPET
3647926214SThomas Gleixner  */
timer_interrupt(int irq,void * dev_id)3747926214SThomas Gleixner static irqreturn_t timer_interrupt(int irq, void *dev_id)
3847926214SThomas Gleixner {
3947926214SThomas Gleixner 	global_clock_event->event_handler(global_clock_event);
4047926214SThomas Gleixner 	return IRQ_HANDLED;
4147926214SThomas Gleixner }
4247926214SThomas Gleixner 
setup_default_timer_irq(void)43b1b4f2feSDou Liyang static void __init setup_default_timer_irq(void)
4447926214SThomas Gleixner {
454dd2a1b9Safzal mohammed 	unsigned long flags = IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER;
464dd2a1b9Safzal mohammed 
476d671e1bSPeter Zijlstra 	/*
484dd2a1b9Safzal mohammed 	 * Unconditionally register the legacy timer interrupt; even
494dd2a1b9Safzal mohammed 	 * without legacy PIC/PIT we need this for the HPET0 in legacy
504dd2a1b9Safzal mohammed 	 * replacement mode.
516d671e1bSPeter Zijlstra 	 */
524dd2a1b9Safzal mohammed 	if (request_irq(0, timer_interrupt, flags, "timer", NULL))
536d671e1bSPeter Zijlstra 		pr_info("Failed to register legacy timer interrupt\n");
5447926214SThomas Gleixner }
5547926214SThomas Gleixner 
5647926214SThomas Gleixner /* Default timer init function */
hpet_time_init(void)5747926214SThomas Gleixner void __init hpet_time_init(void)
5847926214SThomas Gleixner {
59c8c40767SThomas Gleixner 	if (!hpet_enable()) {
60c8c40767SThomas Gleixner 		if (!pit_timer_init())
61c8c40767SThomas Gleixner 			return;
62c8c40767SThomas Gleixner 	}
63c8c40767SThomas Gleixner 
6447926214SThomas Gleixner 	setup_default_timer_irq();
6547926214SThomas Gleixner }
6647926214SThomas Gleixner 
x86_late_time_init(void)6754e2603fSThomas Gleixner static __init void x86_late_time_init(void)
6847926214SThomas Gleixner {
69935356ceSDou Liyang 	/*
7097992387SThomas Gleixner 	 * Before PIT/HPET init, select the interrupt mode. This is required
7197992387SThomas Gleixner 	 * to make the decision whether PIT should be initialized correct.
7297992387SThomas Gleixner 	 */
7397992387SThomas Gleixner 	x86_init.irqs.intr_mode_select();
7497992387SThomas Gleixner 
7597992387SThomas Gleixner 	/* Setup the legacy timers */
7697992387SThomas Gleixner 	x86_init.timers.timer_init();
7797992387SThomas Gleixner 
7897992387SThomas Gleixner 	/*
7997992387SThomas Gleixner 	 * After PIT/HPET timers init, set up the final interrupt mode for
8097992387SThomas Gleixner 	 * delivering IRQs.
81935356ceSDou Liyang 	 */
82935356ceSDou Liyang 	x86_init.irqs.intr_mode_init();
83dd0a70c8SThomas Gleixner 	tsc_init();
84cec5f268SKyung Min Park 
85cec5f268SKyung Min Park 	if (static_cpu_has(X86_FEATURE_WAITPKG))
86cec5f268SKyung Min Park 		use_tpause_delay();
8747926214SThomas Gleixner }
8847926214SThomas Gleixner 
8947926214SThomas Gleixner /*
9047926214SThomas Gleixner  * Initialize TSC and delay the periodic timer init to
9147926214SThomas Gleixner  * late x86_late_time_init() so ioremap works.
9247926214SThomas Gleixner  */
time_init(void)9347926214SThomas Gleixner void __init time_init(void)
9447926214SThomas Gleixner {
9547926214SThomas Gleixner 	late_time_init = x86_late_time_init;
9647926214SThomas Gleixner }
972a21ad57SThomas Gleixner 
982a21ad57SThomas Gleixner /*
992a21ad57SThomas Gleixner  * Sanity check the vdso related archdata content.
1002a21ad57SThomas Gleixner  */
clocksource_arch_init(struct clocksource * cs)1012a21ad57SThomas Gleixner void clocksource_arch_init(struct clocksource *cs)
1022a21ad57SThomas Gleixner {
103b95a8a27SThomas Gleixner 	if (cs->vdso_clock_mode == VDSO_CLOCKMODE_NONE)
1042a21ad57SThomas Gleixner 		return;
1052a21ad57SThomas Gleixner 
106a51e996dSThomas Gleixner 	if (cs->mask != CLOCKSOURCE_MASK(64)) {
107b95a8a27SThomas Gleixner 		pr_warn("clocksource %s registered with invalid mask %016llx for VDSO. Disabling VDSO support.\n",
108a51e996dSThomas Gleixner 			cs->name, cs->mask);
109b95a8a27SThomas Gleixner 		cs->vdso_clock_mode = VDSO_CLOCKMODE_NONE;
110a51e996dSThomas Gleixner 	}
1112a21ad57SThomas Gleixner }
112