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 * Lists of clock routines.
79 struct clock_ops sysclk_ops
= {
80 sysclk_config
, sysclk_init
,
82 sysclk_getattr
, sysclk_setattr
,
86 int calend_config(void);
88 int calend_init(void);
90 kern_return_t
calend_gettime(
91 mach_timespec_t
*cur_time
);
93 kern_return_t
calend_settime(
94 mach_timespec_t
*cur_time
);
96 kern_return_t
calend_getattr(
97 clock_flavor_t flavor
,
99 mach_msg_type_number_t
*count
);
101 struct clock_ops calend_ops
= {
102 calend_config
, calend_init
,
103 calend_gettime
, calend_settime
,
108 /* local data declarations */
109 mach_timespec_t
*RtcTime
= (mach_timespec_t
*)0;
110 mach_timespec_t
*RtcAlrm
;
113 /* global data declarations */
115 AbsoluteTime abstime
;
117 mach_timespec_t time
;
118 mach_timespec_t alarm_time
; /* time of next alarm */
120 mach_timespec_t calend_offset
;
121 boolean_t calend_is_set
;
123 AbsoluteTime timer_deadline
;
124 boolean_t timer_is_set
;
125 clock_timer_func_t timer_expire
;
127 clock_res_t new_ires
; /* pending new resolution (nano ) */
128 clock_res_t intr_nsec
; /* interrupt resolution (nano) */
130 decl_simple_lock_data(,lock
) /* real-time clock device lock */
133 unsigned int clknum
; /* clks per second */
134 unsigned int new_clknum
; /* pending clknum */
135 unsigned int time_per_clk
; /* time per clk in ZHZ */
136 unsigned int clks_per_int
; /* clks per interrupt */
137 unsigned int clks_per_int_99
;
138 int rtc_intr_count
; /* interrupt counter */
139 int rtc_intr_hertz
; /* interrupts per HZ */
140 int rtc_intr_freq
; /* interrupt frequency */
141 int rtc_print_lost_tick
; /* print lost tick */
144 * Macros to lock/unlock real-time clock device.
146 #define LOCK_RTC(s) \
149 simple_lock(&rtclock.lock); \
152 #define UNLOCK_RTC(s) \
154 simple_unlock(&rtclock.lock); \
159 * i8254 control. ** MONUMENT **
161 * The i8254 is a traditional PC device with some arbitrary characteristics.
162 * Basically, it is a register that counts at a fixed rate and can be
163 * programmed to generate an interrupt every N counts. The count rate is
164 * clknum counts per second (see pit.h), historically 1193167 we believe.
165 * Various constants are computed based on this value, and we calculate
166 * them at init time for execution efficiency. To obtain sufficient
167 * accuracy, some of the calculation are most easily done in floating
168 * point and then converted to int.
170 * We want an interrupt every 10 milliseconds, approximately. The count
171 * which will do that is clks_per_int. However, that many counts is not
172 * *exactly* 10 milliseconds; it is a bit more or less depending on
173 * roundoff. The actual time per tick is calculated and saved in
174 * rtclock.intr_nsec, and it is that value which is added to the time
175 * register on each tick.
177 * The i8254 counter can be read between interrupts in order to determine
178 * the time more accurately. The counter counts down from the preset value
179 * toward 0, and we have to handle the case where the counter has been
180 * reset just before being read and before the interrupt has been serviced.
181 * Given a count since the last interrupt, the time since then is given
182 * by (count * time_per_clk). In order to minimize integer truncation,
183 * we perform this calculation in an arbitrary unit of time which maintains
184 * the maximum precision, i.e. such that one tick is 1.0e9 of these units,
185 * or close to the precision of a 32-bit int. We then divide by this unit
186 * (which doesn't lose precision) to get nanoseconds. For notation
187 * purposes, this unit is defined as ZHZ = zanoseconds per nanosecond.
189 * This sequence to do all this is in sysclk_gettime. For efficiency, this
190 * sequence also needs the value that the counter will have if it has just
191 * overflowed, so we precompute that also. ALSO, certain platforms
192 * (specifically the DEC XL5100) have been observed to have problem
193 * with latching the counter, and they occasionally (say, one out of
194 * 100,000 times) return a bogus value. Hence, the present code reads
195 * the counter twice and checks for a consistent pair of values.
197 * Some attributes of the rt clock can be changed, including the
198 * interrupt resolution. We default to the minimum resolution (10 ms),
199 * but allow a finer resolution to be requested. The assumed frequency
200 * of the clock can also be set since it appears that the actual
201 * frequency of real-world hardware can vary from the nominal by
202 * 200 ppm or more. When the frequency is set, the values above are
203 * recomputed and we continue without resetting or changing anything else.
205 #define RTC_MINRES (NSEC_PER_SEC / HZ) /* nsec per tick */
206 #define RTC_MAXRES (RTC_MINRES / 20) /* nsec per tick */
207 #define ZANO (1000000000)
208 #define ZHZ (ZANO / (NSEC_PER_SEC / HZ))
209 #define READ_8254(val) { \
210 outb(PITCTL_PORT, PIT_C0); \
211 (val) = inb(PITCTR0_PORT); \
212 (val) |= inb(PITCTR0_PORT) << 8 ; }
215 * Calibration delay counts.
217 unsigned int delaycount
= 10;
218 unsigned int microdata
= 50;
224 extern int measure_delay(int us
);
225 void rtc_setvals( unsigned int, clock_res_t
);
228 * Initialize non-zero clock structure values.
232 unsigned int new_clknum
,
236 unsigned int timeperclk
;
242 rtc_intr_freq
= (NSEC_PER_SEC
/ new_ires
);
243 rtc_intr_hertz
= rtc_intr_freq
/ HZ
;
244 clks_per_int
= (clknum
+ (rtc_intr_freq
/ 2)) / rtc_intr_freq
;
245 clks_per_int_99
= clks_per_int
- clks_per_int
/100;
248 * The following calculations are done with scaling integer operations
249 * in order that the integer results are accurate to the lsb.
251 timeperclk
= div_scale(ZANO
, clknum
, &scale0
); /* 838.105647 nsec */
253 time_per_clk
= mul_scale(ZHZ
, timeperclk
, &scale1
); /* 83810 */
255 time_per_clk
>>= (scale0
- scale1
);
256 else if (scale0
< scale1
)
257 panic("rtc_clock: time_per_clk overflow\n");
260 * Notice that rtclock.intr_nsec is signed ==> use unsigned int res
262 res
= mul_scale(clks_per_int
, timeperclk
, &scale1
); /* 10000276 */
264 rtclock
.intr_nsec
= res
>> (scale0
- scale1
);
266 panic("rtc_clock: rtclock.intr_nsec overflow\n");
269 RtcDelt
= rtclock
.intr_nsec
/2;
273 * Configure the real-time clock device. Return success (1)
284 mp_disable_preemption();
285 if (cpu_number() != master_cpu
) {
286 mp_enable_preemption();
289 mp_enable_preemption();
296 extern boolean_t mp_v1_1_initialized
;
297 if (mp_v1_1_initialized
)
303 pic
= 0; /* FIXME .. interrupt registration moved to AppleIntelClock */
308 * We should attempt to test the real-time clock
309 * device here. If it were to fail, we should panic
312 RtcFlag
= /* test device */1;
313 printf("realtime clock configured\n");
315 simple_lock_init(&rtclock
.lock
, ETAP_NO_TRACE
);
320 * Initialize the real-time clock device. Return success (1)
321 * or failure (0). Since the real-time clock is required to
322 * provide canonical mapped time, we allocate a page to keep
323 * the clock time value. In addition, various variables used
324 * to support the clock are initialized. Note: the clock is
325 * not started until rtclock_reset is called.
332 mp_disable_preemption();
333 if (cpu_number() != master_cpu
) {
334 mp_enable_preemption();
337 mp_enable_preemption();
340 RtcTime
= &rtclock
.time
;
341 rtc_setvals( CLKNUM
, RTC_MINRES
); /* compute constants */
345 static volatile unsigned int last_ival
= 0;
348 * Get the clock device time. This routine is responsible
349 * for converting the device's machine dependent time value
350 * into a canonical mach_timespec_t value.
354 mach_timespec_t
*cur_time
) /* OUT */
356 mach_timespec_t itime
= {0, 0};
357 unsigned int val
, val2
;
362 cur_time
->tv_nsec
= 0;
363 cur_time
->tv_sec
= 0;
364 return (KERN_SUCCESS
);
368 * Inhibit interrupts. Determine the incremental
369 * time since the last interrupt. (This could be
370 * done in assembler for a bit more speed).
374 READ_8254(val
); /* read clock */
375 READ_8254(val2
); /* read clock */
376 } while ( val2
> val
|| val2
< val
- 10 );
377 if ( val
> clks_per_int_99
) {
378 outb( 0x0a, 0x20 ); /* see if interrupt pending */
379 if ( inb( 0x20 ) & 1 )
380 itime
.tv_nsec
= rtclock
.intr_nsec
; /* yes, add a tick */
382 itime
.tv_nsec
+= ((clks_per_int
- val
) * time_per_clk
) / ZHZ
;
383 if ( itime
.tv_nsec
< last_ival
) {
384 if (rtc_print_lost_tick
)
385 printf( "rtclock: missed clock interrupt.\n" );
387 last_ival
= itime
.tv_nsec
;
388 cur_time
->tv_sec
= rtclock
.time
.tv_sec
;
389 cur_time
->tv_nsec
= rtclock
.time
.tv_nsec
;
391 ADD_MACH_TIMESPEC(cur_time
, ((mach_timespec_t
*)&itime
));
392 return (KERN_SUCCESS
);
396 sysclk_gettime_internal(
397 mach_timespec_t
*cur_time
) /* OUT */
399 mach_timespec_t itime
= {0, 0};
400 unsigned int val
, val2
;
404 cur_time
->tv_nsec
= 0;
405 cur_time
->tv_sec
= 0;
406 return (KERN_SUCCESS
);
410 * Inhibit interrupts. Determine the incremental
411 * time since the last interrupt. (This could be
412 * done in assembler for a bit more speed).
415 READ_8254(val
); /* read clock */
416 READ_8254(val2
); /* read clock */
417 } while ( val2
> val
|| val2
< val
- 10 );
418 if ( val
> clks_per_int_99
) {
419 outb( 0x0a, 0x20 ); /* see if interrupt pending */
420 if ( inb( 0x20 ) & 1 )
421 itime
.tv_nsec
= rtclock
.intr_nsec
; /* yes, add a tick */
423 itime
.tv_nsec
+= ((clks_per_int
- val
) * time_per_clk
) / ZHZ
;
424 if ( itime
.tv_nsec
< last_ival
) {
425 if (rtc_print_lost_tick
)
426 printf( "rtclock: missed clock interrupt.\n" );
428 last_ival
= itime
.tv_nsec
;
429 cur_time
->tv_sec
= rtclock
.time
.tv_sec
;
430 cur_time
->tv_nsec
= rtclock
.time
.tv_nsec
;
431 ADD_MACH_TIMESPEC(cur_time
, ((mach_timespec_t
*)&itime
));
432 return (KERN_SUCCESS
);
436 * Get the clock device time when ALL interrupts are already disabled.
437 * Same as above except for turning interrupts off and on.
438 * This routine is responsible for converting the device's machine dependent
439 * time value into a canonical mach_timespec_t value.
442 sysclk_gettime_interrupts_disabled(
443 mach_timespec_t
*cur_time
) /* OUT */
445 mach_timespec_t itime
= {0, 0};
450 cur_time
->tv_nsec
= 0;
451 cur_time
->tv_sec
= 0;
455 simple_lock(&rtclock
.lock
);
458 * Copy the current time knowing that we cant be interrupted
459 * between the two longwords and so dont need to use MTS_TO_TS
461 READ_8254(val
); /* read clock */
462 if ( val
> clks_per_int_99
) {
463 outb( 0x0a, 0x20 ); /* see if interrupt pending */
464 if ( inb( 0x20 ) & 1 )
465 itime
.tv_nsec
= rtclock
.intr_nsec
; /* yes, add a tick */
467 itime
.tv_nsec
+= ((clks_per_int
- val
) * time_per_clk
) / ZHZ
;
468 if ( itime
.tv_nsec
< last_ival
) {
469 if (rtc_print_lost_tick
)
470 printf( "rtclock: missed clock interrupt.\n" );
472 last_ival
= itime
.tv_nsec
;
473 cur_time
->tv_sec
= rtclock
.time
.tv_sec
;
474 cur_time
->tv_nsec
= rtclock
.time
.tv_nsec
;
475 ADD_MACH_TIMESPEC(cur_time
, ((mach_timespec_t
*)&itime
));
477 simple_unlock(&rtclock
.lock
);
482 get_uptime_ticks(void)
484 natural_t result
= 0;
485 unsigned int val
, val2
;
491 * Inhibit interrupts. Determine the incremental
492 * time since the last interrupt. (This could be
493 * done in assembler for a bit more speed).
496 READ_8254(val
); /* read clock */
497 READ_8254(val2
); /* read clock */
498 } while (val2
> val
|| val2
< val
- 10);
499 if (val
> clks_per_int_99
) {
500 outb(0x0a, 0x20); /* see if interrupt pending */
502 result
= rtclock
.intr_nsec
; /* yes, add a tick */
504 result
+= ((clks_per_int
- val
) * time_per_clk
) / ZHZ
;
505 if (result
< last_ival
) {
506 if (rtc_print_lost_tick
)
507 printf( "rtclock: missed clock interrupt.\n" );
514 * Get clock device attributes.
518 clock_flavor_t flavor
,
519 clock_attr_t attr
, /* OUT */
520 mach_msg_type_number_t
*count
) /* IN/OUT */
525 return (KERN_FAILURE
);
528 case CLOCK_GET_TIME_RES
: /* >0 res */
529 #if (NCPUS == 1 || (MP_V1_1 && 0))
531 *(clock_res_t
*) attr
= 1000;
534 #endif /* (NCPUS == 1 || (MP_V1_1 && 0)) && AT386 */
535 case CLOCK_ALARM_CURRES
: /* =0 no alarm */
537 *(clock_res_t
*) attr
= rtclock
.intr_nsec
;
541 case CLOCK_ALARM_MAXRES
:
542 *(clock_res_t
*) attr
= RTC_MAXRES
;
545 case CLOCK_ALARM_MINRES
:
546 *(clock_res_t
*) attr
= RTC_MINRES
;
550 return (KERN_INVALID_VALUE
);
552 return (KERN_SUCCESS
);
556 * Set clock device attributes.
560 clock_flavor_t flavor
,
561 clock_attr_t attr
, /* IN */
562 mach_msg_type_number_t count
) /* IN */
567 clock_res_t new_ires
;
570 return (KERN_FAILURE
);
573 case CLOCK_GET_TIME_RES
:
574 case CLOCK_ALARM_MAXRES
:
575 case CLOCK_ALARM_MINRES
:
576 return (KERN_FAILURE
);
578 case CLOCK_ALARM_CURRES
:
579 new_ires
= *(clock_res_t
*) attr
;
582 * The new resolution must be within the predetermined
583 * range. If the desired resolution cannot be achieved
584 * to within 0.1%, an error is returned.
586 if (new_ires
< RTC_MAXRES
|| new_ires
> RTC_MINRES
)
587 return (KERN_INVALID_VALUE
);
588 freq
= (NSEC_PER_SEC
/ new_ires
);
589 adj
= (((clknum
% freq
) * new_ires
) / clknum
);
590 if (adj
> (new_ires
/ 1000))
591 return (KERN_INVALID_VALUE
);
593 * Record the new alarm resolution which will take effect
594 * on the next HZ aligned clock tick.
597 if ( freq
!= rtc_intr_freq
) {
598 rtclock
.new_ires
= new_ires
;
602 return (KERN_SUCCESS
);
605 return (KERN_INVALID_VALUE
);
610 * Set next alarm time for the clock device. This call
611 * always resets the time to deliver an alarm for the
616 mach_timespec_t
*alarm_time
)
621 rtclock
.alarm_time
= *alarm_time
;
622 RtcAlrm
= &rtclock
.alarm_time
;
627 * Configure the calendar clock.
636 * Initialize calendar clock.
645 * Get the current clock time.
649 mach_timespec_t
*cur_time
) /* OUT */
654 if (!rtclock
.calend_is_set
) {
656 return (KERN_FAILURE
);
659 (void) sysclk_gettime_internal(cur_time
);
660 ADD_MACH_TIMESPEC(cur_time
, &rtclock
.calend_offset
);
663 return (KERN_SUCCESS
);
667 * Set the current clock time.
671 mach_timespec_t
*new_time
)
673 mach_timespec_t curr_time
;
677 (void) sysclk_gettime_internal(&curr_time
);
678 rtclock
.calend_offset
= *new_time
;
679 SUB_MACH_TIMESPEC(&rtclock
.calend_offset
, &curr_time
);
680 rtclock
.calend_is_set
= TRUE
;
683 (void) bbc_settime(new_time
);
685 return (KERN_SUCCESS
);
689 * Get clock device attributes.
693 clock_flavor_t flavor
,
694 clock_attr_t attr
, /* OUT */
695 mach_msg_type_number_t
*count
) /* IN/OUT */
700 return (KERN_FAILURE
);
703 case CLOCK_GET_TIME_RES
: /* >0 res */
704 #if (NCPUS == 1 || (MP_V1_1 && 0))
706 *(clock_res_t
*) attr
= 1000;
709 #else /* (NCPUS == 1 || (MP_V1_1 && 0)) && AT386 */
711 *(clock_res_t
*) attr
= rtclock
.intr_nsec
;
714 #endif /* (NCPUS == 1 || (MP_V1_1 && 0)) && AT386 */
716 case CLOCK_ALARM_CURRES
: /* =0 no alarm */
717 case CLOCK_ALARM_MINRES
:
718 case CLOCK_ALARM_MAXRES
:
719 *(clock_res_t
*) attr
= 0;
723 return (KERN_INVALID_VALUE
);
725 return (KERN_SUCCESS
);
729 clock_adjust_calendar(
735 if (rtclock
.calend_is_set
)
736 ADD_MACH_TIMESPEC_NSEC(&rtclock
.calend_offset
, nsec
);
741 clock_initialize_calendar(void)
743 mach_timespec_t bbc_time
, curr_time
;
746 if (bbc_gettime(&bbc_time
) != KERN_SUCCESS
)
750 if (!rtclock
.calend_is_set
) {
751 (void) sysclk_gettime_internal(&curr_time
);
752 rtclock
.calend_offset
= bbc_time
;
753 SUB_MACH_TIMESPEC(&rtclock
.calend_offset
, &curr_time
);
754 rtclock
.calend_is_set
= TRUE
;
760 clock_get_calendar_offset(void)
762 mach_timespec_t result
= MACH_TIMESPEC_ZERO
;
766 if (rtclock
.calend_is_set
)
767 result
= rtclock
.calend_offset
;
775 mach_timebase_info_t info
)
780 info
->numer
= info
->denom
= 1;
785 clock_set_timer_deadline(
786 AbsoluteTime deadline
)
791 rtclock
.timer_deadline
= deadline
;
792 rtclock
.timer_is_set
= TRUE
;
797 clock_set_timer_func(
798 clock_timer_func_t func
)
803 if (rtclock
.timer_expire
== NULL
)
804 rtclock
.timer_expire
= func
;
811 * Load the count register and start the clock.
813 #define RTCLOCK_RESET() { \
814 outb(PITCTL_PORT, PIT_C0|PIT_NDIVMODE|PIT_READMODE); \
815 outb(PITCTR0_PORT, (clks_per_int & 0xff)); \
816 outb(PITCTR0_PORT, (clks_per_int >> 8)); \
820 * Reset the clock device. This causes the realtime clock
821 * device to reload its mode and count value (frequency).
822 * Note: the CPU should be calibrated
823 * before starting the clock for the first time.
831 #if NCPUS > 1 && !(MP_V1_1 && 0)
832 mp_disable_preemption();
833 if (cpu_number() != master_cpu
) {
834 mp_enable_preemption();
837 mp_enable_preemption();
838 #endif /* NCPUS > 1 && AT386 && !MP_V1_1 */
845 * Real-time clock device interrupt. Called only on the
846 * master processor. Updates the clock time and upcalls
847 * into the higher level clock code to deliver alarms.
852 AbsoluteTime abstime
;
853 mach_timespec_t clock_time
;
858 * Update clock time. Do the update so that the macro
859 * MTS_TO_TS() for reading the mapped time works (e.g.
860 * update in order: mtv_csec, mtv_time.tv_nsec, mtv_time.tv_sec).
863 i
= rtclock
.time
.tv_nsec
+ rtclock
.intr_nsec
;
864 if (i
< NSEC_PER_SEC
)
865 rtclock
.time
.tv_nsec
= i
;
867 rtclock
.time
.tv_nsec
= i
- NSEC_PER_SEC
;
868 rtclock
.time
.tv_sec
++;
870 /* note time now up to date */
873 ADD_ABSOLUTETIME_TICKS(&rtclock
.abstime
, NSEC_PER_SEC
/HZ
);
874 abstime
= rtclock
.abstime
;
875 if (rtclock
.timer_is_set
&&
876 CMP_ABSOLUTETIME(&rtclock
.timer_deadline
, &abstime
) <= 0) {
877 rtclock
.timer_is_set
= FALSE
;
880 (*rtclock
.timer_expire
)(abstime
);
886 * Perform alarm clock processing if needed. The time
887 * passed up is incremented by a half-interrupt tick
888 * to trigger alarms closest to their desired times.
889 * The clock_alarm_intr() routine calls sysclk_setalrm()
890 * before returning if later alarms are pending.
893 if (RtcAlrm
&& (RtcAlrm
->tv_sec
< RtcTime
->tv_sec
||
894 (RtcAlrm
->tv_sec
== RtcTime
->tv_sec
&&
895 RtcDelt
>= RtcAlrm
->tv_nsec
- RtcTime
->tv_nsec
))) {
896 clock_time
.tv_sec
= 0;
897 clock_time
.tv_nsec
= RtcDelt
;
898 ADD_MACH_TIMESPEC (&clock_time
, RtcTime
);
902 * Call clock_alarm_intr() without RTC-lock.
903 * The lock ordering is always CLOCK-lock
906 clock_alarm_intr(SYSTEM_CLOCK
, &clock_time
);
911 * On a HZ-tick boundary: return 0 and adjust the clock
912 * alarm resolution (if requested). Otherwise return a
915 if ((i
= --rtc_intr_count
) == 0) {
916 if (rtclock
.new_ires
) {
917 rtc_setvals(new_clknum
, rtclock
.new_ires
);
918 RTCLOCK_RESET(); /* lock clock register */
919 rtclock
.new_ires
= 0;
921 rtc_intr_count
= rtc_intr_hertz
;
929 AbsoluteTime
*result
)
935 ticks
= get_uptime_ticks();
936 *result
= rtclock
.abstime
;
939 ADD_ABSOLUTETIME_TICKS(result
, ticks
);
943 clock_interval_to_deadline(
945 natural_t scale_factor
,
946 AbsoluteTime
*result
)
948 AbsoluteTime abstime
;
950 clock_get_uptime(result
);
952 clock_interval_to_absolutetime_interval(interval
, scale_factor
, &abstime
);
954 ADD_ABSOLUTETIME(result
, &abstime
);
958 clock_interval_to_absolutetime_interval(
960 natural_t scale_factor
,
961 AbsoluteTime
*result
)
963 AbsoluteTime_to_scalar(result
) = (uint64_t)interval
* scale_factor
;
967 clock_absolutetime_interval_to_deadline(
968 AbsoluteTime abstime
,
969 AbsoluteTime
*result
)
971 clock_get_uptime(result
);
973 ADD_ABSOLUTETIME(result
, &abstime
);
977 absolutetime_to_nanoseconds(
978 AbsoluteTime abstime
,
981 *result
= AbsoluteTime_to_scalar(&abstime
);
985 nanoseconds_to_absolutetime(
987 AbsoluteTime
*result
)
989 AbsoluteTime_to_scalar(result
) = nanoseconds
;
993 * measure_delay(microseconds)
995 * Measure elapsed time for delay calls
996 * Returns microseconds.
998 * Microseconds must not be too large since the counter (short)
999 * will roll over. Max is about 13 ms. Values smaller than 1 ms are ok.
1000 * This uses the assumed frequency of the rt clock which is emperically
1001 * accurate to only about 200 ppm.
1008 unsigned int lsb
, val
;
1010 outb(PITCTL_PORT
, PIT_C0
|PIT_NDIVMODE
|PIT_READMODE
);
1011 outb(PITCTR0_PORT
, 0xff); /* set counter to max value */
1012 outb(PITCTR0_PORT
, 0xff);
1014 outb(PITCTL_PORT
, PIT_C0
);
1015 lsb
= inb(PITCTR0_PORT
);
1016 val
= (inb(PITCTR0_PORT
) << 8) | lsb
;
1024 * calibrate_delay(void)
1026 * Adjust delaycount. Called from startup before clock is started
1027 * for normal interrupt generation.
1031 calibrate_delay(void)
1037 printf("adjusting delay count: %d", delaycount
);
1038 for (i
=0; i
<10; i
++) {
1041 * microdata must not be to large since measure_timer
1042 * will not return accurate values if the counter (short)
1045 val
= measure_delay(microdata
);
1046 delaycount
*= microdata
;
1047 delaycount
+= val
-1; /* round up to upper us */
1049 if (delaycount
<= 0)
1051 if (delaycount
!= prev
)
1052 printf(" %d", delaycount
);
1066 for (i
= 0; i
< 10; i
++)
1067 printf("%d, %d\n", i
, measure_delay(i
));
1068 for (i
= 10; i
<= 100; i
+=10)
1069 printf("%d, %d\n", i
, measure_delay(i
));
1071 #endif /* MACH_KDB */