x86: Add timer_init to x86_init_ops
[firefly-linux-kernel-4.4.55.git] / arch / x86 / kernel / time_64.c
1 /*
2  *  "High Precision Event Timer" based timekeeping.
3  *
4  *  Copyright (c) 1991,1992,1995  Linus Torvalds
5  *  Copyright (c) 1994  Alan Modra
6  *  Copyright (c) 1995  Markus Kuhn
7  *  Copyright (c) 1996  Ingo Molnar
8  *  Copyright (c) 1998  Andrea Arcangeli
9  *  Copyright (c) 2002,2006  Vojtech Pavlik
10  *  Copyright (c) 2003  Andi Kleen
11  *  RTC support code taken from arch/i386/kernel/timers/time_hpet.c
12  */
13
14 #include <linux/clockchips.h>
15 #include <linux/init.h>
16 #include <linux/interrupt.h>
17 #include <linux/module.h>
18 #include <linux/time.h>
19 #include <linux/mca.h>
20 #include <linux/nmi.h>
21
22 #include <asm/x86_init.h>
23 #include <asm/i8253.h>
24 #include <asm/hpet.h>
25 #include <asm/vgtod.h>
26 #include <asm/time.h>
27 #include <asm/timer.h>
28
29 volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
30
31 unsigned long profile_pc(struct pt_regs *regs)
32 {
33         unsigned long pc = instruction_pointer(regs);
34
35         /* Assume the lock function has either no stack frame or a copy
36            of flags from PUSHF
37            Eflags always has bits 22 and up cleared unlike kernel addresses. */
38         if (!user_mode_vm(regs) && in_lock_functions(pc)) {
39 #ifdef CONFIG_FRAME_POINTER
40                 return *(unsigned long *)(regs->bp + sizeof(long));
41 #else
42                 unsigned long *sp = (unsigned long *)regs->sp;
43                 if (sp[0] >> 22)
44                         return sp[0];
45                 if (sp[1] >> 22)
46                         return sp[1];
47 #endif
48         }
49         return pc;
50 }
51 EXPORT_SYMBOL(profile_pc);
52
53 static irqreturn_t timer_interrupt(int irq, void *dev_id)
54 {
55         inc_irq_stat(irq0_irqs);
56
57         global_clock_event->event_handler(global_clock_event);
58
59 #ifdef CONFIG_MCA
60         if (MCA_bus) {
61                 u8 irq_v = inb_p(0x61);       /* read the current state */
62                 outb_p(irq_v|0x80, 0x61);     /* reset the IRQ */
63         }
64 #endif
65
66         return IRQ_HANDLED;
67 }
68
69 /* calibrate_cpu is used on systems with fixed rate TSCs to determine
70  * processor frequency */
71 #define TICK_COUNT 100000000
72 unsigned long __init calibrate_cpu(void)
73 {
74         int tsc_start, tsc_now;
75         int i, no_ctr_free;
76         unsigned long evntsel3 = 0, pmc3 = 0, pmc_now = 0;
77         unsigned long flags;
78
79         for (i = 0; i < 4; i++)
80                 if (avail_to_resrv_perfctr_nmi_bit(i))
81                         break;
82         no_ctr_free = (i == 4);
83         if (no_ctr_free) {
84                 WARN(1, KERN_WARNING "Warning: AMD perfctrs busy ... "
85                      "cpu_khz value may be incorrect.\n");
86                 i = 3;
87                 rdmsrl(MSR_K7_EVNTSEL3, evntsel3);
88                 wrmsrl(MSR_K7_EVNTSEL3, 0);
89                 rdmsrl(MSR_K7_PERFCTR3, pmc3);
90         } else {
91                 reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i);
92                 reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
93         }
94         local_irq_save(flags);
95         /* start measuring cycles, incrementing from 0 */
96         wrmsrl(MSR_K7_PERFCTR0 + i, 0);
97         wrmsrl(MSR_K7_EVNTSEL0 + i, 1 << 22 | 3 << 16 | 0x76);
98         rdtscl(tsc_start);
99         do {
100                 rdmsrl(MSR_K7_PERFCTR0 + i, pmc_now);
101                 tsc_now = get_cycles();
102         } while ((tsc_now - tsc_start) < TICK_COUNT);
103
104         local_irq_restore(flags);
105         if (no_ctr_free) {
106                 wrmsrl(MSR_K7_EVNTSEL3, 0);
107                 wrmsrl(MSR_K7_PERFCTR3, pmc3);
108                 wrmsrl(MSR_K7_EVNTSEL3, evntsel3);
109         } else {
110                 release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
111                 release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
112         }
113
114         return pmc_now * tsc_khz / (tsc_now - tsc_start);
115 }
116
117 static struct irqaction irq0 = {
118         .handler        = timer_interrupt,
119         .flags          = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING | IRQF_TIMER,
120         .name           = "timer"
121 };
122
123 void __init hpet_time_init(void)
124 {
125         if (!hpet_enable())
126                 setup_pit_timer();
127
128         setup_irq(0, &irq0);
129 }
130
131 static void x86_late_time_init(void)
132 {
133         x86_init.timers.timer_init();
134 }
135
136 void __init time_init(void)
137 {
138         tsc_init();
139         late_time_init = x86_late_time_init;
140 }