linux/arch/x86/kernel/time.c
<<
>>
Prefs
   1// 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
  28#ifdef CONFIG_X86_64
  29__visible volatile unsigned long jiffies __cacheline_aligned_in_smp = INITIAL_JIFFIES;
  30#endif
  31
  32unsigned long profile_pc(struct pt_regs *regs)
  33{
  34        unsigned long pc = instruction_pointer(regs);
  35
  36        if (!user_mode(regs) && in_lock_functions(pc)) {
  37#ifdef CONFIG_FRAME_POINTER
  38                return *(unsigned long *)(regs->bp + sizeof(long));
  39#else
  40                unsigned long *sp =
  41                        (unsigned long *)kernel_stack_pointer(regs);
  42                /*
  43                 * Return address is either directly at stack pointer
  44                 * or above a saved flags. Eflags has bits 22-31 zero,
  45                 * kernel addresses don't.
  46                 */
  47                if (sp[0] >> 22)
  48                        return sp[0];
  49                if (sp[1] >> 22)
  50                        return sp[1];
  51#endif
  52        }
  53        return pc;
  54}
  55EXPORT_SYMBOL(profile_pc);
  56
  57/*
  58 * Default timer interrupt handler for PIT/HPET
  59 */
  60static irqreturn_t timer_interrupt(int irq, void *dev_id)
  61{
  62        global_clock_event->event_handler(global_clock_event);
  63        return IRQ_HANDLED;
  64}
  65
  66static struct irqaction irq0  = {
  67        .handler = timer_interrupt,
  68        .flags = IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
  69        .name = "timer"
  70};
  71
  72static void __init setup_default_timer_irq(void)
  73{
  74        /*
  75         * Unconditionally register the legacy timer; even without legacy
  76         * PIC/PIT we need this for the HPET0 in legacy replacement mode.
  77         */
  78        if (setup_irq(0, &irq0))
  79                pr_info("Failed to register legacy timer interrupt\n");
  80}
  81
  82/* Default timer init function */
  83void __init hpet_time_init(void)
  84{
  85        if (!hpet_enable())
  86                setup_pit_timer();
  87        setup_default_timer_irq();
  88}
  89
  90static __init void x86_late_time_init(void)
  91{
  92        x86_init.timers.timer_init();
  93        /*
  94         * After PIT/HPET timers init, select and setup
  95         * the final interrupt mode for delivering IRQs.
  96         */
  97        x86_init.irqs.intr_mode_init();
  98        tsc_init();
  99}
 100
 101/*
 102 * Initialize TSC and delay the periodic timer init to
 103 * late x86_late_time_init() so ioremap works.
 104 */
 105void __init time_init(void)
 106{
 107        late_time_init = x86_late_time_init;
 108}
 109
 110/*
 111 * Sanity check the vdso related archdata content.
 112 */
 113void clocksource_arch_init(struct clocksource *cs)
 114{
 115        if (cs->archdata.vclock_mode == VCLOCK_NONE)
 116                return;
 117
 118        if (cs->archdata.vclock_mode > VCLOCK_MAX) {
 119                pr_warn("clocksource %s registered with invalid vclock_mode %d. Disabling vclock.\n",
 120                        cs->name, cs->archdata.vclock_mode);
 121                cs->archdata.vclock_mode = VCLOCK_NONE;
 122        }
 123
 124        if (cs->mask != CLOCKSOURCE_MASK(64)) {
 125                pr_warn("clocksource %s registered with invalid mask %016llx. Disabling vclock.\n",
 126                        cs->name, cs->mask);
 127                cs->archdata.vclock_mode = VCLOCK_NONE;
 128        }
 129}
 130