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