blob: e42faa792c07931083988931a5061b5e21429499 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
Thomas Gleixnerdd3e6e82009-08-20 15:35:23 +02003 * 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12
Thomas Gleixner2a21ad52018-09-17 14:45:35 +020013#include <linux/clocksource.h>
Thomas Gleixnerecce8502009-08-20 15:28:50 +020014#include <linux/clockchips.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/interrupt.h>
Nicolai Stange447ae312018-07-29 12:15:33 +020016#include <linux/irq.h>
Ralf Baechle334955e2011-06-01 19:04:57 +010017#include <linux/i8253.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/time.h>
Paul Gortmaker69c60c82011-05-26 12:22:53 -040019#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
Thomas Gleixnerdd3e6e82009-08-20 15:35:23 +020021#include <asm/vsyscall.h>
22#include <asm/x86_init.h>
Thomas Gleixnerecce8502009-08-20 15:28:50 +020023#include <asm/i8259.h>
Thomas Gleixnerdd3e6e82009-08-20 15:35:23 +020024#include <asm/timer.h>
25#include <asm/hpet.h>
26#include <asm/time.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
Linus Torvalds1da177e2005-04-16 15:20:36 -070028unsigned long profile_pc(struct pt_regs *regs)
29{
30 unsigned long pc = instruction_pointer(regs);
31
Andy Lutomirskif39b6f02015-03-18 18:33:33 -070032 if (!user_mode(regs) && in_lock_functions(pc)) {
Andi Kleen0cb91a22006-09-26 10:52:28 +020033#ifdef CONFIG_FRAME_POINTER
Glauber Costa2c460d02008-07-11 16:06:40 -030034 return *(unsigned long *)(regs->bp + sizeof(long));
Andi Kleen0cb91a22006-09-26 10:52:28 +020035#else
Peter Zijlstra3c88c692019-05-07 23:25:54 +020036 unsigned long *sp = (unsigned long *)regs->sp;
Thomas Gleixneref451282009-08-21 13:24:08 +020037 /*
38 * Return address is either directly at stack pointer
39 * or above a saved flags. Eflags has bits 22-31 zero,
40 * kernel addresses don't.
41 */
Thomas Gleixnerfe599f92008-01-30 13:30:26 +010042 if (sp[0] >> 22)
Andi Kleen0cb91a22006-09-26 10:52:28 +020043 return sp[0];
44 if (sp[1] >> 22)
45 return sp[1];
46#endif
47 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 return pc;
49}
50EXPORT_SYMBOL(profile_pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52/*
Thomas Gleixner454ede72009-08-20 16:07:40 +020053 * Default timer interrupt handler for PIT/HPET
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 */
Thomas Gleixner845b3942009-08-19 15:37:03 +020055static irqreturn_t timer_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -070056{
Thomas Gleixnerecce8502009-08-20 15:28:50 +020057 global_clock_event->event_handler(global_clock_event);
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 return IRQ_HANDLED;
59}
60
Dou Liyangb1b4f2f2017-06-13 10:30:29 +080061static void __init setup_default_timer_irq(void)
Thomas Gleixner845b3942009-08-19 15:37:03 +020062{
afzal mohammed4dd2a1b2020-02-24 06:22:26 +053063 unsigned long flags = IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER;
64
Peter Zijlstra6d671e12017-12-22 10:20:12 +010065 /*
afzal mohammed4dd2a1b2020-02-24 06:22:26 +053066 * Unconditionally register the legacy timer interrupt; even
67 * without legacy PIC/PIT we need this for the HPET0 in legacy
68 * replacement mode.
Peter Zijlstra6d671e12017-12-22 10:20:12 +010069 */
afzal mohammed4dd2a1b2020-02-24 06:22:26 +053070 if (request_irq(0, timer_interrupt, flags, "timer", NULL))
Peter Zijlstra6d671e12017-12-22 10:20:12 +010071 pr_info("Failed to register legacy timer interrupt\n");
Thomas Gleixner845b3942009-08-19 15:37:03 +020072}
73
74/* Default timer init function */
Zachary Amsdene30fab32007-03-05 00:30:39 -080075void __init hpet_time_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070076{
Thomas Gleixnerc8c40762019-06-28 15:23:07 +080077 if (!hpet_enable()) {
78 if (!pit_timer_init())
79 return;
80 }
81
Thomas Gleixner845b3942009-08-19 15:37:03 +020082 setup_default_timer_irq();
83}
84
Thomas Gleixner54e26032009-09-16 08:42:26 +020085static __init void x86_late_time_init(void)
Thomas Gleixner845b3942009-08-19 15:37:03 +020086{
Dou Liyang935356c2017-09-13 17:12:54 +080087 /*
Thomas Gleixner97992382020-01-23 12:54:53 +010088 * Before PIT/HPET init, select the interrupt mode. This is required
89 * to make the decision whether PIT should be initialized correct.
90 */
91 x86_init.irqs.intr_mode_select();
92
93 /* Setup the legacy timers */
94 x86_init.timers.timer_init();
95
96 /*
97 * After PIT/HPET timers init, set up the final interrupt mode for
98 * delivering IRQs.
Dou Liyang935356c2017-09-13 17:12:54 +080099 */
100 x86_init.irqs.intr_mode_init();
Thomas Gleixnerdd0a70c2009-08-20 16:51:07 +0200101 tsc_init();
Kyung Min Parkcec5f262020-04-24 12:37:56 -0700102
103 if (static_cpu_has(X86_FEATURE_WAITPKG))
104 use_tpause_delay();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
Zachary Amsdene30fab32007-03-05 00:30:39 -0800107/*
Thomas Gleixner845b3942009-08-19 15:37:03 +0200108 * Initialize TSC and delay the periodic timer init to
109 * late x86_late_time_init() so ioremap works.
Zachary Amsdene30fab32007-03-05 00:30:39 -0800110 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111void __init time_init(void)
112{
Thomas Gleixner845b3942009-08-19 15:37:03 +0200113 late_time_init = x86_late_time_init;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114}
Thomas Gleixner2a21ad52018-09-17 14:45:35 +0200115
116/*
117 * Sanity check the vdso related archdata content.
118 */
119void clocksource_arch_init(struct clocksource *cs)
120{
Thomas Gleixnerb95a8a22020-02-07 13:38:56 +0100121 if (cs->vdso_clock_mode == VDSO_CLOCKMODE_NONE)
Thomas Gleixner2a21ad52018-09-17 14:45:35 +0200122 return;
123
Thomas Gleixnera51e9962018-09-17 14:45:36 +0200124 if (cs->mask != CLOCKSOURCE_MASK(64)) {
Thomas Gleixnerb95a8a22020-02-07 13:38:56 +0100125 pr_warn("clocksource %s registered with invalid mask %016llx for VDSO. Disabling VDSO support.\n",
Thomas Gleixnera51e9962018-09-17 14:45:36 +0200126 cs->name, cs->mask);
Thomas Gleixnerb95a8a22020-02-07 13:38:56 +0100127 cs->vdso_clock_mode = VDSO_CLOCKMODE_NONE;
Thomas Gleixnera51e9962018-09-17 14:45:36 +0200128 }
Thomas Gleixner2a21ad52018-09-17 14:45:35 +0200129}