clock.h revision 32052
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.28 1997/12/26 20:42:01 phk 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	TSC_COMULTIPLIER_SHIFT	20
21#define	TSC_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 */
29extern int	adjkerntz;
30extern int	disable_rtc_set;
31extern int	statclock_disable;
32extern u_int	timer_freq;
33extern int	timer0_max_count;
34extern u_int	timer0_overflow_threshold;
35extern u_int	timer0_prescaler_count;
36#if defined(I586_CPU) || defined(I686_CPU)
37#ifndef SMP
38extern u_int	tsc_bias;
39extern u_int	tsc_comultiplier;
40#endif
41extern u_int	tsc_freq;
42#ifndef SMP
43extern u_int	tsc_multiplier;
44#endif
45#endif
46extern int	wall_cmos_clock;
47
48/*
49 * Driver to clock driver interface.
50 */
51struct clockframe;
52
53void	DELAY __P((int usec));
54int	acquire_timer0 __P((int rate,
55			    void (*function)(struct clockframe *frame)));
56int	acquire_timer2 __P((int mode));
57int	release_timer0 __P((void));
58int	release_timer2 __P((void));
59#ifndef PC98
60int	rtcin __P((int val));
61#else
62int	acquire_timer1 __P((int mode));
63int	release_timer1 __P((void));
64#endif
65int	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
76static __inline u_int
77clock_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 we also update `tsc_bias'
91 * atomically.  `tsc_bias' is the best available approximation to
92 * the value of the TSC (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 */
100static __inline void
101cpu_clockupdate(volatile struct timeval *otime, struct timeval *ntime)
102{
103	if (tsc_freq != 0) {
104		u_int tsc_count;	/* truncated */
105		u_int i8254_count;
106
107		disable_intr();
108		i8254_count = clock_latency();
109		tsc_count = rdtsc();
110		tsc_bias = tsc_count
111				- (u_int)
112				  (((unsigned long long)tsc_comultiplier
113				    * i8254_count)
114				   >> TSC_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