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$ 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 */ 29 extern int adjkerntz; 30 extern int disable_rtc_set; 31 #if defined(I586_CPU) || defined(I686_CPU) 32 extern u_int i586_ctr_bias; 33 extern u_int i586_ctr_comultiplier; 34 extern u_int i586_ctr_freq; 35 extern u_int i586_ctr_multiplier; 36 #endif 37 extern int statclock_disable; 38 extern u_int timer_freq; 39 extern int timer0_max_count; 40 extern u_int timer0_overflow_threshold; 41 extern u_int timer0_prescaler_count; 42 extern int wall_cmos_clock; 43 44 /* 45 * Driver to clock driver interface. 46 */ 47 struct clockframe; 48 49 void DELAY __P((int usec)); 50 int acquire_timer0 __P((int rate, 51 void (*function)(struct clockframe *frame))); 52 int acquire_timer2 __P((int mode)); 53 int release_timer0 __P((void)); 54 int release_timer2 __P((void)); 55 #ifndef PC98 56 int rtcin __P((int val)); 57 #else 58 int acquire_timer1 __P((int mode)); 59 int release_timer1 __P((void)); 60 #endif 61 int 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 72 static __inline u_int 73 clock_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) 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 */ 96 static __inline void 97 cpu_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