]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/rtclock.c
xnu-1228.5.18.tar.gz
[apple/xnu.git] / osfmk / ppc / rtclock.c
1 /*
2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31 /*
32 * @APPLE_FREE_COPYRIGHT@
33 */
34 /*
35 * File: rtclock.c
36 * Purpose: Routines for handling the machine dependent
37 * real-time clock.
38 */
39
40 #include <mach/mach_types.h>
41
42 #include <kern/clock.h>
43 #include <kern/thread.h>
44 #include <kern/processor.h>
45 #include <kern/macro_help.h>
46 #include <kern/spl.h>
47 #include <kern/pms.h>
48
49 #include <machine/commpage.h>
50 #include <machine/machine_routines.h>
51 #include <ppc/exception.h>
52 #include <ppc/proc_reg.h>
53 #include <ppc/rtclock.h>
54
55 #include <sys/kdebug.h>
56
57 int rtclock_config(void);
58
59 int rtclock_init(void);
60
61 #define NSEC_PER_HZ (NSEC_PER_SEC / 100)
62
63 static uint32_t rtclock_sec_divisor;
64
65 static mach_timebase_info_data_t rtclock_timebase_const;
66
67 static boolean_t rtclock_timebase_initialized;
68
69 /* XXX this should really be in a header somewhere */
70 extern clock_timer_func_t rtclock_timer_expire;
71
72 decl_simple_lock_data(static,rtclock_lock)
73
74 /*
75 * Macros to lock/unlock real-time clock device.
76 */
77 #define LOCK_RTC(s) \
78 MACRO_BEGIN \
79 (s) = splclock(); \
80 simple_lock(&rtclock_lock); \
81 MACRO_END
82
83 #define UNLOCK_RTC(s) \
84 MACRO_BEGIN \
85 simple_unlock(&rtclock_lock); \
86 splx(s); \
87 MACRO_END
88
89 static void
90 timebase_callback(
91 struct timebase_freq_t *freq)
92 {
93 uint32_t numer, denom;
94 spl_t s;
95
96 if ( freq->timebase_den < 1 || freq->timebase_den > 4 ||
97 freq->timebase_num < freq->timebase_den )
98 panic("rtclock timebase_callback: invalid constant %lu / %lu",
99 freq->timebase_num, freq->timebase_den);
100
101 denom = freq->timebase_num;
102 numer = freq->timebase_den * NSEC_PER_SEC;
103
104 LOCK_RTC(s);
105 if (!rtclock_timebase_initialized) {
106 commpage_set_timestamp(0,0,0);
107
108 rtclock_timebase_const.numer = numer;
109 rtclock_timebase_const.denom = denom;
110 rtclock_sec_divisor = freq->timebase_num / freq->timebase_den;
111
112 ml_init_lock_timeout();
113 }
114 else {
115 UNLOCK_RTC(s);
116 printf("rtclock timebase_callback: late old %d / %d new %d / %d\n",
117 rtclock_timebase_const.numer, rtclock_timebase_const.denom,
118 numer, denom);
119 return;
120 }
121 UNLOCK_RTC(s);
122
123 clock_timebase_init();
124 }
125
126 /*
127 * Configure the system clock device.
128 */
129 int
130 rtclock_config(void)
131 {
132 simple_lock_init(&rtclock_lock, 0);
133
134 PE_register_timebase_callback(timebase_callback);
135
136 return (1);
137 }
138
139 /*
140 * Initialize the system clock device.
141 */
142 int
143 rtclock_init(void)
144 {
145 etimer_resync_deadlines(); /* Start the timers going */
146
147 return (1);
148 }
149
150 void
151 clock_get_system_microtime(
152 uint32_t *secs,
153 uint32_t *microsecs)
154 {
155 uint64_t now, t64;
156 uint32_t divisor;
157
158 now = mach_absolute_time();
159
160 *secs = t64 = now / (divisor = rtclock_sec_divisor);
161 now -= (t64 * divisor);
162 *microsecs = (now * USEC_PER_SEC) / divisor;
163 }
164
165 void
166 clock_get_system_nanotime(
167 uint32_t *secs,
168 uint32_t *nanosecs)
169 {
170 uint64_t now, t64;
171 uint32_t divisor;
172
173 now = mach_absolute_time();
174
175 *secs = t64 = now / (divisor = rtclock_sec_divisor);
176 now -= (t64 * divisor);
177 *nanosecs = (now * NSEC_PER_SEC) / divisor;
178 }
179
180 void
181 clock_gettimeofday_set_commpage(
182 uint64_t abstime,
183 uint64_t epoch,
184 uint64_t offset,
185 uint32_t *secs,
186 uint32_t *microsecs)
187 {
188 uint64_t t64, now = abstime;
189
190 simple_lock(&rtclock_lock);
191
192 now += offset;
193
194 *secs = t64 = now / rtclock_sec_divisor;
195 now -= (t64 * rtclock_sec_divisor);
196 *microsecs = (now * USEC_PER_SEC) / rtclock_sec_divisor;
197
198 *secs += epoch;
199
200 commpage_set_timestamp(abstime - now, *secs, rtclock_sec_divisor);
201
202 simple_unlock(&rtclock_lock);
203 }
204
205 void
206 clock_timebase_info(
207 mach_timebase_info_t info)
208 {
209 spl_t s;
210
211 LOCK_RTC(s);
212 *info = rtclock_timebase_const;
213 rtclock_timebase_initialized = TRUE;
214 UNLOCK_RTC(s);
215 }
216
217 void
218 clock_set_timer_func(
219 clock_timer_func_t func)
220 {
221 spl_t s;
222
223 LOCK_RTC(s);
224 if (rtclock_timer_expire == NULL)
225 rtclock_timer_expire = func;
226 UNLOCK_RTC(s);
227 }
228
229 void
230 clock_interval_to_absolutetime_interval(
231 uint32_t interval,
232 uint32_t scale_factor,
233 uint64_t *result)
234 {
235 uint64_t nanosecs = (uint64_t)interval * scale_factor;
236 uint64_t t64;
237 uint32_t divisor;
238
239 *result = (t64 = nanosecs / NSEC_PER_SEC) *
240 (divisor = rtclock_sec_divisor);
241 nanosecs -= (t64 * NSEC_PER_SEC);
242 *result += (nanosecs * divisor) / NSEC_PER_SEC;
243 }
244
245 void
246 absolutetime_to_microtime(
247 uint64_t abstime,
248 uint32_t *secs,
249 uint32_t *microsecs)
250 {
251 uint64_t t64;
252 uint32_t divisor;
253
254 *secs = t64 = abstime / (divisor = rtclock_sec_divisor);
255 abstime -= (t64 * divisor);
256 *microsecs = (abstime * USEC_PER_SEC) / divisor;
257 }
258
259 void
260 absolutetime_to_nanotime(
261 uint64_t abstime,
262 uint32_t *secs,
263 uint32_t *nanosecs)
264 {
265 uint64_t t64;
266 uint32_t divisor;
267
268 *secs = t64 = abstime / (divisor = rtclock_sec_divisor);
269 abstime -= (t64 * divisor);
270 *nanosecs = (abstime * NSEC_PER_SEC) / divisor;
271 }
272
273 void
274 nanotime_to_absolutetime(
275 uint32_t secs,
276 uint32_t nanosecs,
277 uint64_t *result)
278 {
279 uint32_t divisor = rtclock_sec_divisor;
280
281 *result = ((uint64_t)secs * divisor) +
282 ((uint64_t)nanosecs * divisor) / NSEC_PER_SEC;
283 }
284
285 void
286 absolutetime_to_nanoseconds(
287 uint64_t abstime,
288 uint64_t *result)
289 {
290 uint64_t t64;
291 uint32_t divisor;
292
293 *result = (t64 = abstime / (divisor = rtclock_sec_divisor)) * NSEC_PER_SEC;
294 abstime -= (t64 * divisor);
295 *result += (abstime * NSEC_PER_SEC) / divisor;
296 }
297
298 void
299 nanoseconds_to_absolutetime(
300 uint64_t nanosecs,
301 uint64_t *result)
302 {
303 uint64_t t64;
304 uint32_t divisor;
305
306 *result = (t64 = nanosecs / NSEC_PER_SEC) *
307 (divisor = rtclock_sec_divisor);
308 nanosecs -= (t64 * NSEC_PER_SEC);
309 *result += (nanosecs * divisor) / NSEC_PER_SEC;
310 }
311
312 void
313 machine_delay_until(
314 uint64_t deadline)
315 {
316 uint64_t now;
317
318 do {
319 now = mach_absolute_time();
320 } while (now < deadline);
321 }