1
2
3
4
5
6
7#include <linux/clocksource.h>
8#include <linux/workqueue.h>
9#include <linux/cpufreq.h>
10#include <linux/jiffies.h>
11#include <linux/init.h>
12#include <linux/dmi.h>
13
14#include <asm/delay.h>
15#include <asm/tsc.h>
16#include <asm/io.h>
17#include <asm/timer.h>
18
19#include "mach_timer.h"
20
21static int tsc_enabled;
22
23
24
25
26
27
28unsigned int tsc_khz;
29
30int tsc_disable;
31
32#ifdef CONFIG_X86_TSC
33static int __init tsc_setup(char *str)
34{
35 printk(KERN_WARNING "notsc: Kernel compiled with CONFIG_X86_TSC, "
36 "cannot disable TSC.\n");
37 return 1;
38}
39#else
40
41
42
43
44static int __init tsc_setup(char *str)
45{
46 tsc_disable = 1;
47
48 return 1;
49}
50#endif
51
52__setup("notsc", tsc_setup);
53
54
55
56
57
58static int tsc_unstable;
59
60static inline int check_tsc_unstable(void)
61{
62 return tsc_unstable;
63}
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86static unsigned long cyc2ns_scale __read_mostly;
87
88#define CYC2NS_SCALE_FACTOR 10
89
90static inline void set_cyc2ns_scale(unsigned long cpu_khz)
91{
92 cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz;
93}
94
95static inline unsigned long long cycles_2_ns(unsigned long long cyc)
96{
97 return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
98}
99
100
101
102
103unsigned long long sched_clock(void)
104{
105 unsigned long long this_offset;
106
107
108
109
110 if (unlikely(!tsc_enabled))
111
112 return (jiffies_64 - INITIAL_JIFFIES) * (1000000000 / HZ);
113
114
115 get_scheduled_cycles(this_offset);
116
117
118 return cycles_2_ns(this_offset);
119}
120
121unsigned long native_calculate_cpu_khz(void)
122{
123 unsigned long long start, end;
124 unsigned long count;
125 u64 delta64 = (u64)ULLONG_MAX;
126 int i;
127 unsigned long flags;
128
129 local_irq_save(flags);
130
131
132 for (i = 0; i < 3; i++) {
133 mach_prepare_counter();
134 rdtscll(start);
135 mach_countup(&count);
136 rdtscll(end);
137 delta64 = min(delta64, (end - start));
138 }
139
140
141
142
143
144
145 if (count <= 1)
146 goto err;
147
148
149 if (delta64 > (1ULL<<32))
150 goto err;
151
152
153 if (delta64 <= CALIBRATE_TIME_MSEC)
154 goto err;
155
156 delta64 += CALIBRATE_TIME_MSEC/2;
157 do_div(delta64,CALIBRATE_TIME_MSEC);
158
159 local_irq_restore(flags);
160 return (unsigned long)delta64;
161err:
162 local_irq_restore(flags);
163 return 0;
164}
165
166int recalibrate_cpu_khz(void)
167{
168#ifndef CONFIG_SMP
169 unsigned long cpu_khz_old = cpu_khz;
170
171 if (cpu_has_tsc) {
172 cpu_khz = calculate_cpu_khz();
173 tsc_khz = cpu_khz;
174 cpu_data[0].loops_per_jiffy =
175 cpufreq_scale(cpu_data[0].loops_per_jiffy,
176 cpu_khz_old, cpu_khz);
177 return 0;
178 } else
179 return -ENODEV;
180#else
181 return -ENODEV;
182#endif
183}
184
185EXPORT_SYMBOL(recalibrate_cpu_khz);
186
187#ifdef CONFIG_CPU_FREQ
188
189
190
191
192
193static unsigned int ref_freq = 0;
194static unsigned long loops_per_jiffy_ref = 0;
195static unsigned long cpu_khz_ref = 0;
196
197static int
198time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data)
199{
200 struct cpufreq_freqs *freq = data;
201
202 if (!ref_freq) {
203 if (!freq->old){
204 ref_freq = freq->new;
205 return 0;
206 }
207 ref_freq = freq->old;
208 loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy;
209 cpu_khz_ref = cpu_khz;
210 }
211
212 if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
213 (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
214 (val == CPUFREQ_RESUMECHANGE)) {
215 if (!(freq->flags & CPUFREQ_CONST_LOOPS))
216 cpu_data[freq->cpu].loops_per_jiffy =
217 cpufreq_scale(loops_per_jiffy_ref,
218 ref_freq, freq->new);
219
220 if (cpu_khz) {
221
222 if (num_online_cpus() == 1)
223 cpu_khz = cpufreq_scale(cpu_khz_ref,
224 ref_freq, freq->new);
225 if (!(freq->flags & CPUFREQ_CONST_LOOPS)) {
226 tsc_khz = cpu_khz;
227 set_cyc2ns_scale(cpu_khz);
228
229
230
231
232 mark_tsc_unstable("cpufreq changes");
233 }
234 }
235 }
236
237 return 0;
238}
239
240static struct notifier_block time_cpufreq_notifier_block = {
241 .notifier_call = time_cpufreq_notifier
242};
243
244static int __init cpufreq_tsc(void)
245{
246 return cpufreq_register_notifier(&time_cpufreq_notifier_block,
247 CPUFREQ_TRANSITION_NOTIFIER);
248}
249core_initcall(cpufreq_tsc);
250
251#endif
252
253
254
255static unsigned long current_tsc_khz = 0;
256
257static cycle_t read_tsc(void)
258{
259 cycle_t ret;
260
261 rdtscll(ret);
262
263 return ret;
264}
265
266static struct clocksource clocksource_tsc = {
267 .name = "tsc",
268 .rating = 300,
269 .read = read_tsc,
270 .mask = CLOCKSOURCE_MASK(64),
271 .mult = 0,
272 .shift = 22,
273 .flags = CLOCK_SOURCE_IS_CONTINUOUS |
274 CLOCK_SOURCE_MUST_VERIFY,
275};
276
277void mark_tsc_unstable(char *reason)
278{
279 if (!tsc_unstable) {
280 tsc_unstable = 1;
281 tsc_enabled = 0;
282 printk("Marking TSC unstable due to: %s.\n", reason);
283
284 if (clocksource_tsc.mult)
285 clocksource_change_rating(&clocksource_tsc, 0);
286 else
287 clocksource_tsc.rating = 0;
288 }
289}
290EXPORT_SYMBOL_GPL(mark_tsc_unstable);
291
292static int __init dmi_mark_tsc_unstable(struct dmi_system_id *d)
293{
294 printk(KERN_NOTICE "%s detected: marking TSC unstable.\n",
295 d->ident);
296 tsc_unstable = 1;
297 return 0;
298}
299
300
301static struct dmi_system_id __initdata bad_tsc_dmi_table[] = {
302 {
303 .callback = dmi_mark_tsc_unstable,
304 .ident = "IBM Thinkpad 380XD",
305 .matches = {
306 DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
307 DMI_MATCH(DMI_BOARD_NAME, "2635FA0"),
308 },
309 },
310 {}
311};
312
313
314
315
316
317__cpuinit int unsynchronized_tsc(void)
318{
319 if (!cpu_has_tsc || tsc_unstable)
320 return 1;
321
322
323
324
325 if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) {
326
327 if (num_possible_cpus() > 1)
328 tsc_unstable = 1;
329 }
330 return tsc_unstable;
331}
332
333
334
335
336#ifdef CONFIG_MGEODE_LX
337
338#define RTSC_SUSP 0x100
339
340static void __init check_geode_tsc_reliable(void)
341{
342 unsigned long val;
343
344 rdmsrl(MSR_GEODE_BUSCONT_CONF0, val);
345 if ((val & RTSC_SUSP))
346 clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
347}
348#else
349static inline void check_geode_tsc_reliable(void) { }
350#endif
351
352
353void __init tsc_init(void)
354{
355 if (!cpu_has_tsc || tsc_disable)
356 goto out_no_tsc;
357
358 cpu_khz = calculate_cpu_khz();
359 tsc_khz = cpu_khz;
360
361 if (!cpu_khz)
362 goto out_no_tsc;
363
364 printk("Detected %lu.%03lu MHz processor.\n",
365 (unsigned long)cpu_khz / 1000,
366 (unsigned long)cpu_khz % 1000);
367
368 set_cyc2ns_scale(cpu_khz);
369 use_tsc_delay();
370
371
372 dmi_check_system(bad_tsc_dmi_table);
373
374 unsynchronized_tsc();
375 check_geode_tsc_reliable();
376 current_tsc_khz = tsc_khz;
377 clocksource_tsc.mult = clocksource_khz2mult(current_tsc_khz,
378 clocksource_tsc.shift);
379
380 if (check_tsc_unstable()) {
381 clocksource_tsc.rating = 0;
382 clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS;
383 } else
384 tsc_enabled = 1;
385
386 clocksource_register(&clocksource_tsc);
387
388 return;
389
390out_no_tsc:
391
392
393
394
395
396 tsc_disable = 1;
397}
398