clock.h revision 25164
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.24 1997/02/22 09:33:59 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)) && !defined(SMP)
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));
60#endif
61int	sysbeep __P((int pitch, int period));
62
63#ifdef CLOCK_HAIR
64
65#ifdef PC98
66#include <pc98/pc98/pc98.h>		/* XXX */
67#else
68#include <i386/isa/isa.h>		/* XXX */
69#endif
70#include <i386/isa/timerreg.h>		/* XXX */
71
72static __inline u_int
73clock_latency(void)
74{
75	u_char high, low;
76
77	outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
78	low = inb(TIMER_CNTR0);
79	high = inb(TIMER_CNTR0);
80	return (timer0_prescaler_count + timer0_max_count
81		- ((high << 8) | low));
82}
83
84#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP)
85/*
86 * When we update `time', on i586's we also update `i586_ctr_bias'
87 * atomically.  `i586_ctr_bias' is the best available approximation to
88 * the value of the i586 counter (mod 2^32) at the time of the i8254
89 * counter transition that caused the clock interrupt that caused the
90 * update.  clock_latency() gives the time between the transition and
91 * the update to within a few usec provided another such transition
92 * hasn't occurred.  We don't bother checking for counter overflow as
93 * in microtime(), since if it occurs then we're close to losing clock
94 * interrupts.
95 */
96static __inline void
97cpu_clockupdate(volatile struct timeval *otime, struct timeval *ntime)
98{
99	if (i586_ctr_freq != 0) {
100		u_int i586_count;	/* truncated */
101		u_int i8254_count;
102
103		disable_intr();
104		i8254_count = clock_latency();
105		i586_count = rdtsc();
106		i586_ctr_bias = i586_count
107				- (u_int)
108				  (((unsigned long long)i586_ctr_comultiplier
109				    * i8254_count)
110				   >> I586_CTR_COMULTIPLIER_SHIFT);
111		*otime = *ntime;
112		enable_intr();
113	} else
114		*otime = *ntime;
115}
116#endif /* I586_CPU || I686_CPU */
117
118#endif /* CLOCK_HAIR */
119
120#endif /* KERNEL */
121
122#endif /* !_MACHINE_CLOCK_H_ */
123