/*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
*
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
*
- * @APPLE_LICENSE_HEADER_END@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
* @OSF_COPYRIGHT@
#include <kern/clock.h>
#include <kern/thread.h>
+#include <kern/processor.h>
#include <kern/macro_help.h>
#include <kern/spl.h>
+#include <kern/pms.h>
-#include <kern/host_notify.h>
-
-#include <machine/mach_param.h> /* HZ */
#include <machine/commpage.h>
#include <machine/machine_routines.h>
#include <ppc/exception.h>
#include <ppc/proc_reg.h>
-
-#include <pexpert/pexpert.h>
+#include <ppc/rtclock.h>
#include <sys/kdebug.h>
-int sysclk_config(void);
-
-int sysclk_init(void);
-
-void treqs(uint32_t dec);
-
-kern_return_t sysclk_gettime(
- mach_timespec_t *cur_time);
-
-kern_return_t sysclk_getattr(
- clock_flavor_t flavor,
- clock_attr_t attr,
- mach_msg_type_number_t *count);
-
-void sysclk_setalarm(
- mach_timespec_t *deadline);
-
-struct clock_ops sysclk_ops = {
- sysclk_config, sysclk_init,
- sysclk_gettime, 0,
- sysclk_getattr, 0,
- sysclk_setalarm,
-};
-
-int calend_config(void);
-
-int calend_init(void);
-
-kern_return_t calend_gettime(
- mach_timespec_t *cur_time);
+int rtclock_config(void);
-kern_return_t calend_getattr(
- clock_flavor_t flavor,
- clock_attr_t attr,
- mach_msg_type_number_t *count);
+int rtclock_init(void);
-struct clock_ops calend_ops = {
- calend_config, calend_init,
- calend_gettime, 0,
- calend_getattr, 0,
- 0,
-};
-
-/* local data declarations */
-
-static struct rtclock_calend {
- uint32_t epoch;
- uint32_t microepoch;
-
- uint64_t epoch1;
-
- int64_t adjtotal;
- int32_t adjdelta;
-} rtclock_calend;
-
-static boolean_t rtclock_initialized;
-
-static uint64_t rtclock_tick_deadline[NCPUS];
-
-#define NSEC_PER_HZ (NSEC_PER_SEC / HZ)
-static uint32_t rtclock_tick_interval;
+#define NSEC_PER_HZ (NSEC_PER_SEC / 100)
static uint32_t rtclock_sec_divisor;
static boolean_t rtclock_timebase_initialized;
-static struct rtclock_timer {
- uint64_t deadline;
- uint32_t
- /*boolean_t*/ is_set:1,
- has_expired:1,
- :0;
-} rtclock_timer[NCPUS];
-
-static clock_timer_func_t rtclock_timer_expire;
-
-static timer_call_data_t rtclock_alarm_timer;
-
-static void timespec_to_absolutetime(
- mach_timespec_t *ts,
- 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;
+/* XXX this should really be in a header somewhere */
+extern clock_timer_func_t rtclock_timer_expire;
decl_simple_lock_data(static,rtclock_lock)
struct timebase_freq_t *freq)
{
uint32_t numer, denom;
- uint64_t abstime;
spl_t s;
if ( freq->timebase_den < 1 || freq->timebase_den > 4 ||
freq->timebase_num < freq->timebase_den )
- panic("rtclock timebase_callback: invalid constant %d / %d",
+ panic("rtclock timebase_callback: invalid constant %lu / %lu",
freq->timebase_num, freq->timebase_den);
denom = freq->timebase_num;
LOCK_RTC(s);
if (!rtclock_timebase_initialized) {
- commpage_set_timestamp(0,0,0,0);
+ commpage_set_timestamp(0,0,0);
rtclock_timebase_const.numer = numer;
rtclock_timebase_const.denom = denom;
rtclock_sec_divisor = freq->timebase_num / freq->timebase_den;
- nanoseconds_to_absolutetime(NSEC_PER_HZ, &abstime);
- rtclock_tick_interval = abstime;
-
ml_init_lock_timeout();
}
else {
UNLOCK_RTC(s);
- printf("rtclock timebase_callback: late old %d / %d new %d / %d",
+ printf("rtclock timebase_callback: late old %d / %d new %d / %d\n",
rtclock_timebase_const.numer, rtclock_timebase_const.denom,
numer, denom);
return;
}
/*
- * Configure the real-time clock device.
+ * Configure the system clock device.
*/
int
-sysclk_config(void)
+rtclock_config(void)
{
- if (cpu_number() != master_cpu)
- return(1);
-
- timer_call_setup(&rtclock_alarm_timer, rtclock_alarm_expire, NULL);
-
- simple_lock_init(&rtclock_lock, ETAP_MISC_RT_CLOCK);
+ simple_lock_init(&rtclock_lock, 0);
PE_register_timebase_callback(timebase_callback);
* Initialize the system clock device.
*/
int
-sysclk_init(void)
+rtclock_init(void)
{
- uint64_t abstime;
- int decr, mycpu = cpu_number();
-
- if (mycpu != master_cpu) {
- if (rtclock_initialized == FALSE) {
- panic("sysclk_init on cpu %d, rtc not initialized\n", mycpu);
- }
- /* Set decrementer and hence our next tick due */
- abstime = mach_absolute_time();
- rtclock_tick_deadline[mycpu] = abstime;
- rtclock_tick_deadline[mycpu] += rtclock_tick_interval;
- decr = deadline_to_decrementer(rtclock_tick_deadline[mycpu], abstime);
- treqs(decr);
-
- return(1);
- }
-
- /* Set decrementer and our next tick due */
- abstime = mach_absolute_time();
- rtclock_tick_deadline[mycpu] = abstime;
- rtclock_tick_deadline[mycpu] += rtclock_tick_interval;
- decr = deadline_to_decrementer(rtclock_tick_deadline[mycpu], abstime);
- treqs(decr);
-
- rtclock_initialized = TRUE;
+ etimer_resync_deadlines(); /* Start the timers going */
return (1);
}
-kern_return_t
-sysclk_gettime(
- mach_timespec_t *time) /* OUT */
-{
- uint64_t now, t64;
- uint32_t divisor;
-
- now = mach_absolute_time();
-
- time->tv_sec = t64 = now / (divisor = rtclock_sec_divisor);
- now -= (t64 * divisor);
- time->tv_nsec = (now * NSEC_PER_SEC) / divisor;
-
- return (KERN_SUCCESS);
-}
-
void
clock_get_system_microtime(
uint32_t *secs,
*nanosecs = (now * NSEC_PER_SEC) / divisor;
}
-/*
- * Get clock device attributes.
- */
-kern_return_t
-sysclk_getattr(
- clock_flavor_t flavor,
- clock_attr_t attr, /* OUT */
- mach_msg_type_number_t *count) /* IN/OUT */
-{
- spl_t s;
-
- if (*count != 1)
- return (KERN_FAILURE);
-
- switch (flavor) {
-
- case CLOCK_GET_TIME_RES: /* >0 res */
- case CLOCK_ALARM_CURRES: /* =0 no alarm */
- case CLOCK_ALARM_MINRES:
- case CLOCK_ALARM_MAXRES:
- LOCK_RTC(s);
- *(clock_res_t *) attr = NSEC_PER_HZ;
- UNLOCK_RTC(s);
- break;
-
- default:
- return (KERN_INVALID_VALUE);
- }
-
- return (KERN_SUCCESS);
-}
-
-/*
- * Set deadline for the next alarm on the clock device. This call
- * always resets the time to deliver an alarm for the clock.
- */
-void
-sysclk_setalarm(
- mach_timespec_t *deadline)
-{
- uint64_t abstime;
-
- timespec_to_absolutetime(deadline, &abstime);
- timer_call_enter(&rtclock_alarm_timer, abstime);
-}
-
-/*
- * Configure the calendar clock.
- */
-int
-calend_config(void)
-{
- return (1);
-}
-
-/*
- * Initialize the calendar clock.
- */
-int
-calend_init(void)
-{
- if (cpu_number() != master_cpu)
- return(1);
-
- return (1);
-}
-
-/*
- * Get the current clock time.
- */
-kern_return_t
-calend_gettime(
- mach_timespec_t *time) /* OUT */
-{
- clock_get_calendar_nanotime(
- &time->tv_sec, &time->tv_nsec);
-
- return (KERN_SUCCESS);
-}
-
-/*
- * Get clock device attributes.
- */
-kern_return_t
-calend_getattr(
- clock_flavor_t flavor,
- clock_attr_t attr, /* OUT */
- mach_msg_type_number_t *count) /* IN/OUT */
-{
- spl_t s;
-
- if (*count != 1)
- return (KERN_FAILURE);
-
- switch (flavor) {
-
- case CLOCK_GET_TIME_RES: /* >0 res */
- LOCK_RTC(s);
- *(clock_res_t *) attr = NSEC_PER_HZ;
- UNLOCK_RTC(s);
- break;
-
- case CLOCK_ALARM_CURRES: /* =0 no alarm */
- case CLOCK_ALARM_MINRES:
- case CLOCK_ALARM_MAXRES:
- *(clock_res_t *) attr = 0;
- break;
-
- default:
- return (KERN_INVALID_VALUE);
- }
-
- return (KERN_SUCCESS);
-}
-
-void
-clock_get_calendar_microtime(
- uint32_t *secs,
- uint32_t *microsecs)
-{
- uint32_t epoch, microepoch;
- uint64_t now, t64;
- spl_t s = splclock();
-
- simple_lock(&rtclock_lock);
-
- if (rtclock_calend.adjdelta >= 0) {
- uint32_t divisor;
-
- now = mach_absolute_time();
-
- epoch = rtclock_calend.epoch;
- microepoch = rtclock_calend.microepoch;
-
- simple_unlock(&rtclock_lock);
-
- *secs = t64 = now / (divisor = rtclock_sec_divisor);
- now -= (t64 * divisor);
- *microsecs = (now * USEC_PER_SEC) / divisor;
-
- if ((*microsecs += microepoch) >= USEC_PER_SEC) {
- *microsecs -= USEC_PER_SEC;
- epoch += 1;
- }
-
- *secs += epoch;
- }
- else {
- uint32_t delta, t32;
-
- delta = -rtclock_calend.adjdelta;
-
- now = mach_absolute_time();
-
- *secs = rtclock_calend.epoch;
- *microsecs = rtclock_calend.microepoch;
-
- if (now > rtclock_calend.epoch1) {
- t64 = now - rtclock_calend.epoch1;
-
- t32 = (t64 * USEC_PER_SEC) / rtclock_sec_divisor;
-
- if (t32 > delta)
- *microsecs += (t32 - delta);
-
- if (*microsecs >= USEC_PER_SEC) {
- *microsecs -= USEC_PER_SEC;
- *secs += 1;
- }
- }
-
- simple_unlock(&rtclock_lock);
- }
-
- splx(s);
-}
-
-/* This is only called from the gettimeofday() syscall. As a side
- * effect, it updates the commpage timestamp. Otherwise it is
- * identical to clock_get_calendar_microtime(). Because most
- * gettimeofday() calls are handled by the commpage in user mode,
- * this routine should be infrequently used except when slowing down
- * the clock.
- */
-void
-clock_gettimeofday(
- uint32_t *secs_p,
- uint32_t *microsecs_p)
-{
- uint32_t epoch, microepoch;
- uint32_t secs, microsecs;
- uint64_t now, t64, secs_64, usec_64;
- spl_t s = splclock();
-
- simple_lock(&rtclock_lock);
-
- if (rtclock_calend.adjdelta >= 0) {
- now = mach_absolute_time();
-
- epoch = rtclock_calend.epoch;
- microepoch = rtclock_calend.microepoch;
-
- secs = secs_64 = now / rtclock_sec_divisor;
- t64 = now - (secs_64 * rtclock_sec_divisor);
- microsecs = usec_64 = (t64 * USEC_PER_SEC) / rtclock_sec_divisor;
-
- if ((microsecs += microepoch) >= USEC_PER_SEC) {
- microsecs -= USEC_PER_SEC;
- epoch += 1;
- }
-
- secs += epoch;
-
- /* adjust "now" to be absolute time at _start_ of usecond */
- now -= t64 - ((usec_64 * rtclock_sec_divisor) / USEC_PER_SEC);
-
- commpage_set_timestamp(now,secs,microsecs,rtclock_sec_divisor);
- }
- else {
- uint32_t delta, t32;
-
- delta = -rtclock_calend.adjdelta;
-
- now = mach_absolute_time();
-
- secs = rtclock_calend.epoch;
- microsecs = rtclock_calend.microepoch;
-
- if (now > rtclock_calend.epoch1) {
- t64 = now - rtclock_calend.epoch1;
-
- t32 = (t64 * USEC_PER_SEC) / rtclock_sec_divisor;
-
- if (t32 > delta)
- microsecs += (t32 - delta);
-
- if (microsecs >= USEC_PER_SEC) {
- microsecs -= USEC_PER_SEC;
- secs += 1;
- }
- }
-
- /* no need to disable timestamp, it is already off */
- }
-
- simple_unlock(&rtclock_lock);
- splx(s);
-
- *secs_p = secs;
- *microsecs_p = microsecs;
-}
-
void
-clock_get_calendar_nanotime(
- uint32_t *secs,
- uint32_t *nanosecs)
+clock_gettimeofday_set_commpage(
+ uint64_t abstime,
+ uint64_t epoch,
+ uint64_t offset,
+ uint32_t *secs,
+ uint32_t *microsecs)
{
- uint32_t epoch, nanoepoch;
- uint64_t now, t64;
- spl_t s = splclock();
+ uint64_t t64, now = abstime;
simple_lock(&rtclock_lock);
- if (rtclock_calend.adjdelta >= 0) {
- uint32_t divisor;
-
- now = mach_absolute_time();
-
- epoch = rtclock_calend.epoch;
- nanoepoch = rtclock_calend.microepoch * NSEC_PER_USEC;
-
- simple_unlock(&rtclock_lock);
-
- *secs = t64 = now / (divisor = rtclock_sec_divisor);
- now -= (t64 * divisor);
- *nanosecs = ((now * USEC_PER_SEC) / divisor) * NSEC_PER_USEC;
-
- if ((*nanosecs += nanoepoch) >= NSEC_PER_SEC) {
- *nanosecs -= NSEC_PER_SEC;
- epoch += 1;
- }
-
- *secs += epoch;
- }
- else {
- uint32_t delta, t32;
-
- delta = -rtclock_calend.adjdelta;
-
- now = mach_absolute_time();
-
- *secs = rtclock_calend.epoch;
- *nanosecs = rtclock_calend.microepoch * NSEC_PER_USEC;
-
- if (now > rtclock_calend.epoch1) {
- t64 = now - rtclock_calend.epoch1;
-
- t32 = (t64 * USEC_PER_SEC) / rtclock_sec_divisor;
-
- if (t32 > delta)
- *nanosecs += ((t32 - delta) * NSEC_PER_USEC);
-
- if (*nanosecs >= NSEC_PER_SEC) {
- *nanosecs -= NSEC_PER_SEC;
- *secs += 1;
- }
- }
-
- simple_unlock(&rtclock_lock);
- }
-
- splx(s);
-}
-
-void
-clock_set_calendar_microtime(
- uint32_t secs,
- uint32_t microsecs)
-{
- uint32_t sys, microsys;
- uint32_t newsecs;
- spl_t s;
-
- newsecs = (microsecs < 500*USEC_PER_SEC)?
- secs: secs + 1;
-
- LOCK_RTC(s);
- commpage_set_timestamp(0,0,0,0);
-
- clock_get_system_microtime(&sys, µsys);
- if ((int32_t)(microsecs -= microsys) < 0) {
- microsecs += USEC_PER_SEC;
- secs -= 1;
- }
-
- secs -= sys;
-
- rtclock_calend.epoch = secs;
- rtclock_calend.microepoch = microsecs;
- rtclock_calend.epoch1 = 0;
- rtclock_calend.adjdelta = rtclock_calend.adjtotal = 0;
- UNLOCK_RTC(s);
-
- PESetGMTTimeOfDay(newsecs);
-
- host_notify_calendar_change();
-}
-
-#define tickadj (40) /* "standard" skew, us / tick */
-#define bigadj (USEC_PER_SEC) /* use 10x skew above bigadj us */
-
-uint32_t
-clock_set_calendar_adjtime(
- int32_t *secs,
- int32_t *microsecs)
-{
- int64_t total, ototal;
- uint32_t interval = 0;
- spl_t s;
-
- total = (int64_t)*secs * USEC_PER_SEC + *microsecs;
-
- LOCK_RTC(s);
- commpage_set_timestamp(0,0,0,0);
-
- ototal = rtclock_calend.adjtotal;
-
- if (rtclock_calend.adjdelta < 0) {
- uint64_t now, t64;
- uint32_t delta, t32;
- uint32_t sys, microsys;
-
- 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)
- microsys += (t32 - delta);
-
- if (microsys >= USEC_PER_SEC) {
- microsys -= USEC_PER_SEC;
- sys += 1;
- }
-
- 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;
-
- if ((int32_t)(rtclock_calend.microepoch -= microsys) < 0) {
- rtclock_calend.microepoch += USEC_PER_SEC;
- sys += 1;
- }
-
- rtclock_calend.epoch -= sys;
- }
-
- if (total != 0) {
- int32_t delta = tickadj;
-
- if (total > 0) {
- if (total > bigadj)
- delta *= 10;
- if (delta > total)
- delta = total;
-
- rtclock_calend.epoch1 = 0;
- }
- else {
- uint64_t now, t64;
- uint32_t sys, microsys;
-
- if (total < -bigadj)
- delta *= 10;
- delta = -delta;
- if (delta < total)
- delta = total;
-
- rtclock_calend.epoch1 = now = mach_absolute_time();
-
- sys = t64 = now / rtclock_sec_divisor;
- now -= (t64 * rtclock_sec_divisor);
- microsys = (now * USEC_PER_SEC) / rtclock_sec_divisor;
-
- if ((rtclock_calend.microepoch += microsys) >= USEC_PER_SEC) {
- rtclock_calend.microepoch -= USEC_PER_SEC;
- sys += 1;
- }
-
- rtclock_calend.epoch += sys;
- }
-
- rtclock_calend.adjtotal = total;
- rtclock_calend.adjdelta = delta;
-
- interval = rtclock_tick_interval;
- }
- else {
- rtclock_calend.epoch1 = 0;
- rtclock_calend.adjdelta = rtclock_calend.adjtotal = 0;
- }
-
- UNLOCK_RTC(s);
-
- if (ototal == 0)
- *secs = *microsecs = 0;
- else {
- *secs = ototal / USEC_PER_SEC;
- *microsecs = ototal % USEC_PER_SEC;
- }
-
- return (interval);
-}
-
-uint32_t
-clock_adjust_calendar(void)
-{
- uint32_t micronew, interval = 0;
- int32_t delta;
- spl_t s;
+ now += offset;
- LOCK_RTC(s);
- commpage_set_timestamp(0,0,0,0);
-
- delta = rtclock_calend.adjdelta;
-
- if (delta > 0) {
- micronew = rtclock_calend.microepoch + delta;
- if (micronew >= USEC_PER_SEC) {
- micronew -= USEC_PER_SEC;
- rtclock_calend.epoch += 1;
- }
-
- rtclock_calend.microepoch = micronew;
-
- rtclock_calend.adjtotal -= delta;
- if (delta > rtclock_calend.adjtotal)
- rtclock_calend.adjdelta = rtclock_calend.adjtotal;
- }
- else
- if (delta < 0) {
- uint64_t now, t64;
- uint32_t t32;
-
- now = mach_absolute_time();
-
- if (now > rtclock_calend.epoch1)
- t64 = now - rtclock_calend.epoch1;
- else
- t64 = 0;
-
- rtclock_calend.epoch1 = now;
-
- t32 = (t64 * USEC_PER_SEC) / rtclock_sec_divisor;
-
- micronew = rtclock_calend.microepoch + t32 + delta;
- if (micronew >= USEC_PER_SEC) {
- micronew -= USEC_PER_SEC;
- rtclock_calend.epoch += 1;
- }
+ *secs = t64 = now / rtclock_sec_divisor;
+ now -= (t64 * rtclock_sec_divisor);
+ *microsecs = (now * USEC_PER_SEC) / rtclock_sec_divisor;
- rtclock_calend.microepoch = micronew;
+ *secs += epoch;
- rtclock_calend.adjtotal -= delta;
- if (delta < rtclock_calend.adjtotal)
- rtclock_calend.adjdelta = rtclock_calend.adjtotal;
+ commpage_set_timestamp(abstime - now, *secs, rtclock_sec_divisor);
- if (rtclock_calend.adjdelta == 0) {
- uint32_t sys, microsys;
-
- sys = t64 = now / rtclock_sec_divisor;
- now -= (t64 * rtclock_sec_divisor);
- microsys = (now * USEC_PER_SEC) / rtclock_sec_divisor;
-
- if ((int32_t)(rtclock_calend.microepoch -= microsys) < 0) {
- rtclock_calend.microepoch += USEC_PER_SEC;
- sys += 1;
- }
-
- rtclock_calend.epoch -= sys;
-
- rtclock_calend.epoch1 = 0;
- }
- }
-
- if (rtclock_calend.adjdelta != 0)
- interval = rtclock_tick_interval;
-
- UNLOCK_RTC(s);
-
- return (interval);
-}
-
-void
-clock_initialize_calendar(void)
-{
- uint32_t sys, microsys;
- uint32_t microsecs = 0, secs = PEGetGMTTimeOfDay();
- spl_t s;
-
- LOCK_RTC(s);
- commpage_set_timestamp(0,0,0,0);
-
- clock_get_system_microtime(&sys, µsys);
- if ((int32_t)(microsecs -= microsys) < 0) {
- microsecs += USEC_PER_SEC;
- secs -= 1;
- }
-
- secs -= sys;
-
- rtclock_calend.epoch = secs;
- rtclock_calend.microepoch = microsecs;
- rtclock_calend.epoch1 = 0;
- rtclock_calend.adjdelta = rtclock_calend.adjtotal = 0;
- UNLOCK_RTC(s);
-
- host_notify_calendar_change();
+ simple_unlock(&rtclock_lock);
}
void
spl_t s;
LOCK_RTC(s);
- rtclock_timebase_initialized = TRUE;
*info = rtclock_timebase_const;
+ rtclock_timebase_initialized = TRUE;
UNLOCK_RTC(s);
}
-void
-clock_set_timer_deadline(
- uint64_t deadline)
-{
- uint64_t abstime;
- int decr, mycpu;
- struct rtclock_timer *mytimer;
- spl_t s;
-
- s = splclock();
- mycpu = cpu_number();
- mytimer = &rtclock_timer[mycpu];
- mytimer->deadline = deadline;
- mytimer->is_set = TRUE;
- if (!mytimer->has_expired) {
- abstime = mach_absolute_time();
- if ( mytimer->deadline < rtclock_tick_deadline[mycpu] ) {
- 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);
- }
- }
- splx(s);
-}
-
void
clock_set_timer_func(
clock_timer_func_t func)
UNLOCK_RTC(s);
}
-/*
- * Reset the clock device. This causes the realtime clock
- * device to reload its mode and count value (frequency).
- */
-void
-rtclock_reset(void)
-{
- return;
-}
-
-/*
- * Real-time clock device interrupt.
- */
-void
-rtclock_intr(
- int device,
- struct savearea *ssp,
- spl_t old_spl)
-{
- uint64_t abstime;
- int decr1, decr2, mycpu = cpu_number();
- struct rtclock_timer *mytimer = &rtclock_timer[mycpu];
-
- /*
- * We may receive interrupts too early, we must reject them.
- */
- if (rtclock_initialized == FALSE) {
- treqs(DECREMENTER_MAX); /* Max the decrementer if not init */
- return;
- }
-
- decr1 = decr2 = DECREMENTER_MAX;
-
- abstime = mach_absolute_time();
- if ( rtclock_tick_deadline[mycpu] <= abstime ) {
- clock_deadline_for_periodic_event(rtclock_tick_interval, abstime,
- &rtclock_tick_deadline[mycpu]);
- hertz_tick(USER_MODE(ssp->save_srr1), ssp->save_srr0);
- }
-
- abstime = mach_absolute_time();
- if ( mytimer->is_set &&
- mytimer->deadline <= abstime ) {
- mytimer->has_expired = TRUE; mytimer->is_set = FALSE;
- (*rtclock_timer_expire)(abstime);
- mytimer->has_expired = FALSE;
- }
-
- abstime = mach_absolute_time();
- decr1 = deadline_to_decrementer(rtclock_tick_deadline[mycpu], abstime);
-
- if (mytimer->is_set)
- decr2 = deadline_to_decrementer(mytimer->deadline, abstime);
-
- if (decr1 > decr2)
- decr1 = decr2;
-
- if ( rtclock_decrementer_min != 0 &&
- rtclock_decrementer_min < (natural_t)decr1 )
- decr1 = rtclock_decrementer_min;
-
- treqs(decr1);
-
- KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 1)
- | DBG_FUNC_NONE, decr1, 3, 0, 0, 0);
-}
-
-static void
-rtclock_alarm_expire(
- timer_call_param_t p0,
- timer_call_param_t p1)
-{
- mach_timespec_t timestamp;
-
- (void) sysclk_gettime(×tamp);
-
- clock_alarm_intr(SYSTEM_CLOCK, ×tamp);
-}
-
-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
-timespec_to_absolutetime(
- mach_timespec_t *ts,
- uint64_t *result)
-{
- uint32_t divisor;
-
- *result = ((uint64_t)ts->tv_sec * (divisor = rtclock_sec_divisor)) +
- ((uint64_t)ts->tv_nsec * divisor) / NSEC_PER_SEC;
-}
-
-void
-clock_interval_to_deadline(
- uint32_t interval,
- uint32_t scale_factor,
- uint64_t *result)
-{
- uint64_t abstime;
-
- clock_get_uptime(result);
-
- clock_interval_to_absolutetime_interval(interval, scale_factor, &abstime);
-
- *result += abstime;
-}
-
void
clock_interval_to_absolutetime_interval(
uint32_t interval,
}
void
-clock_absolutetime_interval_to_deadline(
+absolutetime_to_microtime(
+ uint64_t abstime,
+ uint32_t *secs,
+ uint32_t *microsecs)
+{
+ uint64_t t64;
+ uint32_t divisor;
+
+ *secs = t64 = abstime / (divisor = rtclock_sec_divisor);
+ abstime -= (t64 * divisor);
+ *microsecs = (abstime * USEC_PER_SEC) / divisor;
+}
+
+void
+absolutetime_to_nanotime(
uint64_t abstime,
+ uint32_t *secs,
+ uint32_t *nanosecs)
+{
+ uint64_t t64;
+ uint32_t divisor;
+
+ *secs = t64 = abstime / (divisor = rtclock_sec_divisor);
+ abstime -= (t64 * divisor);
+ *nanosecs = (abstime * NSEC_PER_SEC) / divisor;
+}
+
+void
+nanotime_to_absolutetime(
+ uint32_t secs,
+ uint32_t nanosecs,
uint64_t *result)
{
- clock_get_uptime(result);
+ uint32_t divisor = rtclock_sec_divisor;
- *result += abstime;
+ *result = ((uint64_t)secs * divisor) +
+ ((uint64_t)nanosecs * divisor) / NSEC_PER_SEC;
}
void
*result += (nanosecs * divisor) / NSEC_PER_SEC;
}
-/*
- * Spin-loop delay primitives.
- */
-void
-delay_for_interval(
- uint32_t interval,
- uint32_t scale_factor)
-{
- uint64_t now, end;
-
- clock_interval_to_deadline(interval, scale_factor, &end);
-
- do {
- now = mach_absolute_time();
- } while (now < end);
-}
-
void
-clock_delay_until(
+machine_delay_until(
uint64_t deadline)
{
uint64_t now;
now = mach_absolute_time();
} while (now < deadline);
}
-
-void
-delay(
- int usec)
-{
- delay_for_interval((usec < 0)? -usec: usec, NSEC_PER_USEC);
-}
-
-/*
- * 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;
-
-}