]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/ppc/rtclock.c
xnu-792.6.22.tar.gz
[apple/xnu.git] / osfmk / ppc / rtclock.c
index bd97881bd024dff5bebe97bfaa05175988099b41..ecd5ee24f9887a960e3bd520e907e9b9a89c9435 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -44,6 +44,8 @@
 #include <machine/machine_routines.h>
 #include <ppc/exception.h>
 #include <ppc/proc_reg.h>
+#include <ppc/pms.h>
+#include <ppc/rtclock.h>
 
 #include <IOKit/IOPlatformExpert.h>
 
@@ -53,8 +55,6 @@ int           sysclk_config(void);
 
 int            sysclk_init(void);
 
-void treqs(uint32_t dec);
-
 kern_return_t  sysclk_gettime(
        mach_timespec_t                 *cur_time);
 
@@ -140,21 +140,12 @@ static void               nanotime_to_absolutetime(
                                        uint32_t                nanosecs,
                                        uint64_t                *result);
 
-static int             deadline_to_decrementer(
-                                       uint64_t                deadline,
-                                       uint64_t                now);
-
 static void            rtclock_alarm_expire(
                                        timer_call_param_t              p0,
                                        timer_call_param_t              p1);
 
 /* global data declarations */
 
-#define DECREMENTER_MAX                0x7FFFFFFFUL
-#define DECREMENTER_MIN                0xAUL
-
-natural_t              rtclock_decrementer_min;
-
 decl_simple_lock_data(static,rtclock_lock)
 
 /*
@@ -234,28 +225,16 @@ sysclk_config(void)
 int
 sysclk_init(void)
 {
-       uint64_t                                abstime, nexttick;
-       int                                             decr1, decr2;
-       struct rtclock_timer    *mytimer;
+       uint64_t                                abstime;
        struct per_proc_info    *pp;
 
-       decr1 = decr2 = DECREMENTER_MAX;
-
        pp = getPerProc();
-       mytimer = &pp->rtclock_timer;
 
        abstime = mach_absolute_time();
-       nexttick = abstime + rtclock_tick_interval;
-       pp->rtclock_tick_deadline = nexttick;
-       decr1 = deadline_to_decrementer(nexttick, abstime);
-
-       if (mytimer->is_set)
-               decr2 = deadline_to_decrementer(mytimer->deadline, abstime);
-
-       if (decr1 > decr2)
-               decr1 = decr2;
-
-       treqs(decr1);
+       pp->rtclock_tick_deadline = abstime + rtclock_tick_interval;    /* Get the time we need to pop */
+       pp->rtcPop = pp->rtclock_tick_deadline; /* Set the rtc pop time the same for now */
+       
+       (void)setTimerReq();                    /* Start the timers going */
 
        return (1);
 }
@@ -595,6 +574,43 @@ clock_set_calendar_microtime(
 
     commpage_set_timestamp(0,0,0,0);
 
+       /*
+        *      Cancel any adjustment in progress.
+        */
+       if (rtclock_calend.adjdelta < 0) {
+               uint64_t        now, t64;
+               uint32_t        delta, t32;
+
+               delta = -rtclock_calend.adjdelta;
+
+               sys = rtclock_calend.epoch;
+               microsys = rtclock_calend.microepoch;
+
+               now = mach_absolute_time();
+
+               if (now > rtclock_calend.epoch1)
+                       t64 = now - rtclock_calend.epoch1;
+               else
+                       t64 = 0;
+
+               t32 = (t64 * USEC_PER_SEC) / rtclock_sec_divisor;
+
+               if (t32 > delta)
+                       TIME_ADD(sys, 0, microsys, (t32 - delta), USEC_PER_SEC);
+
+               rtclock_calend.epoch = sys;
+               rtclock_calend.microepoch = microsys;
+
+               sys = t64 = now / rtclock_sec_divisor;
+               now -= (t64 * rtclock_sec_divisor);
+               microsys = (now * USEC_PER_SEC) / rtclock_sec_divisor;
+
+               TIME_SUB(rtclock_calend.epoch, sys, rtclock_calend.microepoch, microsys, USEC_PER_SEC);
+       }
+
+       rtclock_calend.epoch1 = 0;
+       rtclock_calend.adjdelta = rtclock_calend.adjtotal = 0;
+
        /*
         *      Calculate the new calendar epoch based on
         *      the new value and the system clock.
@@ -613,12 +629,6 @@ clock_set_calendar_microtime(
        rtclock_calend.epoch = secs;
        rtclock_calend.microepoch = microsecs;
 
-       /*
-        *      Cancel any adjustment in progress.
-        */
-       rtclock_calend.epoch1 = 0;
-       rtclock_calend.adjdelta = rtclock_calend.adjtotal = 0;
-
        simple_unlock(&rtclock_lock);
 
        /*
@@ -877,9 +887,9 @@ void
 clock_set_timer_deadline(
        uint64_t                                deadline)
 {
-       uint64_t                                abstime;
        int                                             decr;
-       struct rtclock_timer    *mytimer;
+       uint64_t                                abstime;
+       rtclock_timer_t                 *mytimer;
        struct per_proc_info    *pp;
        spl_t                                   s;
 
@@ -887,21 +897,15 @@ clock_set_timer_deadline(
        pp = getPerProc();
        mytimer = &pp->rtclock_timer;
        mytimer->deadline = deadline;
-       mytimer->is_set = TRUE;
-       if (!mytimer->has_expired) {
-               abstime = mach_absolute_time();
-               if (    mytimer->deadline < pp->rtclock_tick_deadline                   ) {
-                       decr = deadline_to_decrementer(mytimer->deadline, abstime);
-                       if (    rtclock_decrementer_min != 0                            &&
-                                       rtclock_decrementer_min < (natural_t)decr               )
-                               decr = rtclock_decrementer_min;
-
-                       treqs(decr);
-
-                       KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 1)
-                                                                               | DBG_FUNC_NONE, decr, 2, 0, 0, 0);
-               }
+
+       if (!mytimer->has_expired && (deadline < pp->rtclock_tick_deadline)) {          /* Has the timer already expired or is less that set? */
+               pp->rtcPop = deadline;                  /* Yes, set the new rtc pop time */
+               decr = setTimerReq();                   /* Start the timers going */
+
+               KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 1)
+                                                                       | DBG_FUNC_NONE, decr, 2, 0, 0, 0);
        }
+
        splx(s);
 }
 
@@ -917,64 +921,67 @@ clock_set_timer_func(
        UNLOCK_RTC(s);
 }
 
-void
-rtclock_intr(
-       int                                     device,
-       struct savearea         *ssp,
-       spl_t                           old);
-
 /*
  * Real-time clock device interrupt.
  */
 void
-rtclock_intr(
-       __unused int                    device,
-       struct savearea                 *ssp,
-       __unused spl_t                  old_spl)
-{
+rtclock_intr(struct savearea *ssp) {
+       
        uint64_t                                abstime;
-       int                                             decr1, decr2;
-       struct rtclock_timer    *mytimer;
+       int                                             decr;
+       rtclock_timer_t                 *mytimer;
        struct per_proc_info    *pp;
 
-       decr1 = decr2 = DECREMENTER_MAX;
-
        pp = getPerProc();
+       mytimer = &pp->rtclock_timer;
 
        abstime = mach_absolute_time();
-       if (    pp->rtclock_tick_deadline <= abstime            ) {
+       if (pp->rtclock_tick_deadline <= abstime) {     /* Have we passed the pop time? */
                clock_deadline_for_periodic_event(rtclock_tick_interval, abstime,
                                                                                                &pp->rtclock_tick_deadline);
                hertz_tick(USER_MODE(ssp->save_srr1), ssp->save_srr0);
+               abstime = mach_absolute_time();                 /* Refresh the current time since we went away */
        }
 
-       mytimer = &pp->rtclock_timer;
-
-       abstime = mach_absolute_time();
-       if (    mytimer->is_set                                 &&
-                       mytimer->deadline <= abstime            ) {
-               mytimer->has_expired = TRUE; mytimer->is_set = FALSE;
-               (*rtclock_timer_expire)(abstime);
+       if (mytimer->deadline <= abstime) {                     /* Have we expired the deadline? */
+               mytimer->has_expired = TRUE;                    /* Remember that we popped */
+               mytimer->deadline = EndOfAllTime;               /* Set timer request to the end of all time in case we have no more events */
+               (*rtclock_timer_expire)(abstime);               /* Process pop */
                mytimer->has_expired = FALSE;
        }
 
-       abstime = mach_absolute_time();
-       decr1 = deadline_to_decrementer(pp->rtclock_tick_deadline, abstime);
+       pp->rtcPop = (pp->rtclock_tick_deadline < mytimer->deadline) ?  /* Get shortest pop */
+               pp->rtclock_tick_deadline :                             /* It was the periodic timer */
+               mytimer->deadline;                                              /* Actually, an event request */
+       
+       decr = setTimerReq();                                           /* Request the timer pop */
 
-       if (mytimer->is_set)
-               decr2 = deadline_to_decrementer(mytimer->deadline, abstime);
+       KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 1)
+                                                 | DBG_FUNC_NONE, decr, 3, 0, 0, 0);
+}
 
-       if (decr1 > decr2)
-               decr1 = decr2;
+/*
+ *     Request an interruption at a specific time 
+ *
+ *     Sets the decrementer to pop at the right time based on the timebase.
+ *     The value is chosen by comparing the rtc request with the power management.
+ *     request.  We may add other values at a future time.
+ *
+ */
+int setTimerReq(void) {
 
-       if (    rtclock_decrementer_min != 0                                    &&
-                       rtclock_decrementer_min < (natural_t)decr1              )
-               decr1 = rtclock_decrementer_min;
+       struct per_proc_info *pp;
+       int decr;
+       uint64_t nexttime;
+       
+       pp = getPerProc();                                                      /* Get per_proc */
 
-       treqs(decr1);
+       nexttime = pp->rtcPop;                                          /* Assume main timer */
 
-       KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 1)
-                                                 | DBG_FUNC_NONE, decr1, 3, 0, 0, 0);
+       decr = setPop((pp->pms.pmsPop < nexttime) ? pp->pms.pmsPop : nexttime); /* Schedule timer pop */
+
+       return decr;                                                            /* Pass back what we actually set */
 }
 
 static void
@@ -989,22 +996,6 @@ rtclock_alarm_expire(
        clock_alarm_intr(SYSTEM_CLOCK, &timestamp);
 }
 
-static int
-deadline_to_decrementer(
-       uint64_t                deadline,
-       uint64_t                now)
-{
-       uint64_t                delt;
-
-       if (deadline <= now)
-               return DECREMENTER_MIN;
-       else {
-               delt = deadline - now;
-               return (delt >= (DECREMENTER_MAX + 1))? DECREMENTER_MAX:
-                               ((delt >= (DECREMENTER_MIN + 1))? (delt - 1): DECREMENTER_MIN);
-       }
-}
-
 static void
 nanotime_to_absolutetime(
        uint32_t                        secs,
@@ -1110,23 +1101,3 @@ machine_delay_until(
        } while (now < deadline);
 }
 
-/*
- *     Request a decrementer pop
- *
- */
-
-void treqs(uint32_t dec) {
-
-
-       struct per_proc_info *pp;
-       uint64_t nowtime, newtime;
-       
-       nowtime = mach_absolute_time();                                         /* What time is it? */
-       pp = getPerProc();                                                                      /* Get our processor block */
-       newtime = nowtime + (uint64_t)dec;                                      /* Get requested pop time */
-       pp->rtcPop = newtime;                                                           /* Copy it */
-       
-       mtdec((uint32_t)(newtime - nowtime));                           /* Set decrementer */
-       return;
-
-}