|
|
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.