Greg Kroah-Hartman | b244131 | 2017-11-01 15:07:57 +0100 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2 | /* |
Thomas Gleixner | dd3e6e8 | 2009-08-20 15:35:23 +0200 | [diff] [blame] | 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 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 10 | * |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 11 | */ |
| 12 | |
Thomas Gleixner | 2a21ad5 | 2018-09-17 14:45:35 +0200 | [diff] [blame] | 13 | #include <linux/clocksource.h> |
Thomas Gleixner | ecce850 | 2009-08-20 15:28:50 +0200 | [diff] [blame] | 14 | #include <linux/clockchips.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 15 | #include <linux/interrupt.h> |
Nicolai Stange | 447ae31 | 2018-07-29 12:15:33 +0200 | [diff] [blame] | 16 | #include <linux/irq.h> |
Ralf Baechle | 334955e | 2011-06-01 19:04:57 +0100 | [diff] [blame] | 17 | #include <linux/i8253.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 18 | #include <linux/time.h> |
Paul Gortmaker | 69c60c8 | 2011-05-26 12:22:53 -0400 | [diff] [blame] | 19 | #include <linux/export.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 20 | |
Thomas Gleixner | dd3e6e8 | 2009-08-20 15:35:23 +0200 | [diff] [blame] | 21 | #include <asm/vsyscall.h> |
| 22 | #include <asm/x86_init.h> |
Thomas Gleixner | ecce850 | 2009-08-20 15:28:50 +0200 | [diff] [blame] | 23 | #include <asm/i8259.h> |
Thomas Gleixner | dd3e6e8 | 2009-08-20 15:35:23 +0200 | [diff] [blame] | 24 | #include <asm/timer.h> |
| 25 | #include <asm/hpet.h> |
| 26 | #include <asm/time.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 27 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 28 | unsigned long profile_pc(struct pt_regs *regs) |
| 29 | { |
| 30 | unsigned long pc = instruction_pointer(regs); |
| 31 | |
Andy Lutomirski | f39b6f0 | 2015-03-18 18:33:33 -0700 | [diff] [blame] | 32 | if (!user_mode(regs) && in_lock_functions(pc)) { |
Andi Kleen | 0cb91a2 | 2006-09-26 10:52:28 +0200 | [diff] [blame] | 33 | #ifdef CONFIG_FRAME_POINTER |
Glauber Costa | 2c460d0 | 2008-07-11 16:06:40 -0300 | [diff] [blame] | 34 | return *(unsigned long *)(regs->bp + sizeof(long)); |
Andi Kleen | 0cb91a2 | 2006-09-26 10:52:28 +0200 | [diff] [blame] | 35 | #else |
Peter Zijlstra | 3c88c69 | 2019-05-07 23:25:54 +0200 | [diff] [blame] | 36 | unsigned long *sp = (unsigned long *)regs->sp; |
Thomas Gleixner | ef45128 | 2009-08-21 13:24:08 +0200 | [diff] [blame] | 37 | /* |
| 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 Gleixner | fe599f9 | 2008-01-30 13:30:26 +0100 | [diff] [blame] | 42 | if (sp[0] >> 22) |
Andi Kleen | 0cb91a2 | 2006-09-26 10:52:28 +0200 | [diff] [blame] | 43 | return sp[0]; |
| 44 | if (sp[1] >> 22) |
| 45 | return sp[1]; |
| 46 | #endif |
| 47 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 48 | return pc; |
| 49 | } |
| 50 | EXPORT_SYMBOL(profile_pc); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 51 | |
| 52 | /* |
Thomas Gleixner | 454ede7 | 2009-08-20 16:07:40 +0200 | [diff] [blame] | 53 | * Default timer interrupt handler for PIT/HPET |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 54 | */ |
Thomas Gleixner | 845b394 | 2009-08-19 15:37:03 +0200 | [diff] [blame] | 55 | static irqreturn_t timer_interrupt(int irq, void *dev_id) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 56 | { |
Thomas Gleixner | ecce850 | 2009-08-20 15:28:50 +0200 | [diff] [blame] | 57 | global_clock_event->event_handler(global_clock_event); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 58 | return IRQ_HANDLED; |
| 59 | } |
| 60 | |
Dou Liyang | b1b4f2f | 2017-06-13 10:30:29 +0800 | [diff] [blame] | 61 | static void __init setup_default_timer_irq(void) |
Thomas Gleixner | 845b394 | 2009-08-19 15:37:03 +0200 | [diff] [blame] | 62 | { |
afzal mohammed | 4dd2a1b | 2020-02-24 06:22:26 +0530 | [diff] [blame] | 63 | unsigned long flags = IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER; |
| 64 | |
Peter Zijlstra | 6d671e1 | 2017-12-22 10:20:12 +0100 | [diff] [blame] | 65 | /* |
afzal mohammed | 4dd2a1b | 2020-02-24 06:22:26 +0530 | [diff] [blame] | 66 | * Unconditionally register the legacy timer interrupt; even |
| 67 | * without legacy PIC/PIT we need this for the HPET0 in legacy |
| 68 | * replacement mode. |
Peter Zijlstra | 6d671e1 | 2017-12-22 10:20:12 +0100 | [diff] [blame] | 69 | */ |
afzal mohammed | 4dd2a1b | 2020-02-24 06:22:26 +0530 | [diff] [blame] | 70 | if (request_irq(0, timer_interrupt, flags, "timer", NULL)) |
Peter Zijlstra | 6d671e1 | 2017-12-22 10:20:12 +0100 | [diff] [blame] | 71 | pr_info("Failed to register legacy timer interrupt\n"); |
Thomas Gleixner | 845b394 | 2009-08-19 15:37:03 +0200 | [diff] [blame] | 72 | } |
| 73 | |
| 74 | /* Default timer init function */ |
Zachary Amsden | e30fab3 | 2007-03-05 00:30:39 -0800 | [diff] [blame] | 75 | void __init hpet_time_init(void) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 76 | { |
Thomas Gleixner | c8c4076 | 2019-06-28 15:23:07 +0800 | [diff] [blame] | 77 | if (!hpet_enable()) { |
| 78 | if (!pit_timer_init()) |
| 79 | return; |
| 80 | } |
| 81 | |
Thomas Gleixner | 845b394 | 2009-08-19 15:37:03 +0200 | [diff] [blame] | 82 | setup_default_timer_irq(); |
| 83 | } |
| 84 | |
Thomas Gleixner | 54e2603 | 2009-09-16 08:42:26 +0200 | [diff] [blame] | 85 | static __init void x86_late_time_init(void) |
Thomas Gleixner | 845b394 | 2009-08-19 15:37:03 +0200 | [diff] [blame] | 86 | { |
Dou Liyang | 935356c | 2017-09-13 17:12:54 +0800 | [diff] [blame] | 87 | /* |
Thomas Gleixner | 9799238 | 2020-01-23 12:54:53 +0100 | [diff] [blame] | 88 | * 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 Liyang | 935356c | 2017-09-13 17:12:54 +0800 | [diff] [blame] | 99 | */ |
| 100 | x86_init.irqs.intr_mode_init(); |
Thomas Gleixner | dd0a70c | 2009-08-20 16:51:07 +0200 | [diff] [blame] | 101 | tsc_init(); |
Kyung Min Park | cec5f26 | 2020-04-24 12:37:56 -0700 | [diff] [blame] | 102 | |
| 103 | if (static_cpu_has(X86_FEATURE_WAITPKG)) |
| 104 | use_tpause_delay(); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 105 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 106 | |
Zachary Amsden | e30fab3 | 2007-03-05 00:30:39 -0800 | [diff] [blame] | 107 | /* |
Thomas Gleixner | 845b394 | 2009-08-19 15:37:03 +0200 | [diff] [blame] | 108 | * Initialize TSC and delay the periodic timer init to |
| 109 | * late x86_late_time_init() so ioremap works. |
Zachary Amsden | e30fab3 | 2007-03-05 00:30:39 -0800 | [diff] [blame] | 110 | */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 111 | void __init time_init(void) |
| 112 | { |
Thomas Gleixner | 845b394 | 2009-08-19 15:37:03 +0200 | [diff] [blame] | 113 | late_time_init = x86_late_time_init; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 114 | } |
Thomas Gleixner | 2a21ad5 | 2018-09-17 14:45:35 +0200 | [diff] [blame] | 115 | |
| 116 | /* |
| 117 | * Sanity check the vdso related archdata content. |
| 118 | */ |
| 119 | void clocksource_arch_init(struct clocksource *cs) |
| 120 | { |
Thomas Gleixner | b95a8a2 | 2020-02-07 13:38:56 +0100 | [diff] [blame] | 121 | if (cs->vdso_clock_mode == VDSO_CLOCKMODE_NONE) |
Thomas Gleixner | 2a21ad5 | 2018-09-17 14:45:35 +0200 | [diff] [blame] | 122 | return; |
| 123 | |
Thomas Gleixner | a51e996 | 2018-09-17 14:45:36 +0200 | [diff] [blame] | 124 | if (cs->mask != CLOCKSOURCE_MASK(64)) { |
Thomas Gleixner | b95a8a2 | 2020-02-07 13:38:56 +0100 | [diff] [blame] | 125 | pr_warn("clocksource %s registered with invalid mask %016llx for VDSO. Disabling VDSO support.\n", |
Thomas Gleixner | a51e996 | 2018-09-17 14:45:36 +0200 | [diff] [blame] | 126 | cs->name, cs->mask); |
Thomas Gleixner | b95a8a2 | 2020-02-07 13:38:56 +0100 | [diff] [blame] | 127 | cs->vdso_clock_mode = VDSO_CLOCKMODE_NONE; |
Thomas Gleixner | a51e996 | 2018-09-17 14:45:36 +0200 | [diff] [blame] | 128 | } |
Thomas Gleixner | 2a21ad5 | 2018-09-17 14:45:35 +0200 | [diff] [blame] | 129 | } |