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