Merge branch 'master' of /home/src/linux-2.6/
[linux-2.6] / arch / i386 / kernel / timers / timer.c
1 #include <linux/init.h>
2 #include <linux/kernel.h>
3 #include <linux/string.h>
4 #include <asm/timer.h>
5
6 #ifdef CONFIG_HPET_TIMER
7 /*
8  * HPET memory read is slower than tsc reads, but is more dependable as it
9  * always runs at constant frequency and reduces complexity due to
10  * cpufreq. So, we prefer HPET timer to tsc based one. Also, we cannot use
11  * timer_pit when HPET is active. So, we default to timer_tsc.
12  */
13 #endif
14 /* list of timers, ordered by preference, NULL terminated */
15 static struct init_timer_opts* __initdata timers[] = {
16 #ifdef CONFIG_X86_CYCLONE_TIMER
17         &timer_cyclone_init,
18 #endif
19 #ifdef CONFIG_HPET_TIMER
20         &timer_hpet_init,
21 #endif
22 #ifdef CONFIG_X86_PM_TIMER
23         &timer_pmtmr_init,
24 #endif
25         &timer_tsc_init,
26         &timer_pit_init,
27         NULL,
28 };
29
30 static char clock_override[10] __initdata;
31
32 static int __init clock_setup(char* str)
33 {
34         if (str)
35                 strlcpy(clock_override, str, sizeof(clock_override));
36         return 1;
37 }
38 __setup("clock=", clock_setup);
39
40
41 /* The chosen timesource has been found to be bad.
42  * Fall back to a known good timesource (the PIT)
43  */
44 void clock_fallback(void)
45 {
46         cur_timer = &timer_pit;
47 }
48
49 /* iterates through the list of timers, returning the first 
50  * one that initializes successfully.
51  */
52 struct timer_opts* __init select_timer(void)
53 {
54         int i = 0;
55         
56         /* find most preferred working timer */
57         while (timers[i]) {
58                 if (timers[i]->init)
59                         if (timers[i]->init(clock_override) == 0)
60                                 return timers[i]->opts;
61                 ++i;
62         }
63                 
64         panic("select_timer: Cannot find a suitable timer\n");
65         return NULL;
66 }
67
68 int read_current_timer(unsigned long *timer_val)
69 {
70         if (cur_timer->read_timer) {
71                 *timer_val = cur_timer->read_timer();
72                 return 0;
73         }
74         return -1;
75 }