x86: merge the TSC cpu-freq code
[linux-flexiantxendom0.git] / arch / x86 / kernel / tsc.c
1 #include <linux/kernel.h>
2 #include <linux/sched.h>
3 #include <linux/init.h>
4 #include <linux/module.h>
5 #include <linux/timer.h>
6 #include <linux/acpi_pmtmr.h>
7 #include <linux/cpufreq.h>
8
9 #include <asm/hpet.h>
10
11 unsigned int cpu_khz;           /* TSC clocks / usec, not used here */
12 EXPORT_SYMBOL(cpu_khz);
13 unsigned int tsc_khz;
14 EXPORT_SYMBOL(tsc_khz);
15
16 /*
17  * TSC can be unstable due to cpufreq or due to unsynced TSCs
18  */
19 int tsc_unstable;
20
21 /* native_sched_clock() is called before tsc_init(), so
22    we must start with the TSC soft disabled to prevent
23    erroneous rdtsc usage on !cpu_has_tsc processors */
24 int tsc_disabled = -1;
25
26 /*
27  * Scheduler clock - returns current time in nanosec units.
28  */
29 u64 native_sched_clock(void)
30 {
31         u64 this_offset;
32
33         /*
34          * Fall back to jiffies if there's no TSC available:
35          * ( But note that we still use it if the TSC is marked
36          *   unstable. We do this because unlike Time Of Day,
37          *   the scheduler clock tolerates small errors and it's
38          *   very important for it to be as fast as the platform
39          *   can achive it. )
40          */
41         if (unlikely(tsc_disabled)) {
42                 /* No locking but a rare wrong value is not a big deal: */
43                 return (jiffies_64 - INITIAL_JIFFIES) * (1000000000 / HZ);
44         }
45
46         /* read the Time Stamp Counter: */
47         rdtscll(this_offset);
48
49         /* return the value in ns */
50         return cycles_2_ns(this_offset);
51 }
52
53 /* We need to define a real function for sched_clock, to override the
54    weak default version */
55 #ifdef CONFIG_PARAVIRT
56 unsigned long long sched_clock(void)
57 {
58         return paravirt_sched_clock();
59 }
60 #else
61 unsigned long long
62 sched_clock(void) __attribute__((alias("native_sched_clock")));
63 #endif
64
65 int check_tsc_unstable(void)
66 {
67         return tsc_unstable;
68 }
69 EXPORT_SYMBOL_GPL(check_tsc_unstable);
70
71 #ifdef CONFIG_X86_TSC
72 int __init notsc_setup(char *str)
73 {
74         printk(KERN_WARNING "notsc: Kernel compiled with CONFIG_X86_TSC, "
75                         "cannot disable TSC completely.\n");
76         tsc_disabled = 1;
77         return 1;
78 }
79 #else
80 /*
81  * disable flag for tsc. Takes effect by clearing the TSC cpu flag
82  * in cpu/common.c
83  */
84 int __init notsc_setup(char *str)
85 {
86         setup_clear_cpu_cap(X86_FEATURE_TSC);
87         return 1;
88 }
89 #endif
90
91 __setup("notsc", notsc_setup);
92
93 #define MAX_RETRIES     5
94 #define SMI_TRESHOLD    50000
95
96 /*
97  * Read TSC and the reference counters. Take care of SMI disturbance
98  */
99 static u64 __init tsc_read_refs(u64 *pm, u64 *hpet)
100 {
101         u64 t1, t2;
102         int i;
103
104         for (i = 0; i < MAX_RETRIES; i++) {
105                 t1 = get_cycles();
106                 if (hpet)
107                         *hpet = hpet_readl(HPET_COUNTER) & 0xFFFFFFFF;
108                 else
109                         *pm = acpi_pm_read_early();
110                 t2 = get_cycles();
111                 if ((t2 - t1) < SMI_TRESHOLD)
112                         return t2;
113         }
114         return ULLONG_MAX;
115 }
116
117 /**
118  * tsc_calibrate - calibrate the tsc on boot
119  */
120 static unsigned int __init tsc_calibrate(void)
121 {
122         unsigned long flags;
123         u64 tsc1, tsc2, tr1, tr2, delta, pm1, pm2, hpet1, hpet2;
124         int hpet = is_hpet_enabled();
125         unsigned int tsc_khz_val = 0;
126
127         local_irq_save(flags);
128
129         tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL);
130
131         outb((inb(0x61) & ~0x02) | 0x01, 0x61);
132
133         outb(0xb0, 0x43);
134         outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42);
135         outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42);
136         tr1 = get_cycles();
137         while ((inb(0x61) & 0x20) == 0);
138         tr2 = get_cycles();
139
140         tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL);
141
142         local_irq_restore(flags);
143
144         /*
145          * Preset the result with the raw and inaccurate PIT
146          * calibration value
147          */
148         delta = (tr2 - tr1);
149         do_div(delta, 50);
150         tsc_khz_val = delta;
151
152         /* hpet or pmtimer available ? */
153         if (!hpet && !pm1 && !pm2) {
154                 printk(KERN_INFO "TSC calibrated against PIT\n");
155                 goto out;
156         }
157
158         /* Check, whether the sampling was disturbed by an SMI */
159         if (tsc1 == ULLONG_MAX || tsc2 == ULLONG_MAX) {
160                 printk(KERN_WARNING "TSC calibration disturbed by SMI, "
161                                 "using PIT calibration result\n");
162                 goto out;
163         }
164
165         tsc2 = (tsc2 - tsc1) * 1000000LL;
166
167         if (hpet) {
168                 printk(KERN_INFO "TSC calibrated against HPET\n");
169                 if (hpet2 < hpet1)
170                         hpet2 += 0x100000000ULL;
171                 hpet2 -= hpet1;
172                 tsc1 = ((u64)hpet2 * hpet_readl(HPET_PERIOD));
173                 do_div(tsc1, 1000000);
174         } else {
175                 printk(KERN_INFO "TSC calibrated against PM_TIMER\n");
176                 if (pm2 < pm1)
177                         pm2 += (u64)ACPI_PM_OVRRUN;
178                 pm2 -= pm1;
179                 tsc1 = pm2 * 1000000000LL;
180                 do_div(tsc1, PMTMR_TICKS_PER_SEC);
181         }
182
183         do_div(tsc2, tsc1);
184         tsc_khz_val = tsc2;
185
186 out:
187         return tsc_khz_val;
188 }
189
190 unsigned long native_calculate_cpu_khz(void)
191 {
192         return tsc_calibrate();
193 }
194
195 #ifdef CONFIG_X86_32
196 /* Only called from the Powernow K7 cpu freq driver */
197 int recalibrate_cpu_khz(void)
198 {
199 #ifndef CONFIG_SMP
200         unsigned long cpu_khz_old = cpu_khz;
201
202         if (cpu_has_tsc) {
203                 cpu_khz = calculate_cpu_khz();
204                 tsc_khz = cpu_khz;
205                 cpu_data(0).loops_per_jiffy =
206                         cpufreq_scale(cpu_data(0).loops_per_jiffy,
207                                         cpu_khz_old, cpu_khz);
208                 return 0;
209         } else
210                 return -ENODEV;
211 #else
212         return -ENODEV;
213 #endif
214 }
215
216 EXPORT_SYMBOL(recalibrate_cpu_khz);
217
218 #endif /* CONFIG_X86_32 */
219
220 /* Accelerators for sched_clock()
221  * convert from cycles(64bits) => nanoseconds (64bits)
222  *  basic equation:
223  *              ns = cycles / (freq / ns_per_sec)
224  *              ns = cycles * (ns_per_sec / freq)
225  *              ns = cycles * (10^9 / (cpu_khz * 10^3))
226  *              ns = cycles * (10^6 / cpu_khz)
227  *
228  *      Then we use scaling math (suggested by george@mvista.com) to get:
229  *              ns = cycles * (10^6 * SC / cpu_khz) / SC
230  *              ns = cycles * cyc2ns_scale / SC
231  *
232  *      And since SC is a constant power of two, we can convert the div
233  *  into a shift.
234  *
235  *  We can use khz divisor instead of mhz to keep a better precision, since
236  *  cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits.
237  *  (mathieu.desnoyers@polymtl.ca)
238  *
239  *                      -johnstul@us.ibm.com "math is hard, lets go shopping!"
240  */
241
242 DEFINE_PER_CPU(unsigned long, cyc2ns);
243
244 void set_cyc2ns_scale(unsigned long cpu_khz, int cpu)
245 {
246         unsigned long long tsc_now, ns_now;
247         unsigned long flags, *scale;
248
249         local_irq_save(flags);
250         sched_clock_idle_sleep_event();
251
252         scale = &per_cpu(cyc2ns, cpu);
253
254         rdtscll(tsc_now);
255         ns_now = __cycles_2_ns(tsc_now);
256
257         if (cpu_khz)
258                 *scale = (NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR)/cpu_khz;
259
260         sched_clock_idle_wakeup_event(0);
261         local_irq_restore(flags);
262 }
263
264 #ifdef CONFIG_CPU_FREQ
265
266 /* Frequency scaling support. Adjust the TSC based timer when the cpu frequency
267  * changes.
268  *
269  * RED-PEN: On SMP we assume all CPUs run with the same frequency.  It's
270  * not that important because current Opteron setups do not support
271  * scaling on SMP anyroads.
272  *
273  * Should fix up last_tsc too. Currently gettimeofday in the
274  * first tick after the change will be slightly wrong.
275  */
276
277 static unsigned int  ref_freq;
278 static unsigned long loops_per_jiffy_ref;
279 static unsigned long tsc_khz_ref;
280
281 static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
282                                 void *data)
283 {
284         struct cpufreq_freqs *freq = data;
285         unsigned long *lpj, dummy;
286
287         if (cpu_has(&cpu_data(freq->cpu), X86_FEATURE_CONSTANT_TSC))
288                 return 0;
289
290         lpj = &dummy;
291         if (!(freq->flags & CPUFREQ_CONST_LOOPS))
292 #ifdef CONFIG_SMP
293                 lpj = &cpu_data(freq->cpu).loops_per_jiffy;
294 #else
295         lpj = &boot_cpu_data.loops_per_jiffy;
296 #endif
297
298         if (!ref_freq) {
299                 ref_freq = freq->old;
300                 loops_per_jiffy_ref = *lpj;
301                 tsc_khz_ref = tsc_khz;
302         }
303         if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
304                         (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
305                         (val == CPUFREQ_RESUMECHANGE)) {
306                 *lpj =  cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
307
308                 tsc_khz = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new);
309                 if (!(freq->flags & CPUFREQ_CONST_LOOPS))
310                         mark_tsc_unstable("cpufreq changes");
311         }
312
313         set_cyc2ns_scale(tsc_khz_ref, freq->cpu);
314
315         return 0;
316 }
317
318 static struct notifier_block time_cpufreq_notifier_block = {
319         .notifier_call  = time_cpufreq_notifier
320 };
321
322 static int __init cpufreq_tsc(void)
323 {
324         cpufreq_register_notifier(&time_cpufreq_notifier_block,
325                                 CPUFREQ_TRANSITION_NOTIFIER);
326         return 0;
327 }
328
329 core_initcall(cpufreq_tsc);
330
331 #endif /* CONFIG_CPU_FREQ */