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