]>
Commit | Line | Data |
---|---|---|
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 | 59 | int rtclock_config(void); |
8ad349bb | 60 | |
5d5c5d0d | 61 | int rtclock_init(void); |
1c79356b | 62 | |
91447636 | 63 | #define NSEC_PER_HZ (NSEC_PER_SEC / 100) |
1c79356b | 64 | |
55e303ae | 65 | static uint32_t rtclock_sec_divisor; |
1c79356b | 66 | |
55e303ae | 67 | static mach_timebase_info_data_t rtclock_timebase_const; |
1c79356b | 68 | |
55e303ae A |
69 | static boolean_t rtclock_timebase_initialized; |
70 | ||
5d5c5d0d A |
71 | /* XXX this should really be in a header somewhere */ |
72 | extern clock_timer_func_t rtclock_timer_expire; | |
1c79356b | 73 | |
55e303ae A |
74 | decl_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) \ | |
80 | MACRO_BEGIN \ | |
81 | (s) = splclock(); \ | |
55e303ae | 82 | simple_lock(&rtclock_lock); \ |
1c79356b A |
83 | MACRO_END |
84 | ||
85 | #define UNLOCK_RTC(s) \ | |
86 | MACRO_BEGIN \ | |
55e303ae | 87 | simple_unlock(&rtclock_lock); \ |
1c79356b A |
88 | splx(s); \ |
89 | MACRO_END | |
90 | ||
91 | static void | |
92 | timebase_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 | */ |
135 | int | |
5d5c5d0d | 136 | rtclock_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 | */ | |
148 | int | |
5d5c5d0d | 149 | rtclock_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 |
164 | void |
165 | clock_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 |
179 | void |
180 | clock_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 | 194 | void |
5d5c5d0d A |
195 | clock_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 |
219 | void |
220 | clock_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 |
231 | void |
232 | clock_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 | 243 | void |
5d5c5d0d A |
244 | clock_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 | ||
259 | void | |
260 | absolutetime_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 | ||
273 | void | |
5d5c5d0d A |
274 | absolutetime_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 | ||
287 | void | |
5d5c5d0d A |
288 | nanotime_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 | ||
299 | void | |
300 | absolutetime_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 | ||
312 | void | |
313 | nanoseconds_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 | 326 | void |
91447636 | 327 | machine_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 | } |