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