blob: d4352ae0deb3b4e532c1dae002839ef0a8f2388e [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 1991,1992,1995 Linus Torvalds
4 * Copyright (c) 1994 Alan Modra
5 * Copyright (c) 1995 Markus Kuhn
6 * Copyright (c) 1996 Ingo Molnar
7 * Copyright (c) 1998 Andrea Arcangeli
8 * Copyright (c) 2002,2006 Vojtech Pavlik
9 * Copyright (c) 2003 Andi Kleen
10 *
11 */
12
13#include <linux/clocksource.h>
14#include <linux/clockchips.h>
15#include <linux/interrupt.h>
16#include <linux/irq.h>
17#include <linux/i8253.h>
18#include <linux/time.h>
19#include <linux/export.h>
20
21#include <asm/vsyscall.h>
22#include <asm/x86_init.h>
23#include <asm/i8259.h>
24#include <asm/timer.h>
25#include <asm/hpet.h>
26#include <asm/time.h>
27
28unsigned long profile_pc(struct pt_regs *regs)
29{
30 return instruction_pointer(regs);
31}
32EXPORT_SYMBOL(profile_pc);
33
34/*
35 * Default timer interrupt handler for PIT/HPET
36 */
37static irqreturn_t timer_interrupt(int irq, void *dev_id)
38{
39 global_clock_event->event_handler(global_clock_event);
40 return IRQ_HANDLED;
41}
42
43static struct irqaction irq0 = {
44 .handler = timer_interrupt,
45 .flags = IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
46 .name = "timer"
47};
48
49static void __init setup_default_timer_irq(void)
50{
51 /*
52 * Unconditionally register the legacy timer; even without legacy
53 * PIC/PIT we need this for the HPET0 in legacy replacement mode.
54 */
55 if (setup_irq(0, &irq0))
56 pr_info("Failed to register legacy timer interrupt\n");
57}
58
59/* Default timer init function */
60void __init hpet_time_init(void)
61{
62 if (!hpet_enable()) {
63 if (!pit_timer_init())
64 return;
65 }
66
67 setup_default_timer_irq();
68}
69
70static __init void x86_late_time_init(void)
71{
72 /*
73 * Before PIT/HPET init, select the interrupt mode. This is required
74 * to make the decision whether PIT should be initialized correct.
75 */
76 x86_init.irqs.intr_mode_select();
77
78 /* Setup the legacy timers */
79 x86_init.timers.timer_init();
80
81 /*
82 * After PIT/HPET timers init, set up the final interrupt mode for
83 * delivering IRQs.
84 */
85 x86_init.irqs.intr_mode_init();
86 tsc_init();
87}
88
89/*
90 * Initialize TSC and delay the periodic timer init to
91 * late x86_late_time_init() so ioremap works.
92 */
93void __init time_init(void)
94{
95 late_time_init = x86_late_time_init;
96}
97
98/*
99 * Sanity check the vdso related archdata content.
100 */
101void clocksource_arch_init(struct clocksource *cs)
102{
103 if (cs->archdata.vclock_mode == VCLOCK_NONE)
104 return;
105
106 if (cs->archdata.vclock_mode > VCLOCK_MAX) {
107 pr_warn("clocksource %s registered with invalid vclock_mode %d. Disabling vclock.\n",
108 cs->name, cs->archdata.vclock_mode);
109 cs->archdata.vclock_mode = VCLOCK_NONE;
110 }
111
112 if (cs->mask != CLOCKSOURCE_MASK(64)) {
113 pr_warn("clocksource %s registered with invalid mask %016llx. Disabling vclock.\n",
114 cs->name, cs->mask);
115 cs->archdata.vclock_mode = VCLOCK_NONE;
116 }
117}