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/clockchips.h>
  14#include <linux/interrupt.h>
  15#include <linux/i8253.h>
  16#include <linux/time.h>
  17#include <linux/export.h>
  18
  19#include <asm/vsyscall.h>
  20#include <asm/x86_init.h>
  21#include <asm/i8259.h>
  22#include <asm/timer.h>
  23#include <asm/hpet.h>
  24#include <asm/time.h>
  25
  26#ifdef CONFIG_X86_64
  27__visible volatile unsigned long jiffies __cacheline_aligned = INITIAL_JIFFIES;
  28#endif
  29
  30unsigned long profile_pc(struct pt_regs *regs)
  31{
  32        unsigned long pc = instruction_pointer(regs);
  33
  34        if (!user_mode(regs) && in_lock_functions(pc)) {
  35#ifdef CONFIG_FRAME_POINTER
  36                return *(unsigned long *)(regs->bp + sizeof(long));
  37#else
  38                unsigned long *sp =
  39                        (unsigned long *)kernel_stack_pointer(regs);
  40                /*
  41                 * Return address is either directly at stack pointer
  42                 * or above a saved flags. Eflags has bits 22-31 zero,
  43                 * kernel addresses don't.
  44                 */
  45                if (sp[0] >> 22)
  46                        return sp[0];
  47                if (sp[1] >> 22)
  48                        return sp[1];
  49#endif
  50        }
  51        return pc;
  52}
  53EXPORT_SYMBOL(profile_pc);
  54
  55/*
  56 * Default timer interrupt handler for PIT/HPET
  57 */
  58static irqreturn_t timer_interrupt(int irq, void *dev_id)
  59{
  60        global_clock_event->event_handler(global_clock_event);
  61        return IRQ_HANDLED;
  62}
  63
  64static struct irqaction irq0  = {
  65        .handler = timer_interrupt,
  66        .flags = IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
  67        .name = "timer"
  68};
  69
  70static void __init setup_default_timer_irq(void)
  71{
  72        if (!nr_legacy_irqs())
  73                return;
  74        setup_irq(0, &irq0);
  75}
  76
  77/* Default timer init function */
  78void __init hpet_time_init(void)
  79{
  80        if (!hpet_enable())
  81                setup_pit_timer();
  82        setup_default_timer_irq();
  83}
  84
  85static __init void x86_late_time_init(void)
  86{
  87        x86_init.timers.timer_init();
  88        tsc_init();
  89}
  90
  91/*
  92 * Initialize TSC and delay the periodic timer init to
  93 * late x86_late_time_init() so ioremap works.
  94 */
  95void __init time_init(void)
  96{
  97        late_time_init = x86_late_time_init;
  98}
  99