This source file includes following definitions.
- mc146818_read
- mc146818_write
- startrtclock
- rtcdrain
- initrtclock
- clockintr
- rtcintr
- gettick
- i8254_delay
- calibrate_cyclecounter
- i8254_initclocks
- rtcget
- rtcput
- hexdectodec
- dectohexdec
- cmoscheck
- clock_expandyear
- inittodr
- resettodr
- setstatclockrate
- i8254_inittimecounter
- i8254_inittimecounter_simple
- i8254_simple_get_timecount
- i8254_get_timecount
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 #include <sys/types.h>
89 #include <sys/param.h>
90 #include <sys/systm.h>
91 #include <sys/time.h>
92 #include <sys/kernel.h>
93 #include <sys/device.h>
94 #include <sys/timeout.h>
95 #include <sys/timetc.h>
96 #include <sys/mutex.h>
97
98 #include <machine/cpu.h>
99 #include <machine/intr.h>
100 #include <machine/pio.h>
101 #include <machine/cpufunc.h>
102
103 #include <dev/isa/isareg.h>
104 #include <dev/isa/isavar.h>
105 #include <dev/ic/mc146818reg.h>
106 #include <dev/ic/i8253reg.h>
107 #include <i386/isa/nvram.h>
108
109 void spinwait(int);
110 int clockintr(void *);
111 int gettick(void);
112 int rtcget(mc_todregs *);
113 void rtcput(mc_todregs *);
114 int hexdectodec(int);
115 int dectohexdec(int);
116 int rtcintr(void *);
117 void rtcdrain(void *);
118
119 u_int mc146818_read(void *, u_int);
120 void mc146818_write(void *, u_int, u_int);
121
122 #if defined(I586_CPU) || defined(I686_CPU)
123 int cpuspeed;
124 #endif
125 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
126 int clock_broken_latch;
127 #endif
128
129
130 uint32_t i8254_lastcount;
131 uint32_t i8254_offset;
132 int i8254_ticked;
133 u_int i8254_get_timecount(struct timecounter *tc);
134 u_int i8254_simple_get_timecount(struct timecounter *tc);
135
136 static struct timecounter i8254_timecounter = {
137 i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL
138 };
139 struct mutex timer_mutex = MUTEX_INITIALIZER(IPL_HIGH);
140 u_long rtclock_tval;
141
142 #define SECMIN ((unsigned)60)
143 #define SECHOUR ((unsigned)(60*SECMIN))
144
145 u_int
146 mc146818_read(void *sc, u_int reg)
147 {
148 int s;
149 u_char v;
150
151 s = splhigh();
152 outb(IO_RTC, reg);
153 DELAY(1);
154 v = inb(IO_RTC+1);
155 DELAY(1);
156 splx(s);
157 return (v);
158 }
159
160 void
161 mc146818_write(void *sc, u_int reg, u_int datum)
162 {
163 int s;
164
165 s = splhigh();
166 outb(IO_RTC, reg);
167 DELAY(1);
168 outb(IO_RTC+1, datum);
169 DELAY(1);
170 splx(s);
171 }
172
173 void
174 startrtclock(void)
175 {
176 int s;
177
178 initrtclock();
179
180
181 if ((s = mc146818_read(NULL, NVRAM_DIAG)) != 0)
182 printf("RTC BIOS diagnostic error %b\n", (unsigned int) s,
183 NVRAM_DIAG_BITS);
184 }
185
186 void
187 rtcdrain(void *v)
188 {
189 struct timeout *to = (struct timeout *)v;
190
191 if (to != NULL)
192 timeout_del(to);
193
194
195
196
197
198 while (mc146818_read(NULL, MC_REGC) & MC_REGC_PF)
199 ;
200 }
201
202 void
203 initrtclock(void)
204 {
205 mtx_enter(&timer_mutex);
206
207
208 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
209
210
211 outb(IO_TIMER1, TIMER_DIV(hz) % 256);
212 outb(IO_TIMER1, TIMER_DIV(hz) / 256);
213
214 rtclock_tval = TIMER_DIV(hz);
215 mtx_leave(&timer_mutex);
216 }
217
218 int
219 clockintr(void *arg)
220 {
221 struct clockframe *frame = arg;
222
223 if (timecounter->tc_get_timecount == i8254_get_timecount) {
224 if (i8254_ticked) {
225 i8254_ticked = 0;
226 } else {
227 i8254_offset += rtclock_tval;
228 i8254_lastcount = 0;
229 }
230 }
231
232 hardclock(frame);
233 return (1);
234 }
235
236 int
237 rtcintr(void *arg)
238 {
239 struct clockframe *frame = arg;
240 u_int stat = 0;
241
242
243
244
245
246 while (mc146818_read(NULL, MC_REGC) & MC_REGC_PF) {
247 statclock(frame);
248 stat = 1;
249 }
250 return (stat);
251 }
252
253 int
254 gettick(void)
255 {
256
257 #if defined(I586_CPU) || defined(I686_CPU)
258 if (clock_broken_latch) {
259 int v1, v2, v3;
260 int w1, w2, w3;
261
262
263
264
265
266
267 disable_intr();
268
269 v1 = inb(IO_TIMER1 + TIMER_CNTR0);
270 v1 |= inb(IO_TIMER1 + TIMER_CNTR0) << 8;
271 v2 = inb(IO_TIMER1 + TIMER_CNTR0);
272 v2 |= inb(IO_TIMER1 + TIMER_CNTR0) << 8;
273 v3 = inb(IO_TIMER1 + TIMER_CNTR0);
274 v3 |= inb(IO_TIMER1 + TIMER_CNTR0) << 8;
275
276 enable_intr();
277
278 if (v1 >= v2 && v2 >= v3 && v1 - v3 < 0x200)
279 return (v2);
280
281 #define _swap_val(a, b) do { \
282 int c = a; \
283 a = b; \
284 b = c; \
285 } while (0)
286
287
288 if (v1 < v2)
289 _swap_val(v1, v2);
290 if (v2 < v3)
291 _swap_val(v2, v3);
292 if (v1 < v2)
293 _swap_val(v1, v2);
294
295
296 if (v1 - v3 < 0x200)
297 return (v2);
298 w1 = v2 - v3;
299 w2 = v3 - v1 + TIMER_DIV(hz);
300 w3 = v1 - v2;
301 if (w1 >= w2) {
302 if (w1 >= w3)
303 return (v1);
304 } else {
305 if (w2 >= w3)
306 return (v2);
307 }
308 return (v3);
309 } else
310 #endif
311 {
312 u_char lo, hi;
313 u_long ef;
314
315 mtx_enter(&timer_mutex);
316 ef = read_eflags();
317 disable_intr();
318
319 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
320 lo = inb(IO_TIMER1 + TIMER_CNTR0);
321 hi = inb(IO_TIMER1 + TIMER_CNTR0);
322
323 write_eflags(ef);
324 mtx_leave(&timer_mutex);
325 return ((hi << 8) | lo);
326 }
327 }
328
329
330
331
332
333
334
335
336 void
337 i8254_delay(int n)
338 {
339 int limit, tick, otick;
340
341
342
343
344
345 otick = gettick();
346
347 #ifdef __GNUC__
348
349
350
351
352
353 n -= 5;
354 if (n < 0)
355 return;
356 __asm __volatile("mul %2\n\tdiv %3"
357 : "=a" (n)
358 : "0" (n), "r" (TIMER_FREQ), "r" (1000000)
359 : "%edx", "cc");
360 #else
361
362
363
364
365 n -= 20;
366 {
367 int sec = n / 1000000,
368 usec = n % 1000000;
369 n = sec * TIMER_FREQ +
370 usec * (TIMER_FREQ / 1000000) +
371 usec * ((TIMER_FREQ % 1000000) / 1000) / 1000 +
372 usec * (TIMER_FREQ % 1000) / 1000000;
373 }
374 #endif
375
376 limit = TIMER_FREQ / hz;
377
378 while (n > 0) {
379 tick = gettick();
380 if (tick > otick)
381 n -= limit - (tick - otick);
382 else
383 n -= otick - tick;
384 otick = tick;
385 }
386 }
387
388 #if defined(I586_CPU) || defined(I686_CPU)
389 void
390 calibrate_cyclecounter(void)
391 {
392 unsigned long long count, last_count;
393
394 __asm __volatile("rdtsc" : "=A" (last_count));
395 delay(1000000);
396 __asm __volatile("rdtsc" : "=A" (count));
397 cpuspeed = ((count - last_count) + 999999) / 1000000;
398 }
399 #endif
400
401 void
402 i8254_initclocks(void)
403 {
404 static struct timeout rtcdrain_timeout;
405 stathz = 128;
406 profhz = 1024;
407
408
409
410
411
412 (void)isa_intr_establish(NULL, 0, IST_PULSE, IPL_CLOCK, clockintr,
413 0, "clock");
414 (void)isa_intr_establish(NULL, 8, IST_PULSE, IPL_CLOCK, rtcintr,
415 0, "rtc");
416
417 mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_128_Hz);
418 mc146818_write(NULL, MC_REGB, MC_REGB_24HR | MC_REGB_PIE);
419
420
421
422
423
424
425
426
427
428
429 timeout_set(&rtcdrain_timeout, rtcdrain, (void *)&rtcdrain_timeout);
430 timeout_add(&rtcdrain_timeout, 1);
431 }
432
433 int
434 rtcget(mc_todregs *regs)
435 {
436 if ((mc146818_read(NULL, MC_REGD) & MC_REGD_VRT) == 0)
437 return (-1);
438 MC146818_GETTOD(NULL, regs);
439 return (0);
440 }
441
442 void
443 rtcput(mc_todregs *regs)
444 {
445 MC146818_PUTTOD(NULL, regs);
446 }
447
448 int
449 hexdectodec(int n)
450 {
451
452 return (((n >> 4) & 0x0f) * 10 + (n & 0x0f));
453 }
454
455 int
456 dectohexdec(int n)
457 {
458
459 return ((u_char)(((n / 10) << 4) & 0xf0) | ((n % 10) & 0x0f));
460 }
461
462 static int timeset;
463
464
465
466
467
468 int cmoscheck(void);
469 int
470 cmoscheck(void)
471 {
472 int i;
473 unsigned short cksum = 0;
474
475 for (i = 0x10; i <= 0x2d; i++)
476 cksum += mc146818_read(NULL, i);
477
478 return (cksum == (mc146818_read(NULL, 0x2e) << 8)
479 + mc146818_read(NULL, 0x2f));
480 }
481
482
483
484
485
486
487
488 int rtc_update_century = 0;
489
490
491
492
493
494
495 int clock_expandyear(int);
496 int
497 clock_expandyear(int clockyear)
498 {
499 int s, clockcentury, cmoscentury;
500
501 clockcentury = (clockyear < 70) ? 20 : 19;
502 clockyear += 100 * clockcentury;
503
504 if (rtc_update_century < 0)
505 return (clockyear);
506
507 s = splclock();
508 if (cmoscheck())
509 cmoscentury = mc146818_read(NULL, NVRAM_CENTURY);
510 else
511 cmoscentury = 0;
512 splx(s);
513 if (!cmoscentury) {
514 #ifdef DIAGNOSTIC
515 printf("clock: unknown CMOS layout\n");
516 #endif
517 return (clockyear);
518 }
519 cmoscentury = hexdectodec(cmoscentury);
520
521 if (cmoscentury != clockcentury) {
522
523 printf("WARNING: NVRAM century is %d but RTC year is %d\n",
524 cmoscentury, clockyear);
525
526
527 if ((rtc_update_century > 0) ||
528 ((cmoscentury == 19) && (clockcentury == 20) &&
529 (clockyear == 2000))) {
530 printf("WARNING: Setting NVRAM century to %d\n",
531 clockcentury);
532 s = splclock();
533 mc146818_write(NULL, NVRAM_CENTURY,
534 dectohexdec(clockcentury));
535 splx(s);
536 }
537 } else if (cmoscentury == 19 && rtc_update_century == 0)
538 rtc_update_century = 1;
539
540 return (clockyear);
541 }
542
543
544
545
546
547 void
548 inittodr(time_t base)
549 {
550 struct timespec ts;
551 mc_todregs rtclk;
552 struct clock_ymdhms dt;
553 int s;
554
555
556 ts.tv_nsec = 0;
557
558
559
560
561
562
563
564
565
566 if (base < 15*SECYR) {
567 printf("WARNING: preposterous time in file system\n");
568
569 base = 17*SECYR + 186*SECDAY + SECDAY/2;
570 }
571
572 s = splclock();
573 if (rtcget(&rtclk)) {
574 splx(s);
575 printf("WARNING: invalid time in clock chip\n");
576 goto fstime;
577 }
578 splx(s);
579
580 dt.dt_sec = hexdectodec(rtclk[MC_SEC]);
581 dt.dt_min = hexdectodec(rtclk[MC_MIN]);
582 dt.dt_hour = hexdectodec(rtclk[MC_HOUR]);
583 dt.dt_day = hexdectodec(rtclk[MC_DOM]);
584 dt.dt_mon = hexdectodec(rtclk[MC_MONTH]);
585 dt.dt_year = clock_expandyear(hexdectodec(rtclk[MC_YEAR]));
586
587
588
589
590
591
592
593
594
595
596
597
598 if (sizeof(time_t) <= sizeof(int32_t)) {
599 if (dt.dt_year >= 2038) {
600 printf("WARNING: RTC time at or beyond 2038.\n");
601 dt.dt_year = 2037;
602 printf("WARNING: year set back to 2037.\n");
603 printf("WARNING: CHECK AND RESET THE DATE!\n");
604 }
605 }
606
607 ts.tv_sec = clock_ymdhms_to_secs(&dt) + tz.tz_minuteswest * 60;
608 if (tz.tz_dsttime)
609 ts.tv_sec -= 3600;
610
611 if (base < ts.tv_sec - 5*SECYR)
612 printf("WARNING: file system time much less than clock time\n");
613 else if (base > ts.tv_sec + 5*SECYR) {
614 printf("WARNING: clock time much less than file system time\n");
615 printf("WARNING: using file system time\n");
616 goto fstime;
617 }
618
619 tc_setclock(&ts);
620 timeset = 1;
621 return;
622
623 fstime:
624 ts.tv_sec = base;
625 tc_setclock(&ts);
626 timeset = 1;
627 printf("WARNING: CHECK AND RESET THE DATE!\n");
628 }
629
630
631
632
633 void
634 resettodr(void)
635 {
636 mc_todregs rtclk;
637 struct clock_ymdhms dt;
638 int diff;
639 int century;
640 int s;
641
642
643
644
645
646 if (!timeset)
647 return;
648
649 s = splclock();
650 if (rtcget(&rtclk))
651 bzero(&rtclk, sizeof(rtclk));
652 splx(s);
653
654 diff = tz.tz_minuteswest * 60;
655 if (tz.tz_dsttime)
656 diff -= 3600;
657 clock_secs_to_ymdhms(time_second - diff, &dt);
658
659 rtclk[MC_SEC] = dectohexdec(dt.dt_sec);
660 rtclk[MC_MIN] = dectohexdec(dt.dt_min);
661 rtclk[MC_HOUR] = dectohexdec(dt.dt_hour);
662 rtclk[MC_DOW] = dt.dt_wday;
663 rtclk[MC_YEAR] = dectohexdec(dt.dt_year % 100);
664 rtclk[MC_MONTH] = dectohexdec(dt.dt_mon);
665 rtclk[MC_DOM] = dectohexdec(dt.dt_day);
666 s = splclock();
667 rtcput(&rtclk);
668 if (rtc_update_century > 0) {
669 century = dectohexdec(dt.dt_year / 100);
670 mc146818_write(NULL, NVRAM_CENTURY, century);
671 }
672 splx(s);
673 }
674
675 void
676 setstatclockrate(int arg)
677 {
678 if (arg == stathz)
679 mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_128_Hz);
680 else
681 mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_1024_Hz);
682 }
683
684 void
685 i8254_inittimecounter(void)
686 {
687 tc_init(&i8254_timecounter);
688 }
689
690
691
692
693
694 void
695 i8254_inittimecounter_simple(void)
696 {
697 u_long tval = 0x8000;
698
699 i8254_timecounter.tc_get_timecount = i8254_simple_get_timecount;
700 i8254_timecounter.tc_counter_mask = 0x7fff;
701
702 i8254_timecounter.tc_frequency = TIMER_FREQ;
703
704 mtx_enter(&timer_mutex);
705 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
706 outb(IO_TIMER1, tval & 0xff);
707 outb(IO_TIMER1, tval >> 8);
708
709 rtclock_tval = tval;
710 mtx_leave(&timer_mutex);
711
712 tc_init(&i8254_timecounter);
713 }
714
715 u_int
716 i8254_simple_get_timecount(struct timecounter *tc)
717 {
718 return (rtclock_tval - gettick());
719 }
720
721 u_int
722 i8254_get_timecount(struct timecounter *tc)
723 {
724 u_char hi, lo;
725 u_int count;
726 u_long ef;
727
728 ef = read_eflags();
729 disable_intr();
730
731 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
732 lo = inb(IO_TIMER1 + TIMER_CNTR0);
733 hi = inb(IO_TIMER1 + TIMER_CNTR0);
734
735 count = rtclock_tval - ((hi << 8) | lo);
736
737 if (count < i8254_lastcount) {
738 i8254_ticked = 1;
739 i8254_offset += rtclock_tval;
740 }
741 i8254_lastcount = count;
742 count += i8254_offset;
743 write_eflags(ef);
744
745 return (count);
746 }