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