xref: /freebsd/sys/i386/include/clock.h (revision 4a0f765fbf09711e612e86fce8bb09ec43f482d9)
1 /*
2  * Kernel interface to machine-dependent clock driver.
3  * Garrett Wollman, September 1994.
4  * This file is in the public domain.
5  *
6  *	$Id$
7  */
8 
9 #ifndef _MACHINE_CLOCK_H_
10 #define	_MACHINE_CLOCK_H_
11 
12 #if defined(I586_CPU) || defined(I686_CPU)
13 #define CPU_CLOCKUPDATE(otime, ntime)	cpu_clockupdate((otime), (ntime))
14 #else
15 #define CPU_CLOCKUPDATE(otime, ntime)	(*(otime) = *(ntime))
16 #endif
17 
18 #define CPU_THISTICKLEN(dflt) dflt
19 
20 #define	I586_CTR_COMULTIPLIER_SHIFT	20
21 #define	I586_CTR_MULTIPLIER_SHIFT	32
22 
23 #ifdef KERNEL
24 /*
25  * i386 to clock driver interface.
26  * XXX almost all of it is misplaced.  i586 stuff is done in isa/clock.c
27  * and isa stuff is done in i386/microtime.s and i386/support.s.
28  */
29 extern int	adjkerntz;
30 extern int	disable_rtc_set;
31 #if defined(I586_CPU) || defined(I686_CPU)
32 extern u_int	i586_ctr_bias;
33 extern u_int	i586_ctr_comultiplier;
34 extern u_int	i586_ctr_freq;
35 extern u_int	i586_ctr_multiplier;
36 #endif
37 extern int	statclock_disable;
38 extern u_int	timer_freq;
39 extern int	timer0_max_count;
40 extern u_int	timer0_overflow_threshold;
41 extern u_int	timer0_prescaler_count;
42 extern int	wall_cmos_clock;
43 
44 /*
45  * Driver to clock driver interface.
46  */
47 struct clockframe;
48 
49 void	DELAY __P((int usec));
50 int	acquire_timer0 __P((int rate,
51 			    void (*function)(struct clockframe *frame)));
52 int	acquire_timer2 __P((int mode));
53 int	release_timer0 __P((void));
54 int	release_timer2 __P((void));
55 #ifndef PC98
56 int	rtcin __P((int val));
57 #else
58 int	acquire_timer1 __P((int mode));
59 int	release_timer1 __P((void));
60 #endif
61 int	sysbeep __P((int pitch, int period));
62 
63 #ifdef CLOCK_HAIR
64 
65 #ifdef PC98
66 #include <pc98/pc98/pc98.h>		/* XXX */
67 #else
68 #include <i386/isa/isa.h>		/* XXX */
69 #endif
70 #include <i386/isa/timerreg.h>		/* XXX */
71 
72 static __inline u_int
73 clock_latency(void)
74 {
75 	u_char high, low;
76 
77 	outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
78 	low = inb(TIMER_CNTR0);
79 	high = inb(TIMER_CNTR0);
80 	return (timer0_prescaler_count + timer0_max_count
81 		- ((high << 8) | low));
82 }
83 
84 #if defined(I586_CPU) || defined(I686_CPU)
85 /*
86  * When we update `time', on i586's we also update `i586_ctr_bias'
87  * atomically.  `i586_ctr_bias' is the best available approximation to
88  * the value of the i586 counter (mod 2^32) at the time of the i8254
89  * counter transition that caused the clock interrupt that caused the
90  * update.  clock_latency() gives the time between the transition and
91  * the update to within a few usec provided another such transition
92  * hasn't occurred.  We don't bother checking for counter overflow as
93  * in microtime(), since if it occurs then we're close to losing clock
94  * interrupts.
95  */
96 static __inline void
97 cpu_clockupdate(volatile struct timeval *otime, struct timeval *ntime)
98 {
99 	if (i586_ctr_freq != 0) {
100 		u_int i586_count;	/* truncated */
101 		u_int i8254_count;
102 
103 		disable_intr();
104 		i8254_count = clock_latency();
105 		i586_count = rdtsc();
106 		i586_ctr_bias = i586_count
107 				- (u_int)
108 				  (((unsigned long long)i586_ctr_comultiplier
109 				    * i8254_count)
110 				   >> I586_CTR_COMULTIPLIER_SHIFT);
111 		*otime = *ntime;
112 		enable_intr();
113 	} else
114 		*otime = *ntime;
115 }
116 #endif /* I586_CPU || I686_CPU */
117 
118 #endif /* CLOCK_HAIR */
119 
120 #endif /* KERNEL */
121 
122 #endif /* !_MACHINE_CLOCK_H_ */
123