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