Annotation of XNU/osfmk/i386/rtclock.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * @OSF_COPYRIGHT@
                     24:  */
                     25: 
                     26: /*
                     27:  *     File:           i386/rtclock.c
                     28:  *     Purpose:        Routines for handling the machine dependent
                     29:  *                     real-time clock. This clock is generated by
                     30:  *                     the Intel 8254 Programmable Interval Timer.
                     31:  */
                     32: 
                     33: #include <cpus.h>
                     34: #include <platforms.h>
                     35: #include <mp_v1_1.h>
                     36: #include <mach_kdb.h>
                     37: #include <kern/cpu_number.h>
                     38: #include <kern/cpu_data.h>
                     39: #include <kern/clock.h>
                     40: #include <kern/macro_help.h>
                     41: #include <kern/misc_protos.h>
                     42: #include <kern/spl.h>
                     43: #include <machine/mach_param.h>        /* HZ */
                     44: #include <mach/vm_prot.h>
                     45: #include <vm/pmap.h>
                     46: #include <vm/vm_kern.h>                /* for kernel_map */
                     47: #include <i386/ipl.h>
                     48: #include <i386/pit.h>
                     49: #include <i386/pio.h>
                     50: #include <i386/misc_protos.h>
                     51: #include <i386/rtclock_entries.h>
                     52: #include <i386/hardclock_entries.h>
                     53: 
                     54: int            sysclk_config(void);
                     55: 
                     56: int            sysclk_init(void);
                     57: 
                     58: kern_return_t  sysclk_gettime(
                     59:        mach_timespec_t                 *cur_time);
                     60: 
                     61: kern_return_t  sysclk_getattr(
                     62:        clock_flavor_t                  flavor,
                     63:        clock_attr_t                    attr,
                     64:        mach_msg_type_number_t  *count);
                     65: 
                     66: kern_return_t  sysclk_setattr(
                     67:        clock_flavor_t                  flavor,
                     68:        clock_attr_t                    attr,
                     69:        mach_msg_type_number_t  count);
                     70: 
                     71: void           sysclk_setalarm(
                     72:        mach_timespec_t                 *alarm_time);
                     73: 
                     74: extern void (*IOKitRegisterInterruptHook)(void *,  int irq, int isclock);
                     75: 
                     76: /*
                     77:  * Lists of clock routines.
                     78:  */
                     79: struct clock_ops  sysclk_ops = {
                     80:        sysclk_config,                  sysclk_init,
                     81:        sysclk_gettime,                 0,
                     82:        sysclk_getattr,                 sysclk_setattr,
                     83:        sysclk_setalarm,
                     84: };
                     85: 
                     86: int            calend_config(void);
                     87: 
                     88: int            calend_init(void);
                     89: 
                     90: kern_return_t  calend_gettime(
                     91:        mach_timespec_t                 *cur_time);
                     92: 
                     93: kern_return_t  calend_settime(
                     94:        mach_timespec_t                 *cur_time);
                     95: 
                     96: kern_return_t  calend_getattr(
                     97:        clock_flavor_t                  flavor,
                     98:        clock_attr_t                    attr,
                     99:        mach_msg_type_number_t  *count);
                    100: 
                    101: struct clock_ops calend_ops = {
                    102:        calend_config,                  calend_init,
                    103:        calend_gettime,                 calend_settime,
                    104:        calend_getattr,                 0,
                    105:        0,
                    106: };
                    107: 
                    108: /* local data declarations */
                    109: mach_timespec_t                *RtcTime = (mach_timespec_t *)0;
                    110: mach_timespec_t                *RtcAlrm;
                    111: clock_res_t                    RtcDelt;
                    112: 
                    113: /* global data declarations */
                    114: struct {
                    115:        AbsoluteTime            abstime;
                    116: 
                    117:        mach_timespec_t         time;
                    118:        mach_timespec_t         alarm_time;     /* time of next alarm */
                    119: 
                    120:        mach_timespec_t         calend_offset;
                    121:        boolean_t                       calend_is_set;
                    122: 
                    123:        AbsoluteTime            timer_deadline;
                    124:        boolean_t                       timer_is_set;
                    125:        clock_timer_func_t      timer_expire;
                    126: 
                    127:        clock_res_t                     new_ires;       /* pending new resolution (nano ) */
                    128:        clock_res_t                     intr_nsec;      /* interrupt resolution (nano) */
                    129: 
                    130:        decl_simple_lock_data(,lock)    /* real-time clock device lock */
                    131: } rtclock;
                    132: 
                    133: unsigned int           clknum;                        /* clks per second */
                    134: unsigned int           new_clknum;                    /* pending clknum */
                    135: unsigned int           time_per_clk;                  /* time per clk in ZHZ */
                    136: unsigned int           clks_per_int;                  /* clks per interrupt */
                    137: unsigned int           clks_per_int_99;
                    138: int                                    rtc_intr_count;                /* interrupt counter */
                    139: int                                    rtc_intr_hertz;                /* interrupts per HZ */
                    140: int                                    rtc_intr_freq;                 /* interrupt frequency */
                    141: int                                    rtc_print_lost_tick;           /* print lost tick */
                    142: 
                    143: /*
                    144:  *     Macros to lock/unlock real-time clock device.
                    145:  */
                    146: #define LOCK_RTC(s)                                    \
                    147: MACRO_BEGIN                                                    \
                    148:        (s) = splclock();                               \
                    149:        simple_lock(&rtclock.lock);             \
                    150: MACRO_END
                    151: 
                    152: #define UNLOCK_RTC(s)                          \
                    153: MACRO_BEGIN                                                    \
                    154:        simple_unlock(&rtclock.lock);   \
                    155:        splx(s);                                                \
                    156: MACRO_END
                    157: 
                    158: /*
                    159:  * i8254 control.  ** MONUMENT **
                    160:  *
                    161:  * The i8254 is a traditional PC device with some arbitrary characteristics.
                    162:  * Basically, it is a register that counts at a fixed rate and can be
                    163:  * programmed to generate an interrupt every N counts.  The count rate is
                    164:  * clknum counts per second (see pit.h), historically 1193167 we believe.
                    165:  * Various constants are computed based on this value, and we calculate
                    166:  * them at init time for execution efficiency.  To obtain sufficient
                    167:  * accuracy, some of the calculation are most easily done in floating
                    168:  * point and then converted to int.
                    169:  *
                    170:  * We want an interrupt every 10 milliseconds, approximately.  The count
                    171:  * which will do that is clks_per_int.  However, that many counts is not
                    172:  * *exactly* 10 milliseconds; it is a bit more or less depending on
                    173:  * roundoff.  The actual time per tick is calculated and saved in
                    174:  * rtclock.intr_nsec, and it is that value which is added to the time
                    175:  * register on each tick.
                    176:  *
                    177:  * The i8254 counter can be read between interrupts in order to determine
                    178:  * the time more accurately.  The counter counts down from the preset value
                    179:  * toward 0, and we have to handle the case where the counter has been
                    180:  * reset just before being read and before the interrupt has been serviced.
                    181:  * Given a count since the last interrupt, the time since then is given
                    182:  * by (count * time_per_clk).  In order to minimize integer truncation,
                    183:  * we perform this calculation in an arbitrary unit of time which maintains
                    184:  * the maximum precision, i.e. such that one tick is 1.0e9 of these units,
                    185:  * or close to the precision of a 32-bit int.  We then divide by this unit
                    186:  * (which doesn't lose precision) to get nanoseconds.  For notation
                    187:  * purposes, this unit is defined as ZHZ = zanoseconds per nanosecond.
                    188:  *
                    189:  * This sequence to do all this is in sysclk_gettime.  For efficiency, this
                    190:  * sequence also needs the value that the counter will have if it has just
                    191:  * overflowed, so we precompute that also.  ALSO, certain platforms
                    192:  * (specifically the DEC XL5100) have been observed to have problem
                    193:  * with latching the counter, and they occasionally (say, one out of
                    194:  * 100,000 times) return a bogus value.  Hence, the present code reads
                    195:  * the counter twice and checks for a consistent pair of values.
                    196:  *
                    197:  * Some attributes of the rt clock can be changed, including the
                    198:  * interrupt resolution.  We default to the minimum resolution (10 ms),
                    199:  * but allow a finer resolution to be requested.  The assumed frequency
                    200:  * of the clock can also be set since it appears that the actual
                    201:  * frequency of real-world hardware can vary from the nominal by
                    202:  * 200 ppm or more.  When the frequency is set, the values above are
                    203:  * recomputed and we continue without resetting or changing anything else.
                    204:  */
                    205: #define RTC_MINRES     (NSEC_PER_SEC / HZ)     /* nsec per tick */
                    206: #define        RTC_MAXRES      (RTC_MINRES / 20)       /* nsec per tick */
                    207: #define        ZANO            (1000000000)
                    208: #define ZHZ             (ZANO / (NSEC_PER_SEC / HZ))
                    209: #define READ_8254(val) { \
                    210:         outb(PITCTL_PORT, PIT_C0);             \
                    211:        (val) = inb(PITCTR0_PORT);               \
                    212:        (val) |= inb(PITCTR0_PORT) << 8 ; }
                    213: 
                    214: /*
                    215:  * Calibration delay counts.
                    216:  */
                    217: unsigned int   delaycount = 10;
                    218: unsigned int   microdata = 50;
                    219: 
                    220: /*
                    221:  * Forward decl.
                    222:  */
                    223: 
                    224: extern int   measure_delay(int us);
                    225: void         rtc_setvals( unsigned int, clock_res_t );
                    226: 
                    227: /*
                    228:  * Initialize non-zero clock structure values.
                    229:  */
                    230: void
                    231: rtc_setvals(
                    232:        unsigned int new_clknum,
                    233:        clock_res_t  new_ires
                    234:        )
                    235: {
                    236:     unsigned int timeperclk;
                    237:     unsigned int scale0;
                    238:     unsigned int scale1;
                    239:     unsigned int res;
                    240: 
                    241:     clknum = new_clknum;
                    242:     rtc_intr_freq = (NSEC_PER_SEC / new_ires);
                    243:     rtc_intr_hertz = rtc_intr_freq / HZ;
                    244:     clks_per_int = (clknum + (rtc_intr_freq / 2)) / rtc_intr_freq;
                    245:     clks_per_int_99 = clks_per_int - clks_per_int/100;
                    246: 
                    247:     /*
                    248:      * The following calculations are done with scaling integer operations
                    249:      * in order that the integer results are accurate to the lsb.
                    250:      */
                    251:     timeperclk = div_scale(ZANO, clknum, &scale0);     /* 838.105647 nsec */
                    252: 
                    253:     time_per_clk = mul_scale(ZHZ, timeperclk, &scale1);        /* 83810 */
                    254:     if (scale0 > scale1)
                    255:        time_per_clk >>= (scale0 - scale1);
                    256:     else if (scale0 < scale1)
                    257:        panic("rtc_clock: time_per_clk overflow\n");
                    258: 
                    259:     /*
                    260:      * Notice that rtclock.intr_nsec is signed ==> use unsigned int res
                    261:      */
                    262:     res = mul_scale(clks_per_int, timeperclk, &scale1);        /* 10000276 */
                    263:     if (scale0 > scale1)
                    264:        rtclock.intr_nsec = res >> (scale0 - scale1);
                    265:     else
                    266:        panic("rtc_clock: rtclock.intr_nsec overflow\n");
                    267: 
                    268:     rtc_intr_count = 1;
                    269:     RtcDelt = rtclock.intr_nsec/2;
                    270: }
                    271: 
                    272: /*
                    273:  * Configure the real-time clock device. Return success (1)
                    274:  * or failure (0).
                    275:  */
                    276: 
                    277: int
                    278: sysclk_config(void)
                    279: {
                    280:        int     RtcFlag;
                    281:        int     pic;
                    282: 
                    283: #if    NCPUS > 1
                    284:        mp_disable_preemption();
                    285:        if (cpu_number() != master_cpu) {
                    286:                mp_enable_preemption();
                    287:                return(1);
                    288:        }
                    289:        mp_enable_preemption();
                    290: #endif
                    291:        /*
                    292:         * Setup device.
                    293:         */
                    294: #if    MP_V1_1
                    295:     {
                    296:        extern boolean_t mp_v1_1_initialized;
                    297:        if (mp_v1_1_initialized)
                    298:            pic = 2;
                    299:        else
                    300:            pic = 0;
                    301:     }
                    302: #else
                    303:        pic = 0;        /* FIXME .. interrupt registration moved to AppleIntelClock */
                    304: #endif
                    305: 
                    306: 
                    307:        /*
                    308:         * We should attempt to test the real-time clock
                    309:         * device here. If it were to fail, we should panic
                    310:         * the system.
                    311:         */
                    312:        RtcFlag = /* test device */1;
                    313:        printf("realtime clock configured\n");
                    314: 
                    315:        simple_lock_init(&rtclock.lock, ETAP_NO_TRACE);
                    316:        return (RtcFlag);
                    317: }
                    318: 
                    319: /*
                    320:  * Initialize the real-time clock device. Return success (1)
                    321:  * or failure (0). Since the real-time clock is required to
                    322:  * provide canonical mapped time, we allocate a page to keep
                    323:  * the clock time value. In addition, various variables used
                    324:  * to support the clock are initialized.  Note: the clock is
                    325:  * not started until rtclock_reset is called.
                    326:  */
                    327: int
                    328: sysclk_init(void)
                    329: {
                    330:        vm_offset_t     *vp;
                    331: #if    NCPUS > 1
                    332:        mp_disable_preemption();
                    333:        if (cpu_number() != master_cpu) {
                    334:                mp_enable_preemption();
                    335:                return(1);
                    336:        }
                    337:        mp_enable_preemption();
                    338: #endif
                    339: 
                    340:        RtcTime = &rtclock.time;
                    341:        rtc_setvals( CLKNUM, RTC_MINRES );  /* compute constants */
                    342:        return (1);
                    343: }
                    344: 
                    345: static volatile unsigned int     last_ival = 0;
                    346: 
                    347: /*
                    348:  * Get the clock device time. This routine is responsible
                    349:  * for converting the device's machine dependent time value
                    350:  * into a canonical mach_timespec_t value.
                    351:  */
                    352: kern_return_t
                    353: sysclk_gettime(
                    354:        mach_timespec_t *cur_time)      /* OUT */
                    355: {
                    356:         mach_timespec_t        itime = {0, 0};
                    357:        unsigned int    val, val2;
                    358:        int             s;
                    359: 
                    360:        if (!RtcTime) {
                    361:                /* Uninitialized */
                    362:                cur_time->tv_nsec = 0;
                    363:                cur_time->tv_sec = 0;
                    364:                return (KERN_SUCCESS);
                    365:        }
                    366: 
                    367:        /*
                    368:         * Inhibit interrupts. Determine the incremental
                    369:         * time since the last interrupt. (This could be
                    370:         * done in assembler for a bit more speed).
                    371:         */
                    372:        LOCK_RTC(s);
                    373:        do {
                    374:            READ_8254(val);                 /* read clock */
                    375:            READ_8254(val2);                /* read clock */
                    376:        } while ( val2 > val || val2 < val - 10 );
                    377:        if ( val > clks_per_int_99 ) {
                    378:            outb( 0x0a, 0x20 );             /* see if interrupt pending */
                    379:            if ( inb( 0x20 ) & 1 )
                    380:                itime.tv_nsec = rtclock.intr_nsec; /* yes, add a tick */
                    381:        }
                    382:        itime.tv_nsec += ((clks_per_int - val) * time_per_clk) / ZHZ;
                    383:        if ( itime.tv_nsec < last_ival ) {
                    384:            if (rtc_print_lost_tick)
                    385:                printf( "rtclock: missed clock interrupt.\n" );
                    386:        }
                    387:        last_ival = itime.tv_nsec;
                    388:        cur_time->tv_sec = rtclock.time.tv_sec;
                    389:        cur_time->tv_nsec = rtclock.time.tv_nsec;
                    390:        UNLOCK_RTC(s);
                    391:        ADD_MACH_TIMESPEC(cur_time, ((mach_timespec_t *)&itime));
                    392:        return (KERN_SUCCESS);
                    393: }
                    394: 
                    395: kern_return_t
                    396: sysclk_gettime_internal(
                    397:        mach_timespec_t *cur_time)      /* OUT */
                    398: {
                    399:         mach_timespec_t        itime = {0, 0};
                    400:        unsigned int    val, val2;
                    401: 
                    402:        if (!RtcTime) {
                    403:                /* Uninitialized */
                    404:                cur_time->tv_nsec = 0;
                    405:                cur_time->tv_sec = 0;
                    406:                return (KERN_SUCCESS);
                    407:        }
                    408: 
                    409:        /*
                    410:         * Inhibit interrupts. Determine the incremental
                    411:         * time since the last interrupt. (This could be
                    412:         * done in assembler for a bit more speed).
                    413:         */
                    414:        do {
                    415:            READ_8254(val);                 /* read clock */
                    416:            READ_8254(val2);                /* read clock */
                    417:        } while ( val2 > val || val2 < val - 10 );
                    418:        if ( val > clks_per_int_99 ) {
                    419:            outb( 0x0a, 0x20 );             /* see if interrupt pending */
                    420:            if ( inb( 0x20 ) & 1 )
                    421:                itime.tv_nsec = rtclock.intr_nsec; /* yes, add a tick */
                    422:        }
                    423:        itime.tv_nsec += ((clks_per_int - val) * time_per_clk) / ZHZ;
                    424:        if ( itime.tv_nsec < last_ival ) {
                    425:            if (rtc_print_lost_tick)
                    426:                printf( "rtclock: missed clock interrupt.\n" );
                    427:        }
                    428:        last_ival = itime.tv_nsec;
                    429:        cur_time->tv_sec = rtclock.time.tv_sec;
                    430:        cur_time->tv_nsec = rtclock.time.tv_nsec;
                    431:        ADD_MACH_TIMESPEC(cur_time, ((mach_timespec_t *)&itime));
                    432:        return (KERN_SUCCESS);
                    433: }
                    434: 
                    435: /*
                    436:  * Get the clock device time when ALL interrupts are already disabled.
                    437:  * Same as above except for turning interrupts off and on.
                    438:  * This routine is responsible for converting the device's machine dependent
                    439:  * time value into a canonical mach_timespec_t value.
                    440:  */
                    441: void
                    442: sysclk_gettime_interrupts_disabled(
                    443:        mach_timespec_t *cur_time)      /* OUT */
                    444: {
                    445:        mach_timespec_t itime = {0, 0};
                    446:        unsigned int    val;
                    447: 
                    448:        if (!RtcTime) {
                    449:                /* Uninitialized */
                    450:                cur_time->tv_nsec = 0;
                    451:                cur_time->tv_sec = 0;
                    452:                return;
                    453:        }
                    454: 
                    455:        simple_lock(&rtclock.lock);
                    456: 
                    457:        /*
                    458:         * Copy the current time knowing that we cant be interrupted
                    459:         * between the two longwords and so dont need to use MTS_TO_TS
                    460:         */
                    461:        READ_8254(val);                     /* read clock */
                    462:        if ( val > clks_per_int_99 ) {
                    463:            outb( 0x0a, 0x20 );             /* see if interrupt pending */
                    464:            if ( inb( 0x20 ) & 1 )
                    465:                itime.tv_nsec = rtclock.intr_nsec; /* yes, add a tick */
                    466:        }
                    467:        itime.tv_nsec += ((clks_per_int - val) * time_per_clk) / ZHZ;
                    468:        if ( itime.tv_nsec < last_ival ) {
                    469:            if (rtc_print_lost_tick)
                    470:                printf( "rtclock: missed clock interrupt.\n" );
                    471:        }
                    472:        last_ival = itime.tv_nsec;
                    473:        cur_time->tv_sec = rtclock.time.tv_sec;
                    474:        cur_time->tv_nsec = rtclock.time.tv_nsec;
                    475:        ADD_MACH_TIMESPEC(cur_time, ((mach_timespec_t *)&itime));
                    476: 
                    477:        simple_unlock(&rtclock.lock);
                    478: }
                    479: 
                    480: static
                    481: natural_t
                    482: get_uptime_ticks(void)
                    483: {
                    484:        natural_t               result = 0;
                    485:        unsigned int    val, val2;
                    486: 
                    487:        if (!RtcTime)
                    488:                return (result);
                    489: 
                    490:        /*
                    491:         * Inhibit interrupts. Determine the incremental
                    492:         * time since the last interrupt. (This could be
                    493:         * done in assembler for a bit more speed).
                    494:         */
                    495:        do {
                    496:            READ_8254(val);                 /* read clock */
                    497:            READ_8254(val2);                /* read clock */
                    498:        } while (val2 > val || val2 < val - 10);
                    499:        if (val > clks_per_int_99) {
                    500:            outb(0x0a, 0x20);                           /* see if interrupt pending */
                    501:            if (inb(0x20) & 1)
                    502:                        result = rtclock.intr_nsec;     /* yes, add a tick */
                    503:        }
                    504:        result += ((clks_per_int - val) * time_per_clk) / ZHZ;
                    505:        if (result < last_ival) {
                    506:            if (rtc_print_lost_tick)
                    507:                        printf( "rtclock: missed clock interrupt.\n" );
                    508:        }
                    509: 
                    510:        return (result);
                    511: }
                    512: 
                    513: /*
                    514:  * Get clock device attributes.
                    515:  */
                    516: kern_return_t
                    517: sysclk_getattr(
                    518:        clock_flavor_t          flavor,
                    519:        clock_attr_t            attr,           /* OUT */
                    520:        mach_msg_type_number_t  *count)         /* IN/OUT */
                    521: {
                    522:        spl_t   s;
                    523: 
                    524:        if (*count != 1)
                    525:                return (KERN_FAILURE);
                    526:        switch (flavor) {
                    527: 
                    528:        case CLOCK_GET_TIME_RES:        /* >0 res */
                    529: #if    (NCPUS == 1 || (MP_V1_1 && 0))
                    530:                LOCK_RTC(s);
                    531:                *(clock_res_t *) attr = 1000;
                    532:                UNLOCK_RTC(s);
                    533:                break;
                    534: #endif /* (NCPUS == 1 || (MP_V1_1 && 0)) && AT386 */
                    535:        case CLOCK_ALARM_CURRES:        /* =0 no alarm */
                    536:                LOCK_RTC(s);
                    537:                *(clock_res_t *) attr = rtclock.intr_nsec;
                    538:                UNLOCK_RTC(s);
                    539:                break;
                    540: 
                    541:        case CLOCK_ALARM_MAXRES:
                    542:                *(clock_res_t *) attr = RTC_MAXRES;
                    543:                break;
                    544: 
                    545:        case CLOCK_ALARM_MINRES:
                    546:                *(clock_res_t *) attr = RTC_MINRES;
                    547:                break;
                    548: 
                    549:        default:
                    550:                return (KERN_INVALID_VALUE);
                    551:        }
                    552:        return (KERN_SUCCESS);
                    553: }
                    554: 
                    555: /*
                    556:  * Set clock device attributes.
                    557:  */
                    558: kern_return_t
                    559: sysclk_setattr(
                    560:        clock_flavor_t          flavor,
                    561:        clock_attr_t            attr,           /* IN */
                    562:        mach_msg_type_number_t  count)          /* IN */
                    563: {
                    564:        spl_t           s;
                    565:        int             freq;
                    566:        int             adj;
                    567:        clock_res_t     new_ires;
                    568: 
                    569:        if (count != 1)
                    570:                return (KERN_FAILURE);
                    571:        switch (flavor) {
                    572: 
                    573:        case CLOCK_GET_TIME_RES:
                    574:        case CLOCK_ALARM_MAXRES:
                    575:        case CLOCK_ALARM_MINRES:
                    576:                return (KERN_FAILURE);
                    577: 
                    578:        case CLOCK_ALARM_CURRES:
                    579:                new_ires = *(clock_res_t *) attr;
                    580: 
                    581:                /*
                    582:                 * The new resolution must be within the predetermined
                    583:                 * range.  If the desired resolution cannot be achieved
                    584:                 * to within 0.1%, an error is returned.
                    585:                 */
                    586:                if (new_ires < RTC_MAXRES || new_ires > RTC_MINRES)
                    587:                        return (KERN_INVALID_VALUE);
                    588:                freq = (NSEC_PER_SEC / new_ires);
                    589:                adj = (((clknum % freq) * new_ires) / clknum);
                    590:                if (adj > (new_ires / 1000))
                    591:                        return (KERN_INVALID_VALUE);
                    592:                /*
                    593:                 * Record the new alarm resolution which will take effect
                    594:                 * on the next HZ aligned clock tick.
                    595:                 */
                    596:                LOCK_RTC(s);
                    597:                if ( freq != rtc_intr_freq ) {
                    598:                    rtclock.new_ires = new_ires;
                    599:                    new_clknum = clknum;
                    600:                }
                    601:                UNLOCK_RTC(s);
                    602:                return (KERN_SUCCESS);
                    603: 
                    604:        default:
                    605:                return (KERN_INVALID_VALUE);
                    606:        }
                    607: }
                    608: 
                    609: /*
                    610:  * Set next alarm time for the clock device. This call
                    611:  * always resets the time to deliver an alarm for the
                    612:  * clock.
                    613:  */
                    614: void
                    615: sysclk_setalarm(
                    616:        mach_timespec_t *alarm_time)
                    617: {
                    618:        spl_t           s;
                    619: 
                    620:        LOCK_RTC(s);
                    621:        rtclock.alarm_time = *alarm_time;
                    622:        RtcAlrm = &rtclock.alarm_time;
                    623:        UNLOCK_RTC(s);
                    624: }
                    625: 
                    626: /*
                    627:  * Configure the calendar clock.
                    628:  */
                    629: int
                    630: calend_config(void)
                    631: {
                    632:        return bbc_config();
                    633: }
                    634: 
                    635: /*
                    636:  * Initialize calendar clock.
                    637:  */
                    638: int
                    639: calend_init(void)
                    640: {
                    641:        return (1);
                    642: }
                    643: 
                    644: /*
                    645:  * Get the current clock time.
                    646:  */
                    647: kern_return_t
                    648: calend_gettime(
                    649:        mach_timespec_t *cur_time)      /* OUT */
                    650: {
                    651:        spl_t           s;
                    652: 
                    653:        LOCK_RTC(s);
                    654:        if (!rtclock.calend_is_set) {
                    655:                UNLOCK_RTC(s);
                    656:                return (KERN_FAILURE);
                    657:        }
                    658: 
                    659:        (void) sysclk_gettime_internal(cur_time);
                    660:        ADD_MACH_TIMESPEC(cur_time, &rtclock.calend_offset);
                    661:        UNLOCK_RTC(s);
                    662: 
                    663:        return (KERN_SUCCESS);
                    664: }
                    665: 
                    666: /*
                    667:  * Set the current clock time.
                    668:  */
                    669: kern_return_t
                    670: calend_settime(
                    671:        mach_timespec_t *new_time)
                    672: {
                    673:        mach_timespec_t curr_time;
                    674:        spl_t           s;
                    675: 
                    676:        LOCK_RTC(s);
                    677:        (void) sysclk_gettime_internal(&curr_time);
                    678:        rtclock.calend_offset = *new_time;
                    679:        SUB_MACH_TIMESPEC(&rtclock.calend_offset, &curr_time);
                    680:        rtclock.calend_is_set = TRUE;
                    681:        UNLOCK_RTC(s);
                    682: 
                    683:        (void) bbc_settime(new_time);
                    684: 
                    685:        return (KERN_SUCCESS);
                    686: }
                    687: 
                    688: /*
                    689:  * Get clock device attributes.
                    690:  */
                    691: kern_return_t
                    692: calend_getattr(
                    693:        clock_flavor_t          flavor,
                    694:        clock_attr_t            attr,           /* OUT */
                    695:        mach_msg_type_number_t  *count)         /* IN/OUT */
                    696: {
                    697:        spl_t   s;
                    698: 
                    699:        if (*count != 1)
                    700:                return (KERN_FAILURE);
                    701:        switch (flavor) {
                    702: 
                    703:        case CLOCK_GET_TIME_RES:        /* >0 res */
                    704: #if    (NCPUS == 1 || (MP_V1_1 && 0))
                    705:                LOCK_RTC(s);
                    706:                *(clock_res_t *) attr = 1000;
                    707:                UNLOCK_RTC(s);
                    708:                break;
                    709: #else  /* (NCPUS == 1 || (MP_V1_1 && 0)) && AT386 */
                    710:                LOCK_RTC(s);
                    711:                *(clock_res_t *) attr = rtclock.intr_nsec;
                    712:                UNLOCK_RTC(s);
                    713:                break;
                    714: #endif /* (NCPUS == 1 || (MP_V1_1 && 0)) && AT386 */
                    715: 
                    716:        case CLOCK_ALARM_CURRES:        /* =0 no alarm */
                    717:        case CLOCK_ALARM_MINRES:
                    718:        case CLOCK_ALARM_MAXRES:
                    719:                *(clock_res_t *) attr = 0;
                    720:                break;
                    721: 
                    722:        default:
                    723:                return (KERN_INVALID_VALUE);
                    724:        }
                    725:        return (KERN_SUCCESS);
                    726: }
                    727: 
                    728: void
                    729: clock_adjust_calendar(
                    730:        clock_res_t     nsec)
                    731: {
                    732:        spl_t           s;
                    733: 
                    734:        LOCK_RTC(s);
                    735:        if (rtclock.calend_is_set)
                    736:                ADD_MACH_TIMESPEC_NSEC(&rtclock.calend_offset, nsec);
                    737:        UNLOCK_RTC(s);
                    738: }
                    739: 
                    740: void
                    741: clock_initialize_calendar(void)
                    742: {
                    743:        mach_timespec_t bbc_time, curr_time;
                    744:        spl_t           s;
                    745: 
                    746:        if (bbc_gettime(&bbc_time) != KERN_SUCCESS)
                    747:                return;
                    748: 
                    749:        LOCK_RTC(s);
                    750:        if (!rtclock.calend_is_set) {
                    751:                (void) sysclk_gettime_internal(&curr_time);
                    752:                rtclock.calend_offset = bbc_time;
                    753:                SUB_MACH_TIMESPEC(&rtclock.calend_offset, &curr_time);
                    754:                rtclock.calend_is_set = TRUE;
                    755:        }
                    756:        UNLOCK_RTC(s);
                    757: }
                    758: 
                    759: mach_timespec_t
                    760: clock_get_calendar_offset(void)
                    761: {
                    762:        mach_timespec_t result = MACH_TIMESPEC_ZERO;
                    763:        spl_t           s;
                    764: 
                    765:        LOCK_RTC(s);
                    766:        if (rtclock.calend_is_set)
                    767:                result = rtclock.calend_offset;
                    768:        UNLOCK_RTC(s);
                    769: 
                    770:        return (result);
                    771: }
                    772: 
                    773: void
                    774: clock_get_timebase_info(
                    775:        natural_t               *delta,
                    776:        natural_t               *abs_to_ns_num,
                    777:        natural_t               *abs_to_ns_denom,
                    778:        natural_t               *proc_to_abs_num,
                    779:        natural_t               *proc_to_abs_denom)
                    780: {
                    781:        spl_t   s;
                    782: 
                    783:        LOCK_RTC(s);
                    784:        *abs_to_ns_num = *abs_to_ns_denom =     1;
                    785:        UNLOCK_RTC(s);
                    786: 
                    787:        *delta = 1;
                    788:        *proc_to_abs_num = *proc_to_abs_denom = 1;
                    789: }      
                    790: 
                    791: void
                    792: clock_set_timer_deadline(
                    793:        AbsoluteTime                    deadline)
                    794: {
                    795:        spl_t                   s;
                    796: 
                    797:        LOCK_RTC(s);
                    798:        rtclock.timer_deadline = deadline;
                    799:        rtclock.timer_is_set = TRUE;
                    800:        UNLOCK_RTC(s);
                    801: }
                    802: 
                    803: void
                    804: clock_set_timer_func(
                    805:        clock_timer_func_t              func)
                    806: {
                    807:        spl_t           s;
                    808: 
                    809:        LOCK_RTC(s);
                    810:        if (rtclock.timer_expire == NULL)
                    811:                rtclock.timer_expire = func;
                    812:        UNLOCK_RTC(s);
                    813: }
                    814: 
                    815: 
                    816: 
                    817: /*
                    818:  * Load the count register and start the clock.
                    819:  */
                    820: #define RTCLOCK_RESET()        {                                       \
                    821:        outb(PITCTL_PORT, PIT_C0|PIT_NDIVMODE|PIT_READMODE);    \
                    822:        outb(PITCTR0_PORT, (clks_per_int & 0xff));              \
                    823:        outb(PITCTR0_PORT, (clks_per_int >> 8));                \
                    824: }
                    825: 
                    826: /*
                    827:  * Reset the clock device. This causes the realtime clock
                    828:  * device to reload its mode and count value (frequency).
                    829:  * Note: the CPU should be calibrated
                    830:  * before starting the clock for the first time.
                    831:  */
                    832: 
                    833: void
                    834: rtclock_reset(void)
                    835: {
                    836:        int             s;
                    837: 
                    838: #if    NCPUS > 1 && !(MP_V1_1 && 0)
                    839:        mp_disable_preemption();
                    840:        if (cpu_number() != master_cpu) {
                    841:                mp_enable_preemption();
                    842:                return;
                    843:        }
                    844:        mp_enable_preemption();
                    845: #endif /* NCPUS > 1 && AT386 && !MP_V1_1 */
                    846:        LOCK_RTC(s);
                    847:        RTCLOCK_RESET();
                    848:        UNLOCK_RTC(s);
                    849: }
                    850: 
                    851: /*
                    852:  * Real-time clock device interrupt. Called only on the
                    853:  * master processor. Updates the clock time and upcalls
                    854:  * into the higher level clock code to deliver alarms.
                    855:  */
                    856: int
                    857: rtclock_intr(void)
                    858: {
                    859:        AbsoluteTime    abstime;
                    860:        mach_timespec_t clock_time;
                    861:        int                             i;
                    862:        spl_t                   s;
                    863: 
                    864:        /*
                    865:         * Update clock time. Do the update so that the macro
                    866:         * MTS_TO_TS() for reading the mapped time works (e.g.
                    867:         * update in order: mtv_csec, mtv_time.tv_nsec, mtv_time.tv_sec).
                    868:         */      
                    869:        LOCK_RTC(s);
                    870:        i = rtclock.time.tv_nsec + rtclock.intr_nsec;
                    871:        if (i < NSEC_PER_SEC)
                    872:            rtclock.time.tv_nsec = i;
                    873:        else {
                    874:            rtclock.time.tv_nsec = i - NSEC_PER_SEC;
                    875:            rtclock.time.tv_sec++;
                    876:        }
                    877:        /* note time now up to date */
                    878:        last_ival = 0;
                    879: 
                    880:        ADD_ABSOLUTETIME_TICKS(&rtclock.abstime, NSEC_PER_SEC/HZ);
                    881:        abstime = rtclock.abstime;
                    882:        if (rtclock.timer_is_set &&
                    883:                        CMP_ABSOLUTETIME(&rtclock.timer_deadline, &abstime) <= 0) {
                    884:                rtclock.timer_is_set = FALSE;
                    885:                UNLOCK_RTC(s);
                    886: 
                    887:                (*rtclock.timer_expire)(abstime);
                    888: 
                    889:                LOCK_RTC(s);
                    890:        }
                    891: 
                    892:        /*
                    893:         * Perform alarm clock processing if needed. The time
                    894:         * passed up is incremented by a half-interrupt tick
                    895:         * to trigger alarms closest to their desired times.
                    896:         * The clock_alarm_intr() routine calls sysclk_setalrm()
                    897:         * before returning if later alarms are pending.
                    898:         */
                    899: 
                    900:        if (RtcAlrm && (RtcAlrm->tv_sec < RtcTime->tv_sec ||
                    901:                        (RtcAlrm->tv_sec == RtcTime->tv_sec &&
                    902:                         RtcDelt >= RtcAlrm->tv_nsec - RtcTime->tv_nsec))) {
                    903:                clock_time.tv_sec = 0;
                    904:                clock_time.tv_nsec = RtcDelt;
                    905:                ADD_MACH_TIMESPEC (&clock_time, RtcTime);
                    906:                RtcAlrm = 0;
                    907:                UNLOCK_RTC(s);
                    908:                /*
                    909:                 * Call clock_alarm_intr() without RTC-lock.
                    910:                 * The lock ordering is always CLOCK-lock
                    911:                 * before RTC-lock.
                    912:                 */
                    913:                clock_alarm_intr(SYSTEM_CLOCK, &clock_time);
                    914:                LOCK_RTC(s);
                    915:        }
                    916: 
                    917:        /*
                    918:         * On a HZ-tick boundary: return 0 and adjust the clock
                    919:         * alarm resolution (if requested).  Otherwise return a
                    920:         * non-zero value.
                    921:         */
                    922:        if ((i = --rtc_intr_count) == 0) {
                    923:            if (rtclock.new_ires) {
                    924:                        rtc_setvals(new_clknum, rtclock.new_ires);
                    925:                        RTCLOCK_RESET();            /* lock clock register */
                    926:                        rtclock.new_ires = 0;
                    927:            }
                    928:            rtc_intr_count = rtc_intr_hertz;
                    929:        }
                    930:        UNLOCK_RTC(s);
                    931:        return (i);
                    932: }
                    933: 
                    934: void
                    935: clock_get_uptime(
                    936:        AbsoluteTime    *result)
                    937: {
                    938:        natural_t               ticks;
                    939:        spl_t                   s;
                    940: 
                    941:        LOCK_RTC(s);
                    942:        ticks = get_uptime_ticks();
                    943:        *result = rtclock.abstime;
                    944:        UNLOCK_RTC(s);
                    945: 
                    946:        ADD_ABSOLUTETIME_TICKS(result, ticks);
                    947: }
                    948: 
                    949: void
                    950: clock_interval_to_deadline(
                    951:        natural_t                       interval,
                    952:        natural_t                       scale_factor,
                    953:        AbsoluteTime            *result)
                    954: {
                    955:        AbsoluteTime            abstime;
                    956: 
                    957:        clock_get_uptime(result);
                    958: 
                    959:        clock_interval_to_absolutetime_interval(interval, scale_factor, &abstime);
                    960: 
                    961:        ADD_ABSOLUTETIME(result, &abstime);
                    962: }
                    963: 
                    964: void
                    965: clock_interval_to_absolutetime_interval(
                    966:        natural_t                       interval,
                    967:        natural_t                       scale_factor,
                    968:        AbsoluteTime            *result)
                    969: {
                    970:        AbsoluteTime_to_scalar(result) = (abstime_scalar_t)interval * scale_factor;
                    971: }
                    972: 
                    973: void
                    974: clock_absolutetime_interval_to_deadline(
                    975:        AbsoluteTime            abstime,
                    976:        AbsoluteTime            *result)
                    977: {
                    978:        clock_get_uptime(result);
                    979: 
                    980:        ADD_ABSOLUTETIME(result, &abstime);
                    981: }
                    982: 
                    983: void
                    984: absolutetime_to_nanoseconds(
                    985:        AbsoluteTime            abstime,
                    986:        UInt64                          *result)
                    987: {
                    988:        *result = AbsoluteTime_to_scalar(&abstime);
                    989: }
                    990: 
                    991: void
                    992: nanoseconds_to_absolutetime(
                    993:        UInt64                          nanoseconds,
                    994:        AbsoluteTime            *result)
                    995: {
                    996:        AbsoluteTime_to_scalar(result) = nanoseconds;
                    997: }
                    998: 
                    999: /*
                   1000:  * measure_delay(microseconds)
                   1001:  *
                   1002:  * Measure elapsed time for delay calls
                   1003:  * Returns microseconds.
                   1004:  * 
                   1005:  * Microseconds must not be too large since the counter (short) 
                   1006:  * will roll over.  Max is about 13 ms.  Values smaller than 1 ms are ok.
                   1007:  * This uses the assumed frequency of the rt clock which is emperically
                   1008:  * accurate to only about 200 ppm.
                   1009:  */
                   1010: 
                   1011: int
                   1012: measure_delay(
                   1013:        int us)
                   1014: {
                   1015:        unsigned int    lsb, val;
                   1016: 
                   1017:        outb(PITCTL_PORT, PIT_C0|PIT_NDIVMODE|PIT_READMODE);
                   1018:        outb(PITCTR0_PORT, 0xff);       /* set counter to max value */
                   1019:        outb(PITCTR0_PORT, 0xff);
                   1020:        delay(us);
                   1021:        outb(PITCTL_PORT, PIT_C0);
                   1022:        lsb = inb(PITCTR0_PORT);
                   1023:        val = (inb(PITCTR0_PORT) << 8) | lsb;
                   1024:        val = 0xffff - val;
                   1025:        val *= 1000000;
                   1026:        val /= CLKNUM;
                   1027:        return(val);
                   1028: }
                   1029: 
                   1030: /*
                   1031:  * calibrate_delay(void)
                   1032:  *
                   1033:  * Adjust delaycount.  Called from startup before clock is started
                   1034:  * for normal interrupt generation.
                   1035:  */
                   1036: 
                   1037: void
                   1038: calibrate_delay(void)
                   1039: {
                   1040:        unsigned        val;
                   1041:        int             prev = 0;
                   1042:        register int    i;
                   1043: 
                   1044:        printf("adjusting delay count: %d", delaycount);
                   1045:        for (i=0; i<10; i++) {
                   1046:                prev = delaycount;
                   1047:                /* 
                   1048:                 * microdata must not be to large since measure_timer
                   1049:                 * will not return accurate values if the counter (short) 
                   1050:                 * rolls over
                   1051:                 */
                   1052:                val = measure_delay(microdata);
                   1053:                delaycount *= microdata;
                   1054:                delaycount += val-1;    /* round up to upper us */
                   1055:                delaycount /= val;
                   1056:                if (delaycount <= 0)
                   1057:                        delaycount = 1;
                   1058:                if (delaycount != prev)
                   1059:                        printf(" %d", delaycount);
                   1060:        }
                   1061:        printf("\n");
                   1062: }
                   1063: 
                   1064: #if    MACH_KDB
                   1065: void
                   1066: test_delay(void);
                   1067: 
                   1068: void
                   1069: test_delay(void)
                   1070: {
                   1071:        register i;
                   1072: 
                   1073:        for (i = 0; i < 10; i++)
                   1074:                printf("%d, %d\n", i, measure_delay(i));
                   1075:        for (i = 10; i <= 100; i+=10)
                   1076:                printf("%d, %d\n", i, measure_delay(i));
                   1077: }
                   1078: #endif /* MACH_KDB */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.