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