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