]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/i386/rtclock.c
xnu-4570.41.2.tar.gz
[apple/xnu.git] / osfmk / i386 / rtclock.c
index 8a5f8c667b5beec375c59a05e56cae9a347505a3..c8abc4b1eba22c88ca0d342f957f70fe99ec471f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -39,7 +39,6 @@
  *                     the cpu clock counted by the timestamp MSR.
  */
 
-#include <platforms.h>
 
 #include <mach/mach_types.h>
 
@@ -51,7 +50,7 @@
 #include <kern/misc_protos.h>
 #include <kern/spl.h>
 #include <kern/assert.h>
-#include <kern/etimer.h>
+#include <kern/timer_queue.h>
 #include <mach/vm_prot.h>
 #include <vm/pmap.h>
 #include <vm/vm_kern.h>                /* for kernel_map */
 #include <sys/kdebug.h>
 #include <i386/tsc.h>
 #include <i386/rtclock_protos.h>
-
 #define UI_CPUFREQ_ROUNDING_FACTOR     10000000
 
-int            rtclock_config(void);
-
 int            rtclock_init(void);
 
 uint64_t       tsc_rebase_abs_time = 0;
@@ -88,97 +84,27 @@ rtc_timer_start(void)
        /*
         * Force a complete re-evaluation of timer deadlines.
         */
-       etimer_resync_deadlines();
-}
-
-/*
- * tsc_to_nanoseconds:
- *
- * Basic routine to convert a raw 64 bit TSC value to a
- * 64 bit nanosecond value.  The conversion is implemented
- * based on the scale factor and an implicit 32 bit shift.
- */
-static inline uint64_t
-_tsc_to_nanoseconds(uint64_t value)
-{
-#if defined(__i386__)
-    asm volatile("movl %%edx,%%esi     ;"
-                "mull  %%ecx           ;"
-                "movl  %%edx,%%edi     ;"
-                "movl  %%esi,%%eax     ;"
-                "mull  %%ecx           ;"
-                "addl  %%edi,%%eax     ;"      
-                "adcl  $0,%%edx         "
-                : "+A" (value)
-                : "c" (pal_rtc_nanotime_info.scale)
-                : "esi", "edi");
-#elif defined(__x86_64__)
-    asm volatile("mul %%rcx;"
-                "shrq $32, %%rax;"
-                "shlq $32, %%rdx;"
-                "orq %%rdx, %%rax;"
-                : "=a"(value)
-                : "a"(value), "c"(pal_rtc_nanotime_info.scale)
-                : "rdx", "cc" );
-#else
-#error Unsupported architecture
-#endif
-
-    return (value);
+       x86_lcpu()->rtcDeadline = EndOfAllTime;
+       timer_resync_deadlines();
 }
 
 static inline uint32_t
 _absolutetime_to_microtime(uint64_t abstime, clock_sec_t *secs, clock_usec_t *microsecs)
 {
        uint32_t remain;
-#if defined(__i386__)
-       asm volatile(
-                       "divl %3"
-                               : "=a" (*secs), "=d" (remain)
-                               : "A" (abstime), "r" (NSEC_PER_SEC));
-       asm volatile(
-                       "divl %3"
-                               : "=a" (*microsecs)
-                               : "0" (remain), "d" (0), "r" (NSEC_PER_USEC));
-#elif defined(__x86_64__)
        *secs = abstime / (uint64_t)NSEC_PER_SEC;
        remain = (uint32_t)(abstime % (uint64_t)NSEC_PER_SEC);
        *microsecs = remain / NSEC_PER_USEC;
-#else
-#error Unsupported architecture
-#endif
        return remain;
 }
 
 static inline void
 _absolutetime_to_nanotime(uint64_t abstime, clock_sec_t *secs, clock_usec_t *nanosecs)
 {
-#if defined(__i386__)
-       asm volatile(
-                       "divl %3"
-                       : "=a" (*secs), "=d" (*nanosecs)
-                       : "A" (abstime), "r" (NSEC_PER_SEC));
-#elif defined(__x86_64__)
        *secs = abstime / (uint64_t)NSEC_PER_SEC;
        *nanosecs = (clock_usec_t)(abstime % (uint64_t)NSEC_PER_SEC);
-#else
-#error Unsupported architecture
-#endif
 }
 
-/*
- * Configure the real-time clock device. Return success (1)
- * or failure (0).
- */
-
-int
-rtclock_config(void)
-{
-       /* nothing to do */
-       return (1);
-}
-
-
 /*
  * Nanotime/mach_absolutime_time
  * -----------------------------
@@ -219,7 +145,7 @@ _rtc_nanotime_init(pal_rtc_nanotime_t *rntp, uint64_t base)
        _pal_rtc_nanotime_store(tsc, base, rntp->scale, rntp->shift, rntp);
 }
 
-static void
+void
 rtc_nanotime_init(uint64_t base)
 {
        _rtc_nanotime_init(&pal_rtc_nanotime_info, base);
@@ -251,13 +177,7 @@ rtc_nanotime_init_commpage(void)
 static inline uint64_t
 rtc_nanotime_read(void)
 {
-       
-#if CONFIG_EMBEDDED
-       if (gPEClockFrequencyInfo.timebase_frequency_hz > SLOW_TSC_THRESHOLD)
-               return  _rtc_nanotime_read(&rtc_nanotime_info, 1);      /* slow processor */
-       else
-#endif
-       return  _rtc_nanotime_read(&pal_rtc_nanotime_info, 0);  /* assume fast processor */
+       return  _rtc_nanotime_read(&pal_rtc_nanotime_info);
 }
 
 /*
@@ -277,8 +197,8 @@ rtc_clock_napped(uint64_t base, uint64_t tsc_base)
 
        assert(!ml_get_interrupts_enabled());
        tsc = rdtsc64();
-       oldnsecs = rntp->ns_base + _tsc_to_nanoseconds(tsc - rntp->tsc_base);
-       newnsecs = base + _tsc_to_nanoseconds(tsc - tsc_base);
+       oldnsecs = rntp->ns_base + _rtc_tsc_to_nanoseconds(tsc - rntp->tsc_base, rntp);
+       newnsecs = base + _rtc_tsc_to_nanoseconds(tsc - tsc_base, rntp);
        
        /*
         * Only update the base values if time using the new base values
@@ -287,7 +207,6 @@ rtc_clock_napped(uint64_t base, uint64_t tsc_base)
        if (oldnsecs < newnsecs) {
            _pal_rtc_nanotime_store(tsc_base, base, rntp->scale, rntp->shift, rntp);
            rtc_nanotime_set_commpage(rntp);
-               trace_set_timebases(tsc_base, base);
        }
 }
 
@@ -326,8 +245,8 @@ rtc_clock_stepped(__unused uint32_t new_frequency,
  * rtc_sleep_wakeup:
  *
  * Invoked from power management when we have awoken from a sleep (S3)
- * and the TSC has been reset.  The nanotime data is updated based on
- * the passed in value.
+ * and the TSC has been reset, or from Deep Idle (S0) sleep when the TSC
+ * has progressed.  The nanotime data is updated based on the passed-in value.
  *
  * The caller must guarantee non-reentrancy.
  */
@@ -336,7 +255,7 @@ rtc_sleep_wakeup(
        uint64_t                base)
 {
        /* Set fixed configuration for lapic timers */
-       rtc_timer->config();
+       rtc_timer->rtc_config();
 
        /*
         * Reset nanotime.
@@ -346,6 +265,21 @@ rtc_sleep_wakeup(
        rtc_nanotime_init(base);
 }
 
+void
+rtc_decrementer_configure(void) {
+       rtc_timer->rtc_config();
+}
+/*
+ * rtclock_early_init() is called very early at boot to
+ * establish mach_absolute_time() and set it to zero.
+ */
+void
+rtclock_early_init(void)
+{
+       assert(tscFreq);
+       rtc_set_timescale(tscFreq);
+}
+
 /*
  * Initialize the real-time clock device.
  * In addition, various variables used to support the clock are initialized.
@@ -360,7 +294,6 @@ rtclock_init(void)
        if (cpu_number() == master_cpu) {
 
                assert(tscFreq);
-               rtc_set_timescale(tscFreq);
 
                /*
                 * Adjust and set the exported cpu speed.
@@ -377,11 +310,11 @@ rtclock_init(void)
                rtc_timer_init();
                clock_timebase_init();
                ml_init_lock_timeout();
-               ml_init_delay_spin_threshold();
+               ml_init_delay_spin_threshold(10);
        }
 
        /* Set fixed configuration for lapic timers */
-       rtc_timer->config();
+       rtc_timer->rtc_config();
        rtc_timer_start();
 
        return (1);
@@ -394,17 +327,28 @@ static void
 rtc_set_timescale(uint64_t cycles)
 {
        pal_rtc_nanotime_t      *rntp = &pal_rtc_nanotime_info;
+       uint32_t    shift = 0;
+    
+       /* the "scale" factor will overflow unless cycles>SLOW_TSC_THRESHOLD */
+    
+       while ( cycles <= SLOW_TSC_THRESHOLD) {
+               shift++;
+               cycles <<= 1;
+       }
+       
        rntp->scale = (uint32_t)(((uint64_t)NSEC_PER_SEC << 32) / cycles);
 
-#if CONFIG_EMBEDDED
-       if (cycles <= SLOW_TSC_THRESHOLD)
-               rntp->shift = (uint32_t)cycles;
-       else
-#endif
-               rntp->shift = 32;
+       rntp->shift = shift;
 
+       /*
+        * On some platforms, the TSC is not reset at warm boot. But the
+        * rebase time must be relative to the current boot so we can't use
+        * mach_absolute_time(). Instead, we convert the TSC delta since boot
+        * to nanoseconds.
+        */
        if (tsc_rebase_abs_time == 0)
-               tsc_rebase_abs_time = mach_absolute_time();
+               tsc_rebase_abs_time = _rtc_tsc_to_nanoseconds(
+                                               rdtsc64() - tsc_at_boot, rntp);
 
        rtc_nanotime_init(0);
 }
@@ -412,8 +356,12 @@ rtc_set_timescale(uint64_t cycles)
 static uint64_t
 rtc_export_speed(uint64_t cyc_per_sec)
 {
+       pal_rtc_nanotime_t      *rntp = &pal_rtc_nanotime_info;
        uint64_t        cycles;
 
+       if (rntp->shift != 0 )
+               printf("Slow TSC, rtc_nanotime.shift == %d\n", rntp->shift);
+    
        /* Round: */
         cycles = ((cyc_per_sec + (UI_CPUFREQ_ROUNDING_FACTOR/2))
                        / UI_CPUFREQ_ROUNDING_FACTOR)
@@ -454,21 +402,9 @@ clock_get_system_nanotime(
 }
 
 void
-clock_gettimeofday_set_commpage(
-       uint64_t                                abstime,
-       uint64_t                                epoch,
-       uint64_t                                offset,
-       clock_sec_t                             *secs,
-       clock_usec_t                    *microsecs)
+clock_gettimeofday_set_commpage(uint64_t abstime, uint64_t sec, uint64_t frac, uint64_t scale, uint64_t tick_per_sec)
 {
-       uint64_t        now = abstime + offset;
-       uint32_t        remain;
-
-       remain = _absolutetime_to_microtime(now, secs, microsecs);
-
-       *secs += (clock_sec_t)epoch;
-
-       commpage_set_timestamp(abstime - remain, *secs);
+       commpage_set_timestamp(abstime, sec, frac, scale, tick_per_sec);
 }
 
 void
@@ -510,7 +446,7 @@ rtclock_intr(
        }
 
        /* call the generic etimer */
-       etimer_intr(user_mode, rip);
+       timer_intr(user_mode, rip);
 }
 
 
@@ -519,8 +455,7 @@ rtclock_intr(
  */
 
 uint64_t
-setPop(
-       uint64_t time)
+setPop(uint64_t time)
 {
        uint64_t        now;
        uint64_t        pop;
@@ -529,10 +464,10 @@ setPop(
        if (time == 0 || time == EndOfAllTime ) {
                time = EndOfAllTime;
                now = 0;
-               pop = rtc_timer->set(0, 0);
+               pop = rtc_timer->rtc_set(0, 0);
        } else {
                now = rtc_nanotime_read();      /* The time in nanoseconds */
-               pop = rtc_timer->set(time, now);
+               pop = rtc_timer->rtc_set(time, now);
        }
 
        /* Record requested and actual deadlines set */
@@ -548,6 +483,12 @@ mach_absolute_time(void)
        return rtc_nanotime_read();
 }
 
+uint64_t
+mach_approximate_time(void)
+{
+       return rtc_nanotime_read();
+}
+
 void
 clock_interval_to_absolutetime_interval(
        uint32_t                interval,
@@ -566,15 +507,6 @@ absolutetime_to_microtime(
        _absolutetime_to_microtime(abstime, secs, microsecs);
 }
 
-void
-absolutetime_to_nanotime(
-       uint64_t                        abstime,
-       clock_sec_t                     *secs,
-       clock_nsec_t            *nanosecs)
-{
-       _absolutetime_to_nanotime(abstime, secs, nanosecs);
-}
-
 void
 nanotime_to_absolutetime(
        clock_sec_t                     secs,
@@ -602,12 +534,11 @@ nanoseconds_to_absolutetime(
 
 void
 machine_delay_until(
+       uint64_t interval,
        uint64_t                deadline)
 {
-       uint64_t                now;
-
-       do {
+       (void)interval;
+       while (mach_absolute_time() < deadline) {
                cpu_pause();
-               now = mach_absolute_time();
-       } while (now < deadline);
+       } 
 }