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