[PATCH] x86: i8253/i8259A lock cleanup
[pandora-kernel.git] / arch / i386 / kernel / timers / timer_pit.c
1 /*
2  * This code largely moved from arch/i386/kernel/time.c.
3  * See comments there for proper credits.
4  */
5
6 #include <linux/spinlock.h>
7 #include <linux/module.h>
8 #include <linux/device.h>
9 #include <linux/irq.h>
10 #include <linux/sysdev.h>
11 #include <linux/timex.h>
12 #include <asm/delay.h>
13 #include <asm/mpspec.h>
14 #include <asm/timer.h>
15 #include <asm/smp.h>
16 #include <asm/io.h>
17 #include <asm/arch_hooks.h>
18 #include <asm/i8253.h>
19
20 #include "do_timer.h"
21 #include "io_ports.h"
22
23 static int count_p; /* counter in get_offset_pit() */
24
25 static int __init init_pit(char* override)
26 {
27         /* check clock override */
28         if (override[0] && strncmp(override,"pit",3))
29                 printk(KERN_ERR "Warning: clock= override failed. Defaulting to PIT\n");
30  
31         count_p = LATCH;
32         return 0;
33 }
34
35 static void mark_offset_pit(void)
36 {
37         /* nothing needed */
38 }
39
40 static unsigned long long monotonic_clock_pit(void)
41 {
42         return 0;
43 }
44
45 static void delay_pit(unsigned long loops)
46 {
47         int d0;
48         __asm__ __volatile__(
49                 "\tjmp 1f\n"
50                 ".align 16\n"
51                 "1:\tjmp 2f\n"
52                 ".align 16\n"
53                 "2:\tdecl %0\n\tjns 2b"
54                 :"=&a" (d0)
55                 :"0" (loops));
56 }
57
58
59 /* This function must be called with xtime_lock held.
60  * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
61  * 
62  * However, the pc-audio speaker driver changes the divisor so that
63  * it gets interrupted rather more often - it loads 64 into the
64  * counter rather than 11932! This has an adverse impact on
65  * do_gettimeoffset() -- it stops working! What is also not
66  * good is that the interval that our timer function gets called
67  * is no longer 10.0002 ms, but 9.9767 ms. To get around this
68  * would require using a different timing source. Maybe someone
69  * could use the RTC - I know that this can interrupt at frequencies
70  * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
71  * it so that at startup, the timer code in sched.c would select
72  * using either the RTC or the 8253 timer. The decision would be
73  * based on whether there was any other device around that needed
74  * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
75  * and then do some jiggery to have a version of do_timer that 
76  * advanced the clock by 1/1024 s. Every time that reached over 1/100
77  * of a second, then do all the old code. If the time was kept correct
78  * then do_gettimeoffset could just return 0 - there is no low order
79  * divider that can be accessed.
80  *
81  * Ideally, you would be able to use the RTC for the speaker driver,
82  * but it appears that the speaker driver really needs interrupt more
83  * often than every 120 us or so.
84  *
85  * Anyway, this needs more thought....          pjsg (1993-08-28)
86  * 
87  * If you are really that interested, you should be reading
88  * comp.protocols.time.ntp!
89  */
90
91 static unsigned long get_offset_pit(void)
92 {
93         int count;
94         unsigned long flags;
95         static unsigned long jiffies_p = 0;
96
97         /*
98          * cache volatile jiffies temporarily; we have xtime_lock. 
99          */
100         unsigned long jiffies_t;
101
102         spin_lock_irqsave(&i8253_lock, flags);
103         /* timer count may underflow right here */
104         outb_p(0x00, PIT_MODE); /* latch the count ASAP */
105
106         count = inb_p(PIT_CH0); /* read the latched count */
107
108         /*
109          * We do this guaranteed double memory access instead of a _p 
110          * postfix in the previous port access. Wheee, hackady hack
111          */
112         jiffies_t = jiffies;
113
114         count |= inb_p(PIT_CH0) << 8;
115         
116         /* VIA686a test code... reset the latch if count > max + 1 */
117         if (count > LATCH) {
118                 outb_p(0x34, PIT_MODE);
119                 outb_p(LATCH & 0xff, PIT_CH0);
120                 outb(LATCH >> 8, PIT_CH0);
121                 count = LATCH - 1;
122         }
123         
124         /*
125          * avoiding timer inconsistencies (they are rare, but they happen)...
126          * there are two kinds of problems that must be avoided here:
127          *  1. the timer counter underflows
128          *  2. hardware problem with the timer, not giving us continuous time,
129          *     the counter does small "jumps" upwards on some Pentium systems,
130          *     (see c't 95/10 page 335 for Neptun bug.)
131          */
132
133         if( jiffies_t == jiffies_p ) {
134                 if( count > count_p ) {
135                         /* the nutcase */
136                         count = do_timer_overflow(count);
137                 }
138         } else
139                 jiffies_p = jiffies_t;
140
141         count_p = count;
142
143         spin_unlock_irqrestore(&i8253_lock, flags);
144
145         count = ((LATCH-1) - count) * TICK_SIZE;
146         count = (count + LATCH/2) / LATCH;
147
148         return count;
149 }
150
151
152 /* tsc timer_opts struct */
153 struct timer_opts timer_pit = {
154         .name = "pit",
155         .mark_offset = mark_offset_pit, 
156         .get_offset = get_offset_pit,
157         .monotonic_clock = monotonic_clock_pit,
158         .delay = delay_pit,
159 };
160
161 struct init_timer_opts __initdata timer_pit_init = {
162         .init = init_pit, 
163         .opts = &timer_pit,
164 };
165
166 void setup_pit_timer(void)
167 {
168         unsigned long flags;
169
170         spin_lock_irqsave(&i8253_lock, flags);
171         outb_p(0x34,PIT_MODE);          /* binary, mode 2, LSB/MSB, ch 0 */
172         udelay(10);
173         outb_p(LATCH & 0xff , PIT_CH0); /* LSB */
174         udelay(10);
175         outb(LATCH >> 8 , PIT_CH0);     /* MSB */
176         spin_unlock_irqrestore(&i8253_lock, flags);
177 }
178
179 static int timer_resume(struct sys_device *dev)
180 {
181         setup_pit_timer();
182         return 0;
183 }
184
185 static struct sysdev_class timer_sysclass = {
186         set_kset_name("timer_pit"),
187         .resume = timer_resume,
188 };
189
190 static struct sys_device device_timer = {
191         .id     = 0,
192         .cls    = &timer_sysclass,
193 };
194
195 static int __init init_timer_sysfs(void)
196 {
197         int error = sysdev_class_register(&timer_sysclass);
198         if (!error)
199                 error = sysdev_register(&device_timer);
200         return error;
201 }
202
203 device_initcall(init_timer_sysfs);
204