]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2000-2008 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
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 | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | /* | |
29 | * @OSF_COPYRIGHT@ | |
30 | */ | |
31 | ||
32 | /* | |
33 | * File: i386/rtclock.c | |
34 | * Purpose: Routines for handling the machine dependent | |
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. | |
40 | */ | |
41 | ||
42 | #include <platforms.h> | |
43 | #include <mach_kdb.h> | |
44 | ||
45 | #include <mach/mach_types.h> | |
46 | ||
47 | #include <kern/cpu_data.h> | |
48 | #include <kern/cpu_number.h> | |
49 | #include <kern/clock.h> | |
50 | #include <kern/host_notify.h> | |
51 | #include <kern/macro_help.h> | |
52 | #include <kern/misc_protos.h> | |
53 | #include <kern/spl.h> | |
54 | #include <kern/assert.h> | |
55 | #include <mach/vm_prot.h> | |
56 | #include <vm/pmap.h> | |
57 | #include <vm/vm_kern.h> /* for kernel_map */ | |
58 | #include <i386/ipl.h> | |
59 | #include <architecture/i386/pio.h> | |
60 | #include <i386/misc_protos.h> | |
61 | #include <i386/proc_reg.h> | |
62 | #include <i386/machine_cpu.h> | |
63 | #include <i386/lapic.h> | |
64 | #include <i386/cpuid.h> | |
65 | #include <i386/cpu_data.h> | |
66 | #include <i386/cpu_threads.h> | |
67 | #include <i386/perfmon.h> | |
68 | #include <i386/machine_routines.h> | |
69 | #include <pexpert/pexpert.h> | |
70 | #include <machine/limits.h> | |
71 | #include <machine/commpage.h> | |
72 | #include <sys/kdebug.h> | |
73 | #include <i386/tsc.h> | |
74 | #include <i386/rtclock.h> | |
75 | ||
76 | #define NSEC_PER_HZ (NSEC_PER_SEC / 100) /* nsec per tick */ | |
77 | ||
78 | #define UI_CPUFREQ_ROUNDING_FACTOR 10000000 | |
79 | ||
80 | int rtclock_config(void); | |
81 | ||
82 | int rtclock_init(void); | |
83 | ||
84 | uint64_t rtc_decrementer_min; | |
85 | ||
86 | void rtclock_intr(x86_saved_state_t *regs); | |
87 | static uint64_t maxDec; /* longest interval our hardware timer can handle (nsec) */ | |
88 | ||
89 | static void rtc_set_timescale(uint64_t cycles); | |
90 | static uint64_t rtc_export_speed(uint64_t cycles); | |
91 | ||
92 | rtc_nanotime_t rtc_nanotime_info = {0,0,0,0,1,0}; | |
93 | ||
94 | /* | |
95 | * tsc_to_nanoseconds: | |
96 | * | |
97 | * Basic routine to convert a raw 64 bit TSC value to a | |
98 | * 64 bit nanosecond value. The conversion is implemented | |
99 | * based on the scale factor and an implicit 32 bit shift. | |
100 | */ | |
101 | static inline uint64_t | |
102 | _tsc_to_nanoseconds(uint64_t value) | |
103 | { | |
104 | asm volatile("movl %%edx,%%esi ;" | |
105 | "mull %%ecx ;" | |
106 | "movl %%edx,%%edi ;" | |
107 | "movl %%esi,%%eax ;" | |
108 | "mull %%ecx ;" | |
109 | "addl %%edi,%%eax ;" | |
110 | "adcl $0,%%edx " | |
111 | : "+A" (value) | |
112 | : "c" (current_cpu_datap()->cpu_nanotime->scale) | |
113 | : "esi", "edi"); | |
114 | ||
115 | return (value); | |
116 | } | |
117 | ||
118 | static uint32_t | |
119 | deadline_to_decrementer( | |
120 | uint64_t deadline, | |
121 | uint64_t now) | |
122 | { | |
123 | uint64_t delta; | |
124 | ||
125 | if (deadline <= now) | |
126 | return rtc_decrementer_min; | |
127 | else { | |
128 | delta = deadline - now; | |
129 | return MIN(MAX(rtc_decrementer_min,delta),maxDec); | |
130 | } | |
131 | } | |
132 | ||
133 | void | |
134 | rtc_lapic_start_ticking(void) | |
135 | { | |
136 | x86_lcpu_t *lcpu = x86_lcpu(); | |
137 | ||
138 | /* | |
139 | * Force a complete re-evaluation of timer deadlines. | |
140 | */ | |
141 | lcpu->rtcPop = EndOfAllTime; | |
142 | etimer_resync_deadlines(); | |
143 | } | |
144 | ||
145 | /* | |
146 | * Configure the real-time clock device. Return success (1) | |
147 | * or failure (0). | |
148 | */ | |
149 | ||
150 | int | |
151 | rtclock_config(void) | |
152 | { | |
153 | /* nothing to do */ | |
154 | return (1); | |
155 | } | |
156 | ||
157 | ||
158 | /* | |
159 | * Nanotime/mach_absolutime_time | |
160 | * ----------------------------- | |
161 | * The timestamp counter (TSC) - which counts cpu clock cycles and can be read | |
162 | * efficiently by the kernel and in userspace - is the reference for all timing. | |
163 | * The cpu clock rate is platform-dependent and may stop or be reset when the | |
164 | * processor is napped/slept. As a result, nanotime is the software abstraction | |
165 | * used to maintain a monotonic clock, adjusted from an outside reference as needed. | |
166 | * | |
167 | * The kernel maintains nanotime information recording: | |
168 | * - the ratio of tsc to nanoseconds | |
169 | * with this ratio expressed as a 32-bit scale and shift | |
170 | * (power of 2 divider); | |
171 | * - { tsc_base, ns_base } pair of corresponding timestamps. | |
172 | * | |
173 | * The tuple {tsc_base, ns_base, scale, shift} is exported in the commpage | |
174 | * for the userspace nanotime routine to read. | |
175 | * | |
176 | * All of the routines which update the nanotime data are non-reentrant. This must | |
177 | * be guaranteed by the caller. | |
178 | */ | |
179 | static inline void | |
180 | rtc_nanotime_set_commpage(rtc_nanotime_t *rntp) | |
181 | { | |
182 | commpage_set_nanotime(rntp->tsc_base, rntp->ns_base, rntp->scale, rntp->shift); | |
183 | } | |
184 | ||
185 | /* | |
186 | * rtc_nanotime_init: | |
187 | * | |
188 | * Intialize the nanotime info from the base time. | |
189 | */ | |
190 | static inline void | |
191 | _rtc_nanotime_init(rtc_nanotime_t *rntp, uint64_t base) | |
192 | { | |
193 | uint64_t tsc = rdtsc64(); | |
194 | ||
195 | _rtc_nanotime_store(tsc, base, rntp->scale, rntp->shift, rntp); | |
196 | } | |
197 | ||
198 | static void | |
199 | rtc_nanotime_init(uint64_t base) | |
200 | { | |
201 | rtc_nanotime_t *rntp = current_cpu_datap()->cpu_nanotime; | |
202 | ||
203 | _rtc_nanotime_init(rntp, base); | |
204 | rtc_nanotime_set_commpage(rntp); | |
205 | } | |
206 | ||
207 | /* | |
208 | * rtc_nanotime_init_commpage: | |
209 | * | |
210 | * Call back from the commpage initialization to | |
211 | * cause the commpage data to be filled in once the | |
212 | * commpages have been created. | |
213 | */ | |
214 | void | |
215 | rtc_nanotime_init_commpage(void) | |
216 | { | |
217 | spl_t s = splclock(); | |
218 | ||
219 | rtc_nanotime_set_commpage(current_cpu_datap()->cpu_nanotime); | |
220 | ||
221 | splx(s); | |
222 | } | |
223 | ||
224 | /* | |
225 | * rtc_nanotime_read: | |
226 | * | |
227 | * Returns the current nanotime value, accessable from any | |
228 | * context. | |
229 | */ | |
230 | static inline uint64_t | |
231 | rtc_nanotime_read(void) | |
232 | { | |
233 | ||
234 | #if CONFIG_EMBEDDED | |
235 | if (gPEClockFrequencyInfo.timebase_frequency_hz > SLOW_TSC_THRESHOLD) | |
236 | return _rtc_nanotime_read(current_cpu_datap()->cpu_nanotime, 1); /* slow processor */ | |
237 | else | |
238 | #endif | |
239 | return _rtc_nanotime_read(current_cpu_datap()->cpu_nanotime, 0); /* assume fast processor */ | |
240 | } | |
241 | ||
242 | /* | |
243 | * rtc_clock_napped: | |
244 | * | |
245 | * Invoked from power management when we exit from a low C-State (>= C4) | |
246 | * and the TSC has stopped counting. The nanotime data is updated according | |
247 | * to the provided value which represents the new value for nanotime. | |
248 | */ | |
249 | void | |
250 | rtc_clock_napped(uint64_t base, uint64_t tsc_base) | |
251 | { | |
252 | rtc_nanotime_t *rntp = current_cpu_datap()->cpu_nanotime; | |
253 | uint64_t oldnsecs; | |
254 | uint64_t newnsecs; | |
255 | uint64_t tsc; | |
256 | ||
257 | assert(!ml_get_interrupts_enabled()); | |
258 | tsc = rdtsc64(); | |
259 | oldnsecs = rntp->ns_base + _tsc_to_nanoseconds(tsc - rntp->tsc_base); | |
260 | newnsecs = base + _tsc_to_nanoseconds(tsc - tsc_base); | |
261 | ||
262 | /* | |
263 | * Only update the base values if time using the new base values | |
264 | * is later than the time using the old base values. | |
265 | */ | |
266 | if (oldnsecs < newnsecs) { | |
267 | _rtc_nanotime_store(tsc_base, base, rntp->scale, rntp->shift, rntp); | |
268 | rtc_nanotime_set_commpage(rntp); | |
269 | } | |
270 | } | |
271 | ||
272 | void | |
273 | rtc_clock_stepping(__unused uint32_t new_frequency, | |
274 | __unused uint32_t old_frequency) | |
275 | { | |
276 | panic("rtc_clock_stepping unsupported"); | |
277 | } | |
278 | ||
279 | void | |
280 | rtc_clock_stepped(__unused uint32_t new_frequency, | |
281 | __unused uint32_t old_frequency) | |
282 | { | |
283 | panic("rtc_clock_stepped unsupported"); | |
284 | } | |
285 | ||
286 | /* | |
287 | * rtc_sleep_wakeup: | |
288 | * | |
289 | * Invoked from power manageent when we have awoken from a sleep (S3) | |
290 | * and the TSC has been reset. The nanotime data is updated based on | |
291 | * the passed in value. | |
292 | * | |
293 | * The caller must guarantee non-reentrancy. | |
294 | */ | |
295 | void | |
296 | rtc_sleep_wakeup( | |
297 | uint64_t base) | |
298 | { | |
299 | /* | |
300 | * Reset nanotime. | |
301 | * The timestamp counter will have been reset | |
302 | * but nanotime (uptime) marches onward. | |
303 | */ | |
304 | rtc_nanotime_init(base); | |
305 | } | |
306 | ||
307 | /* | |
308 | * Initialize the real-time clock device. | |
309 | * In addition, various variables used to support the clock are initialized. | |
310 | */ | |
311 | int | |
312 | rtclock_init(void) | |
313 | { | |
314 | uint64_t cycles; | |
315 | ||
316 | assert(!ml_get_interrupts_enabled()); | |
317 | ||
318 | if (cpu_number() == master_cpu) { | |
319 | ||
320 | assert(tscFreq); | |
321 | rtc_set_timescale(tscFreq); | |
322 | ||
323 | /* | |
324 | * Adjust and set the exported cpu speed. | |
325 | */ | |
326 | cycles = rtc_export_speed(tscFreq); | |
327 | ||
328 | /* | |
329 | * Set min/max to actual. | |
330 | * ACPI may update these later if speed-stepping is detected. | |
331 | */ | |
332 | gPEClockFrequencyInfo.cpu_frequency_min_hz = cycles; | |
333 | gPEClockFrequencyInfo.cpu_frequency_max_hz = cycles; | |
334 | ||
335 | /* | |
336 | * Compute the longest interval we can represent. | |
337 | */ | |
338 | maxDec = tmrCvt(0x7fffffffULL, busFCvtt2n); | |
339 | kprintf("maxDec: %lld\n", maxDec); | |
340 | ||
341 | /* Minimum interval is 1usec */ | |
342 | rtc_decrementer_min = deadline_to_decrementer(NSEC_PER_USEC, 0ULL); | |
343 | /* Point LAPIC interrupts to hardclock() */ | |
344 | lapic_set_timer_func((i386_intr_func_t) rtclock_intr); | |
345 | ||
346 | clock_timebase_init(); | |
347 | ml_init_lock_timeout(); | |
348 | } | |
349 | ||
350 | rtc_lapic_start_ticking(); | |
351 | ||
352 | return (1); | |
353 | } | |
354 | ||
355 | // utility routine | |
356 | // Code to calculate how many processor cycles are in a second... | |
357 | ||
358 | static void | |
359 | rtc_set_timescale(uint64_t cycles) | |
360 | { | |
361 | rtc_nanotime_t *rntp = current_cpu_datap()->cpu_nanotime; | |
362 | rntp->scale = ((uint64_t)NSEC_PER_SEC << 32) / cycles; | |
363 | ||
364 | if (cycles <= SLOW_TSC_THRESHOLD) | |
365 | rntp->shift = cycles; | |
366 | else | |
367 | rntp->shift = 32; | |
368 | ||
369 | rtc_nanotime_init(0); | |
370 | } | |
371 | ||
372 | static uint64_t | |
373 | rtc_export_speed(uint64_t cyc_per_sec) | |
374 | { | |
375 | uint64_t cycles; | |
376 | ||
377 | /* Round: */ | |
378 | cycles = ((cyc_per_sec + (UI_CPUFREQ_ROUNDING_FACTOR/2)) | |
379 | / UI_CPUFREQ_ROUNDING_FACTOR) | |
380 | * UI_CPUFREQ_ROUNDING_FACTOR; | |
381 | ||
382 | /* | |
383 | * Set current measured speed. | |
384 | */ | |
385 | if (cycles >= 0x100000000ULL) { | |
386 | gPEClockFrequencyInfo.cpu_clock_rate_hz = 0xFFFFFFFFUL; | |
387 | } else { | |
388 | gPEClockFrequencyInfo.cpu_clock_rate_hz = (unsigned long)cycles; | |
389 | } | |
390 | gPEClockFrequencyInfo.cpu_frequency_hz = cycles; | |
391 | ||
392 | kprintf("[RTCLOCK] frequency %llu (%llu)\n", cycles, cyc_per_sec); | |
393 | return(cycles); | |
394 | } | |
395 | ||
396 | void | |
397 | clock_get_system_microtime( | |
398 | uint32_t *secs, | |
399 | uint32_t *microsecs) | |
400 | { | |
401 | uint64_t now = rtc_nanotime_read(); | |
402 | uint32_t remain; | |
403 | ||
404 | asm volatile( | |
405 | "divl %3" | |
406 | : "=a" (*secs), "=d" (remain) | |
407 | : "A" (now), "r" (NSEC_PER_SEC)); | |
408 | asm volatile( | |
409 | "divl %3" | |
410 | : "=a" (*microsecs) | |
411 | : "0" (remain), "d" (0), "r" (NSEC_PER_USEC)); | |
412 | } | |
413 | ||
414 | void | |
415 | clock_get_system_nanotime( | |
416 | uint32_t *secs, | |
417 | uint32_t *nanosecs) | |
418 | { | |
419 | uint64_t now = rtc_nanotime_read(); | |
420 | ||
421 | asm volatile( | |
422 | "divl %3" | |
423 | : "=a" (*secs), "=d" (*nanosecs) | |
424 | : "A" (now), "r" (NSEC_PER_SEC)); | |
425 | } | |
426 | ||
427 | void | |
428 | clock_gettimeofday_set_commpage( | |
429 | uint64_t abstime, | |
430 | uint64_t epoch, | |
431 | uint64_t offset, | |
432 | uint32_t *secs, | |
433 | uint32_t *microsecs) | |
434 | { | |
435 | uint64_t now = abstime; | |
436 | uint32_t remain; | |
437 | ||
438 | now += offset; | |
439 | ||
440 | asm volatile( | |
441 | "divl %3" | |
442 | : "=a" (*secs), "=d" (remain) | |
443 | : "A" (now), "r" (NSEC_PER_SEC)); | |
444 | asm volatile( | |
445 | "divl %3" | |
446 | : "=a" (*microsecs) | |
447 | : "0" (remain), "d" (0), "r" (NSEC_PER_USEC)); | |
448 | ||
449 | *secs += epoch; | |
450 | ||
451 | commpage_set_timestamp(abstime - remain, *secs); | |
452 | } | |
453 | ||
454 | void | |
455 | clock_timebase_info( | |
456 | mach_timebase_info_t info) | |
457 | { | |
458 | info->numer = info->denom = 1; | |
459 | } | |
460 | ||
461 | /* | |
462 | * Real-time clock device interrupt. | |
463 | */ | |
464 | void | |
465 | rtclock_intr( | |
466 | x86_saved_state_t *tregs) | |
467 | { | |
468 | uint64_t rip; | |
469 | boolean_t user_mode = FALSE; | |
470 | uint64_t abstime; | |
471 | uint32_t latency; | |
472 | x86_lcpu_t *lcpu = x86_lcpu(); | |
473 | ||
474 | assert(get_preemption_level() > 0); | |
475 | assert(!ml_get_interrupts_enabled()); | |
476 | ||
477 | abstime = rtc_nanotime_read(); | |
478 | latency = (uint32_t)(abstime - lcpu->rtcDeadline); | |
479 | if (abstime < lcpu->rtcDeadline) | |
480 | latency = 1; | |
481 | ||
482 | if (is_saved_state64(tregs) == TRUE) { | |
483 | x86_saved_state64_t *regs; | |
484 | ||
485 | regs = saved_state64(tregs); | |
486 | ||
487 | user_mode = TRUE; | |
488 | rip = regs->isf.rip; | |
489 | } else { | |
490 | x86_saved_state32_t *regs; | |
491 | ||
492 | regs = saved_state32(tregs); | |
493 | ||
494 | if (regs->cs & 0x03) | |
495 | user_mode = TRUE; | |
496 | rip = regs->eip; | |
497 | } | |
498 | ||
499 | /* Log the interrupt service latency (-ve value expected by tool) */ | |
500 | KERNEL_DEBUG_CONSTANT( | |
501 | MACHDBG_CODE(DBG_MACH_EXCP_DECI, 0) | DBG_FUNC_NONE, | |
502 | -latency, (uint32_t)rip, user_mode, 0, 0); | |
503 | ||
504 | /* call the generic etimer */ | |
505 | etimer_intr(user_mode, rip); | |
506 | } | |
507 | ||
508 | /* | |
509 | * Request timer pop from the hardware | |
510 | */ | |
511 | ||
512 | int | |
513 | setPop( | |
514 | uint64_t time) | |
515 | { | |
516 | uint64_t now; | |
517 | uint32_t decr; | |
518 | uint64_t count; | |
519 | ||
520 | now = rtc_nanotime_read(); /* The time in nanoseconds */ | |
521 | decr = deadline_to_decrementer(time, now); | |
522 | ||
523 | count = tmrCvt(decr, busFCvtn2t); | |
524 | lapic_set_timer(TRUE, one_shot, divide_by_1, (uint32_t) count); | |
525 | ||
526 | return decr; /* Pass back what we set */ | |
527 | } | |
528 | ||
529 | ||
530 | uint64_t | |
531 | mach_absolute_time(void) | |
532 | { | |
533 | return rtc_nanotime_read(); | |
534 | } | |
535 | ||
536 | void | |
537 | clock_interval_to_absolutetime_interval( | |
538 | uint32_t interval, | |
539 | uint32_t scale_factor, | |
540 | uint64_t *result) | |
541 | { | |
542 | *result = (uint64_t)interval * scale_factor; | |
543 | } | |
544 | ||
545 | void | |
546 | absolutetime_to_microtime( | |
547 | uint64_t abstime, | |
548 | uint32_t *secs, | |
549 | uint32_t *microsecs) | |
550 | { | |
551 | uint32_t remain; | |
552 | ||
553 | asm volatile( | |
554 | "divl %3" | |
555 | : "=a" (*secs), "=d" (remain) | |
556 | : "A" (abstime), "r" (NSEC_PER_SEC)); | |
557 | asm volatile( | |
558 | "divl %3" | |
559 | : "=a" (*microsecs) | |
560 | : "0" (remain), "d" (0), "r" (NSEC_PER_USEC)); | |
561 | } | |
562 | ||
563 | void | |
564 | absolutetime_to_nanotime( | |
565 | uint64_t abstime, | |
566 | uint32_t *secs, | |
567 | uint32_t *nanosecs) | |
568 | { | |
569 | asm volatile( | |
570 | "divl %3" | |
571 | : "=a" (*secs), "=d" (*nanosecs) | |
572 | : "A" (abstime), "r" (NSEC_PER_SEC)); | |
573 | } | |
574 | ||
575 | void | |
576 | nanotime_to_absolutetime( | |
577 | uint32_t secs, | |
578 | uint32_t nanosecs, | |
579 | uint64_t *result) | |
580 | { | |
581 | *result = ((uint64_t)secs * NSEC_PER_SEC) + nanosecs; | |
582 | } | |
583 | ||
584 | void | |
585 | absolutetime_to_nanoseconds( | |
586 | uint64_t abstime, | |
587 | uint64_t *result) | |
588 | { | |
589 | *result = abstime; | |
590 | } | |
591 | ||
592 | void | |
593 | nanoseconds_to_absolutetime( | |
594 | uint64_t nanoseconds, | |
595 | uint64_t *result) | |
596 | { | |
597 | *result = nanoseconds; | |
598 | } | |
599 | ||
600 | void | |
601 | machine_delay_until( | |
602 | uint64_t deadline) | |
603 | { | |
604 | uint64_t now; | |
605 | ||
606 | do { | |
607 | cpu_pause(); | |
608 | now = mach_absolute_time(); | |
609 | } while (now < deadline); | |
610 | } |