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