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