]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/rtclock.c
xnu-1228.12.14.tar.gz
[apple/xnu.git] / osfmk / ppc / rtclock.c
1 /*
2 * Copyright (c) 2000-2008 Apple 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 decl_simple_lock_data(static,rtclock_lock)
70
71 /*
72 * Macros to lock/unlock real-time clock device.
73 */
74 #define LOCK_RTC(s) \
75 MACRO_BEGIN \
76 (s) = splclock(); \
77 simple_lock(&rtclock_lock); \
78 MACRO_END
79
80 #define UNLOCK_RTC(s) \
81 MACRO_BEGIN \
82 simple_unlock(&rtclock_lock); \
83 splx(s); \
84 MACRO_END
85
86 static void
87 timebase_callback(
88 struct timebase_freq_t *freq)
89 {
90 uint32_t numer, denom;
91 spl_t s;
92
93 if ( freq->timebase_den < 1 || freq->timebase_den > 4 ||
94 freq->timebase_num < freq->timebase_den )
95 panic("rtclock timebase_callback: invalid constant %lu / %lu",
96 freq->timebase_num, freq->timebase_den);
97
98 denom = freq->timebase_num;
99 numer = freq->timebase_den * NSEC_PER_SEC;
100
101 LOCK_RTC(s);
102 if (!rtclock_timebase_initialized) {
103 commpage_set_timestamp(0,0,0);
104
105 rtclock_timebase_const.numer = numer;
106 rtclock_timebase_const.denom = denom;
107 rtclock_sec_divisor = freq->timebase_num / freq->timebase_den;
108
109 ml_init_lock_timeout();
110 }
111 else {
112 UNLOCK_RTC(s);
113 printf("rtclock timebase_callback: late old %d / %d new %d / %d\n",
114 rtclock_timebase_const.numer, rtclock_timebase_const.denom,
115 numer, denom);
116 return;
117 }
118 UNLOCK_RTC(s);
119
120 clock_timebase_init();
121 }
122
123 /*
124 * Configure the system clock device.
125 */
126 int
127 rtclock_config(void)
128 {
129 simple_lock_init(&rtclock_lock, 0);
130
131 PE_register_timebase_callback(timebase_callback);
132
133 return (1);
134 }
135
136 /*
137 * Initialize the system clock device.
138 */
139 int
140 rtclock_init(void)
141 {
142 etimer_resync_deadlines(); /* Start the timers going */
143
144 return (1);
145 }
146
147 void
148 clock_get_system_microtime(
149 uint32_t *secs,
150 uint32_t *microsecs)
151 {
152 uint64_t now, t64;
153 uint32_t divisor;
154
155 now = mach_absolute_time();
156
157 *secs = t64 = now / (divisor = rtclock_sec_divisor);
158 now -= (t64 * divisor);
159 *microsecs = (now * USEC_PER_SEC) / divisor;
160 }
161
162 void
163 clock_get_system_nanotime(
164 uint32_t *secs,
165 uint32_t *nanosecs)
166 {
167 uint64_t now, t64;
168 uint32_t divisor;
169
170 now = mach_absolute_time();
171
172 *secs = t64 = now / (divisor = rtclock_sec_divisor);
173 now -= (t64 * divisor);
174 *nanosecs = (now * NSEC_PER_SEC) / divisor;
175 }
176
177 void
178 clock_gettimeofday_set_commpage(
179 uint64_t abstime,
180 uint64_t epoch,
181 uint64_t offset,
182 uint32_t *secs,
183 uint32_t *microsecs)
184 {
185 uint64_t t64, now = abstime;
186
187 simple_lock(&rtclock_lock);
188
189 now += offset;
190
191 *secs = t64 = now / rtclock_sec_divisor;
192 now -= (t64 * rtclock_sec_divisor);
193 *microsecs = (now * USEC_PER_SEC) / rtclock_sec_divisor;
194
195 *secs += epoch;
196
197 commpage_set_timestamp(abstime - now, *secs, rtclock_sec_divisor);
198
199 simple_unlock(&rtclock_lock);
200 }
201
202 void
203 clock_timebase_info(
204 mach_timebase_info_t info)
205 {
206 spl_t s;
207
208 LOCK_RTC(s);
209 *info = rtclock_timebase_const;
210 rtclock_timebase_initialized = TRUE;
211 UNLOCK_RTC(s);
212 }
213
214 void
215 clock_interval_to_absolutetime_interval(
216 uint32_t interval,
217 uint32_t scale_factor,
218 uint64_t *result)
219 {
220 uint64_t nanosecs = (uint64_t)interval * scale_factor;
221 uint64_t t64;
222 uint32_t divisor;
223
224 *result = (t64 = nanosecs / NSEC_PER_SEC) *
225 (divisor = rtclock_sec_divisor);
226 nanosecs -= (t64 * NSEC_PER_SEC);
227 *result += (nanosecs * divisor) / NSEC_PER_SEC;
228 }
229
230 void
231 absolutetime_to_microtime(
232 uint64_t abstime,
233 uint32_t *secs,
234 uint32_t *microsecs)
235 {
236 uint64_t t64;
237 uint32_t divisor;
238
239 *secs = t64 = abstime / (divisor = rtclock_sec_divisor);
240 abstime -= (t64 * divisor);
241 *microsecs = (abstime * USEC_PER_SEC) / divisor;
242 }
243
244 void
245 absolutetime_to_nanotime(
246 uint64_t abstime,
247 uint32_t *secs,
248 uint32_t *nanosecs)
249 {
250 uint64_t t64;
251 uint32_t divisor;
252
253 *secs = t64 = abstime / (divisor = rtclock_sec_divisor);
254 abstime -= (t64 * divisor);
255 *nanosecs = (abstime * NSEC_PER_SEC) / divisor;
256 }
257
258 void
259 nanotime_to_absolutetime(
260 uint32_t secs,
261 uint32_t nanosecs,
262 uint64_t *result)
263 {
264 uint32_t divisor = rtclock_sec_divisor;
265
266 *result = ((uint64_t)secs * divisor) +
267 ((uint64_t)nanosecs * divisor) / NSEC_PER_SEC;
268 }
269
270 void
271 absolutetime_to_nanoseconds(
272 uint64_t abstime,
273 uint64_t *result)
274 {
275 uint64_t t64;
276 uint32_t divisor;
277
278 *result = (t64 = abstime / (divisor = rtclock_sec_divisor)) * NSEC_PER_SEC;
279 abstime -= (t64 * divisor);
280 *result += (abstime * NSEC_PER_SEC) / divisor;
281 }
282
283 void
284 nanoseconds_to_absolutetime(
285 uint64_t nanosecs,
286 uint64_t *result)
287 {
288 uint64_t t64;
289 uint32_t divisor;
290
291 *result = (t64 = nanosecs / NSEC_PER_SEC) *
292 (divisor = rtclock_sec_divisor);
293 nanosecs -= (t64 * NSEC_PER_SEC);
294 *result += (nanosecs * divisor) / NSEC_PER_SEC;
295 }
296
297 void
298 machine_delay_until(
299 uint64_t deadline)
300 {
301 uint64_t now;
302
303 do {
304 now = mach_absolute_time();
305 } while (now < deadline);
306 }