PageRenderTime 27ms CodeModel.GetById 14ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/i386/kernel/timers/timer_pit.c

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