|
|
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: * @APPLE_FREE_COPYRIGHT@ ! 27: */ ! 28: /* ! 29: * File: rtclock.c ! 30: * Purpose: Routines for handling the machine dependent ! 31: * real-time clock. ! 32: */ ! 33: ! 34: #include <platforms.h> ! 35: ! 36: #include <kern/cpu_number.h> ! 37: #include <kern/clock.h> ! 38: #include <kern/macro_help.h> ! 39: #include <kern/misc_protos.h> ! 40: #include <kern/spl.h> ! 41: #include <machine/mach_param.h> /* HZ */ ! 42: #include <mach/vm_prot.h> ! 43: #include <vm/pmap.h> ! 44: #include <vm/vm_kern.h> /* for kernel_map */ ! 45: #include <ppc/misc_protos.h> ! 46: #include <ppc/proc_reg.h> ! 47: #include <ppc/spl.h> ! 48: ! 49: #include <IOKit/IOPlatformExpert.h> ! 50: ! 51: #include <sys/kdebug.h> ! 52: ! 53: int sysclk_config(void); ! 54: ! 55: int sysclk_init(void); ! 56: ! 57: kern_return_t sysclk_gettime( ! 58: mach_timespec_t *cur_time); ! 59: ! 60: kern_return_t sysclk_getattr( ! 61: clock_flavor_t flavor, ! 62: clock_attr_t attr, ! 63: mach_msg_type_number_t *count); ! 64: ! 65: void sysclk_setalarm( ! 66: mach_timespec_t *deadline); ! 67: ! 68: struct clock_ops sysclk_ops = { ! 69: sysclk_config, sysclk_init, ! 70: sysclk_gettime, 0, ! 71: sysclk_getattr, 0, ! 72: sysclk_setalarm, ! 73: }; ! 74: ! 75: int calend_config(void); ! 76: ! 77: int calend_init(void); ! 78: ! 79: kern_return_t calend_gettime( ! 80: mach_timespec_t *cur_time); ! 81: ! 82: kern_return_t calend_settime( ! 83: mach_timespec_t *cur_time); ! 84: ! 85: kern_return_t calend_getattr( ! 86: clock_flavor_t flavor, ! 87: clock_attr_t attr, ! 88: mach_msg_type_number_t *count); ! 89: ! 90: struct clock_ops calend_ops = { ! 91: calend_config, calend_init, ! 92: calend_gettime, calend_settime, ! 93: calend_getattr, 0, ! 94: 0, ! 95: }; ! 96: ! 97: /* local data declarations */ ! 98: ! 99: static struct rtclock { ! 100: AbsoluteTime alarm_deadline; ! 101: boolean_t alarm_is_set; ! 102: ! 103: mach_timespec_t calend_offset; ! 104: boolean_t calend_is_set; ! 105: ! 106: struct { ! 107: natural_t numer, denom; ! 108: } timebase_const; ! 109: ! 110: AbsoluteTime timer_deadline; ! 111: boolean_t timer_is_set; ! 112: clock_timer_func_t timer_expire; ! 113: ! 114: /* debugging */ ! 115: AbsoluteTime last_abstime[NCPUS]; ! 116: int last_decr[NCPUS]; ! 117: natural_t intr_entry; ! 118: natural_t intr_exit; ! 119: ! 120: decl_simple_lock_data(,lock) /* real-time clock device lock */ ! 121: } rtclock; ! 122: ! 123: static boolean_t rtclock_initialized; ! 124: ! 125: static AbsoluteTime rtclock_tick_deadline[NCPUS]; ! 126: static AbsoluteTime rtclock_tick_interval; ! 127: ! 128: static void absolutetime_to_timespec_internal( ! 129: AbsoluteTime abstime, ! 130: mach_timespec_t *result); ! 131: ! 132: static void timespec_to_absolutetime_internal( ! 133: mach_timespec_t timespec, ! 134: AbsoluteTime *result); ! 135: ! 136: static int deadline_to_decrementer( ! 137: AbsoluteTime deadline, ! 138: AbsoluteTime now); ! 139: ! 140: /* global data declarations */ ! 141: ! 142: #define RTC_TICKPERIOD (NSEC_PER_SEC / HZ) ! 143: ! 144: #define DECREMENTER_MAX 0x7FFFFFFFUL ! 145: #define DECREMENTER_MIN 0xAUL ! 146: ! 147: natural_t rtclock_decrementer_min; ! 148: ! 149: /* ! 150: * Macros to lock/unlock real-time clock device. ! 151: */ ! 152: #define LOCK_RTC(s) \ ! 153: MACRO_BEGIN \ ! 154: (s) = splclock(); \ ! 155: simple_lock(&rtclock.lock); \ ! 156: MACRO_END ! 157: ! 158: #define UNLOCK_RTC(s) \ ! 159: MACRO_BEGIN \ ! 160: simple_unlock(&rtclock.lock); \ ! 161: splx(s); \ ! 162: MACRO_END ! 163: ! 164: static void ! 165: timebase_callback( ! 166: struct timebase_freq_t *freq) ! 167: { ! 168: natural_t numer, denom; ! 169: int n; ! 170: spl_t s; ! 171: ! 172: denom = freq->timebase_num; ! 173: n = 9; ! 174: while (!(denom % 10)) { ! 175: if (n < 1) ! 176: break; ! 177: denom /= 10; ! 178: n--; ! 179: } ! 180: ! 181: numer = freq->timebase_den; ! 182: while (n-- > 0) { ! 183: numer *= 10; ! 184: } ! 185: ! 186: LOCK_RTC(s); ! 187: rtclock.timebase_const.numer = numer; ! 188: rtclock.timebase_const.denom = denom; ! 189: UNLOCK_RTC(s); ! 190: } ! 191: ! 192: /* ! 193: * Configure the real-time clock device. ! 194: */ ! 195: int ! 196: sysclk_config(void) ! 197: { ! 198: if (cpu_number() != master_cpu) ! 199: return(1); ! 200: ! 201: simple_lock_init(&rtclock.lock, ETAP_MISC_RT_CLOCK); ! 202: ! 203: PE_register_timebase_callback(timebase_callback); ! 204: ! 205: return (1); ! 206: } ! 207: ! 208: /* ! 209: * Initialize the system clock device. ! 210: */ ! 211: int ! 212: sysclk_init(void) ! 213: { ! 214: AbsoluteTime abstime; ! 215: int decr, mycpu = cpu_number(); ! 216: ! 217: if (mycpu != master_cpu) { ! 218: if (rtclock_initialized == FALSE) { ! 219: panic("sysclk_init on cpu %d, rtc not initialized\n", mycpu); ! 220: } ! 221: /* Set decrementer and hence our next tick due */ ! 222: clock_get_uptime(&abstime); ! 223: rtclock_tick_deadline[mycpu] = abstime; ! 224: ADD_ABSOLUTETIME(&rtclock_tick_deadline[mycpu], ! 225: &rtclock_tick_interval); ! 226: decr = deadline_to_decrementer(rtclock_tick_deadline[mycpu], abstime); ! 227: mtdec(decr); ! 228: rtclock.last_decr[mycpu] = decr; ! 229: ! 230: return(1); ! 231: } ! 232: ! 233: /* ! 234: * Initialize non-zero clock structure values. ! 235: */ ! 236: clock_interval_to_absolutetime_interval(RTC_TICKPERIOD, 1, ! 237: &rtclock_tick_interval); ! 238: /* Set decrementer and our next tick due */ ! 239: clock_get_uptime(&abstime); ! 240: rtclock_tick_deadline[mycpu] = abstime; ! 241: ADD_ABSOLUTETIME(&rtclock_tick_deadline[mycpu], &rtclock_tick_interval); ! 242: decr = deadline_to_decrementer(rtclock_tick_deadline[mycpu], abstime); ! 243: mtdec(decr); ! 244: rtclock.last_decr[mycpu] = decr; ! 245: ! 246: rtclock_initialized = TRUE; ! 247: ! 248: return (1); ! 249: } ! 250: ! 251: /* ! 252: * Perform a full 64 bit by 32 bit unsigned multiply, ! 253: * yielding a 96 bit product. The most significant ! 254: * portion of the product is returned as a 64 bit ! 255: * quantity, with the lower portion as a 32 bit word. ! 256: */ ! 257: static void ! 258: umul_64by32( ! 259: AbsoluteTime now64, ! 260: natural_t mult32, ! 261: AbsoluteTime *result64, ! 262: natural_t *result32) ! 263: { ! 264: natural_t mid, mid2; ! 265: ! 266: asm volatile(" mullw %0,%1,%2" : ! 267: "=r" (*result32) : ! 268: "r" (now64.lo), "r" (mult32)); ! 269: ! 270: asm volatile(" mullw %0,%1,%2" : ! 271: "=r" (mid2) : ! 272: "r" (now64.hi), "r" (mult32)); ! 273: asm volatile(" mulhwu %0,%1,%2" : ! 274: "=r" (mid) : ! 275: "r" (now64.lo), "r" (mult32)); ! 276: ! 277: asm volatile(" mulhwu %0,%1,%2" : ! 278: "=r" (result64->hi) : ! 279: "r" (now64.hi), "r" (mult32)); ! 280: ! 281: asm volatile(" addc %0,%2,%3; ! 282: addze %1,%4" : ! 283: "=r" (result64->lo), "=r" (result64->hi) : ! 284: "r" (mid), "r" (mid2), "1" (result64->hi)); ! 285: } ! 286: ! 287: /* ! 288: * Perform a partial 64 bit by 32 bit unsigned multiply, ! 289: * yielding a 64 bit product. Only the least significant ! 290: * 64 bits of the product are calculated and returned. ! 291: */ ! 292: static void ! 293: umul_64by32to64( ! 294: AbsoluteTime now64, ! 295: natural_t mult32, ! 296: AbsoluteTime *result64) ! 297: { ! 298: natural_t mid, mid2; ! 299: ! 300: asm volatile(" mullw %0,%1,%2" : ! 301: "=r" (result64->lo) : ! 302: "r" (now64.lo), "r" (mult32)); ! 303: ! 304: asm volatile(" mullw %0,%1,%2" : ! 305: "=r" (mid2) : ! 306: "r" (now64.hi), "r" (mult32)); ! 307: asm volatile(" mulhwu %0,%1,%2" : ! 308: "=r" (mid) : ! 309: "r" (now64.lo), "r" (mult32)); ! 310: ! 311: asm volatile(" add %0,%1,%2" : ! 312: "=r" (result64->hi) : ! 313: "r" (mid), "r" (mid2)); ! 314: } ! 315: ! 316: /* ! 317: * Perform an unsigned division of a 96 bit value ! 318: * by a 32 bit value, yielding a 96 bit quotient. ! 319: * The most significant portion of the product is ! 320: * returned as a 64 bit quantity, with the lower ! 321: * portion as a 32 bit word. ! 322: */ ! 323: static __inline__ ! 324: void ! 325: udiv_96by32( ! 326: AbsoluteTime now64, ! 327: natural_t now32, ! 328: natural_t div32, ! 329: AbsoluteTime *result64, ! 330: natural_t *result32) ! 331: { ! 332: AbsoluteTime t64; ! 333: ! 334: if (now64.hi > 0 || now64.lo >= div32) { ! 335: AbsoluteTime_to_scalar(result64) = ! 336: AbsoluteTime_to_scalar(&now64) / div32; ! 337: ! 338: umul_64by32to64(*result64, div32, &t64); ! 339: ! 340: AbsoluteTime_to_scalar(&t64) = ! 341: AbsoluteTime_to_scalar(&now64) - AbsoluteTime_to_scalar(&t64); ! 342: ! 343: *result32 = (((unsigned long long)t64.lo << 32) | now32) / div32; ! 344: } ! 345: else { ! 346: AbsoluteTime_to_scalar(result64) = ! 347: (((unsigned long long)now64.lo << 32) | now32) / div32; ! 348: ! 349: *result32 = result64->lo; ! 350: result64->lo = result64->hi; ! 351: result64->hi = 0; ! 352: } ! 353: } ! 354: ! 355: /* ! 356: * Perform an unsigned division of a 96 bit value ! 357: * by a 32 bit value, yielding a 64 bit quotient. ! 358: * Any higher order bits of the quotient are simply ! 359: * discarded. ! 360: */ ! 361: static __inline__ ! 362: void ! 363: udiv_96by32to64( ! 364: AbsoluteTime now64, ! 365: natural_t now32, ! 366: natural_t div32, ! 367: AbsoluteTime *result64) ! 368: { ! 369: AbsoluteTime t64; ! 370: ! 371: if (now64.hi > 0 || now64.lo >= div32) { ! 372: AbsoluteTime_to_scalar(result64) = ! 373: AbsoluteTime_to_scalar(&now64) / div32; ! 374: ! 375: umul_64by32to64(*result64, div32, &t64); ! 376: ! 377: AbsoluteTime_to_scalar(&t64) = ! 378: AbsoluteTime_to_scalar(&now64) - AbsoluteTime_to_scalar(&t64); ! 379: ! 380: result64->hi = result64->lo; ! 381: result64->lo = (((unsigned long long)t64.lo << 32) | now32) / div32; ! 382: } ! 383: else { ! 384: AbsoluteTime_to_scalar(result64) = ! 385: (((unsigned long long)now64.lo << 32) | now32) / div32; ! 386: } ! 387: } ! 388: ! 389: /* ! 390: * Perform an unsigned division of a 96 bit value ! 391: * by a 32 bit value, yielding a 32 bit quotient, ! 392: * and a 32 bit remainder. Any higher order bits ! 393: * of the quotient are simply discarded. ! 394: */ ! 395: static __inline__ ! 396: void ! 397: udiv_96by32to32and32( ! 398: AbsoluteTime now64, ! 399: natural_t now32, ! 400: natural_t div32, ! 401: natural_t *result32, ! 402: natural_t *remain32) ! 403: { ! 404: AbsoluteTime t64, u64; ! 405: ! 406: if (now64.hi > 0 || now64.lo >= div32) { ! 407: AbsoluteTime_to_scalar(&t64) = ! 408: AbsoluteTime_to_scalar(&now64) / div32; ! 409: ! 410: umul_64by32to64(t64, div32, &t64); ! 411: ! 412: AbsoluteTime_to_scalar(&t64) = ! 413: AbsoluteTime_to_scalar(&now64) - AbsoluteTime_to_scalar(&t64); ! 414: ! 415: AbsoluteTime_to_scalar(&t64) = ! 416: ((unsigned long long)t64.lo << 32) | now32; ! 417: ! 418: AbsoluteTime_to_scalar(&u64) = ! 419: AbsoluteTime_to_scalar(&t64) / div32; ! 420: ! 421: *result32 = u64.lo; ! 422: ! 423: umul_64by32to64(u64, div32, &u64); ! 424: ! 425: *remain32 = AbsoluteTime_to_scalar(&t64) - ! 426: AbsoluteTime_to_scalar(&u64); ! 427: } ! 428: else { ! 429: AbsoluteTime_to_scalar(&t64) = ! 430: ((unsigned long long)now64.lo << 32) | now32; ! 431: ! 432: AbsoluteTime_to_scalar(&u64) = ! 433: AbsoluteTime_to_scalar(&t64) / div32; ! 434: ! 435: *result32 = u64.lo; ! 436: ! 437: umul_64by32to64(u64, div32, &u64); ! 438: ! 439: *remain32 = AbsoluteTime_to_scalar(&t64) - ! 440: AbsoluteTime_to_scalar(&u64); ! 441: } ! 442: } ! 443: ! 444: /* ! 445: * Get the clock device time. This routine is responsible ! 446: * for converting the device's machine dependent time value ! 447: * into a canonical mach_timespec_t value. ! 448: * ! 449: * SMP configurations - *this currently assumes that the processor ! 450: * clocks will be synchronised* ! 451: */ ! 452: kern_return_t ! 453: sysclk_gettime_internal( ! 454: mach_timespec_t *time) /* OUT */ ! 455: { ! 456: AbsoluteTime now; ! 457: AbsoluteTime t64; ! 458: natural_t t32; ! 459: natural_t numer, denom; ! 460: ! 461: numer = rtclock.timebase_const.numer; ! 462: denom = rtclock.timebase_const.denom; ! 463: ! 464: clock_get_uptime(&now); ! 465: ! 466: umul_64by32(now, numer, &t64, &t32); ! 467: ! 468: udiv_96by32(t64, t32, denom, &t64, &t32); ! 469: ! 470: udiv_96by32to32and32(t64, t32, NSEC_PER_SEC, ! 471: &time->tv_sec, &time->tv_nsec); ! 472: ! 473: return (KERN_SUCCESS); ! 474: } ! 475: ! 476: kern_return_t ! 477: sysclk_gettime( ! 478: mach_timespec_t *time) /* OUT */ ! 479: { ! 480: AbsoluteTime now; ! 481: AbsoluteTime t64; ! 482: natural_t t32; ! 483: natural_t numer, denom; ! 484: spl_t s; ! 485: ! 486: LOCK_RTC(s); ! 487: numer = rtclock.timebase_const.numer; ! 488: denom = rtclock.timebase_const.denom; ! 489: UNLOCK_RTC(s); ! 490: ! 491: clock_get_uptime(&now); ! 492: ! 493: umul_64by32(now, numer, &t64, &t32); ! 494: ! 495: udiv_96by32(t64, t32, denom, &t64, &t32); ! 496: ! 497: udiv_96by32to32and32(t64, t32, NSEC_PER_SEC, ! 498: &time->tv_sec, &time->tv_nsec); ! 499: ! 500: return (KERN_SUCCESS); ! 501: } ! 502: ! 503: /* ! 504: * Get clock device attributes. ! 505: */ ! 506: kern_return_t ! 507: sysclk_getattr( ! 508: clock_flavor_t flavor, ! 509: clock_attr_t attr, /* OUT */ ! 510: mach_msg_type_number_t *count) /* IN/OUT */ ! 511: { ! 512: spl_t s; ! 513: ! 514: if (*count != 1) ! 515: return (KERN_FAILURE); ! 516: switch (flavor) { ! 517: ! 518: case CLOCK_GET_TIME_RES: /* >0 res */ ! 519: case CLOCK_ALARM_CURRES: /* =0 no alarm */ ! 520: case CLOCK_ALARM_MINRES: ! 521: case CLOCK_ALARM_MAXRES: ! 522: LOCK_RTC(s); ! 523: *(clock_res_t *) attr = RTC_TICKPERIOD; ! 524: UNLOCK_RTC(s); ! 525: break; ! 526: ! 527: default: ! 528: return (KERN_INVALID_VALUE); ! 529: } ! 530: return (KERN_SUCCESS); ! 531: } ! 532: ! 533: /* ! 534: * Set deadline for the next alarm on the clock device. This call ! 535: * always resets the time to deliver an alarm for the clock. ! 536: */ ! 537: void ! 538: sysclk_setalarm( ! 539: mach_timespec_t *deadline) ! 540: { ! 541: AbsoluteTime abstime; ! 542: int decr, mycpu; ! 543: spl_t s; ! 544: ! 545: LOCK_RTC(s); ! 546: mycpu = cpu_number(); ! 547: clock_get_uptime(&abstime); ! 548: rtclock.last_abstime[mycpu] = abstime; ! 549: timespec_to_absolutetime_internal(*deadline, &rtclock.alarm_deadline); ! 550: rtclock.alarm_is_set = TRUE; ! 551: if ( (!rtclock.timer_is_set || ! 552: CMP_ABSOLUTETIME(&rtclock.alarm_deadline, ! 553: &rtclock.timer_deadline) < 0) && ! 554: CMP_ABSOLUTETIME(&rtclock.alarm_deadline, ! 555: &rtclock_tick_deadline[mycpu]) < 0) { ! 556: decr = deadline_to_decrementer(rtclock.alarm_deadline, abstime); ! 557: if ( rtclock_decrementer_min != 0 && ! 558: rtclock_decrementer_min < (natural_t)decr ) ! 559: decr = rtclock_decrementer_min; ! 560: ! 561: KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 1) ! 562: | DBG_FUNC_NONE, decr, 1, 0, 0, 0); ! 563: ! 564: mtdec(decr); ! 565: rtclock.last_decr[mycpu] = decr; ! 566: } ! 567: UNLOCK_RTC(s); ! 568: } ! 569: ! 570: /* ! 571: * Configure the calendar clock. ! 572: */ ! 573: int ! 574: calend_config(void) ! 575: { ! 576: return (1); ! 577: } ! 578: ! 579: /* ! 580: * Initialize the calendar clock. ! 581: */ ! 582: int ! 583: calend_init(void) ! 584: { ! 585: if (cpu_number() != master_cpu) ! 586: return(1); ! 587: ! 588: return (1); ! 589: } ! 590: ! 591: /* ! 592: * Get the current clock time. ! 593: */ ! 594: kern_return_t ! 595: calend_gettime( ! 596: mach_timespec_t *curr_time) /* OUT */ ! 597: { ! 598: spl_t s; ! 599: ! 600: LOCK_RTC(s); ! 601: if (!rtclock.calend_is_set) { ! 602: UNLOCK_RTC(s); ! 603: return (KERN_FAILURE); ! 604: } ! 605: ! 606: (void) sysclk_gettime_internal(curr_time); ! 607: ADD_MACH_TIMESPEC(curr_time, &rtclock.calend_offset); ! 608: UNLOCK_RTC(s); ! 609: ! 610: return (KERN_SUCCESS); ! 611: } ! 612: ! 613: /* ! 614: * Set the current clock time. ! 615: */ ! 616: kern_return_t ! 617: calend_settime( ! 618: mach_timespec_t *new_time) ! 619: { ! 620: mach_timespec_t curr_time; ! 621: spl_t s; ! 622: ! 623: LOCK_RTC(s); ! 624: (void) sysclk_gettime_internal(&curr_time); ! 625: rtclock.calend_offset = *new_time; ! 626: SUB_MACH_TIMESPEC(&rtclock.calend_offset, &curr_time); ! 627: rtclock.calend_is_set = TRUE; ! 628: UNLOCK_RTC(s); ! 629: ! 630: PESetGMTTimeOfDay(new_time->tv_sec); ! 631: ! 632: return (KERN_SUCCESS); ! 633: } ! 634: ! 635: /* ! 636: * Get clock device attributes. ! 637: */ ! 638: kern_return_t ! 639: calend_getattr( ! 640: clock_flavor_t flavor, ! 641: clock_attr_t attr, /* OUT */ ! 642: mach_msg_type_number_t *count) /* IN/OUT */ ! 643: { ! 644: spl_t s; ! 645: ! 646: if (*count != 1) ! 647: return (KERN_FAILURE); ! 648: switch (flavor) { ! 649: ! 650: case CLOCK_GET_TIME_RES: /* >0 res */ ! 651: LOCK_RTC(s); ! 652: *(clock_res_t *) attr = RTC_TICKPERIOD; ! 653: UNLOCK_RTC(s); ! 654: break; ! 655: ! 656: case CLOCK_ALARM_CURRES: /* =0 no alarm */ ! 657: case CLOCK_ALARM_MINRES: ! 658: case CLOCK_ALARM_MAXRES: ! 659: *(clock_res_t *) attr = 0; ! 660: break; ! 661: ! 662: default: ! 663: return (KERN_INVALID_VALUE); ! 664: } ! 665: return (KERN_SUCCESS); ! 666: } ! 667: ! 668: void ! 669: clock_adjust_calendar( ! 670: clock_res_t nsec) ! 671: { ! 672: spl_t s; ! 673: ! 674: LOCK_RTC(s); ! 675: if (rtclock.calend_is_set) ! 676: ADD_MACH_TIMESPEC_NSEC(&rtclock.calend_offset, nsec); ! 677: UNLOCK_RTC(s); ! 678: } ! 679: ! 680: void ! 681: clock_initialize_calendar(void) ! 682: { ! 683: mach_timespec_t curr_time; ! 684: long seconds = PEGetGMTTimeOfDay(); ! 685: spl_t s; ! 686: ! 687: LOCK_RTC(s); ! 688: if (!rtclock.calend_is_set) { ! 689: (void) sysclk_gettime_internal(&curr_time); ! 690: rtclock.calend_offset.tv_sec = seconds; ! 691: rtclock.calend_offset.tv_nsec = 0; ! 692: SUB_MACH_TIMESPEC(&rtclock.calend_offset, &curr_time); ! 693: rtclock.calend_is_set = TRUE; ! 694: } ! 695: UNLOCK_RTC(s); ! 696: } ! 697: ! 698: mach_timespec_t ! 699: clock_get_calendar_offset(void) ! 700: { ! 701: mach_timespec_t result = MACH_TIMESPEC_ZERO; ! 702: spl_t s; ! 703: ! 704: LOCK_RTC(s); ! 705: if (rtclock.calend_is_set) ! 706: result = rtclock.calend_offset; ! 707: UNLOCK_RTC(s); ! 708: ! 709: return (result); ! 710: } ! 711: ! 712: void ! 713: clock_get_timebase_info( ! 714: natural_t *delta, ! 715: natural_t *abs_to_ns_num, ! 716: natural_t *abs_to_ns_denom, ! 717: natural_t *proc_to_abs_num, ! 718: natural_t *proc_to_abs_denom) ! 719: { ! 720: spl_t s; ! 721: ! 722: LOCK_RTC(s); ! 723: *abs_to_ns_num = rtclock.timebase_const.numer; ! 724: *abs_to_ns_denom = rtclock.timebase_const.denom; ! 725: UNLOCK_RTC(s); ! 726: ! 727: /* ! 728: * Other values as returned by Mac OS 8.6. ! 729: */ ! 730: *delta = 1; ! 731: *proc_to_abs_num = *proc_to_abs_denom = 1; ! 732: } ! 733: ! 734: void ! 735: clock_set_timer_deadline( ! 736: AbsoluteTime deadline) ! 737: { ! 738: AbsoluteTime abstime; ! 739: int decr, mycpu; ! 740: spl_t s; ! 741: ! 742: LOCK_RTC(s); ! 743: mycpu = cpu_number(); ! 744: clock_get_uptime(&abstime); ! 745: rtclock.last_abstime[mycpu] = abstime; ! 746: rtclock.timer_deadline = deadline; ! 747: rtclock.timer_is_set = TRUE; ! 748: if ( (!rtclock.alarm_is_set || ! 749: CMP_ABSOLUTETIME(&rtclock.timer_deadline, ! 750: &rtclock.alarm_deadline) < 0) && ! 751: CMP_ABSOLUTETIME(&rtclock.timer_deadline, ! 752: &rtclock_tick_deadline[mycpu]) < 0) { ! 753: decr = deadline_to_decrementer(rtclock.timer_deadline, abstime); ! 754: if ( rtclock_decrementer_min != 0 && ! 755: rtclock_decrementer_min < (natural_t)decr ) ! 756: decr = rtclock_decrementer_min; ! 757: ! 758: KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 1) ! 759: | DBG_FUNC_NONE, decr, 2, 0, 0, 0); ! 760: ! 761: mtdec(decr); ! 762: rtclock.last_decr[mycpu] = decr; ! 763: } ! 764: UNLOCK_RTC(s); ! 765: } ! 766: ! 767: void ! 768: clock_set_timer_func( ! 769: clock_timer_func_t func) ! 770: { ! 771: spl_t s; ! 772: ! 773: LOCK_RTC(s); ! 774: if (rtclock.timer_expire == NULL) ! 775: rtclock.timer_expire = func; ! 776: UNLOCK_RTC(s); ! 777: } ! 778: ! 779: /* ! 780: * Reset the clock device. This causes the realtime clock ! 781: * device to reload its mode and count value (frequency). ! 782: */ ! 783: void ! 784: rtclock_reset(void) ! 785: { ! 786: return; ! 787: } ! 788: ! 789: /* ! 790: * Real-time clock device interrupt. ! 791: */ ! 792: void ! 793: rtclock_intr( ! 794: int device, ! 795: struct ppc_saved_state *ssp, ! 796: spl_t old_spl) ! 797: { ! 798: AbsoluteTime abstime; ! 799: mach_timespec_t timespec; ! 800: int decr[4], mycpu = cpu_number(); ! 801: spl_t s; ! 802: ! 803: /* ! 804: * We may receive interrupts too early, we must reject them. ! 805: */ ! 806: if (rtclock_initialized == FALSE) { ! 807: mtdec(DECREMENTER_MAX); /* Max the decrementer if not init */ ! 808: return; ! 809: } ! 810: ! 811: decr[1] = decr[2] = decr[3] = DECREMENTER_MAX; ! 812: ! 813: LOCK_RTC(s); ! 814: ! 815: rtclock.intr_entry++; ! 816: ! 817: clock_get_uptime(&abstime); ! 818: rtclock.last_abstime[mycpu] = abstime; ! 819: if (CMP_ABSOLUTETIME(&rtclock_tick_deadline[mycpu], &abstime) <= 0) { ! 820: clock_deadline_for_periodic_event(rtclock_tick_interval, abstime, ! 821: &rtclock_tick_deadline[mycpu]); ! 822: UNLOCK_RTC(s); ! 823: ! 824: hertz_tick(USER_MODE(ssp->srr1), ssp->srr0); ! 825: ! 826: LOCK_RTC(s); ! 827: } ! 828: ! 829: if (rtclock.timer_is_set && ! 830: CMP_ABSOLUTETIME(&rtclock.timer_deadline, &abstime) <= 0) { ! 831: rtclock.timer_is_set = FALSE; ! 832: UNLOCK_RTC(s); ! 833: ! 834: (*rtclock.timer_expire)(abstime); ! 835: ! 836: LOCK_RTC(s); ! 837: } ! 838: ! 839: if (rtclock.alarm_is_set && ! 840: CMP_ABSOLUTETIME(&rtclock.alarm_deadline, &abstime) <= 0) { ! 841: absolutetime_to_timespec_internal(abstime, ×pec); ! 842: rtclock.alarm_is_set = FALSE; ! 843: UNLOCK_RTC(s); ! 844: ! 845: clock_alarm_intr(SYSTEM_CLOCK, ×pec); ! 846: ! 847: LOCK_RTC(s); ! 848: } ! 849: ! 850: clock_get_uptime(&abstime); ! 851: rtclock.last_abstime[mycpu] = abstime; ! 852: decr[1] = deadline_to_decrementer(rtclock_tick_deadline[mycpu], abstime); ! 853: ! 854: if (rtclock.timer_is_set) ! 855: decr[2] = deadline_to_decrementer(rtclock.timer_deadline, abstime); ! 856: ! 857: if (rtclock.alarm_is_set) ! 858: decr[3] = deadline_to_decrementer(rtclock.alarm_deadline, abstime); ! 859: ! 860: if (decr[1] > decr[2]) ! 861: decr[1] = decr[2]; ! 862: ! 863: if (decr[1] > decr[3]) ! 864: decr[1] = decr[3]; ! 865: ! 866: if ( rtclock_decrementer_min != 0 && ! 867: rtclock_decrementer_min < (natural_t)decr[1] ) ! 868: decr[1] = rtclock_decrementer_min; ! 869: ! 870: KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 1) ! 871: | DBG_FUNC_NONE, decr[1], 3, 0, 0, 0); ! 872: ! 873: mtdec(decr[1]); ! 874: rtclock.last_decr[mycpu] = decr[1]; ! 875: ! 876: rtclock.intr_exit++; ! 877: ! 878: UNLOCK_RTC(s); ! 879: } ! 880: ! 881: void ! 882: clock_get_uptime( ! 883: AbsoluteTime *result) ! 884: { ! 885: natural_t hi, lo, hic; ! 886: ! 887: do { ! 888: asm volatile(" mftbu %0" : "=r" (hi)); ! 889: asm volatile(" mftb %0" : "=r" (lo)); ! 890: asm volatile(" mftbu %0" : "=r" (hic)); ! 891: } while (hic != hi); ! 892: ! 893: result->lo = lo; ! 894: result->hi = hi; ! 895: } ! 896: ! 897: static int ! 898: deadline_to_decrementer( ! 899: AbsoluteTime deadline, ! 900: AbsoluteTime now) ! 901: { ! 902: abstime_scalar_t delt; ! 903: ! 904: if (CMP_ABSOLUTETIME(&deadline, &now) <= 0) ! 905: return DECREMENTER_MIN; ! 906: else { ! 907: delt = AbsoluteTime_to_scalar(&deadline) - ! 908: AbsoluteTime_to_scalar(&now); ! 909: return (delt >= (DECREMENTER_MAX + 1))? DECREMENTER_MAX: ! 910: ((delt >= (DECREMENTER_MIN + 1))? (delt - 1): DECREMENTER_MIN); ! 911: } ! 912: } ! 913: ! 914: static void ! 915: absolutetime_to_timespec_internal( ! 916: AbsoluteTime abstime, ! 917: mach_timespec_t *result) ! 918: { ! 919: AbsoluteTime t64; ! 920: natural_t t32; ! 921: natural_t numer, denom; ! 922: ! 923: numer = rtclock.timebase_const.numer; ! 924: denom = rtclock.timebase_const.denom; ! 925: ! 926: umul_64by32(abstime, numer, &t64, &t32); ! 927: ! 928: udiv_96by32(t64, t32, denom, &t64, &t32); ! 929: ! 930: udiv_96by32to32and32(t64, t32, NSEC_PER_SEC, ! 931: &result->tv_sec, &result->tv_nsec); ! 932: } ! 933: ! 934: static void ! 935: timespec_to_absolutetime_internal( ! 936: mach_timespec_t timespec, ! 937: AbsoluteTime *result) ! 938: { ! 939: AbsoluteTime t64; ! 940: natural_t t32; ! 941: natural_t numer, denom; ! 942: ! 943: numer = rtclock.timebase_const.numer; ! 944: denom = rtclock.timebase_const.denom; ! 945: ! 946: asm volatile(" mullw %0,%1,%2" : ! 947: "=r" (t64.lo) : ! 948: "r" (timespec.tv_sec), "r" (NSEC_PER_SEC)); ! 949: ! 950: asm volatile(" mulhwu %0,%1,%2" : ! 951: "=r" (t64.hi) : ! 952: "r" (timespec.tv_sec), "r" (NSEC_PER_SEC)); ! 953: ! 954: AbsoluteTime_to_scalar(&t64) += timespec.tv_nsec; ! 955: ! 956: umul_64by32(t64, denom, &t64, &t32); ! 957: ! 958: udiv_96by32(t64, t32, numer, &t64, &t32); ! 959: ! 960: result->hi = t64.lo; ! 961: result->lo = t32; ! 962: } ! 963: ! 964: void ! 965: clock_interval_to_deadline( ! 966: natural_t interval, ! 967: natural_t scale_factor, ! 968: AbsoluteTime *result) ! 969: { ! 970: AbsoluteTime abstime; ! 971: ! 972: clock_get_uptime(result); ! 973: ! 974: clock_interval_to_absolutetime_interval(interval, scale_factor, &abstime); ! 975: ! 976: ADD_ABSOLUTETIME(result, &abstime); ! 977: } ! 978: ! 979: void ! 980: clock_interval_to_absolutetime_interval( ! 981: natural_t interval, ! 982: natural_t scale_factor, ! 983: AbsoluteTime *result) ! 984: { ! 985: AbsoluteTime t64; ! 986: natural_t t32; ! 987: natural_t numer, denom; ! 988: spl_t s; ! 989: ! 990: LOCK_RTC(s); ! 991: numer = rtclock.timebase_const.numer; ! 992: denom = rtclock.timebase_const.denom; ! 993: UNLOCK_RTC(s); ! 994: ! 995: asm volatile(" mullw %0,%1,%2" : ! 996: "=r" (t64.lo) : ! 997: "r" (interval), "r" (scale_factor)); ! 998: asm volatile(" mulhwu %0,%1,%2" : ! 999: "=r" (t64.hi) : ! 1000: "r" (interval), "r" (scale_factor)); ! 1001: ! 1002: umul_64by32(t64, denom, &t64, &t32); ! 1003: ! 1004: udiv_96by32(t64, t32, numer, &t64, &t32); ! 1005: ! 1006: result->hi = t64.lo; ! 1007: result->lo = t32; ! 1008: } ! 1009: ! 1010: void ! 1011: clock_absolutetime_interval_to_deadline( ! 1012: AbsoluteTime abstime, ! 1013: AbsoluteTime *result) ! 1014: { ! 1015: clock_get_uptime(result); ! 1016: ! 1017: ADD_ABSOLUTETIME(result, &abstime); ! 1018: } ! 1019: ! 1020: void ! 1021: absolutetime_to_nanoseconds( ! 1022: AbsoluteTime abstime, ! 1023: UInt64 *result) ! 1024: { ! 1025: AbsoluteTime t64; ! 1026: natural_t t32; ! 1027: natural_t numer, denom; ! 1028: spl_t s; ! 1029: ! 1030: LOCK_RTC(s); ! 1031: numer = rtclock.timebase_const.numer; ! 1032: denom = rtclock.timebase_const.denom; ! 1033: UNLOCK_RTC(s); ! 1034: ! 1035: umul_64by32(abstime, numer, &t64, &t32); ! 1036: ! 1037: udiv_96by32to64(t64, t32, denom, (void *)result); ! 1038: } ! 1039: ! 1040: void ! 1041: nanoseconds_to_absolutetime( ! 1042: UInt64 nanoseconds, ! 1043: AbsoluteTime *result) ! 1044: { ! 1045: AbsoluteTime t64; ! 1046: natural_t t32; ! 1047: natural_t numer, denom; ! 1048: spl_t s; ! 1049: ! 1050: LOCK_RTC(s); ! 1051: numer = rtclock.timebase_const.numer; ! 1052: denom = rtclock.timebase_const.denom; ! 1053: UNLOCK_RTC(s); ! 1054: ! 1055: AbsoluteTime_to_scalar(&t64) = nanoseconds; ! 1056: ! 1057: umul_64by32(t64, denom, &t64, &t32); ! 1058: ! 1059: udiv_96by32to64(t64, t32, numer, result); ! 1060: } ! 1061: ! 1062: /* ! 1063: * Spin-loop delay primitives. ! 1064: */ ! 1065: void ! 1066: delay_for_interval( ! 1067: natural_t interval, ! 1068: natural_t scale_factor) ! 1069: { ! 1070: AbsoluteTime now, end; ! 1071: ! 1072: clock_interval_to_deadline(interval, scale_factor, &end); ! 1073: ! 1074: do { ! 1075: clock_get_uptime(&now); ! 1076: } while (CMP_ABSOLUTETIME(&now, &end) < 0); ! 1077: } ! 1078: ! 1079: void ! 1080: clock_delay_until( ! 1081: AbsoluteTime deadline) ! 1082: { ! 1083: AbsoluteTime now; ! 1084: ! 1085: do { ! 1086: clock_get_uptime(&now); ! 1087: } while (CMP_ABSOLUTETIME(&now, &deadline) < 0); ! 1088: } ! 1089: ! 1090: void ! 1091: delay( ! 1092: int usec) ! 1093: { ! 1094: delay_for_interval((usec < 0)? -usec: usec, NSEC_PER_USEC); ! 1095: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.