2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
27 * File: i386/rtclock.c
28 * Purpose: Routines for handling the machine dependent
29 * real-time clock. This clock is generated by
30 * the Intel 8254 Programmable Interval Timer.
34 #include <platforms.h>
37 #include <kern/cpu_number.h>
38 #include <kern/cpu_data.h>
39 #include <kern/clock.h>
40 #include <kern/macro_help.h>
41 #include <kern/misc_protos.h>
43 #include <machine/mach_param.h> /* HZ */
44 #include <mach/vm_prot.h>
46 #include <vm/vm_kern.h> /* for kernel_map */
50 #include <i386/misc_protos.h>
51 #include <i386/rtclock_entries.h>
52 #include <i386/hardclock_entries.h>
54 int sysclk_config(void);
56 int sysclk_init(void);
58 kern_return_t
sysclk_gettime(
59 mach_timespec_t
*cur_time
);
61 kern_return_t
sysclk_getattr(
62 clock_flavor_t flavor
,
64 mach_msg_type_number_t
*count
);
66 kern_return_t
sysclk_setattr(
67 clock_flavor_t flavor
,
69 mach_msg_type_number_t count
);
72 mach_timespec_t
*alarm_time
);
74 extern void (*IOKitRegisterInterruptHook
)(void *, int irq
, int isclock
);
77 * Inlines to get timestamp counter value.
80 static inline void rdtsc_hilo(uint32_t *hi
, uint32_t *lo
) {
81 asm volatile("rdtsc": "=a" (*lo
), "=d" (*hi
));
84 static inline uint64_t rdtsc_64(void) {
86 asm volatile("rdtsc": "=A" (result
));
91 * Lists of clock routines.
93 struct clock_ops sysclk_ops
= {
94 sysclk_config
, sysclk_init
,
96 sysclk_getattr
, sysclk_setattr
,
100 int calend_config(void);
102 int calend_init(void);
104 kern_return_t
calend_gettime(
105 mach_timespec_t
*cur_time
);
107 kern_return_t
calend_settime(
108 mach_timespec_t
*cur_time
);
110 kern_return_t
calend_getattr(
111 clock_flavor_t flavor
,
113 mach_msg_type_number_t
*count
);
115 struct clock_ops calend_ops
= {
116 calend_config
, calend_init
,
117 calend_gettime
, calend_settime
,
122 /* local data declarations */
123 mach_timespec_t
*RtcTime
= (mach_timespec_t
*)0;
124 mach_timespec_t
*RtcAlrm
;
127 /* global data declarations */
131 mach_timespec_t time
;
132 mach_timespec_t alarm_time
; /* time of next alarm */
134 mach_timespec_t calend_offset
;
135 boolean_t calend_is_set
;
137 uint64_t timer_deadline
;
138 boolean_t timer_is_set
;
139 clock_timer_func_t timer_expire
;
141 clock_res_t new_ires
; /* pending new resolution (nano ) */
142 clock_res_t intr_nsec
; /* interrupt resolution (nano) */
144 decl_simple_lock_data(,lock
) /* real-time clock device lock */
147 unsigned int clknum
; /* clks per second */
148 unsigned int new_clknum
; /* pending clknum */
149 unsigned int time_per_clk
; /* time per clk in ZHZ */
150 unsigned int clks_per_int
; /* clks per interrupt */
151 unsigned int clks_per_int_99
;
152 int rtc_intr_count
; /* interrupt counter */
153 int rtc_intr_hertz
; /* interrupts per HZ */
154 int rtc_intr_freq
; /* interrupt frequency */
155 int rtc_print_lost_tick
; /* print lost tick */
157 uint32_t rtc_cyc_per_sec
; /* processor cycles per seconds */
158 uint32_t rtc_last_int_tsc_lo
; /* tsc values saved per interupt */
159 uint32_t rtc_last_int_tsc_hi
;
162 * Macros to lock/unlock real-time clock device.
164 #define LOCK_RTC(s) \
167 simple_lock(&rtclock.lock); \
170 #define UNLOCK_RTC(s) \
172 simple_unlock(&rtclock.lock); \
177 * i8254 control. ** MONUMENT **
179 * The i8254 is a traditional PC device with some arbitrary characteristics.
180 * Basically, it is a register that counts at a fixed rate and can be
181 * programmed to generate an interrupt every N counts. The count rate is
182 * clknum counts per second (see pit.h), historically 1193167 we believe.
183 * Various constants are computed based on this value, and we calculate
184 * them at init time for execution efficiency. To obtain sufficient
185 * accuracy, some of the calculation are most easily done in floating
186 * point and then converted to int.
188 * We want an interrupt every 10 milliseconds, approximately. The count
189 * which will do that is clks_per_int. However, that many counts is not
190 * *exactly* 10 milliseconds; it is a bit more or less depending on
191 * roundoff. The actual time per tick is calculated and saved in
192 * rtclock.intr_nsec, and it is that value which is added to the time
193 * register on each tick.
195 * The i8254 counter can be read between interrupts in order to determine
196 * the time more accurately. The counter counts down from the preset value
197 * toward 0, and we have to handle the case where the counter has been
198 * reset just before being read and before the interrupt has been serviced.
199 * Given a count since the last interrupt, the time since then is given
200 * by (count * time_per_clk). In order to minimize integer truncation,
201 * we perform this calculation in an arbitrary unit of time which maintains
202 * the maximum precision, i.e. such that one tick is 1.0e9 of these units,
203 * or close to the precision of a 32-bit int. We then divide by this unit
204 * (which doesn't lose precision) to get nanoseconds. For notation
205 * purposes, this unit is defined as ZHZ = zanoseconds per nanosecond.
207 * This sequence to do all this is in sysclk_gettime. For efficiency, this
208 * sequence also needs the value that the counter will have if it has just
209 * overflowed, so we precompute that also. ALSO, certain platforms
210 * (specifically the DEC XL5100) have been observed to have problem
211 * with latching the counter, and they occasionally (say, one out of
212 * 100,000 times) return a bogus value. Hence, the present code reads
213 * the counter twice and checks for a consistent pair of values.
215 * Some attributes of the rt clock can be changed, including the
216 * interrupt resolution. We default to the minimum resolution (10 ms),
217 * but allow a finer resolution to be requested. The assumed frequency
218 * of the clock can also be set since it appears that the actual
219 * frequency of real-world hardware can vary from the nominal by
220 * 200 ppm or more. When the frequency is set, the values above are
221 * recomputed and we continue without resetting or changing anything else.
223 #define RTC_MINRES (NSEC_PER_SEC / HZ) /* nsec per tick */
224 #define RTC_MAXRES (RTC_MINRES / 20) /* nsec per tick */
225 #define ZANO (1000000000)
226 #define ZHZ (ZANO / (NSEC_PER_SEC / HZ))
227 #define READ_8254(val) { \
228 outb(PITCTL_PORT, PIT_C0); \
229 (val) = inb(PITCTR0_PORT); \
230 (val) |= inb(PITCTR0_PORT) << 8 ; }
233 * Calibration delay counts.
235 unsigned int delaycount
= 100;
236 unsigned int microdata
= 50;
242 extern int measure_delay(int us
);
243 void rtc_setvals( unsigned int, clock_res_t
);
245 static void rtc_set_cyc_per_sec();
248 * Initialize non-zero clock structure values.
252 unsigned int new_clknum
,
256 unsigned int timeperclk
;
262 rtc_intr_freq
= (NSEC_PER_SEC
/ new_ires
);
263 rtc_intr_hertz
= rtc_intr_freq
/ HZ
;
264 clks_per_int
= (clknum
+ (rtc_intr_freq
/ 2)) / rtc_intr_freq
;
265 clks_per_int_99
= clks_per_int
- clks_per_int
/100;
268 * The following calculations are done with scaling integer operations
269 * in order that the integer results are accurate to the lsb.
271 timeperclk
= div_scale(ZANO
, clknum
, &scale0
); /* 838.105647 nsec */
273 time_per_clk
= mul_scale(ZHZ
, timeperclk
, &scale1
); /* 83810 */
275 time_per_clk
>>= (scale0
- scale1
);
276 else if (scale0
< scale1
)
277 panic("rtc_clock: time_per_clk overflow\n");
280 * Notice that rtclock.intr_nsec is signed ==> use unsigned int res
282 res
= mul_scale(clks_per_int
, timeperclk
, &scale1
); /* 10000276 */
284 rtclock
.intr_nsec
= res
>> (scale0
- scale1
);
286 panic("rtc_clock: rtclock.intr_nsec overflow\n");
289 RtcDelt
= rtclock
.intr_nsec
/2;
293 * Configure the real-time clock device. Return success (1)
304 mp_disable_preemption();
305 if (cpu_number() != master_cpu
) {
306 mp_enable_preemption();
309 mp_enable_preemption();
316 extern boolean_t mp_v1_1_initialized
;
317 if (mp_v1_1_initialized
)
323 pic
= 0; /* FIXME .. interrupt registration moved to AppleIntelClock */
328 * We should attempt to test the real-time clock
329 * device here. If it were to fail, we should panic
332 RtcFlag
= /* test device */1;
333 printf("realtime clock configured\n");
335 simple_lock_init(&rtclock
.lock
, ETAP_NO_TRACE
);
340 * Initialize the real-time clock device. Return success (1)
341 * or failure (0). Since the real-time clock is required to
342 * provide canonical mapped time, we allocate a page to keep
343 * the clock time value. In addition, various variables used
344 * to support the clock are initialized. Note: the clock is
345 * not started until rtclock_reset is called.
352 mp_disable_preemption();
353 if (cpu_number() != master_cpu
) {
354 mp_enable_preemption();
357 mp_enable_preemption();
360 RtcTime
= &rtclock
.time
;
361 rtc_setvals( CLKNUM
, RTC_MINRES
); /* compute constants */
362 rtc_set_cyc_per_sec(); /* compute number of tsc beats per second */
366 static volatile unsigned int last_ival
= 0;
369 * Get the clock device time. This routine is responsible
370 * for converting the device's machine dependent time value
371 * into a canonical mach_timespec_t value.
375 mach_timespec_t
*cur_time
) /* OUT */
377 mach_timespec_t itime
= {0, 0};
378 unsigned int val
, val2
;
383 cur_time
->tv_nsec
= 0;
384 cur_time
->tv_sec
= 0;
385 return (KERN_SUCCESS
);
389 * Inhibit interrupts. Determine the incremental
390 * time since the last interrupt. (This could be
391 * done in assembler for a bit more speed).
395 READ_8254(val
); /* read clock */
396 READ_8254(val2
); /* read clock */
397 } while ( val2
> val
|| val2
< val
- 10 );
398 if ( val
> clks_per_int_99
) {
399 outb( 0x0a, 0x20 ); /* see if interrupt pending */
400 if ( inb( 0x20 ) & 1 )
401 itime
.tv_nsec
= rtclock
.intr_nsec
; /* yes, add a tick */
403 itime
.tv_nsec
+= ((clks_per_int
- val
) * time_per_clk
) / ZHZ
;
404 if ( itime
.tv_nsec
< last_ival
) {
405 if (rtc_print_lost_tick
)
406 printf( "rtclock: missed clock interrupt.\n" );
408 last_ival
= itime
.tv_nsec
;
409 cur_time
->tv_sec
= rtclock
.time
.tv_sec
;
410 cur_time
->tv_nsec
= rtclock
.time
.tv_nsec
;
412 ADD_MACH_TIMESPEC(cur_time
, ((mach_timespec_t
*)&itime
));
413 return (KERN_SUCCESS
);
417 sysclk_gettime_internal(
418 mach_timespec_t
*cur_time
) /* OUT */
420 mach_timespec_t itime
= {0, 0};
421 unsigned int val
, val2
;
425 cur_time
->tv_nsec
= 0;
426 cur_time
->tv_sec
= 0;
427 return (KERN_SUCCESS
);
431 * Inhibit interrupts. Determine the incremental
432 * time since the last interrupt. (This could be
433 * done in assembler for a bit more speed).
436 READ_8254(val
); /* read clock */
437 READ_8254(val2
); /* read clock */
438 } while ( val2
> val
|| val2
< val
- 10 );
439 if ( val
> clks_per_int_99
) {
440 outb( 0x0a, 0x20 ); /* see if interrupt pending */
441 if ( inb( 0x20 ) & 1 )
442 itime
.tv_nsec
= rtclock
.intr_nsec
; /* yes, add a tick */
444 itime
.tv_nsec
+= ((clks_per_int
- val
) * time_per_clk
) / ZHZ
;
445 if ( itime
.tv_nsec
< last_ival
) {
446 if (rtc_print_lost_tick
)
447 printf( "rtclock: missed clock interrupt.\n" );
449 last_ival
= itime
.tv_nsec
;
450 cur_time
->tv_sec
= rtclock
.time
.tv_sec
;
451 cur_time
->tv_nsec
= rtclock
.time
.tv_nsec
;
452 ADD_MACH_TIMESPEC(cur_time
, ((mach_timespec_t
*)&itime
));
453 return (KERN_SUCCESS
);
457 * Get the clock device time when ALL interrupts are already disabled.
458 * Same as above except for turning interrupts off and on.
459 * This routine is responsible for converting the device's machine dependent
460 * time value into a canonical mach_timespec_t value.
463 sysclk_gettime_interrupts_disabled(
464 mach_timespec_t
*cur_time
) /* OUT */
466 mach_timespec_t itime
= {0, 0};
471 cur_time
->tv_nsec
= 0;
472 cur_time
->tv_sec
= 0;
476 simple_lock(&rtclock
.lock
);
479 * Copy the current time knowing that we cant be interrupted
480 * between the two longwords and so dont need to use MTS_TO_TS
482 READ_8254(val
); /* read clock */
483 if ( val
> clks_per_int_99
) {
484 outb( 0x0a, 0x20 ); /* see if interrupt pending */
485 if ( inb( 0x20 ) & 1 )
486 itime
.tv_nsec
= rtclock
.intr_nsec
; /* yes, add a tick */
488 itime
.tv_nsec
+= ((clks_per_int
- val
) * time_per_clk
) / ZHZ
;
489 if ( itime
.tv_nsec
< last_ival
) {
490 if (rtc_print_lost_tick
)
491 printf( "rtclock: missed clock interrupt.\n" );
493 last_ival
= itime
.tv_nsec
;
494 cur_time
->tv_sec
= rtclock
.time
.tv_sec
;
495 cur_time
->tv_nsec
= rtclock
.time
.tv_nsec
;
496 ADD_MACH_TIMESPEC(cur_time
, ((mach_timespec_t
*)&itime
));
498 simple_unlock(&rtclock
.lock
);
502 // Code to calculate how many processor cycles are in a second...
505 rtc_set_cyc_per_sec()
510 uint32_t c
[15]; // array for holding sampled cycle counts
511 mach_timespec_t tst
[15]; // array for holding time values. NOTE for some reason tv_sec not work
513 for (x
=0; x
<15; x
++) { // quick sample 15 times
516 sysclk_gettime_internal(&tst
[x
]);
517 rdtsc_hilo(&y
, &c
[x
]);
521 for (x
=0; x
<14; x
++) {
522 // simple formula really. calculate the numerator as the number of elapsed processor
523 // cycles * 1000 to adjust for the resolution we want. The denominator is the
524 // elapsed "real" time in nano-seconds. The result will be the processor speed in
525 // Mhz. any overflows will be discarded before they are added
526 if ((c
[x
+1] > c
[x
]) && (tst
[x
+1].tv_nsec
> tst
[x
].tv_nsec
)) {
527 cycles
+= ((uint64_t)(c
[x
+1]-c
[x
]) * NSEC_PER_SEC
) / (uint64_t)(tst
[x
+1].tv_nsec
- tst
[x
].tv_nsec
); // elapsed nsecs
531 if (y
>0) { // we got more than 1 valid sample. This also takes care of the case of if the clock isn't running
532 cycles
= cycles
/ y
; // calc our average
534 rtc_cyc_per_sec
= cycles
;
535 rdtsc_hilo(&rtc_last_int_tsc_hi
, &rtc_last_int_tsc_lo
);
540 get_uptime_cycles(void)
542 // get the time since the last interupt based on the processors TSC ignoring the
545 uint32_t a
,d
,intermediate_lo
,intermediate_hi
,result
;
549 if (d
!= rtc_last_int_tsc_hi
) {
550 newTime
= d
-rtc_last_int_tsc_hi
;
551 newTime
= (newTime
<<32) + (a
-rtc_last_int_tsc_lo
);
554 result
= a
-rtc_last_int_tsc_lo
;
556 __asm__
volatile ( " mul %3 ": "=eax" (intermediate_lo
), "=edx" (intermediate_hi
): "a"(result
), "d"(NSEC_PER_SEC
) );
557 __asm__
volatile ( " div %3": "=eax" (result
): "eax"(intermediate_lo
), "edx" (intermediate_hi
), "ecx" (rtc_cyc_per_sec
) );
563 * Get clock device attributes.
567 clock_flavor_t flavor
,
568 clock_attr_t attr
, /* OUT */
569 mach_msg_type_number_t
*count
) /* IN/OUT */
574 return (KERN_FAILURE
);
577 case CLOCK_GET_TIME_RES
: /* >0 res */
578 #if (NCPUS == 1 || (MP_V1_1 && 0))
580 *(clock_res_t
*) attr
= 1000;
583 #endif /* (NCPUS == 1 || (MP_V1_1 && 0)) && AT386 */
584 case CLOCK_ALARM_CURRES
: /* =0 no alarm */
586 *(clock_res_t
*) attr
= rtclock
.intr_nsec
;
590 case CLOCK_ALARM_MAXRES
:
591 *(clock_res_t
*) attr
= RTC_MAXRES
;
594 case CLOCK_ALARM_MINRES
:
595 *(clock_res_t
*) attr
= RTC_MINRES
;
599 return (KERN_INVALID_VALUE
);
601 return (KERN_SUCCESS
);
605 * Set clock device attributes.
609 clock_flavor_t flavor
,
610 clock_attr_t attr
, /* IN */
611 mach_msg_type_number_t count
) /* IN */
616 clock_res_t new_ires
;
619 return (KERN_FAILURE
);
622 case CLOCK_GET_TIME_RES
:
623 case CLOCK_ALARM_MAXRES
:
624 case CLOCK_ALARM_MINRES
:
625 return (KERN_FAILURE
);
627 case CLOCK_ALARM_CURRES
:
628 new_ires
= *(clock_res_t
*) attr
;
631 * The new resolution must be within the predetermined
632 * range. If the desired resolution cannot be achieved
633 * to within 0.1%, an error is returned.
635 if (new_ires
< RTC_MAXRES
|| new_ires
> RTC_MINRES
)
636 return (KERN_INVALID_VALUE
);
637 freq
= (NSEC_PER_SEC
/ new_ires
);
638 adj
= (((clknum
% freq
) * new_ires
) / clknum
);
639 if (adj
> (new_ires
/ 1000))
640 return (KERN_INVALID_VALUE
);
642 * Record the new alarm resolution which will take effect
643 * on the next HZ aligned clock tick.
646 if ( freq
!= rtc_intr_freq
) {
647 rtclock
.new_ires
= new_ires
;
651 return (KERN_SUCCESS
);
654 return (KERN_INVALID_VALUE
);
659 * Set next alarm time for the clock device. This call
660 * always resets the time to deliver an alarm for the
665 mach_timespec_t
*alarm_time
)
670 rtclock
.alarm_time
= *alarm_time
;
671 RtcAlrm
= &rtclock
.alarm_time
;
676 * Configure the calendar clock.
685 * Initialize calendar clock.
694 * Get the current clock time.
698 mach_timespec_t
*cur_time
) /* OUT */
703 if (!rtclock
.calend_is_set
) {
705 return (KERN_FAILURE
);
708 (void) sysclk_gettime_internal(cur_time
);
709 ADD_MACH_TIMESPEC(cur_time
, &rtclock
.calend_offset
);
712 return (KERN_SUCCESS
);
716 * Set the current clock time.
720 mach_timespec_t
*new_time
)
722 mach_timespec_t curr_time
;
726 (void) sysclk_gettime_internal(&curr_time
);
727 rtclock
.calend_offset
= *new_time
;
728 SUB_MACH_TIMESPEC(&rtclock
.calend_offset
, &curr_time
);
729 rtclock
.calend_is_set
= TRUE
;
732 (void) bbc_settime(new_time
);
734 return (KERN_SUCCESS
);
738 * Get clock device attributes.
742 clock_flavor_t flavor
,
743 clock_attr_t attr
, /* OUT */
744 mach_msg_type_number_t
*count
) /* IN/OUT */
749 return (KERN_FAILURE
);
752 case CLOCK_GET_TIME_RES
: /* >0 res */
753 #if (NCPUS == 1 || (MP_V1_1 && 0))
755 *(clock_res_t
*) attr
= 1000;
758 #else /* (NCPUS == 1 || (MP_V1_1 && 0)) && AT386 */
760 *(clock_res_t
*) attr
= rtclock
.intr_nsec
;
763 #endif /* (NCPUS == 1 || (MP_V1_1 && 0)) && AT386 */
765 case CLOCK_ALARM_CURRES
: /* =0 no alarm */
766 case CLOCK_ALARM_MINRES
:
767 case CLOCK_ALARM_MAXRES
:
768 *(clock_res_t
*) attr
= 0;
772 return (KERN_INVALID_VALUE
);
774 return (KERN_SUCCESS
);
778 clock_adjust_calendar(
784 if (rtclock
.calend_is_set
)
785 ADD_MACH_TIMESPEC_NSEC(&rtclock
.calend_offset
, nsec
);
790 clock_initialize_calendar(void)
792 mach_timespec_t bbc_time
, curr_time
;
795 if (bbc_gettime(&bbc_time
) != KERN_SUCCESS
)
799 if (!rtclock
.calend_is_set
) {
800 (void) sysclk_gettime_internal(&curr_time
);
801 rtclock
.calend_offset
= bbc_time
;
802 SUB_MACH_TIMESPEC(&rtclock
.calend_offset
, &curr_time
);
803 rtclock
.calend_is_set
= TRUE
;
809 clock_get_calendar_offset(void)
811 mach_timespec_t result
= MACH_TIMESPEC_ZERO
;
815 if (rtclock
.calend_is_set
)
816 result
= rtclock
.calend_offset
;
824 mach_timebase_info_t info
)
829 info
->numer
= info
->denom
= 1;
834 clock_set_timer_deadline(
840 rtclock
.timer_deadline
= deadline
;
841 rtclock
.timer_is_set
= TRUE
;
846 clock_set_timer_func(
847 clock_timer_func_t func
)
852 if (rtclock
.timer_expire
== NULL
)
853 rtclock
.timer_expire
= func
;
860 * Load the count register and start the clock.
862 #define RTCLOCK_RESET() { \
863 outb(PITCTL_PORT, PIT_C0|PIT_NDIVMODE|PIT_READMODE); \
864 outb(PITCTR0_PORT, (clks_per_int & 0xff)); \
865 outb(PITCTR0_PORT, (clks_per_int >> 8)); \
869 * Reset the clock device. This causes the realtime clock
870 * device to reload its mode and count value (frequency).
871 * Note: the CPU should be calibrated
872 * before starting the clock for the first time.
880 #if NCPUS > 1 && !(MP_V1_1 && 0)
881 mp_disable_preemption();
882 if (cpu_number() != master_cpu
) {
883 mp_enable_preemption();
886 mp_enable_preemption();
887 #endif /* NCPUS > 1 && AT386 && !MP_V1_1 */
894 * Real-time clock device interrupt. Called only on the
895 * master processor. Updates the clock time and upcalls
896 * into the higher level clock code to deliver alarms.
902 mach_timespec_t clock_time
;
907 * Update clock time. Do the update so that the macro
908 * MTS_TO_TS() for reading the mapped time works (e.g.
909 * update in order: mtv_csec, mtv_time.tv_nsec, mtv_time.tv_sec).
912 rdtsc_hilo(&rtc_last_int_tsc_hi
, &rtc_last_int_tsc_lo
);
913 i
= rtclock
.time
.tv_nsec
+ rtclock
.intr_nsec
;
914 if (i
< NSEC_PER_SEC
)
915 rtclock
.time
.tv_nsec
= i
;
917 rtclock
.time
.tv_nsec
= i
- NSEC_PER_SEC
;
918 rtclock
.time
.tv_sec
++;
920 /* note time now up to date */
923 rtclock
.abstime
+= rtclock
.intr_nsec
;
924 abstime
= rtclock
.abstime
;
925 if ( rtclock
.timer_is_set
&&
926 rtclock
.timer_deadline
<= abstime
) {
927 rtclock
.timer_is_set
= FALSE
;
930 (*rtclock
.timer_expire
)(abstime
);
936 * Perform alarm clock processing if needed. The time
937 * passed up is incremented by a half-interrupt tick
938 * to trigger alarms closest to their desired times.
939 * The clock_alarm_intr() routine calls sysclk_setalrm()
940 * before returning if later alarms are pending.
943 if (RtcAlrm
&& (RtcAlrm
->tv_sec
< RtcTime
->tv_sec
||
944 (RtcAlrm
->tv_sec
== RtcTime
->tv_sec
&&
945 RtcDelt
>= RtcAlrm
->tv_nsec
- RtcTime
->tv_nsec
))) {
946 clock_time
.tv_sec
= 0;
947 clock_time
.tv_nsec
= RtcDelt
;
948 ADD_MACH_TIMESPEC (&clock_time
, RtcTime
);
952 * Call clock_alarm_intr() without RTC-lock.
953 * The lock ordering is always CLOCK-lock
956 clock_alarm_intr(SYSTEM_CLOCK
, &clock_time
);
961 * On a HZ-tick boundary: return 0 and adjust the clock
962 * alarm resolution (if requested). Otherwise return a
965 if ((i
= --rtc_intr_count
) == 0) {
966 if (rtclock
.new_ires
) {
967 rtc_setvals(new_clknum
, rtclock
.new_ires
);
968 RTCLOCK_RESET(); /* lock clock register */
969 rtclock
.new_ires
= 0;
971 rtc_intr_count
= rtc_intr_hertz
;
985 ticks
= get_uptime_cycles();
986 *result
= rtclock
.abstime
;
993 clock_interval_to_deadline(
995 uint32_t scale_factor
,
1000 clock_get_uptime(result
);
1002 clock_interval_to_absolutetime_interval(interval
, scale_factor
, &abstime
);
1008 clock_interval_to_absolutetime_interval(
1010 uint32_t scale_factor
,
1013 *result
= (uint64_t)interval
* scale_factor
;
1017 clock_absolutetime_interval_to_deadline(
1021 clock_get_uptime(result
);
1027 absolutetime_to_nanoseconds(
1035 nanoseconds_to_absolutetime(
1036 uint64_t nanoseconds
,
1039 *result
= nanoseconds
;
1043 * measure_delay(microseconds)
1045 * Measure elapsed time for delay calls
1046 * Returns microseconds.
1048 * Microseconds must not be too large since the counter (short)
1049 * will roll over. Max is about 13 ms. Values smaller than 1 ms are ok.
1050 * This uses the assumed frequency of the rt clock which is emperically
1051 * accurate to only about 200 ppm.
1058 unsigned int lsb
, val
;
1060 outb(PITCTL_PORT
, PIT_C0
|PIT_NDIVMODE
|PIT_READMODE
);
1061 outb(PITCTR0_PORT
, 0xff); /* set counter to max value */
1062 outb(PITCTR0_PORT
, 0xff);
1064 outb(PITCTL_PORT
, PIT_C0
);
1065 lsb
= inb(PITCTR0_PORT
);
1066 val
= (inb(PITCTR0_PORT
) << 8) | lsb
;
1074 * calibrate_delay(void)
1076 * Adjust delaycount. Called from startup before clock is started
1077 * for normal interrupt generation.
1081 calibrate_delay(void)
1087 printf("adjusting delay count: %d", delaycount
);
1088 for (i
=0; i
<10; i
++) {
1091 * microdata must not be too large since measure_timer
1092 * will not return accurate values if the counter (short)
1095 val
= measure_delay(microdata
);
1099 delaycount
*= microdata
;
1100 delaycount
+= val
-1; /* round up to upper us */
1103 if (delaycount
<= 0)
1105 if (delaycount
!= prev
)
1106 printf(" %d", delaycount
);
1120 for (i
= 0; i
< 10; i
++)
1121 printf("%d, %d\n", i
, measure_delay(i
));
1122 for (i
= 10; i
<= 100; i
+=10)
1123 printf("%d, %d\n", i
, measure_delay(i
));
1125 #endif /* MACH_KDB */