2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * @APPLE_FREE_COPYRIGHT@
36 * Purpose: Routines for handling the machine dependent
40 #include <mach/mach_types.h>
42 #include <kern/clock.h>
43 #include <kern/thread.h>
44 #include <kern/processor.h>
45 #include <kern/macro_help.h>
48 #include <machine/commpage.h>
49 #include <machine/machine_routines.h>
50 #include <ppc/exception.h>
51 #include <ppc/proc_reg.h>
53 #include <ppc/rtclock.h>
55 #include <sys/kdebug.h>
57 int rtclock_config(void);
59 int rtclock_init(void);
61 #define NSEC_PER_HZ (NSEC_PER_SEC / 100)
63 static uint32_t rtclock_sec_divisor
;
65 static mach_timebase_info_data_t rtclock_timebase_const
;
67 static boolean_t rtclock_timebase_initialized
;
69 /* XXX this should really be in a header somewhere */
70 extern clock_timer_func_t rtclock_timer_expire
;
72 decl_simple_lock_data(static,rtclock_lock
)
75 * Macros to lock/unlock real-time clock device.
80 simple_lock(&rtclock_lock); \
83 #define UNLOCK_RTC(s) \
85 simple_unlock(&rtclock_lock); \
91 struct timebase_freq_t
*freq
)
93 uint32_t numer
, denom
;
97 if ( freq
->timebase_den
< 1 || freq
->timebase_den
> 4 ||
98 freq
->timebase_num
< freq
->timebase_den
)
99 panic("rtclock timebase_callback: invalid constant %d / %d",
100 freq
->timebase_num
, freq
->timebase_den
);
102 denom
= freq
->timebase_num
;
103 numer
= freq
->timebase_den
* NSEC_PER_SEC
;
106 if (!rtclock_timebase_initialized
) {
107 commpage_set_timestamp(0,0,0);
109 rtclock_timebase_const
.numer
= numer
;
110 rtclock_timebase_const
.denom
= denom
;
111 rtclock_sec_divisor
= freq
->timebase_num
/ freq
->timebase_den
;
113 nanoseconds_to_absolutetime(NSEC_PER_HZ
, &abstime
);
114 rtclock_tick_interval
= abstime
;
116 ml_init_lock_timeout();
120 printf("rtclock timebase_callback: late old %d / %d new %d / %d\n",
121 rtclock_timebase_const
.numer
, rtclock_timebase_const
.denom
,
127 clock_timebase_init();
131 * Configure the system clock device.
136 simple_lock_init(&rtclock_lock
, 0);
138 PE_register_timebase_callback(timebase_callback
);
144 * Initialize the system clock device.
150 struct per_proc_info
*pp
;
154 abstime
= mach_absolute_time();
155 pp
->rtclock_intr_deadline
= abstime
+ rtclock_tick_interval
; /* Get the time we need to pop */
157 etimer_resync_deadlines(); /* Start the timers going */
163 clock_get_system_microtime(
170 now
= mach_absolute_time();
172 *secs
= t64
= now
/ (divisor
= rtclock_sec_divisor
);
173 now
-= (t64
* divisor
);
174 *microsecs
= (now
* USEC_PER_SEC
) / divisor
;
178 clock_get_system_nanotime(
185 now
= mach_absolute_time();
187 *secs
= t64
= now
/ (divisor
= rtclock_sec_divisor
);
188 now
-= (t64
* divisor
);
189 *nanosecs
= (now
* NSEC_PER_SEC
) / divisor
;
193 clock_gettimeofday_set_commpage(
200 uint64_t t64
, now
= abstime
;
202 simple_lock(&rtclock_lock
);
206 *secs
= t64
= now
/ rtclock_sec_divisor
;
207 now
-= (t64
* rtclock_sec_divisor
);
208 *microsecs
= (now
* USEC_PER_SEC
) / rtclock_sec_divisor
;
212 commpage_set_timestamp(abstime
- now
, *secs
, rtclock_sec_divisor
);
214 simple_unlock(&rtclock_lock
);
219 mach_timebase_info_t info
)
224 *info
= rtclock_timebase_const
;
225 rtclock_timebase_initialized
= TRUE
;
230 clock_set_timer_func(
231 clock_timer_func_t func
)
236 if (rtclock_timer_expire
== NULL
)
237 rtclock_timer_expire
= func
;
242 clock_interval_to_absolutetime_interval(
244 uint32_t scale_factor
,
247 uint64_t nanosecs
= (uint64_t)interval
* scale_factor
;
251 *result
= (t64
= nanosecs
/ NSEC_PER_SEC
) *
252 (divisor
= rtclock_sec_divisor
);
253 nanosecs
-= (t64
* NSEC_PER_SEC
);
254 *result
+= (nanosecs
* divisor
) / NSEC_PER_SEC
;
258 absolutetime_to_microtime(
266 *secs
= t64
= abstime
/ (divisor
= rtclock_sec_divisor
);
267 abstime
-= (t64
* divisor
);
268 *microsecs
= (abstime
* USEC_PER_SEC
) / divisor
;
272 absolutetime_to_nanotime(
280 *secs
= t64
= abstime
/ (divisor
= rtclock_sec_divisor
);
281 abstime
-= (t64
* divisor
);
282 *nanosecs
= (abstime
* NSEC_PER_SEC
) / divisor
;
286 nanotime_to_absolutetime(
291 uint32_t divisor
= rtclock_sec_divisor
;
293 *result
= ((uint64_t)secs
* divisor
) +
294 ((uint64_t)nanosecs
* divisor
) / NSEC_PER_SEC
;
298 absolutetime_to_nanoseconds(
305 *result
= (t64
= abstime
/ (divisor
= rtclock_sec_divisor
)) * NSEC_PER_SEC
;
306 abstime
-= (t64
* divisor
);
307 *result
+= (abstime
* NSEC_PER_SEC
) / divisor
;
311 nanoseconds_to_absolutetime(
318 *result
= (t64
= nanosecs
/ NSEC_PER_SEC
) *
319 (divisor
= rtclock_sec_divisor
);
320 nanosecs
-= (t64
* NSEC_PER_SEC
);
321 *result
+= (nanosecs
* divisor
) / NSEC_PER_SEC
;
331 now
= mach_absolute_time();
332 } while (now
< deadline
);