ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / i386 / kernel / timers / timer_pm.c
1 /*
2  * (C) Dominik Brodowski <linux@brodo.de> 2003
3  *
4  * Driver to use the Power Management Timer (PMTMR) available in some
5  * southbridges as primary timing source for the Linux kernel.
6  *
7  * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c,
8  * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4.
9  *
10  * This file is licensed under the GPL v2.
11  */
12
13
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/device.h>
17 #include <linux/init.h>
18 #include <asm/types.h>
19 #include <asm/timer.h>
20 #include <asm/smp.h>
21 #include <asm/io.h>
22 #include <asm/arch_hooks.h>
23
24
25 /* The I/O port the PMTMR resides at.
26  * The location is detected during setup_arch(),
27  * in arch/i386/acpi/boot.c */
28 u32 pmtmr_ioport = 0;
29
30
31 /* value of the Power timer at last timer interrupt */
32 static u32 offset_tick;
33 static u32 offset_delay;
34
35 static unsigned long long monotonic_base;
36 static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED;
37
38 #define ACPI_PM_MASK 0xFFFFFF /* limit it to 24 bits */
39
40 /*helper function to safely read acpi pm timesource*/
41 static inline u32 read_pmtmr(void)
42 {
43         u32 v1=0,v2=0,v3=0;
44         /* It has been reported that because of various broken
45          * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM time
46          * source is not latched, so you must read it multiple
47          * times to insure a safe value is read.
48          */
49         do {
50                 v1 = inl(pmtmr_ioport);
51                 v2 = inl(pmtmr_ioport);
52                 v3 = inl(pmtmr_ioport);
53         } while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
54                         || (v3 > v1 && v3 < v2));
55
56         /* mask the output to 24 bits */
57         return v2 & ACPI_PM_MASK;
58 }
59
60 static int init_pmtmr(char* override)
61 {
62         u32 value1, value2;
63         unsigned int i;
64
65         if (override[0] && strncmp(override,"pmtmr",5))
66                 return -ENODEV;
67
68         if (!pmtmr_ioport)
69                 return -ENODEV;
70
71         /* we use the TSC for delay_pmtmr, so make sure it exists */
72         if (!cpu_has_tsc)
73                 return -ENODEV;
74
75         /* "verify" this timing source */
76         value1 = read_pmtmr();
77         for (i = 0; i < 10000; i++) {
78                 value2 = read_pmtmr();
79                 if (value2 == value1)
80                         continue;
81                 if (value2 > value1)
82                         goto pm_good;
83                 if ((value2 < value1) && ((value2) < 0xFFF))
84                         goto pm_good;
85                 printk(KERN_INFO "PM-Timer had inconsistent results: 0x%#x, 0x%#x - aborting.\n", value1, value2);
86                 return -EINVAL;
87         }
88         printk(KERN_INFO "PM-Timer had no reasonable result: 0x%#x - aborting.\n", value1);
89         return -ENODEV;
90
91 pm_good:
92         init_cpu_khz();
93         return 0;
94 }
95
96 static inline u32 cyc2us(u32 cycles)
97 {
98         /* The Power Management Timer ticks at 3.579545 ticks per microsecond.
99          * 1 / PM_TIMER_FREQUENCY == 0.27936511 =~ 286/1024 [error: 0.024%]
100          *
101          * Even with HZ = 100, delta is at maximum 35796 ticks, so it can
102          * easily be multiplied with 286 (=0x11E) without having to fear
103          * u32 overflows.
104          */
105         cycles *= 286;
106         return (cycles >> 10);
107 }
108
109 /*
110  * this gets called during each timer interrupt
111  *   - Called while holding the writer xtime_lock
112  */
113 static void mark_offset_pmtmr(void)
114 {
115         u32 lost, delta, last_offset;
116         static int first_run = 1;
117         last_offset = offset_tick;
118
119         write_seqlock(&monotonic_lock);
120
121         offset_tick = read_pmtmr();
122
123         /* calculate tick interval */
124         delta = (offset_tick - last_offset) & ACPI_PM_MASK;
125
126         /* convert to usecs */
127         delta = cyc2us(delta);
128
129         /* update the monotonic base value */
130         monotonic_base += delta * NSEC_PER_USEC;
131         write_sequnlock(&monotonic_lock);
132
133         /* convert to ticks */
134         delta += offset_delay;
135         lost = delta / (USEC_PER_SEC / HZ);
136         offset_delay = delta % (USEC_PER_SEC / HZ);
137
138
139         /* compensate for lost ticks */
140         if (lost >= 2)
141                 jiffies_64 += lost - 1;
142
143         /* don't calculate delay for first run,
144            or if we've got less then a tick */
145         if (first_run || (lost < 1)) {
146                 first_run = 0;
147                 offset_delay = 0;
148         }
149 }
150
151
152 static unsigned long long monotonic_clock_pmtmr(void)
153 {
154         u32 last_offset, this_offset;
155         unsigned long long base, ret;
156         unsigned seq;
157
158
159         /* atomically read monotonic base & last_offset */
160         do {
161                 seq = read_seqbegin(&monotonic_lock);
162                 last_offset = offset_tick;
163                 base = monotonic_base;
164         } while (read_seqretry(&monotonic_lock, seq));
165
166         /* Read the pmtmr */
167         this_offset =  read_pmtmr();
168
169         /* convert to nanoseconds */
170         ret = (this_offset - last_offset) & ACPI_PM_MASK;
171         ret = base + (cyc2us(ret) * NSEC_PER_USEC);
172         return ret;
173 }
174
175 static void delay_pmtmr(unsigned long loops)
176 {
177         unsigned long bclock, now;
178
179         rdtscl(bclock);
180         do
181         {
182                 rep_nop();
183                 rdtscl(now);
184         } while ((now-bclock) < loops);
185 }
186
187
188 /*
189  * get the offset (in microseconds) from the last call to mark_offset()
190  *      - Called holding a reader xtime_lock
191  */
192 static unsigned long get_offset_pmtmr(void)
193 {
194         u32 now, offset, delta = 0;
195
196         offset = offset_tick;
197         now = read_pmtmr();
198         delta = (now - offset)&ACPI_PM_MASK;
199
200         return (unsigned long) offset_delay + cyc2us(delta);
201 }
202
203
204 /* acpi timer_opts struct */
205 struct timer_opts timer_pmtmr = {
206         .name                   = "pmtmr",
207         .init                   = init_pmtmr,
208         .mark_offset            = mark_offset_pmtmr,
209         .get_offset             = get_offset_pmtmr,
210         .monotonic_clock        = monotonic_clock_pmtmr,
211         .delay                  = delay_pmtmr,
212 };
213
214
215 MODULE_LICENSE("GPL");
216 MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
217 MODULE_DESCRIPTION("Power Management Timer (PMTMR) as primary timing source for x86");