X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..4a3eedf9ecc9bbe3f3a5c6ce5e53ad199d639d32:/osfmk/ppc/rtclock.c?ds=sidebyside diff --git a/osfmk/ppc/rtclock.c b/osfmk/ppc/rtclock.c index 9ccae5ae7..90a5754ae 100644 --- a/osfmk/ppc/rtclock.c +++ b/osfmk/ppc/rtclock.c @@ -1,23 +1,29 @@ /* - * 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@ @@ -35,119 +41,35 @@ #include #include +#include #include #include +#include -#include /* HZ */ +#include +#include +#include #include - -#include - -/*XXX power management hacks XXX*/ -#include -#include - -extern void *registerSleepWakeInterest( - void *callback, - void *target, - void *refCon); -/*XXX power management hacks XXX*/ +#include #include -int sysclk_config(void); - -int sysclk_init(void); - -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); - -kern_return_t calend_settime( - mach_timespec_t *cur_time); - -kern_return_t calend_getattr( - clock_flavor_t flavor, - clock_attr_t attr, - mach_msg_type_number_t *count); - -struct clock_ops calend_ops = { - calend_config, calend_init, - calend_gettime, calend_settime, - calend_getattr, 0, - 0, -}; - -/* local data declarations */ - -static struct rtclock { - mach_timespec_t calend_offset; - boolean_t calend_is_set; - - mach_timebase_info_data_t timebase_const; - - struct rtclock_timer { - AbsoluteTime deadline; - boolean_t is_set; - } timer[NCPUS]; - - clock_timer_func_t timer_expire; +int rtclock_config(void); - timer_call_data_t alarm[NCPUS]; +int rtclock_init(void); - /* debugging */ - AbsoluteTime last_abstime[NCPUS]; - int last_decr[NCPUS]; +#define NSEC_PER_HZ (NSEC_PER_SEC / 100) - decl_simple_lock_data(,lock) /* real-time clock device lock */ -} rtclock; +static uint32_t rtclock_sec_divisor; -static boolean_t rtclock_initialized; +static mach_timebase_info_data_t rtclock_timebase_const; -static AbsoluteTime rtclock_tick_deadline[NCPUS]; -static AbsoluteTime rtclock_tick_interval; +static boolean_t rtclock_timebase_initialized; -static void timespec_to_absolutetime( - mach_timespec_t timespec, - AbsoluteTime *result); +/* XXX this should really be in a header somewhere */ +extern clock_timer_func_t rtclock_timer_expire; -static int deadline_to_decrementer( - AbsoluteTime deadline, - AbsoluteTime now); - -static void rtclock_alarm_timer( - timer_call_param_t p0, - timer_call_param_t p1); - -/* global data declarations */ - -#define RTC_TICKPERIOD (NSEC_PER_SEC / HZ) - -#define DECREMENTER_MAX 0x7FFFFFFFUL -#define DECREMENTER_MIN 0xAUL - -natural_t rtclock_decrementer_min; +decl_simple_lock_data(static,rtclock_lock) /* * Macros to lock/unlock real-time clock device. @@ -155,12 +77,12 @@ natural_t rtclock_decrementer_min; #define LOCK_RTC(s) \ MACRO_BEGIN \ (s) = splclock(); \ - simple_lock(&rtclock.lock); \ + simple_lock(&rtclock_lock); \ MACRO_END #define UNLOCK_RTC(s) \ MACRO_BEGIN \ - simple_unlock(&rtclock.lock); \ + simple_unlock(&rtclock_lock); \ splx(s); \ MACRO_END @@ -168,626 +90,130 @@ static void timebase_callback( struct timebase_freq_t *freq) { - natural_t numer, denom; - int n; + uint32_t numer, denom; spl_t s; - denom = freq->timebase_num; - n = 9; - while (!(denom % 10)) { - if (n < 1) - break; - denom /= 10; - n--; - } + if ( freq->timebase_den < 1 || freq->timebase_den > 4 || + freq->timebase_num < freq->timebase_den ) + panic("rtclock timebase_callback: invalid constant %lu / %lu", + freq->timebase_num, freq->timebase_den); - numer = freq->timebase_den; - while (n-- > 0) { - numer *= 10; - } + denom = freq->timebase_num; + numer = freq->timebase_den * NSEC_PER_SEC; LOCK_RTC(s); - rtclock.timebase_const.numer = numer; - rtclock.timebase_const.denom = denom; - UNLOCK_RTC(s); -} - -/* - * Configure the real-time clock device. - */ -int -sysclk_config(void) -{ - int i; - - if (cpu_number() != master_cpu) - return(1); - - for (i = 0; i < NCPUS; i++) - timer_call_setup(&rtclock.alarm[i], rtclock_alarm_timer, NULL); - - simple_lock_init(&rtclock.lock, ETAP_MISC_RT_CLOCK); - - PE_register_timebase_callback(timebase_callback); - - return (1); -} - -/* - * Initialize the system clock device. - */ -int -sysclk_init(void) -{ - AbsoluteTime 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 */ - clock_get_uptime(&abstime); - rtclock_tick_deadline[mycpu] = abstime; - ADD_ABSOLUTETIME(&rtclock_tick_deadline[mycpu], - &rtclock_tick_interval); - decr = deadline_to_decrementer(rtclock_tick_deadline[mycpu], abstime); - mtdec(decr); - rtclock.last_decr[mycpu] = decr; - - return(1); - } - - /* - * Initialize non-zero clock structure values. - */ - clock_interval_to_absolutetime_interval(RTC_TICKPERIOD, 1, - &rtclock_tick_interval); - /* Set decrementer and our next tick due */ - clock_get_uptime(&abstime); - rtclock_tick_deadline[mycpu] = abstime; - ADD_ABSOLUTETIME(&rtclock_tick_deadline[mycpu], &rtclock_tick_interval); - decr = deadline_to_decrementer(rtclock_tick_deadline[mycpu], abstime); - mtdec(decr); - rtclock.last_decr[mycpu] = decr; - - rtclock_initialized = TRUE; - - return (1); -} - -/* - * Perform a full 64 bit by 32 bit unsigned multiply, - * yielding a 96 bit product. The most significant - * portion of the product is returned as a 64 bit - * quantity, with the lower portion as a 32 bit word. - */ -static void -umul_64by32( - AbsoluteTime now64, - natural_t mult32, - AbsoluteTime *result64, - natural_t *result32) -{ - natural_t mid, mid2; - - asm volatile(" mullw %0,%1,%2" : - "=r" (*result32) : - "r" (now64.lo), "r" (mult32)); - - asm volatile(" mullw %0,%1,%2" : - "=r" (mid2) : - "r" (now64.hi), "r" (mult32)); - asm volatile(" mulhwu %0,%1,%2" : - "=r" (mid) : - "r" (now64.lo), "r" (mult32)); - - asm volatile(" mulhwu %0,%1,%2" : - "=r" (result64->hi) : - "r" (now64.hi), "r" (mult32)); - - asm volatile(" addc %0,%2,%3; - addze %1,%4" : - "=r" (result64->lo), "=r" (result64->hi) : - "r" (mid), "r" (mid2), "1" (result64->hi)); -} - -/* - * Perform a partial 64 bit by 32 bit unsigned multiply, - * yielding a 64 bit product. Only the least significant - * 64 bits of the product are calculated and returned. - */ -static void -umul_64by32to64( - AbsoluteTime now64, - natural_t mult32, - AbsoluteTime *result64) -{ - natural_t mid, mid2; - - asm volatile(" mullw %0,%1,%2" : - "=r" (result64->lo) : - "r" (now64.lo), "r" (mult32)); - - asm volatile(" mullw %0,%1,%2" : - "=r" (mid2) : - "r" (now64.hi), "r" (mult32)); - asm volatile(" mulhwu %0,%1,%2" : - "=r" (mid) : - "r" (now64.lo), "r" (mult32)); - - asm volatile(" add %0,%1,%2" : - "=r" (result64->hi) : - "r" (mid), "r" (mid2)); -} - -/* - * Perform an unsigned division of a 96 bit value - * by a 32 bit value, yielding a 96 bit quotient. - * The most significant portion of the product is - * returned as a 64 bit quantity, with the lower - * portion as a 32 bit word. - */ -static __inline__ -void -udiv_96by32( - AbsoluteTime now64, - natural_t now32, - natural_t div32, - AbsoluteTime *result64, - natural_t *result32) -{ - AbsoluteTime t64; - - if (now64.hi > 0 || now64.lo >= div32) { - AbsoluteTime_to_scalar(result64) = - AbsoluteTime_to_scalar(&now64) / div32; - - umul_64by32to64(*result64, div32, &t64); - - AbsoluteTime_to_scalar(&t64) = - AbsoluteTime_to_scalar(&now64) - AbsoluteTime_to_scalar(&t64); - - *result32 = (((unsigned long long)t64.lo << 32) | now32) / div32; - } - else { - AbsoluteTime_to_scalar(result64) = - (((unsigned long long)now64.lo << 32) | now32) / div32; - - *result32 = result64->lo; - result64->lo = result64->hi; - result64->hi = 0; - } -} - -/* - * Perform an unsigned division of a 96 bit value - * by a 32 bit value, yielding a 64 bit quotient. - * Any higher order bits of the quotient are simply - * discarded. - */ -static __inline__ -void -udiv_96by32to64( - AbsoluteTime now64, - natural_t now32, - natural_t div32, - AbsoluteTime *result64) -{ - AbsoluteTime t64; - - if (now64.hi > 0 || now64.lo >= div32) { - AbsoluteTime_to_scalar(result64) = - AbsoluteTime_to_scalar(&now64) / div32; - - umul_64by32to64(*result64, div32, &t64); - - AbsoluteTime_to_scalar(&t64) = - AbsoluteTime_to_scalar(&now64) - AbsoluteTime_to_scalar(&t64); + if (!rtclock_timebase_initialized) { + commpage_set_timestamp(0,0,0); - result64->hi = result64->lo; - result64->lo = (((unsigned long long)t64.lo << 32) | now32) / div32; - } - else { - AbsoluteTime_to_scalar(result64) = - (((unsigned long long)now64.lo << 32) | now32) / div32; - } -} - -/* - * Perform an unsigned division of a 96 bit value - * by a 32 bit value, yielding a 32 bit quotient, - * and a 32 bit remainder. Any higher order bits - * of the quotient are simply discarded. - */ -static __inline__ -void -udiv_96by32to32and32( - AbsoluteTime now64, - natural_t now32, - natural_t div32, - natural_t *result32, - natural_t *remain32) -{ - AbsoluteTime t64, u64; - - if (now64.hi > 0 || now64.lo >= div32) { - AbsoluteTime_to_scalar(&t64) = - AbsoluteTime_to_scalar(&now64) / div32; + rtclock_timebase_const.numer = numer; + rtclock_timebase_const.denom = denom; + rtclock_sec_divisor = freq->timebase_num / freq->timebase_den; - umul_64by32to64(t64, div32, &t64); - - AbsoluteTime_to_scalar(&t64) = - AbsoluteTime_to_scalar(&now64) - AbsoluteTime_to_scalar(&t64); - - AbsoluteTime_to_scalar(&t64) = - ((unsigned long long)t64.lo << 32) | now32; - - AbsoluteTime_to_scalar(&u64) = - AbsoluteTime_to_scalar(&t64) / div32; - - *result32 = u64.lo; - - umul_64by32to64(u64, div32, &u64); - - *remain32 = AbsoluteTime_to_scalar(&t64) - - AbsoluteTime_to_scalar(&u64); + ml_init_lock_timeout(); } else { - AbsoluteTime_to_scalar(&t64) = - ((unsigned long long)now64.lo << 32) | now32; - - AbsoluteTime_to_scalar(&u64) = - AbsoluteTime_to_scalar(&t64) / div32; - - *result32 = u64.lo; - - umul_64by32to64(u64, div32, &u64); - - *remain32 = AbsoluteTime_to_scalar(&t64) - - AbsoluteTime_to_scalar(&u64); + UNLOCK_RTC(s); + printf("rtclock timebase_callback: late old %d / %d new %d / %d\n", + rtclock_timebase_const.numer, rtclock_timebase_const.denom, + numer, denom); + return; } -} - -/* - * Get the clock device time. This routine is responsible - * for converting the device's machine dependent time value - * into a canonical mach_timespec_t value. - * - * SMP configurations - *this currently assumes that the processor - * clocks will be synchronised* - */ -kern_return_t -sysclk_gettime_internal( - mach_timespec_t *time) /* OUT */ -{ - AbsoluteTime now; - AbsoluteTime t64; - natural_t t32; - natural_t numer, denom; - - numer = rtclock.timebase_const.numer; - denom = rtclock.timebase_const.denom; - - clock_get_uptime(&now); - - umul_64by32(now, numer, &t64, &t32); - - udiv_96by32(t64, t32, denom, &t64, &t32); - - udiv_96by32to32and32(t64, t32, NSEC_PER_SEC, - &time->tv_sec, &time->tv_nsec); - - return (KERN_SUCCESS); -} - -kern_return_t -sysclk_gettime( - mach_timespec_t *time) /* OUT */ -{ - AbsoluteTime now; - AbsoluteTime t64; - natural_t t32; - natural_t numer, denom; - spl_t s; - - LOCK_RTC(s); - numer = rtclock.timebase_const.numer; - denom = rtclock.timebase_const.denom; UNLOCK_RTC(s); - clock_get_uptime(&now); - - umul_64by32(now, numer, &t64, &t32); - - udiv_96by32(t64, t32, denom, &t64, &t32); - - udiv_96by32to32and32(t64, t32, NSEC_PER_SEC, - &time->tv_sec, &time->tv_nsec); - - return (KERN_SUCCESS); + clock_timebase_init(); } /* - * Get clock device attributes. + * Configure the system clock device. */ -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 = RTC_TICKPERIOD; - 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) +int +rtclock_config(void) { - AbsoluteTime abstime; + simple_lock_init(&rtclock_lock, 0); - timespec_to_absolutetime(*deadline, &abstime); - timer_call_enter(&rtclock.alarm[cpu_number()], abstime); -} + PE_register_timebase_callback(timebase_callback); -/* - * Configure the calendar clock. - */ -int -calend_config(void) -{ return (1); } /* - * Initialize the calendar clock. + * Initialize the system clock device. */ int -calend_init(void) +rtclock_init(void) { - if (cpu_number() != master_cpu) - return(1); + etimer_resync_deadlines(); /* Start the timers going */ return (1); } -/* - * Get the current clock time. - */ -kern_return_t -calend_gettime( - mach_timespec_t *curr_time) /* OUT */ -{ - spl_t s; - - LOCK_RTC(s); - if (!rtclock.calend_is_set) { - UNLOCK_RTC(s); - return (KERN_FAILURE); - } - - (void) sysclk_gettime_internal(curr_time); - ADD_MACH_TIMESPEC(curr_time, &rtclock.calend_offset); - UNLOCK_RTC(s); - - return (KERN_SUCCESS); -} - -/* - * Set the current clock time. - */ -kern_return_t -calend_settime( - mach_timespec_t *new_time) -{ - mach_timespec_t curr_time; - spl_t s; - - LOCK_RTC(s); - (void) sysclk_gettime_internal(&curr_time); - rtclock.calend_offset = *new_time; - SUB_MACH_TIMESPEC(&rtclock.calend_offset, &curr_time); - rtclock.calend_is_set = TRUE; - UNLOCK_RTC(s); - - PESetGMTTimeOfDay(new_time->tv_sec); - - 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 = RTC_TICKPERIOD; - 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_adjust_calendar( - clock_res_t nsec) +clock_get_system_microtime( + uint32_t *secs, + uint32_t *microsecs) { - spl_t s; + uint64_t now, t64; + uint32_t divisor; - LOCK_RTC(s); - if (rtclock.calend_is_set) - ADD_MACH_TIMESPEC_NSEC(&rtclock.calend_offset, nsec); - UNLOCK_RTC(s); -} - -static void -calend_setup_internal( - long seconds) -{ - mach_timespec_t curr_time; - - (void) sysclk_gettime_internal(&curr_time); - if (curr_time.tv_nsec < 500*USEC_PER_SEC) - rtclock.calend_offset.tv_sec = seconds; - else - rtclock.calend_offset.tv_sec = seconds + 1; - rtclock.calend_offset.tv_nsec = 0; - SUB_MACH_TIMESPEC(&rtclock.calend_offset, &curr_time); - rtclock.calend_is_set = TRUE; -} - -static thread_call_t calend_wakeup_call; -static thread_call_data_t calend_wakeup_call_data; - -static void -calend_wakeup_resynch( - thread_call_param_t p0, - thread_call_param_t p1) -{ - long seconds = PEGetGMTTimeOfDay(); - spl_t s; + now = mach_absolute_time(); - LOCK_RTC(s); - calend_setup_internal(seconds); - UNLOCK_RTC(s); + *secs = t64 = now / (divisor = rtclock_sec_divisor); + now -= (t64 * divisor); + *microsecs = (now * USEC_PER_SEC) / divisor; } -static IOReturn -calend_sleep_wake_notif( - void *target, - void *refCon, - UInt32 messageType, - void *provider, - void *messageArg, - vm_size_t argSize) +void +clock_get_system_nanotime( + uint32_t *secs, + uint32_t *nanosecs) { - if (messageType != kIOMessageSystemHasPoweredOn) - return (kIOReturnUnsupported); + uint64_t now, t64; + uint32_t divisor; - if (calend_wakeup_call != NULL) - thread_call_enter(calend_wakeup_call); + now = mach_absolute_time(); - return (kIOReturnSuccess); + *secs = t64 = now / (divisor = rtclock_sec_divisor); + now -= (t64 * divisor); + *nanosecs = (now * NSEC_PER_SEC) / divisor; } void -clock_initialize_calendar(void) +clock_gettimeofday_set_commpage( + uint64_t abstime, + uint64_t epoch, + uint64_t offset, + uint32_t *secs, + uint32_t *microsecs) { - long seconds; - spl_t s; + uint64_t t64, now = abstime; - thread_call_setup(&calend_wakeup_call_data, calend_wakeup_resynch, NULL); - calend_wakeup_call = &calend_wakeup_call_data; + simple_lock(&rtclock_lock); - registerSleepWakeInterest(calend_sleep_wake_notif, NULL, NULL); + now += offset; - seconds = PEGetGMTTimeOfDay(); + *secs = t64 = now / rtclock_sec_divisor; + now -= (t64 * rtclock_sec_divisor); + *microsecs = (now * USEC_PER_SEC) / rtclock_sec_divisor; - LOCK_RTC(s); - if (!rtclock.calend_is_set) - calend_setup_internal(seconds); - UNLOCK_RTC(s); -} + *secs += epoch; -mach_timespec_t -clock_get_calendar_offset(void) -{ - mach_timespec_t result = MACH_TIMESPEC_ZERO; - spl_t s; + commpage_set_timestamp(abstime - now, *secs, rtclock_sec_divisor); - LOCK_RTC(s); - if (rtclock.calend_is_set) - result = rtclock.calend_offset; - UNLOCK_RTC(s); - - return (result); + simple_unlock(&rtclock_lock); } void clock_timebase_info( mach_timebase_info_t info) { - spl_t s; + spl_t s; LOCK_RTC(s); - *info = rtclock.timebase_const; + *info = rtclock_timebase_const; + rtclock_timebase_initialized = TRUE; UNLOCK_RTC(s); } -void -clock_set_timer_deadline( - AbsoluteTime deadline) -{ - AbsoluteTime abstime; - int decr, mycpu; - struct rtclock_timer *mytimer; - spl_t s; - - s = splclock(); - mycpu = cpu_number(); - mytimer = &rtclock.timer[mycpu]; - clock_get_uptime(&abstime); - rtclock.last_abstime[mycpu] = abstime; - mytimer->deadline = deadline; - mytimer->is_set = TRUE; - if ( CMP_ABSOLUTETIME(&mytimer->deadline, - &rtclock_tick_deadline[mycpu]) < 0) { - decr = deadline_to_decrementer(mytimer->deadline, abstime); - if ( rtclock_decrementer_min != 0 && - rtclock_decrementer_min < (natural_t)decr ) - decr = rtclock_decrementer_min; - - KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 1) - | DBG_FUNC_NONE, decr, 2, 0, 0, 0); - - mtdec(decr); - rtclock.last_decr[mycpu] = decr; - } - splx(s); -} - void clock_set_timer_func( clock_timer_func_t func) @@ -795,288 +221,101 @@ clock_set_timer_func( spl_t s; LOCK_RTC(s); - if (rtclock.timer_expire == NULL) - rtclock.timer_expire = func; + if (rtclock_timer_expire == NULL) + rtclock_timer_expire = 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 ppc_saved_state *ssp, - spl_t old_spl) -{ - AbsoluteTime abstime; - int decr[3], mycpu = cpu_number(); - struct rtclock_timer *mytimer = &rtclock.timer[mycpu]; - - /* - * We may receive interrupts too early, we must reject them. - */ - if (rtclock_initialized == FALSE) { - mtdec(DECREMENTER_MAX); /* Max the decrementer if not init */ - return; - } - - decr[1] = decr[2] = DECREMENTER_MAX; - - clock_get_uptime(&abstime); - rtclock.last_abstime[mycpu] = abstime; - if (CMP_ABSOLUTETIME(&rtclock_tick_deadline[mycpu], &abstime) <= 0) { - clock_deadline_for_periodic_event(rtclock_tick_interval, abstime, - &rtclock_tick_deadline[mycpu]); - hertz_tick(USER_MODE(ssp->srr1), ssp->srr0); - } - - clock_get_uptime(&abstime); - rtclock.last_abstime[mycpu] = abstime; - if (mytimer->is_set && - CMP_ABSOLUTETIME(&mytimer->deadline, &abstime) <= 0) { - mytimer->is_set = FALSE; - (*rtclock.timer_expire)(abstime); - } - - clock_get_uptime(&abstime); - rtclock.last_abstime[mycpu] = abstime; - decr[1] = deadline_to_decrementer(rtclock_tick_deadline[mycpu], abstime); - - if (mytimer->is_set) - decr[2] = deadline_to_decrementer(mytimer->deadline, abstime); - - if (decr[1] > decr[2]) - decr[1] = decr[2]; - - if ( rtclock_decrementer_min != 0 && - rtclock_decrementer_min < (natural_t)decr[1] ) - decr[1] = rtclock_decrementer_min; - - KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 1) - | DBG_FUNC_NONE, decr[1], 3, 0, 0, 0); - - mtdec(decr[1]); - rtclock.last_decr[mycpu] = decr[1]; -} - -static void -rtclock_alarm_timer( - timer_call_param_t p0, - timer_call_param_t p1) +clock_interval_to_absolutetime_interval( + uint32_t interval, + uint32_t scale_factor, + uint64_t *result) { - mach_timespec_t timestamp; - - (void) sysclk_gettime(×tamp); + uint64_t nanosecs = (uint64_t)interval * scale_factor; + uint64_t t64; + uint32_t divisor; - clock_alarm_intr(SYSTEM_CLOCK, ×tamp); + *result = (t64 = nanosecs / NSEC_PER_SEC) * + (divisor = rtclock_sec_divisor); + nanosecs -= (t64 * NSEC_PER_SEC); + *result += (nanosecs * divisor) / NSEC_PER_SEC; } void -clock_get_uptime( - AbsoluteTime *result) -{ - natural_t hi, lo, hic; - - do { - asm volatile(" mftbu %0" : "=r" (hi)); - asm volatile(" mftb %0" : "=r" (lo)); - asm volatile(" mftbu %0" : "=r" (hic)); - } while (hic != hi); - - result->lo = lo; - result->hi = hi; -} - -static int -deadline_to_decrementer( - AbsoluteTime deadline, - AbsoluteTime now) +absolutetime_to_microtime( + uint64_t abstime, + uint32_t *secs, + uint32_t *microsecs) { - uint64_t delt; + uint64_t t64; + uint32_t divisor; - if (CMP_ABSOLUTETIME(&deadline, &now) <= 0) - return DECREMENTER_MIN; - else { - delt = AbsoluteTime_to_scalar(&deadline) - - AbsoluteTime_to_scalar(&now); - return (delt >= (DECREMENTER_MAX + 1))? DECREMENTER_MAX: - ((delt >= (DECREMENTER_MIN + 1))? (delt - 1): DECREMENTER_MIN); - } -} - -static void -timespec_to_absolutetime( - mach_timespec_t timespec, - AbsoluteTime *result) -{ - AbsoluteTime t64; - natural_t t32; - natural_t numer, denom; - spl_t s; - - LOCK_RTC(s); - numer = rtclock.timebase_const.numer; - denom = rtclock.timebase_const.denom; - UNLOCK_RTC(s); - - asm volatile(" mullw %0,%1,%2" : - "=r" (t64.lo) : - "r" (timespec.tv_sec), "r" (NSEC_PER_SEC)); - - asm volatile(" mulhwu %0,%1,%2" : - "=r" (t64.hi) : - "r" (timespec.tv_sec), "r" (NSEC_PER_SEC)); - - AbsoluteTime_to_scalar(&t64) += timespec.tv_nsec; - - umul_64by32(t64, denom, &t64, &t32); - - udiv_96by32(t64, t32, numer, &t64, &t32); - - result->hi = t64.lo; - result->lo = t32; -} - -void -clock_interval_to_deadline( - natural_t interval, - natural_t scale_factor, - AbsoluteTime *result) -{ - AbsoluteTime abstime; - - clock_get_uptime(result); - - clock_interval_to_absolutetime_interval(interval, scale_factor, &abstime); - - ADD_ABSOLUTETIME(result, &abstime); + *secs = t64 = abstime / (divisor = rtclock_sec_divisor); + abstime -= (t64 * divisor); + *microsecs = (abstime * USEC_PER_SEC) / divisor; } void -clock_interval_to_absolutetime_interval( - natural_t interval, - natural_t scale_factor, - AbsoluteTime *result) +absolutetime_to_nanotime( + uint64_t abstime, + uint32_t *secs, + uint32_t *nanosecs) { - AbsoluteTime t64; - natural_t t32; - natural_t numer, denom; - spl_t s; - - LOCK_RTC(s); - numer = rtclock.timebase_const.numer; - denom = rtclock.timebase_const.denom; - UNLOCK_RTC(s); - - asm volatile(" mullw %0,%1,%2" : - "=r" (t64.lo) : - "r" (interval), "r" (scale_factor)); - asm volatile(" mulhwu %0,%1,%2" : - "=r" (t64.hi) : - "r" (interval), "r" (scale_factor)); + uint64_t t64; + uint32_t divisor; - umul_64by32(t64, denom, &t64, &t32); - - udiv_96by32(t64, t32, numer, &t64, &t32); - - result->hi = t64.lo; - result->lo = t32; + *secs = t64 = abstime / (divisor = rtclock_sec_divisor); + abstime -= (t64 * divisor); + *nanosecs = (abstime * NSEC_PER_SEC) / divisor; } void -clock_absolutetime_interval_to_deadline( - AbsoluteTime abstime, - AbsoluteTime *result) +nanotime_to_absolutetime( + uint32_t secs, + uint32_t nanosecs, + uint64_t *result) { - clock_get_uptime(result); + uint32_t divisor = rtclock_sec_divisor; - ADD_ABSOLUTETIME(result, &abstime); + *result = ((uint64_t)secs * divisor) + + ((uint64_t)nanosecs * divisor) / NSEC_PER_SEC; } void absolutetime_to_nanoseconds( - AbsoluteTime abstime, - UInt64 *result) + uint64_t abstime, + uint64_t *result) { - AbsoluteTime t64; - natural_t t32; - natural_t numer, denom; - spl_t s; - - LOCK_RTC(s); - numer = rtclock.timebase_const.numer; - denom = rtclock.timebase_const.denom; - UNLOCK_RTC(s); + uint64_t t64; + uint32_t divisor; - umul_64by32(abstime, numer, &t64, &t32); - - udiv_96by32to64(t64, t32, denom, (void *)result); + *result = (t64 = abstime / (divisor = rtclock_sec_divisor)) * NSEC_PER_SEC; + abstime -= (t64 * divisor); + *result += (abstime * NSEC_PER_SEC) / divisor; } void nanoseconds_to_absolutetime( - UInt64 nanoseconds, - AbsoluteTime *result) + uint64_t nanosecs, + uint64_t *result) { - AbsoluteTime t64; - natural_t t32; - natural_t numer, denom; - spl_t s; - - LOCK_RTC(s); - numer = rtclock.timebase_const.numer; - denom = rtclock.timebase_const.denom; - UNLOCK_RTC(s); - - AbsoluteTime_to_scalar(&t64) = nanoseconds; + uint64_t t64; + uint32_t divisor; - umul_64by32(t64, denom, &t64, &t32); - - udiv_96by32to64(t64, t32, numer, result); + *result = (t64 = nanosecs / NSEC_PER_SEC) * + (divisor = rtclock_sec_divisor); + nanosecs -= (t64 * NSEC_PER_SEC); + *result += (nanosecs * divisor) / NSEC_PER_SEC; } -/* - * Spin-loop delay primitives. - */ void -delay_for_interval( - natural_t interval, - natural_t scale_factor) +machine_delay_until( + uint64_t deadline) { - AbsoluteTime now, end; - - clock_interval_to_deadline(interval, scale_factor, &end); + uint64_t now; do { - clock_get_uptime(&now); - } while (CMP_ABSOLUTETIME(&now, &end) < 0); -} - -void -clock_delay_until( - AbsoluteTime deadline) -{ - AbsoluteTime now; - - do { - clock_get_uptime(&now); - } while (CMP_ABSOLUTETIME(&now, &deadline) < 0); -} - -void -delay( - int usec) -{ - delay_for_interval((usec < 0)? -usec: usec, NSEC_PER_USEC); + now = mach_absolute_time(); + } while (now < deadline); }