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