]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
0b4c1975 | 2 | * Copyright (c) 2000-2010 Apple Inc. All rights reserved. |
1c79356b | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
1c79356b | 5 | * |
2d21ac55 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. | |
8f6c56a5 | 14 | * |
2d21ac55 A |
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 | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
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. | |
8f6c56a5 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b A |
27 | */ |
28 | /* | |
29 | * @OSF_COPYRIGHT@ | |
30 | */ | |
31 | ||
32 | /* | |
33 | * File: i386/rtclock.c | |
34 | * Purpose: Routines for handling the machine dependent | |
91447636 A |
35 | * real-time clock. Historically, this clock is |
36 | * generated by the Intel 8254 Programmable Interval | |
37 | * Timer, but local apic timers are now used for | |
38 | * this purpose with the master time reference being | |
39 | * the cpu clock counted by the timestamp MSR. | |
1c79356b A |
40 | */ |
41 | ||
1c79356b | 42 | #include <platforms.h> |
1c79356b | 43 | #include <mach_kdb.h> |
55e303ae A |
44 | |
45 | #include <mach/mach_types.h> | |
46 | ||
1c79356b | 47 | #include <kern/cpu_data.h> |
91447636 | 48 | #include <kern/cpu_number.h> |
1c79356b | 49 | #include <kern/clock.h> |
55e303ae | 50 | #include <kern/host_notify.h> |
1c79356b A |
51 | #include <kern/macro_help.h> |
52 | #include <kern/misc_protos.h> | |
53 | #include <kern/spl.h> | |
91447636 | 54 | #include <kern/assert.h> |
7e4a7d39 | 55 | #include <kern/etimer.h> |
1c79356b A |
56 | #include <mach/vm_prot.h> |
57 | #include <vm/pmap.h> | |
58 | #include <vm/vm_kern.h> /* for kernel_map */ | |
59 | #include <i386/ipl.h> | |
0c530ab8 | 60 | #include <architecture/i386/pio.h> |
55e303ae | 61 | #include <i386/machine_cpu.h> |
91447636 | 62 | #include <i386/cpuid.h> |
91447636 | 63 | #include <i386/cpu_threads.h> |
b0d623f7 | 64 | #include <i386/mp.h> |
91447636 | 65 | #include <i386/machine_routines.h> |
b0d623f7 A |
66 | #include <i386/proc_reg.h> |
67 | #include <i386/misc_protos.h> | |
68 | #include <i386/lapic.h> | |
55e303ae | 69 | #include <pexpert/pexpert.h> |
91447636 A |
70 | #include <machine/limits.h> |
71 | #include <machine/commpage.h> | |
72 | #include <sys/kdebug.h> | |
0c530ab8 | 73 | #include <i386/tsc.h> |
0c530ab8 | 74 | #include <i386/rtclock.h> |
91447636 | 75 | |
91447636 | 76 | #define UI_CPUFREQ_ROUNDING_FACTOR 10000000 |
1c79356b | 77 | |
0c530ab8 | 78 | int rtclock_config(void); |
6601e61a | 79 | |
0c530ab8 | 80 | int rtclock_init(void); |
6601e61a | 81 | |
b0d623f7 A |
82 | uint64_t tsc_rebase_abs_time = 0; |
83 | ||
060df5ea | 84 | void rtclock_intr(x86_saved_state_t *regs); |
6601e61a | 85 | |
0c530ab8 A |
86 | static void rtc_set_timescale(uint64_t cycles); |
87 | static uint64_t rtc_export_speed(uint64_t cycles); | |
8f6c56a5 | 88 | |
2d21ac55 | 89 | rtc_nanotime_t rtc_nanotime_info = {0,0,0,0,1,0}; |
6601e61a | 90 | |
060df5ea A |
91 | static uint64_t rtc_decrementer_min; |
92 | static uint64_t rtc_decrementer_max; | |
93 | ||
94 | static uint64_t | |
95 | deadline_to_decrementer( | |
96 | uint64_t deadline, | |
97 | uint64_t now) | |
98 | { | |
99 | uint64_t delta; | |
100 | ||
101 | if (deadline <= now) | |
102 | return rtc_decrementer_min; | |
103 | else { | |
104 | delta = deadline - now; | |
105 | return MIN(MAX(rtc_decrementer_min,delta),rtc_decrementer_max); | |
106 | } | |
107 | } | |
108 | ||
109 | static inline uint64_t | |
110 | _absolutetime_to_tsc(uint64_t ns) | |
111 | { | |
112 | uint32_t generation; | |
113 | uint64_t tsc; | |
114 | ||
115 | do { | |
116 | generation = rtc_nanotime_info.generation; | |
117 | tsc = tmrCvt(ns - rtc_nanotime_info.ns_base, tscFCvtn2t) | |
118 | + rtc_nanotime_info.tsc_base; | |
119 | } while (generation == 0 || | |
120 | generation != rtc_nanotime_info.generation); | |
121 | ||
122 | return tsc; | |
123 | } | |
124 | ||
125 | /* | |
126 | * Regular local APIC timer case: | |
127 | */ | |
128 | static void | |
129 | rtc_lapic_config_timer(void) | |
130 | { | |
131 | lapic_config_timer(TRUE, one_shot, divide_by_1); | |
132 | } | |
133 | static uint64_t | |
134 | rtc_lapic_set_timer(uint64_t deadline, uint64_t now) | |
135 | { | |
136 | uint64_t count; | |
137 | uint64_t set = 0; | |
138 | ||
139 | if (deadline > 0) { | |
140 | /* | |
141 | * Convert delta to bus ticks | |
142 | * - time now is not relevant | |
143 | */ | |
144 | count = deadline_to_decrementer(deadline, now); | |
145 | set = now + count; | |
146 | lapic_set_timer_fast((uint32_t) tmrCvt(count, busFCvtn2t)); | |
147 | } else { | |
148 | lapic_set_timer(FALSE, one_shot, divide_by_1, 0); | |
149 | } | |
150 | return set; | |
151 | } | |
152 | ||
153 | /* | |
154 | * TSC-deadline timer case: | |
155 | */ | |
156 | static void | |
157 | rtc_lapic_config_tsc_deadline_timer(void) | |
158 | { | |
159 | lapic_config_tsc_deadline_timer(); | |
160 | } | |
161 | static uint64_t | |
162 | rtc_lapic_set_tsc_deadline_timer(uint64_t deadline, uint64_t now) | |
163 | { | |
164 | uint64_t set = 0; | |
165 | ||
166 | if (deadline > 0) { | |
167 | /* | |
168 | * Convert to TSC | |
169 | */ | |
170 | set = now + deadline_to_decrementer(deadline, now); | |
171 | lapic_set_tsc_deadline_timer(_absolutetime_to_tsc(set)); | |
172 | } else { | |
173 | lapic_set_tsc_deadline_timer(0); | |
174 | } | |
175 | return set; | |
176 | } | |
177 | ||
178 | /* | |
179 | * Definitions for timer operations table | |
180 | */ | |
181 | typedef struct { | |
182 | void (*config)(void); | |
183 | uint64_t (*set) (uint64_t, uint64_t); | |
184 | } rtc_timer_t; | |
185 | ||
186 | rtc_timer_t rtc_timer_lapic = { | |
187 | rtc_lapic_config_timer, | |
188 | rtc_lapic_set_timer | |
189 | }; | |
190 | ||
191 | rtc_timer_t rtc_timer_tsc_deadline = { | |
192 | rtc_lapic_config_tsc_deadline_timer, | |
193 | rtc_lapic_set_tsc_deadline_timer | |
194 | }; | |
195 | ||
196 | rtc_timer_t *rtc_timer = &rtc_timer_lapic; /* defaults to LAPIC timer */ | |
197 | ||
198 | /* | |
199 | * rtc_timer_init() is called at startup on the boot processor only. | |
200 | */ | |
201 | static void | |
202 | rtc_timer_init(void) | |
203 | { | |
204 | int TSC_deadline_timer = 0; | |
205 | ||
206 | /* See whether we can use the local apic in TSC-deadline mode */ | |
207 | if ((cpuid_features() & CPUID_FEATURE_TSCTMR)) { | |
208 | TSC_deadline_timer = 1; | |
209 | PE_parse_boot_argn("TSC_deadline_timer", &TSC_deadline_timer, | |
210 | sizeof(TSC_deadline_timer)); | |
211 | printf("TSC Deadline Timer supported %s enabled\n", | |
212 | TSC_deadline_timer ? "and" : "but not"); | |
213 | } | |
214 | ||
215 | if (TSC_deadline_timer) { | |
216 | rtc_timer = &rtc_timer_tsc_deadline; | |
217 | rtc_decrementer_max = UINT64_MAX; /* effectively none */ | |
218 | /* | |
219 | * The min could be as low as 1nsec, | |
220 | * but we're being conservative for now and making it the same | |
221 | * as for the local apic timer. | |
222 | */ | |
223 | rtc_decrementer_min = 1*NSEC_PER_USEC; /* 1 usec */ | |
224 | } else { | |
225 | /* | |
226 | * Compute the longest interval using LAPIC timer. | |
227 | */ | |
228 | rtc_decrementer_max = tmrCvt(0x7fffffffULL, busFCvtt2n); | |
229 | kprintf("maxDec: %lld\n", rtc_decrementer_max); | |
230 | rtc_decrementer_min = 1*NSEC_PER_USEC; /* 1 usec */ | |
231 | } | |
232 | ||
233 | /* Point LAPIC interrupts to hardclock() */ | |
234 | lapic_set_timer_func((i386_intr_func_t) rtclock_intr); | |
235 | } | |
236 | ||
237 | static inline uint64_t | |
238 | rtc_timer_set(uint64_t deadline, uint64_t now) | |
239 | { | |
240 | return rtc_timer->set(deadline, now); | |
241 | } | |
242 | ||
243 | void | |
244 | rtc_timer_start(void) | |
245 | { | |
246 | /* | |
247 | * Force a complete re-evaluation of timer deadlines. | |
248 | */ | |
249 | etimer_resync_deadlines(); | |
250 | } | |
251 | ||
4a3eedf9 A |
252 | /* |
253 | * tsc_to_nanoseconds: | |
254 | * | |
255 | * Basic routine to convert a raw 64 bit TSC value to a | |
256 | * 64 bit nanosecond value. The conversion is implemented | |
257 | * based on the scale factor and an implicit 32 bit shift. | |
258 | */ | |
259 | static inline uint64_t | |
260 | _tsc_to_nanoseconds(uint64_t value) | |
261 | { | |
b0d623f7 | 262 | #if defined(__i386__) |
4a3eedf9 A |
263 | asm volatile("movl %%edx,%%esi ;" |
264 | "mull %%ecx ;" | |
265 | "movl %%edx,%%edi ;" | |
266 | "movl %%esi,%%eax ;" | |
267 | "mull %%ecx ;" | |
268 | "addl %%edi,%%eax ;" | |
269 | "adcl $0,%%edx " | |
593a1d5f | 270 | : "+A" (value) |
060df5ea | 271 | : "c" (rtc_nanotime_info.scale) |
593a1d5f | 272 | : "esi", "edi"); |
b0d623f7 A |
273 | #elif defined(__x86_64__) |
274 | asm volatile("mul %%rcx;" | |
275 | "shrq $32, %%rax;" | |
276 | "shlq $32, %%rdx;" | |
277 | "orq %%rdx, %%rax;" | |
278 | : "=a"(value) | |
279 | : "a"(value), "c"(rtc_nanotime_info.scale) | |
280 | : "rdx", "cc" ); | |
281 | #else | |
282 | #error Unsupported architecture | |
283 | #endif | |
4a3eedf9 A |
284 | |
285 | return (value); | |
286 | } | |
287 | ||
b0d623f7 A |
288 | static inline uint32_t |
289 | _absolutetime_to_microtime(uint64_t abstime, clock_sec_t *secs, clock_usec_t *microsecs) | |
290 | { | |
291 | uint32_t remain; | |
292 | #if defined(__i386__) | |
293 | asm volatile( | |
294 | "divl %3" | |
295 | : "=a" (*secs), "=d" (remain) | |
296 | : "A" (abstime), "r" (NSEC_PER_SEC)); | |
297 | asm volatile( | |
298 | "divl %3" | |
299 | : "=a" (*microsecs) | |
300 | : "0" (remain), "d" (0), "r" (NSEC_PER_USEC)); | |
301 | #elif defined(__x86_64__) | |
302 | *secs = abstime / (uint64_t)NSEC_PER_SEC; | |
303 | remain = (uint32_t)(abstime % (uint64_t)NSEC_PER_SEC); | |
304 | *microsecs = remain / NSEC_PER_USEC; | |
305 | #else | |
306 | #error Unsupported architecture | |
307 | #endif | |
308 | return remain; | |
309 | } | |
310 | ||
311 | static inline void | |
312 | _absolutetime_to_nanotime(uint64_t abstime, clock_sec_t *secs, clock_usec_t *nanosecs) | |
313 | { | |
314 | #if defined(__i386__) | |
315 | asm volatile( | |
316 | "divl %3" | |
317 | : "=a" (*secs), "=d" (*nanosecs) | |
318 | : "A" (abstime), "r" (NSEC_PER_SEC)); | |
319 | #elif defined(__x86_64__) | |
320 | *secs = abstime / (uint64_t)NSEC_PER_SEC; | |
321 | *nanosecs = (clock_usec_t)(abstime % (uint64_t)NSEC_PER_SEC); | |
322 | #else | |
323 | #error Unsupported architecture | |
324 | #endif | |
325 | } | |
326 | ||
1c79356b A |
327 | /* |
328 | * Configure the real-time clock device. Return success (1) | |
329 | * or failure (0). | |
330 | */ | |
331 | ||
332 | int | |
0c530ab8 | 333 | rtclock_config(void) |
1c79356b | 334 | { |
0c530ab8 | 335 | /* nothing to do */ |
91447636 A |
336 | return (1); |
337 | } | |
338 | ||
339 | ||
340 | /* | |
341 | * Nanotime/mach_absolutime_time | |
342 | * ----------------------------- | |
0c530ab8 A |
343 | * The timestamp counter (TSC) - which counts cpu clock cycles and can be read |
344 | * efficiently by the kernel and in userspace - is the reference for all timing. | |
345 | * The cpu clock rate is platform-dependent and may stop or be reset when the | |
346 | * processor is napped/slept. As a result, nanotime is the software abstraction | |
347 | * used to maintain a monotonic clock, adjusted from an outside reference as needed. | |
91447636 A |
348 | * |
349 | * The kernel maintains nanotime information recording: | |
0c530ab8 | 350 | * - the ratio of tsc to nanoseconds |
91447636 A |
351 | * with this ratio expressed as a 32-bit scale and shift |
352 | * (power of 2 divider); | |
0c530ab8 | 353 | * - { tsc_base, ns_base } pair of corresponding timestamps. |
6601e61a | 354 | * |
0c530ab8 A |
355 | * The tuple {tsc_base, ns_base, scale, shift} is exported in the commpage |
356 | * for the userspace nanotime routine to read. | |
6601e61a | 357 | * |
0c530ab8 A |
358 | * All of the routines which update the nanotime data are non-reentrant. This must |
359 | * be guaranteed by the caller. | |
91447636 A |
360 | */ |
361 | static inline void | |
362 | rtc_nanotime_set_commpage(rtc_nanotime_t *rntp) | |
363 | { | |
0c530ab8 A |
364 | commpage_set_nanotime(rntp->tsc_base, rntp->ns_base, rntp->scale, rntp->shift); |
365 | } | |
6601e61a | 366 | |
0c530ab8 A |
367 | /* |
368 | * rtc_nanotime_init: | |
369 | * | |
370 | * Intialize the nanotime info from the base time. | |
371 | */ | |
372 | static inline void | |
373 | _rtc_nanotime_init(rtc_nanotime_t *rntp, uint64_t base) | |
374 | { | |
375 | uint64_t tsc = rdtsc64(); | |
21362eb3 | 376 | |
2d21ac55 | 377 | _rtc_nanotime_store(tsc, base, rntp->scale, rntp->shift, rntp); |
91447636 A |
378 | } |
379 | ||
380 | static void | |
0c530ab8 | 381 | rtc_nanotime_init(uint64_t base) |
91447636 | 382 | { |
060df5ea A |
383 | _rtc_nanotime_init(&rtc_nanotime_info, base); |
384 | rtc_nanotime_set_commpage(&rtc_nanotime_info); | |
91447636 A |
385 | } |
386 | ||
0c530ab8 A |
387 | /* |
388 | * rtc_nanotime_init_commpage: | |
389 | * | |
390 | * Call back from the commpage initialization to | |
391 | * cause the commpage data to be filled in once the | |
392 | * commpages have been created. | |
393 | */ | |
394 | void | |
395 | rtc_nanotime_init_commpage(void) | |
91447636 | 396 | { |
0c530ab8 A |
397 | spl_t s = splclock(); |
398 | ||
060df5ea | 399 | rtc_nanotime_set_commpage(&rtc_nanotime_info); |
4452a7af | 400 | |
0c530ab8 | 401 | splx(s); |
91447636 A |
402 | } |
403 | ||
0c530ab8 A |
404 | /* |
405 | * rtc_nanotime_read: | |
406 | * | |
407 | * Returns the current nanotime value, accessable from any | |
408 | * context. | |
409 | */ | |
2d21ac55 | 410 | static inline uint64_t |
91447636 A |
411 | rtc_nanotime_read(void) |
412 | { | |
2d21ac55 A |
413 | |
414 | #if CONFIG_EMBEDDED | |
415 | if (gPEClockFrequencyInfo.timebase_frequency_hz > SLOW_TSC_THRESHOLD) | |
060df5ea | 416 | return _rtc_nanotime_read(&rtc_nanotime_info, 1); /* slow processor */ |
2d21ac55 A |
417 | else |
418 | #endif | |
060df5ea | 419 | return _rtc_nanotime_read(&rtc_nanotime_info, 0); /* assume fast processor */ |
91447636 A |
420 | } |
421 | ||
91447636 | 422 | /* |
0c530ab8 A |
423 | * rtc_clock_napped: |
424 | * | |
4a3eedf9 A |
425 | * Invoked from power management when we exit from a low C-State (>= C4) |
426 | * and the TSC has stopped counting. The nanotime data is updated according | |
427 | * to the provided value which represents the new value for nanotime. | |
91447636 | 428 | */ |
0c530ab8 | 429 | void |
4a3eedf9 | 430 | rtc_clock_napped(uint64_t base, uint64_t tsc_base) |
0c530ab8 | 431 | { |
060df5ea | 432 | rtc_nanotime_t *rntp = &rtc_nanotime_info; |
4a3eedf9 A |
433 | uint64_t oldnsecs; |
434 | uint64_t newnsecs; | |
435 | uint64_t tsc; | |
2d21ac55 A |
436 | |
437 | assert(!ml_get_interrupts_enabled()); | |
4a3eedf9 A |
438 | tsc = rdtsc64(); |
439 | oldnsecs = rntp->ns_base + _tsc_to_nanoseconds(tsc - rntp->tsc_base); | |
440 | newnsecs = base + _tsc_to_nanoseconds(tsc - tsc_base); | |
441 | ||
442 | /* | |
443 | * Only update the base values if time using the new base values | |
444 | * is later than the time using the old base values. | |
445 | */ | |
446 | if (oldnsecs < newnsecs) { | |
447 | _rtc_nanotime_store(tsc_base, base, rntp->scale, rntp->shift, rntp); | |
448 | rtc_nanotime_set_commpage(rntp); | |
449 | } | |
0c530ab8 A |
450 | } |
451 | ||
0b4c1975 A |
452 | |
453 | /* | |
454 | * Invoked from power management to correct the SFLM TSC entry drift problem: | |
455 | * a small delta is added to the tsc_base. This is equivalent to nudging time | |
456 | * backwards. We require this of the order of a TSC quantum which won't cause | |
457 | * callers of mach_absolute_time() to see time going backwards! | |
458 | */ | |
459 | void | |
460 | rtc_clock_adjust(uint64_t tsc_base_delta) | |
461 | { | |
060df5ea | 462 | rtc_nanotime_t *rntp = &rtc_nanotime_info; |
0b4c1975 A |
463 | |
464 | assert(!ml_get_interrupts_enabled()); | |
465 | assert(tsc_base_delta < 100ULL); /* i.e. it's small */ | |
466 | _rtc_nanotime_adjust(tsc_base_delta, rntp); | |
467 | rtc_nanotime_set_commpage(rntp); | |
468 | } | |
469 | ||
470 | ||
91447636 A |
471 | void |
472 | rtc_clock_stepping(__unused uint32_t new_frequency, | |
473 | __unused uint32_t old_frequency) | |
474 | { | |
0c530ab8 | 475 | panic("rtc_clock_stepping unsupported"); |
91447636 A |
476 | } |
477 | ||
91447636 | 478 | void |
0c530ab8 A |
479 | rtc_clock_stepped(__unused uint32_t new_frequency, |
480 | __unused uint32_t old_frequency) | |
91447636 | 481 | { |
2d21ac55 | 482 | panic("rtc_clock_stepped unsupported"); |
1c79356b A |
483 | } |
484 | ||
485 | /* | |
0c530ab8 A |
486 | * rtc_sleep_wakeup: |
487 | * | |
488 | * Invoked from power manageent when we have awoken from a sleep (S3) | |
489 | * and the TSC has been reset. The nanotime data is updated based on | |
490 | * the passed in value. | |
491 | * | |
492 | * The caller must guarantee non-reentrancy. | |
91447636 A |
493 | */ |
494 | void | |
0c530ab8 A |
495 | rtc_sleep_wakeup( |
496 | uint64_t base) | |
91447636 | 497 | { |
060df5ea A |
498 | /* Set fixed configuration for lapic timers */ |
499 | rtc_timer->config(); | |
500 | ||
91447636 A |
501 | /* |
502 | * Reset nanotime. | |
503 | * The timestamp counter will have been reset | |
504 | * but nanotime (uptime) marches onward. | |
91447636 | 505 | */ |
0c530ab8 | 506 | rtc_nanotime_init(base); |
91447636 A |
507 | } |
508 | ||
509 | /* | |
510 | * Initialize the real-time clock device. | |
511 | * In addition, various variables used to support the clock are initialized. | |
1c79356b A |
512 | */ |
513 | int | |
0c530ab8 | 514 | rtclock_init(void) |
1c79356b | 515 | { |
91447636 A |
516 | uint64_t cycles; |
517 | ||
0c530ab8 A |
518 | assert(!ml_get_interrupts_enabled()); |
519 | ||
91447636 | 520 | if (cpu_number() == master_cpu) { |
0c530ab8 A |
521 | |
522 | assert(tscFreq); | |
523 | rtc_set_timescale(tscFreq); | |
524 | ||
91447636 | 525 | /* |
0c530ab8 | 526 | * Adjust and set the exported cpu speed. |
91447636 | 527 | */ |
0c530ab8 | 528 | cycles = rtc_export_speed(tscFreq); |
91447636 A |
529 | |
530 | /* | |
531 | * Set min/max to actual. | |
532 | * ACPI may update these later if speed-stepping is detected. | |
533 | */ | |
0c530ab8 A |
534 | gPEClockFrequencyInfo.cpu_frequency_min_hz = cycles; |
535 | gPEClockFrequencyInfo.cpu_frequency_max_hz = cycles; | |
91447636 | 536 | |
060df5ea | 537 | rtc_timer_init(); |
91447636 | 538 | clock_timebase_init(); |
0c530ab8 | 539 | ml_init_lock_timeout(); |
1c79356b | 540 | } |
91447636 | 541 | |
060df5ea A |
542 | /* Set fixed configuration for lapic timers */ |
543 | rtc_timer->config(); | |
544 | ||
545 | rtc_timer_start(); | |
91447636 | 546 | |
1c79356b A |
547 | return (1); |
548 | } | |
549 | ||
0c530ab8 A |
550 | // utility routine |
551 | // Code to calculate how many processor cycles are in a second... | |
1c79356b | 552 | |
0c530ab8 A |
553 | static void |
554 | rtc_set_timescale(uint64_t cycles) | |
1c79356b | 555 | { |
060df5ea | 556 | rtc_nanotime_t *rntp = &rtc_nanotime_info; |
b0d623f7 | 557 | rntp->scale = (uint32_t)(((uint64_t)NSEC_PER_SEC << 32) / cycles); |
2d21ac55 A |
558 | |
559 | if (cycles <= SLOW_TSC_THRESHOLD) | |
b0d623f7 | 560 | rntp->shift = (uint32_t)cycles; |
2d21ac55 | 561 | else |
593a1d5f | 562 | rntp->shift = 32; |
1c79356b | 563 | |
b0d623f7 A |
564 | if (tsc_rebase_abs_time == 0) |
565 | tsc_rebase_abs_time = mach_absolute_time(); | |
566 | ||
0c530ab8 | 567 | rtc_nanotime_init(0); |
1c79356b A |
568 | } |
569 | ||
91447636 | 570 | static uint64_t |
0c530ab8 | 571 | rtc_export_speed(uint64_t cyc_per_sec) |
9bccf70c | 572 | { |
0c530ab8 | 573 | uint64_t cycles; |
1c79356b | 574 | |
0c530ab8 A |
575 | /* Round: */ |
576 | cycles = ((cyc_per_sec + (UI_CPUFREQ_ROUNDING_FACTOR/2)) | |
91447636 A |
577 | / UI_CPUFREQ_ROUNDING_FACTOR) |
578 | * UI_CPUFREQ_ROUNDING_FACTOR; | |
9bccf70c | 579 | |
91447636 A |
580 | /* |
581 | * Set current measured speed. | |
582 | */ | |
583 | if (cycles >= 0x100000000ULL) { | |
584 | gPEClockFrequencyInfo.cpu_clock_rate_hz = 0xFFFFFFFFUL; | |
55e303ae | 585 | } else { |
91447636 | 586 | gPEClockFrequencyInfo.cpu_clock_rate_hz = (unsigned long)cycles; |
9bccf70c | 587 | } |
91447636 | 588 | gPEClockFrequencyInfo.cpu_frequency_hz = cycles; |
55e303ae | 589 | |
0c530ab8 | 590 | kprintf("[RTCLOCK] frequency %llu (%llu)\n", cycles, cyc_per_sec); |
91447636 | 591 | return(cycles); |
9bccf70c | 592 | } |
1c79356b | 593 | |
55e303ae A |
594 | void |
595 | clock_get_system_microtime( | |
b0d623f7 A |
596 | clock_sec_t *secs, |
597 | clock_usec_t *microsecs) | |
9bccf70c | 598 | { |
0c530ab8 | 599 | uint64_t now = rtc_nanotime_read(); |
6601e61a | 600 | |
b0d623f7 | 601 | _absolutetime_to_microtime(now, secs, microsecs); |
1c79356b A |
602 | } |
603 | ||
55e303ae A |
604 | void |
605 | clock_get_system_nanotime( | |
b0d623f7 A |
606 | clock_sec_t *secs, |
607 | clock_nsec_t *nanosecs) | |
55e303ae | 608 | { |
0c530ab8 | 609 | uint64_t now = rtc_nanotime_read(); |
8f6c56a5 | 610 | |
b0d623f7 | 611 | _absolutetime_to_nanotime(now, secs, nanosecs); |
6601e61a A |
612 | } |
613 | ||
614 | void | |
0c530ab8 A |
615 | clock_gettimeofday_set_commpage( |
616 | uint64_t abstime, | |
617 | uint64_t epoch, | |
618 | uint64_t offset, | |
b0d623f7 A |
619 | clock_sec_t *secs, |
620 | clock_usec_t *microsecs) | |
0c530ab8 | 621 | { |
b0d623f7 | 622 | uint64_t now = abstime + offset; |
0c530ab8 | 623 | uint32_t remain; |
6601e61a | 624 | |
b0d623f7 | 625 | remain = _absolutetime_to_microtime(now, secs, microsecs); |
6601e61a | 626 | |
b0d623f7 | 627 | *secs += (clock_sec_t)epoch; |
6601e61a | 628 | |
2d21ac55 | 629 | commpage_set_timestamp(abstime - remain, *secs); |
91447636 A |
630 | } |
631 | ||
1c79356b A |
632 | void |
633 | clock_timebase_info( | |
634 | mach_timebase_info_t info) | |
635 | { | |
91447636 | 636 | info->numer = info->denom = 1; |
1c79356b A |
637 | } |
638 | ||
1c79356b | 639 | /* |
91447636 | 640 | * Real-time clock device interrupt. |
1c79356b | 641 | */ |
1c79356b | 642 | void |
0c530ab8 A |
643 | rtclock_intr( |
644 | x86_saved_state_t *tregs) | |
1c79356b | 645 | { |
0c530ab8 A |
646 | uint64_t rip; |
647 | boolean_t user_mode = FALSE; | |
91447636 A |
648 | |
649 | assert(get_preemption_level() > 0); | |
650 | assert(!ml_get_interrupts_enabled()); | |
651 | ||
0c530ab8 A |
652 | if (is_saved_state64(tregs) == TRUE) { |
653 | x86_saved_state64_t *regs; | |
654 | ||
655 | regs = saved_state64(tregs); | |
5d5c5d0d | 656 | |
b0d623f7 A |
657 | if (regs->isf.cs & 0x03) |
658 | user_mode = TRUE; | |
0c530ab8 A |
659 | rip = regs->isf.rip; |
660 | } else { | |
661 | x86_saved_state32_t *regs; | |
8ad349bb | 662 | |
0c530ab8 | 663 | regs = saved_state32(tregs); |
4452a7af | 664 | |
0c530ab8 A |
665 | if (regs->cs & 0x03) |
666 | user_mode = TRUE; | |
667 | rip = regs->eip; | |
668 | } | |
89b3af67 | 669 | |
0c530ab8 A |
670 | /* call the generic etimer */ |
671 | etimer_intr(user_mode, rip); | |
5d5c5d0d A |
672 | } |
673 | ||
060df5ea | 674 | |
0c530ab8 A |
675 | /* |
676 | * Request timer pop from the hardware | |
677 | */ | |
678 | ||
060df5ea | 679 | uint64_t |
0c530ab8 A |
680 | setPop( |
681 | uint64_t time) | |
5d5c5d0d | 682 | { |
0c530ab8 | 683 | uint64_t now; |
060df5ea A |
684 | uint64_t pop; |
685 | ||
686 | /* 0 and EndOfAllTime are special-cases for "clear the timer" */ | |
687 | if (time == 0 || time == EndOfAllTime) { | |
688 | time = EndOfAllTime; | |
689 | now = 0; | |
690 | pop = rtc_timer_set(0, 0); | |
691 | } else { | |
692 | now = rtc_nanotime_read(); | |
693 | pop = rtc_timer_set(time, now); | |
694 | } | |
4452a7af | 695 | |
060df5ea A |
696 | /* Record actual deadline set */ |
697 | x86_lcpu()->rtcDeadline = time; | |
698 | x86_lcpu()->rtcPop = pop; | |
4452a7af | 699 | |
060df5ea A |
700 | /* |
701 | * Pass back the delta we set | |
702 | */ | |
703 | return pop - now; | |
89b3af67 A |
704 | } |
705 | ||
6601e61a A |
706 | uint64_t |
707 | mach_absolute_time(void) | |
4452a7af | 708 | { |
0c530ab8 A |
709 | return rtc_nanotime_read(); |
710 | } | |
711 | ||
712 | void | |
713 | clock_interval_to_absolutetime_interval( | |
714 | uint32_t interval, | |
715 | uint32_t scale_factor, | |
716 | uint64_t *result) | |
717 | { | |
718 | *result = (uint64_t)interval * scale_factor; | |
91447636 A |
719 | } |
720 | ||
721 | void | |
722 | absolutetime_to_microtime( | |
723 | uint64_t abstime, | |
b0d623f7 A |
724 | clock_sec_t *secs, |
725 | clock_usec_t *microsecs) | |
91447636 | 726 | { |
b0d623f7 | 727 | _absolutetime_to_microtime(abstime, secs, microsecs); |
1c79356b A |
728 | } |
729 | ||
730 | void | |
0c530ab8 A |
731 | absolutetime_to_nanotime( |
732 | uint64_t abstime, | |
b0d623f7 A |
733 | clock_sec_t *secs, |
734 | clock_nsec_t *nanosecs) | |
6601e61a | 735 | { |
b0d623f7 | 736 | _absolutetime_to_nanotime(abstime, secs, nanosecs); |
6601e61a A |
737 | } |
738 | ||
739 | void | |
0c530ab8 | 740 | nanotime_to_absolutetime( |
b0d623f7 A |
741 | clock_sec_t secs, |
742 | clock_nsec_t nanosecs, | |
0c530ab8 | 743 | uint64_t *result) |
1c79356b | 744 | { |
0c530ab8 | 745 | *result = ((uint64_t)secs * NSEC_PER_SEC) + nanosecs; |
1c79356b A |
746 | } |
747 | ||
748 | void | |
749 | absolutetime_to_nanoseconds( | |
0b4e3aa0 A |
750 | uint64_t abstime, |
751 | uint64_t *result) | |
1c79356b | 752 | { |
0b4e3aa0 | 753 | *result = abstime; |
1c79356b A |
754 | } |
755 | ||
756 | void | |
757 | nanoseconds_to_absolutetime( | |
0b4e3aa0 A |
758 | uint64_t nanoseconds, |
759 | uint64_t *result) | |
1c79356b | 760 | { |
0b4e3aa0 | 761 | *result = nanoseconds; |
1c79356b A |
762 | } |
763 | ||
55e303ae | 764 | void |
91447636 | 765 | machine_delay_until( |
55e303ae A |
766 | uint64_t deadline) |
767 | { | |
768 | uint64_t now; | |
769 | ||
770 | do { | |
771 | cpu_pause(); | |
772 | now = mach_absolute_time(); | |
773 | } while (now < deadline); | |
774 | } |