|
|
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: /*
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_get_timebase_info(
775: natural_t *delta,
776: natural_t *abs_to_ns_num,
777: natural_t *abs_to_ns_denom,
778: natural_t *proc_to_abs_num,
779: natural_t *proc_to_abs_denom)
780: {
781: spl_t s;
782:
783: LOCK_RTC(s);
784: *abs_to_ns_num = *abs_to_ns_denom = 1;
785: UNLOCK_RTC(s);
786:
787: *delta = 1;
788: *proc_to_abs_num = *proc_to_abs_denom = 1;
789: }
790:
791: void
792: clock_set_timer_deadline(
793: AbsoluteTime deadline)
794: {
795: spl_t s;
796:
797: LOCK_RTC(s);
798: rtclock.timer_deadline = deadline;
799: rtclock.timer_is_set = TRUE;
800: UNLOCK_RTC(s);
801: }
802:
803: void
804: clock_set_timer_func(
805: clock_timer_func_t func)
806: {
807: spl_t s;
808:
809: LOCK_RTC(s);
810: if (rtclock.timer_expire == NULL)
811: rtclock.timer_expire = func;
812: UNLOCK_RTC(s);
813: }
814:
815:
816:
817: /*
818: * Load the count register and start the clock.
819: */
820: #define RTCLOCK_RESET() { \
821: outb(PITCTL_PORT, PIT_C0|PIT_NDIVMODE|PIT_READMODE); \
822: outb(PITCTR0_PORT, (clks_per_int & 0xff)); \
823: outb(PITCTR0_PORT, (clks_per_int >> 8)); \
824: }
825:
826: /*
827: * Reset the clock device. This causes the realtime clock
828: * device to reload its mode and count value (frequency).
829: * Note: the CPU should be calibrated
830: * before starting the clock for the first time.
831: */
832:
833: void
834: rtclock_reset(void)
835: {
836: int s;
837:
838: #if NCPUS > 1 && !(MP_V1_1 && 0)
839: mp_disable_preemption();
840: if (cpu_number() != master_cpu) {
841: mp_enable_preemption();
842: return;
843: }
844: mp_enable_preemption();
845: #endif /* NCPUS > 1 && AT386 && !MP_V1_1 */
846: LOCK_RTC(s);
847: RTCLOCK_RESET();
848: UNLOCK_RTC(s);
849: }
850:
851: /*
852: * Real-time clock device interrupt. Called only on the
853: * master processor. Updates the clock time and upcalls
854: * into the higher level clock code to deliver alarms.
855: */
856: int
857: rtclock_intr(void)
858: {
859: AbsoluteTime abstime;
860: mach_timespec_t clock_time;
861: int i;
862: spl_t s;
863:
864: /*
865: * Update clock time. Do the update so that the macro
866: * MTS_TO_TS() for reading the mapped time works (e.g.
867: * update in order: mtv_csec, mtv_time.tv_nsec, mtv_time.tv_sec).
868: */
869: LOCK_RTC(s);
870: i = rtclock.time.tv_nsec + rtclock.intr_nsec;
871: if (i < NSEC_PER_SEC)
872: rtclock.time.tv_nsec = i;
873: else {
874: rtclock.time.tv_nsec = i - NSEC_PER_SEC;
875: rtclock.time.tv_sec++;
876: }
877: /* note time now up to date */
878: last_ival = 0;
879:
880: ADD_ABSOLUTETIME_TICKS(&rtclock.abstime, NSEC_PER_SEC/HZ);
881: abstime = rtclock.abstime;
882: if (rtclock.timer_is_set &&
883: CMP_ABSOLUTETIME(&rtclock.timer_deadline, &abstime) <= 0) {
884: rtclock.timer_is_set = FALSE;
885: UNLOCK_RTC(s);
886:
887: (*rtclock.timer_expire)(abstime);
888:
889: LOCK_RTC(s);
890: }
891:
892: /*
893: * Perform alarm clock processing if needed. The time
894: * passed up is incremented by a half-interrupt tick
895: * to trigger alarms closest to their desired times.
896: * The clock_alarm_intr() routine calls sysclk_setalrm()
897: * before returning if later alarms are pending.
898: */
899:
900: if (RtcAlrm && (RtcAlrm->tv_sec < RtcTime->tv_sec ||
901: (RtcAlrm->tv_sec == RtcTime->tv_sec &&
902: RtcDelt >= RtcAlrm->tv_nsec - RtcTime->tv_nsec))) {
903: clock_time.tv_sec = 0;
904: clock_time.tv_nsec = RtcDelt;
905: ADD_MACH_TIMESPEC (&clock_time, RtcTime);
906: RtcAlrm = 0;
907: UNLOCK_RTC(s);
908: /*
909: * Call clock_alarm_intr() without RTC-lock.
910: * The lock ordering is always CLOCK-lock
911: * before RTC-lock.
912: */
913: clock_alarm_intr(SYSTEM_CLOCK, &clock_time);
914: LOCK_RTC(s);
915: }
916:
917: /*
918: * On a HZ-tick boundary: return 0 and adjust the clock
919: * alarm resolution (if requested). Otherwise return a
920: * non-zero value.
921: */
922: if ((i = --rtc_intr_count) == 0) {
923: if (rtclock.new_ires) {
924: rtc_setvals(new_clknum, rtclock.new_ires);
925: RTCLOCK_RESET(); /* lock clock register */
926: rtclock.new_ires = 0;
927: }
928: rtc_intr_count = rtc_intr_hertz;
929: }
930: UNLOCK_RTC(s);
931: return (i);
932: }
933:
934: void
935: clock_get_uptime(
936: AbsoluteTime *result)
937: {
938: natural_t ticks;
939: spl_t s;
940:
941: LOCK_RTC(s);
942: ticks = get_uptime_ticks();
943: *result = rtclock.abstime;
944: UNLOCK_RTC(s);
945:
946: ADD_ABSOLUTETIME_TICKS(result, ticks);
947: }
948:
949: void
950: clock_interval_to_deadline(
951: natural_t interval,
952: natural_t scale_factor,
953: AbsoluteTime *result)
954: {
955: AbsoluteTime abstime;
956:
957: clock_get_uptime(result);
958:
959: clock_interval_to_absolutetime_interval(interval, scale_factor, &abstime);
960:
961: ADD_ABSOLUTETIME(result, &abstime);
962: }
963:
964: void
965: clock_interval_to_absolutetime_interval(
966: natural_t interval,
967: natural_t scale_factor,
968: AbsoluteTime *result)
969: {
970: AbsoluteTime_to_scalar(result) = (abstime_scalar_t)interval * scale_factor;
971: }
972:
973: void
974: clock_absolutetime_interval_to_deadline(
975: AbsoluteTime abstime,
976: AbsoluteTime *result)
977: {
978: clock_get_uptime(result);
979:
980: ADD_ABSOLUTETIME(result, &abstime);
981: }
982:
983: void
984: absolutetime_to_nanoseconds(
985: AbsoluteTime abstime,
986: UInt64 *result)
987: {
988: *result = AbsoluteTime_to_scalar(&abstime);
989: }
990:
991: void
992: nanoseconds_to_absolutetime(
993: UInt64 nanoseconds,
994: AbsoluteTime *result)
995: {
996: AbsoluteTime_to_scalar(result) = nanoseconds;
997: }
998:
999: /*
1000: * measure_delay(microseconds)
1001: *
1002: * Measure elapsed time for delay calls
1003: * Returns microseconds.
1004: *
1005: * Microseconds must not be too large since the counter (short)
1006: * will roll over. Max is about 13 ms. Values smaller than 1 ms are ok.
1007: * This uses the assumed frequency of the rt clock which is emperically
1008: * accurate to only about 200 ppm.
1009: */
1010:
1011: int
1012: measure_delay(
1013: int us)
1014: {
1015: unsigned int lsb, val;
1016:
1017: outb(PITCTL_PORT, PIT_C0|PIT_NDIVMODE|PIT_READMODE);
1018: outb(PITCTR0_PORT, 0xff); /* set counter to max value */
1019: outb(PITCTR0_PORT, 0xff);
1020: delay(us);
1021: outb(PITCTL_PORT, PIT_C0);
1022: lsb = inb(PITCTR0_PORT);
1023: val = (inb(PITCTR0_PORT) << 8) | lsb;
1024: val = 0xffff - val;
1025: val *= 1000000;
1026: val /= CLKNUM;
1027: return(val);
1028: }
1029:
1030: /*
1031: * calibrate_delay(void)
1032: *
1033: * Adjust delaycount. Called from startup before clock is started
1034: * for normal interrupt generation.
1035: */
1036:
1037: void
1038: calibrate_delay(void)
1039: {
1040: unsigned val;
1041: int prev = 0;
1042: register int i;
1043:
1044: printf("adjusting delay count: %d", delaycount);
1045: for (i=0; i<10; i++) {
1046: prev = delaycount;
1047: /*
1048: * microdata must not be to large since measure_timer
1049: * will not return accurate values if the counter (short)
1050: * rolls over
1051: */
1052: val = measure_delay(microdata);
1053: delaycount *= microdata;
1054: delaycount += val-1; /* round up to upper us */
1055: delaycount /= val;
1056: if (delaycount <= 0)
1057: delaycount = 1;
1058: if (delaycount != prev)
1059: printf(" %d", delaycount);
1060: }
1061: printf("\n");
1062: }
1063:
1064: #if MACH_KDB
1065: void
1066: test_delay(void);
1067:
1068: void
1069: test_delay(void)
1070: {
1071: register i;
1072:
1073: for (i = 0; i < 10; i++)
1074: printf("%d, %d\n", i, measure_delay(i));
1075: for (i = 10; i <= 100; i+=10)
1076: printf("%d, %d\n", i, measure_delay(i));
1077: }
1078: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.