pcrtc.c revision 27546
1/*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * William Jolitz and Don Ahn. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 37 * $Id: clock.c,v 1.27 1997/07/13 12:14:18 kato Exp $ 38 */ 39 40/* 41 * Routines to handle clock hardware. 42 */ 43 44/* 45 * inittodr, settodr and support routines written 46 * by Christoph Robitschko <chmr@edvz.tu-graz.ac.at> 47 * 48 * reintroduced and updated by Chris Stenton <chris@gnome.co.uk> 8/10/94 49 */ 50 51/* 52 * modified for PC98 by Kakefuda 53 */ 54 55#include "opt_clock.h" 56#include "opt_cpu.h" 57 58#include <sys/param.h> 59#include <sys/systm.h> 60#include <sys/time.h> 61#include <sys/kernel.h> 62#include <sys/sysctl.h> 63 64#include <machine/clock.h> 65#ifdef CLK_CALIBRATION_LOOP 66#include <machine/cons.h> 67#endif 68#include <machine/cpu.h> 69#include <machine/frame.h> 70#include <machine/ipl.h> 71#ifdef APIC_IO 72#include <machine/smp.h> 73#include <machine/smptests.h> /** TEST_ALTTIMER, APIC_PIN0_TIMER */ 74#endif /* APIC_IO */ 75 76#include <i386/isa/icu.h> 77#ifdef PC98 78#include <pc98/pc98/pc98.h> 79#include <pc98/pc98/pc98_machdep.h> 80#include <i386/isa/isa_device.h> 81#else 82#include <i386/isa/isa.h> 83#include <i386/isa/intr_machdep.h> 84#include <i386/isa/rtc.h> 85#endif 86#include <i386/isa/timerreg.h> 87 88/* 89 * 32-bit time_t's can't reach leap years before 1904 or after 2036, so we 90 * can use a simple formula for leap years. 91 */ 92#define LEAPYEAR(y) ((u_int)(y) % 4 == 0) 93#define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31) 94 95#define TIMER_DIV(x) ((timer_freq + (x) / 2) / (x)) 96 97/* 98 * Time in timer cycles that it takes for microtime() to disable interrupts 99 * and latch the count. microtime() currently uses "cli; outb ..." so it 100 * normally takes less than 2 timer cycles. Add a few for cache misses. 101 * Add a few more to allow for latency in bogus calls to microtime() with 102 * interrupts already disabled. 103 */ 104#define TIMER0_LATCH_COUNT 20 105 106/* 107 * Maximum frequency that we are willing to allow for timer0. Must be 108 * low enough to guarantee that the timer interrupt handler returns 109 * before the next timer interrupt. Must result in a lower TIMER_DIV 110 * value than TIMER0_LATCH_COUNT so that we don't have to worry about 111 * underflow in the calculation of timer0_overflow_threshold. 112 */ 113#define TIMER0_MAX_FREQ 20000 114 115int adjkerntz; /* local offset from GMT in seconds */ 116int disable_rtc_set; /* disable resettodr() if != 0 */ 117u_int idelayed; 118#if defined(I586_CPU) || defined(I686_CPU) 119#ifndef SMP 120u_int i586_ctr_bias; 121u_int i586_ctr_comultiplier; 122#endif 123u_int i586_ctr_freq; 124#ifndef SMP 125u_int i586_ctr_multiplier; 126#endif 127#endif 128int statclock_disable; 129u_int stat_imask = SWI_CLOCK_MASK; 130#ifdef TIMER_FREQ 131u_int timer_freq = TIMER_FREQ; 132#else 133#ifdef PC98 134#ifndef AUTO_CLOCK 135#ifndef PC98_8M 136u_int timer_freq = 2457600; 137#else /* !PC98_8M */ 138u_int timer_freq = 1996800; 139#endif /* PC98_8M */ 140#else /* AUTO_CLOCK */ 141u_int timer_freq = 2457600; 142#endif /* AUTO_CLOCK */ 143#else /* IBM-PC */ 144u_int timer_freq = 1193182; 145#endif /* PC98 */ 146#endif 147int timer0_max_count; 148u_int timer0_overflow_threshold; 149u_int timer0_prescaler_count; 150int wall_cmos_clock; /* wall CMOS clock assumed if != 0 */ 151 152static int beeping = 0; 153static u_int clk_imask = HWI_MASK | SWI_MASK; 154static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31}; 155static u_int hardclock_max_count; 156/* 157 * XXX new_function and timer_func should not handle clockframes, but 158 * timer_func currently needs to hold hardclock to handle the 159 * timer0_state == 0 case. We should use register_intr()/unregister_intr() 160 * to switch between clkintr() and a slightly different timerintr(). 161 */ 162static void (*new_function) __P((struct clockframe *frame)); 163static u_int new_rate; 164#ifndef PC98 165static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; 166static u_char rtc_statusb = RTCSB_24HR | RTCSB_PINTR; 167#endif 168 169/* Values for timerX_state: */ 170#define RELEASED 0 171#define RELEASE_PENDING 1 172#define ACQUIRED 2 173#define ACQUIRE_PENDING 3 174 175static u_char timer0_state; 176#ifdef PC98 177static u_char timer1_state; 178#endif 179static u_char timer2_state; 180static void (*timer_func) __P((struct clockframe *frame)) = hardclock; 181#ifdef PC98 182static void rtc_serialcombit __P((int)); 183static void rtc_serialcom __P((int)); 184static int rtc_inb __P((void)); 185static void rtc_outb __P((int)); 186#endif 187 188#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) 189static void set_i586_ctr_freq(u_int i586_freq, u_int i8254_freq); 190#endif 191static void set_timer_freq(u_int freq, int intr_freq); 192 193static void 194clkintr(struct clockframe frame) 195{ 196 timer_func(&frame); 197 switch (timer0_state) { 198 199 case RELEASED: 200 setdelayed(); 201 break; 202 203 case ACQUIRED: 204 if ((timer0_prescaler_count += timer0_max_count) 205 >= hardclock_max_count) { 206 hardclock(&frame); 207 setdelayed(); 208 timer0_prescaler_count -= hardclock_max_count; 209 } 210 break; 211 212 case ACQUIRE_PENDING: 213 setdelayed(); 214 timer0_max_count = TIMER_DIV(new_rate); 215 timer0_overflow_threshold = 216 timer0_max_count - TIMER0_LATCH_COUNT; 217 disable_intr(); 218 outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 219 outb(TIMER_CNTR0, timer0_max_count & 0xff); 220 outb(TIMER_CNTR0, timer0_max_count >> 8); 221 enable_intr(); 222 timer0_prescaler_count = 0; 223 timer_func = new_function; 224 timer0_state = ACQUIRED; 225 break; 226 227 case RELEASE_PENDING: 228 if ((timer0_prescaler_count += timer0_max_count) 229 >= hardclock_max_count) { 230 hardclock(&frame); 231 setdelayed(); 232 timer0_max_count = hardclock_max_count; 233 timer0_overflow_threshold = 234 timer0_max_count - TIMER0_LATCH_COUNT; 235 disable_intr(); 236 outb(TIMER_MODE, 237 TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 238 outb(TIMER_CNTR0, timer0_max_count & 0xff); 239 outb(TIMER_CNTR0, timer0_max_count >> 8); 240 enable_intr(); 241 /* 242 * See microtime.s for this magic. 243 */ 244#ifdef PC98 245#ifndef AUTO_CLOCK 246#ifndef PC98_8M 247 time.tv_usec += (6667 * 248 (timer0_prescaler_count - hardclock_max_count)) 249 >> 14; 250#else /* PC98_8M */ 251 time.tv_usec += (16411 * 252 (timer0_prescaler_count - hardclock_max_count)) 253 >> 15; 254#endif /* PC98_8M */ 255#else /* AUTO_CLOCK */ 256 if (pc98_machine_type & M_8M) { 257 /* PC98_8M */ 258 time.tv_usec += (16411 * 259 (timer0_prescaler_count - 260 hardclock_max_count)) >> 15; 261 } else { 262 time.tv_usec += (6667 * 263 (timer0_prescaler_count - 264 hardclock_max_count)) >> 14; 265 } 266#endif /* AUTO_CLOCK */ 267#else /* IBM-PC */ 268 time.tv_usec += (27465 * 269 (timer0_prescaler_count - hardclock_max_count)) 270 >> 15; 271#endif /* PC98 */ 272 if (time.tv_usec >= 1000000) 273 time.tv_usec -= 1000000; 274 timer0_prescaler_count = 0; 275 timer_func = hardclock; 276 timer0_state = RELEASED; 277 } 278 break; 279 } 280} 281 282/* 283 * The acquire and release functions must be called at ipl >= splclock(). 284 */ 285int 286acquire_timer0(int rate, void (*function) __P((struct clockframe *frame))) 287{ 288 static int old_rate; 289 290 if (rate <= 0 || rate > TIMER0_MAX_FREQ) 291 return (-1); 292 switch (timer0_state) { 293 294 case RELEASED: 295 timer0_state = ACQUIRE_PENDING; 296 break; 297 298 case RELEASE_PENDING: 299 if (rate != old_rate) 300 return (-1); 301 /* 302 * The timer has been released recently, but is being 303 * re-acquired before the release completed. In this 304 * case, we simply reclaim it as if it had not been 305 * released at all. 306 */ 307 timer0_state = ACQUIRED; 308 break; 309 310 default: 311 return (-1); /* busy */ 312 } 313 new_function = function; 314 old_rate = new_rate = rate; 315 return (0); 316} 317 318#ifdef PC98 319int 320acquire_timer1(int mode) 321{ 322 323 if (timer1_state != RELEASED) 324 return (-1); 325 timer1_state = ACQUIRED; 326 327 /* 328 * This access to the timer registers is as atomic as possible 329 * because it is a single instruction. We could do better if we 330 * knew the rate. Use of splclock() limits glitches to 10-100us, 331 * and this is probably good enough for timer2, so we aren't as 332 * careful with it as with timer0. 333 */ 334 outb(TIMER_MODE, TIMER_SEL1 | (mode & 0x3f)); 335 336 return (0); 337} 338#endif 339 340int 341acquire_timer2(int mode) 342{ 343 344 if (timer2_state != RELEASED) 345 return (-1); 346 timer2_state = ACQUIRED; 347 348 /* 349 * This access to the timer registers is as atomic as possible 350 * because it is a single instruction. We could do better if we 351 * knew the rate. Use of splclock() limits glitches to 10-100us, 352 * and this is probably good enough for timer2, so we aren't as 353 * careful with it as with timer0. 354 */ 355 outb(TIMER_MODE, TIMER_SEL2 | (mode & 0x3f)); 356 357 return (0); 358} 359 360int 361release_timer0() 362{ 363 switch (timer0_state) { 364 365 case ACQUIRED: 366 timer0_state = RELEASE_PENDING; 367 break; 368 369 case ACQUIRE_PENDING: 370 /* Nothing happened yet, release quickly. */ 371 timer0_state = RELEASED; 372 break; 373 374 default: 375 return (-1); 376 } 377 return (0); 378} 379 380#ifdef PC98 381int 382release_timer1() 383{ 384 385 if (timer1_state != ACQUIRED) 386 return (-1); 387 timer1_state = RELEASED; 388 outb(TIMER_MODE, TIMER_SEL1 | TIMER_SQWAVE | TIMER_16BIT); 389 return (0); 390} 391#endif 392 393int 394release_timer2() 395{ 396 397 if (timer2_state != ACQUIRED) 398 return (-1); 399 timer2_state = RELEASED; 400 outb(TIMER_MODE, TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT); 401 return (0); 402} 403 404#ifndef PC98 405/* 406 * This routine receives statistical clock interrupts from the RTC. 407 * As explained above, these occur at 128 interrupts per second. 408 * When profiling, we receive interrupts at a rate of 1024 Hz. 409 * 410 * This does not actually add as much overhead as it sounds, because 411 * when the statistical clock is active, the hardclock driver no longer 412 * needs to keep (inaccurate) statistics on its own. This decouples 413 * statistics gathering from scheduling interrupts. 414 * 415 * The RTC chip requires that we read status register C (RTC_INTR) 416 * to acknowledge an interrupt, before it will generate the next one. 417 * Under high interrupt load, rtcintr() can be indefinitely delayed and 418 * the clock can tick immediately after the read from RTC_INTR. In this 419 * case, the mc146818A interrupt signal will not drop for long enough 420 * to register with the 8259 PIC. If an interrupt is missed, the stat 421 * clock will halt, considerably degrading system performance. This is 422 * why we use 'while' rather than a more straightforward 'if' below. 423 * Stat clock ticks can still be lost, causing minor loss of accuracy 424 * in the statistics, but the stat clock will no longer stop. 425 */ 426static void 427rtcintr(struct clockframe frame) 428{ 429 while (rtcin(RTC_INTR) & RTCIR_PERIOD) 430 statclock(&frame); 431} 432 433#include "opt_ddb.h" 434#ifdef DDB 435#include <ddb/ddb.h> 436 437DB_SHOW_COMMAND(rtc, rtc) 438{ 439 printf("%02x/%02x/%02x %02x:%02x:%02x, A = %02x, B = %02x, C = %02x\n", 440 rtcin(RTC_YEAR), rtcin(RTC_MONTH), rtcin(RTC_DAY), 441 rtcin(RTC_HRS), rtcin(RTC_MIN), rtcin(RTC_SEC), 442 rtcin(RTC_STATUSA), rtcin(RTC_STATUSB), rtcin(RTC_INTR)); 443} 444#endif /* DDB */ 445#endif /* for PC98 */ 446 447static int 448getit(void) 449{ 450 u_long ef; 451 int high, low; 452 453 ef = read_eflags(); 454 disable_intr(); 455 456 /* Select timer0 and latch counter value. */ 457 outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 458 459 low = inb(TIMER_CNTR0); 460 high = inb(TIMER_CNTR0); 461 462 write_eflags(ef); 463 return ((high << 8) | low); 464} 465 466/* 467 * Wait "n" microseconds. 468 * Relies on timer 1 counting down from (timer_freq / hz) 469 * Note: timer had better have been programmed before this is first used! 470 */ 471void 472DELAY(int n) 473{ 474 int delta, prev_tick, tick, ticks_left; 475 476#ifdef DELAYDEBUG 477 int getit_calls = 1; 478 int n1; 479 static int state = 0; 480 481 if (state == 0) { 482 state = 1; 483 for (n1 = 1; n1 <= 10000000; n1 *= 10) 484 DELAY(n1); 485 state = 2; 486 } 487 if (state == 1) 488 printf("DELAY(%d)...", n); 489#endif 490 /* 491 * Guard against the timer being uninitialized if we are called 492 * early for console i/o. 493 */ 494 if (timer0_max_count == 0) 495 set_timer_freq(timer_freq, hz); 496 497 /* 498 * Read the counter first, so that the rest of the setup overhead is 499 * counted. Guess the initial overhead is 20 usec (on most systems it 500 * takes about 1.5 usec for each of the i/o's in getit(). The loop 501 * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The 502 * multiplications and divisions to scale the count take a while). 503 */ 504 prev_tick = getit(); 505 n -= 0; /* XXX actually guess no initial overhead */ 506 /* 507 * Calculate (n * (timer_freq / 1e6)) without using floating point 508 * and without any avoidable overflows. 509 */ 510 if (n <= 0) 511 ticks_left = 0; 512 else if (n < 256) 513 /* 514 * Use fixed point to avoid a slow division by 1000000. 515 * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest. 516 * 2^15 is the first power of 2 that gives exact results 517 * for n between 0 and 256. 518 */ 519 ticks_left = ((u_int)n * 39099 + (1 << 15) - 1) >> 15; 520 else 521 /* 522 * Don't bother using fixed point, although gcc-2.7.2 523 * generates particularly poor code for the long long 524 * division, since even the slow way will complete long 525 * before the delay is up (unless we're interrupted). 526 */ 527 ticks_left = ((u_int)n * (long long)timer_freq + 999999) 528 / 1000000; 529 530 while (ticks_left > 0) { 531 tick = getit(); 532#ifdef DELAYDEBUG 533 ++getit_calls; 534#endif 535 delta = prev_tick - tick; 536 prev_tick = tick; 537 if (delta < 0) { 538 delta += timer0_max_count; 539 /* 540 * Guard against timer0_max_count being wrong. 541 * This shouldn't happen in normal operation, 542 * but it may happen if set_timer_freq() is 543 * traced. 544 */ 545 if (delta < 0) 546 delta = 0; 547 } 548 ticks_left -= delta; 549 } 550#ifdef DELAYDEBUG 551 if (state == 1) 552 printf(" %d calls to getit() at %d usec each\n", 553 getit_calls, (n + 5) / getit_calls); 554#endif 555} 556 557static void 558sysbeepstop(void *chan) 559{ 560#ifdef PC98 /* PC98 */ 561 outb(IO_PPI, inb(IO_PPI)|0x08); /* disable counter1 output to speaker */ 562 release_timer1(); 563#else 564 outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */ 565 release_timer2(); 566#endif 567 beeping = 0; 568} 569 570int 571sysbeep(int pitch, int period) 572{ 573 int x = splclock(); 574 575#ifdef PC98 576 if (acquire_timer1(TIMER_SQWAVE|TIMER_16BIT)) 577 if (!beeping) { 578 /* Something else owns it. */ 579 splx(x); 580 return (-1); /* XXX Should be EBUSY, but nobody cares anyway. */ 581 } 582 disable_intr(); 583 outb(0x3fdb, pitch); 584 outb(0x3fdb, (pitch>>8)); 585 enable_intr(); 586 if (!beeping) { 587 /* enable counter1 output to speaker */ 588 outb(IO_PPI, (inb(IO_PPI) & 0xf7)); 589 beeping = period; 590 timeout(sysbeepstop, (void *)NULL, period); 591 } 592#else 593 if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT)) 594 if (!beeping) { 595 /* Something else owns it. */ 596 splx(x); 597 return (-1); /* XXX Should be EBUSY, but nobody cares anyway. */ 598 } 599 disable_intr(); 600 outb(TIMER_CNTR2, pitch); 601 outb(TIMER_CNTR2, (pitch>>8)); 602 enable_intr(); 603 if (!beeping) { 604 /* enable counter2 output to speaker */ 605 outb(IO_PPI, inb(IO_PPI) | 3); 606 beeping = period; 607 timeout(sysbeepstop, (void *)NULL, period); 608 } 609#endif 610 splx(x); 611 return (0); 612} 613 614#ifndef PC98 615/* 616 * RTC support routines 617 */ 618 619int 620rtcin(reg) 621 int reg; 622{ 623 u_char val; 624 625 outb(IO_RTC, reg); 626 inb(0x84); 627 val = inb(IO_RTC + 1); 628 inb(0x84); 629 return (val); 630} 631 632static __inline void 633writertc(u_char reg, u_char val) 634{ 635 outb(IO_RTC, reg); 636 outb(IO_RTC + 1, val); 637} 638 639static __inline int 640readrtc(int port) 641{ 642 return(bcd2bin(rtcin(port))); 643} 644#endif 645 646#ifdef PC98 647unsigned int delaycount; 648#define FIRST_GUESS 0x2000 649static void findcpuspeed(void) 650{ 651 int i; 652 int remainder; 653 654 /* Put counter in count down mode */ 655 outb(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN); 656 outb(TIMER_CNTR0, 0xff); 657 outb(TIMER_CNTR0, 0xff); 658 for (i = FIRST_GUESS; i; i--) 659 ; 660 remainder = getit(); 661 delaycount = (FIRST_GUESS * TIMER_DIV(1000)) / (0xffff - remainder); 662} 663#endif 664 665#ifndef PC98 666static u_int 667calibrate_clocks(void) 668{ 669 u_int count, prev_count, tot_count; 670 int sec, start_sec, timeout; 671 672 if (bootverbose) 673 printf("Calibrating clock(s) ... "); 674 if (!(rtcin(RTC_STATUSD) & RTCSD_PWR)) 675 goto fail; 676 timeout = 100000000; 677 678 /* Read the mc146818A seconds counter. */ 679 for (;;) { 680 if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) { 681 sec = rtcin(RTC_SEC); 682 break; 683 } 684 if (--timeout == 0) 685 goto fail; 686 } 687 688 /* Wait for the mC146818A seconds counter to change. */ 689 start_sec = sec; 690 for (;;) { 691 if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) { 692 sec = rtcin(RTC_SEC); 693 if (sec != start_sec) 694 break; 695 } 696 if (--timeout == 0) 697 goto fail; 698 } 699 700 /* Start keeping track of the i8254 counter. */ 701 prev_count = getit(); 702 if (prev_count == 0 || prev_count > timer0_max_count) 703 goto fail; 704 tot_count = 0; 705 706#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) 707 if (cpu_class == CPUCLASS_586 || cpu_class == CPUCLASS_686) 708 wrmsr(0x10, 0LL); /* XXX 0x10 is the MSR for the TSC */ 709#endif 710 711 /* 712 * Wait for the mc146818A seconds counter to change. Read the i8254 713 * counter for each iteration since this is convenient and only 714 * costs a few usec of inaccuracy. The timing of the final reads 715 * of the counters almost matches the timing of the initial reads, 716 * so the main cause of inaccuracy is the varying latency from 717 * inside getit() or rtcin(RTC_STATUSA) to the beginning of the 718 * rtcin(RTC_SEC) that returns a changed seconds count. The 719 * maximum inaccuracy from this cause is < 10 usec on 486's. 720 */ 721 start_sec = sec; 722 for (;;) { 723 if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) 724 sec = rtcin(RTC_SEC); 725 count = getit(); 726 if (count == 0 || count > timer0_max_count) 727 goto fail; 728 if (count > prev_count) 729 tot_count += prev_count - (count - timer0_max_count); 730 else 731 tot_count += prev_count - count; 732 prev_count = count; 733 if (sec != start_sec) 734 break; 735 if (--timeout == 0) 736 goto fail; 737 } 738 739#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) 740 /* 741 * Read the cpu cycle counter. The timing considerations are 742 * similar to those for the i8254 clock. 743 */ 744 if (cpu_class == CPUCLASS_586 || cpu_class == CPUCLASS_686) { 745 set_i586_ctr_freq((u_int)rdtsc(), tot_count); 746 if (bootverbose) 747 printf("i586 clock: %u Hz, ", i586_ctr_freq); 748 } 749#endif 750 751 if (bootverbose) 752 printf("i8254 clock: %u Hz\n", tot_count); 753 return (tot_count); 754 755fail: 756 if (bootverbose) 757 printf("failed, using default i8254 clock of %u Hz\n", 758 timer_freq); 759 return (timer_freq); 760} 761#endif /* !PC98 */ 762 763static void 764set_timer_freq(u_int freq, int intr_freq) 765{ 766 u_long ef; 767 768 ef = read_eflags(); 769 disable_intr(); 770 timer_freq = freq; 771 timer0_max_count = hardclock_max_count = TIMER_DIV(intr_freq); 772 timer0_overflow_threshold = timer0_max_count - TIMER0_LATCH_COUNT; 773 outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 774 outb(TIMER_CNTR0, timer0_max_count & 0xff); 775 outb(TIMER_CNTR0, timer0_max_count >> 8); 776 write_eflags(ef); 777} 778 779/* 780 * Initialize 8253 timer 0 early so that it can be used in DELAY(). 781 * XXX initialization of other timers is unintentionally left blank. 782 */ 783void 784startrtclock() 785{ 786 u_int delta, freq; 787 788#ifdef PC98 789 findcpuspeed(); 790#ifndef AUTO_CLOCK 791 if (pc98_machine_type & M_8M) { 792#ifndef PC98_8M 793 printf("you must reconfig a kernel with \"PC98_8M\" option.\n"); 794#endif 795 } else { 796#ifdef PC98_8M 797 printf("You must reconfig a kernel without \"PC98_8M\" option.\n"); 798#endif 799 } 800#else /* AUTO_CLOCK */ 801 if (pc98_machine_type & M_8M) 802 timer_freq = 1996800L; /* 1.9968 MHz */ 803 else 804 timer_freq = 2457600L; /* 2.4576 MHz */ 805#endif /* AUTO_CLOCK */ 806#endif /* PC98 */ 807 808#ifndef PC98 809 writertc(RTC_STATUSA, rtc_statusa); 810 writertc(RTC_STATUSB, RTCSB_24HR); 811#endif 812 813#ifndef PC98 814 set_timer_freq(timer_freq, hz); 815 freq = calibrate_clocks(); 816#ifdef CLK_CALIBRATION_LOOP 817 if (bootverbose) { 818 printf( 819 "Press a key on the console to abort clock calibration\n"); 820 while (cncheckc() == -1) 821 calibrate_clocks(); 822 } 823#endif 824 825 /* 826 * Use the calibrated i8254 frequency if it seems reasonable. 827 * Otherwise use the default, and don't use the calibrated i586 828 * frequency. 829 */ 830 delta = freq > timer_freq ? freq - timer_freq : timer_freq - freq; 831 if (delta < timer_freq / 100) { 832#ifndef CLK_USE_I8254_CALIBRATION 833 if (bootverbose) 834 printf( 835"CLK_USE_I8254_CALIBRATION not specified - using default frequency\n"); 836 freq = timer_freq; 837#endif 838 timer_freq = freq; 839 } else { 840 if (bootverbose) 841 printf( 842 "%d Hz differs from default of %d Hz by more than 1%%\n", 843 freq, timer_freq); 844#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) 845 i586_ctr_freq = 0; 846#endif 847 } 848#endif 849 850 set_timer_freq(timer_freq, hz); 851 852#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) 853#ifndef CLK_USE_I586_CALIBRATION 854 if (i586_ctr_freq != 0) { 855 if (bootverbose) 856 printf( 857"CLK_USE_I586_CALIBRATION not specified - using old calibration method\n"); 858 i586_ctr_freq = 0; 859 } 860#endif 861 if (i586_ctr_freq == 0 && 862 (cpu_class == CPUCLASS_586 || cpu_class == CPUCLASS_686)) { 863 /* 864 * Calibration of the i586 clock relative to the mc146818A 865 * clock failed. Do a less accurate calibration relative 866 * to the i8254 clock. 867 */ 868 wrmsr(0x10, 0LL); /* XXX */ 869 DELAY(1000000); 870 set_i586_ctr_freq((u_int)rdtsc(), timer_freq); 871#ifdef CLK_USE_I586_CALIBRATION 872 if (bootverbose) 873 printf("i586 clock: %u Hz\n", i586_ctr_freq); 874#endif 875 } 876#endif 877} 878 879#ifdef PC98 880static void 881rtc_serialcombit(int i) 882{ 883 outb(IO_RTC, ((i&0x01)<<5)|0x07); 884 DELAY(1); 885 outb(IO_RTC, ((i&0x01)<<5)|0x17); 886 DELAY(1); 887 outb(IO_RTC, ((i&0x01)<<5)|0x07); 888 DELAY(1); 889} 890 891static void 892rtc_serialcom(int i) 893{ 894 rtc_serialcombit(i&0x01); 895 rtc_serialcombit((i&0x02)>>1); 896 rtc_serialcombit((i&0x04)>>2); 897 rtc_serialcombit((i&0x08)>>3); 898 outb(IO_RTC, 0x07); 899 DELAY(1); 900 outb(IO_RTC, 0x0f); 901 DELAY(1); 902 outb(IO_RTC, 0x07); 903 DELAY(1); 904} 905 906static void 907rtc_outb(int val) 908{ 909 int s; 910 int sa = 0; 911 912 for (s=0;s<8;s++) { 913 sa = ((val >> s) & 0x01) ? 0x27 : 0x07; 914 outb(IO_RTC, sa); /* set DI & CLK 0 */ 915 DELAY(1); 916 outb(IO_RTC, sa | 0x10); /* CLK 1 */ 917 DELAY(1); 918 } 919 outb(IO_RTC, sa & 0xef); /* CLK 0 */ 920} 921 922static int 923rtc_inb(void) 924{ 925 int s; 926 int sa = 0; 927 928 for (s=0;s<8;s++) { 929 sa |= ((inb(0x33) & 0x01) << s); 930 outb(IO_RTC, 0x17); /* CLK 1 */ 931 DELAY(1); 932 outb(IO_RTC, 0x07); /* CLK 0 */ 933 DELAY(2); 934 } 935 return sa; 936} 937#endif /* PC-98 */ 938 939/* 940 * Initialize the time of day register, based on the time base which is, e.g. 941 * from a filesystem. 942 */ 943void 944inittodr(time_t base) 945{ 946 unsigned long sec, days; 947 int yd; 948 int year, month; 949 int y, m, s; 950#ifdef PC98 951 int second, min, hour; 952#endif 953 954 s = splclock(); 955 time.tv_sec = base; 956 time.tv_usec = 0; 957 splx(s); 958 959#ifdef PC98 960 rtc_serialcom(0x03); /* Time Read */ 961 rtc_serialcom(0x01); /* Register shift command. */ 962 DELAY(20); 963 964 second = bcd2bin(rtc_inb() & 0xff); /* sec */ 965 min = bcd2bin(rtc_inb() & 0xff); /* min */ 966 hour = bcd2bin(rtc_inb() & 0xff); /* hour */ 967 days = bcd2bin(rtc_inb() & 0xff) - 1; /* date */ 968 969 month = (rtc_inb() >> 4) & 0x0f; /* month */ 970 for (m = 1; m < month; m++) 971 days += daysinmonth[m-1]; 972 year = bcd2bin(rtc_inb() & 0xff) + 1900; /* year */ 973 /* 2000 year problem */ 974 if (year < 1995) 975 year += 100; 976 if (year < 1970) 977 goto wrong_time; 978 for (y = 1970; y < year; y++) 979 days += DAYSPERYEAR + LEAPYEAR(y); 980 if ((month > 2) && LEAPYEAR(year)) 981 days ++; 982 sec = ((( days * 24 + 983 hour) * 60 + 984 min) * 60 + 985 second); 986 /* sec now contains the number of seconds, since Jan 1 1970, 987 in the local time zone */ 988#else /* IBM-PC */ 989 /* Look if we have a RTC present and the time is valid */ 990 if (!(rtcin(RTC_STATUSD) & RTCSD_PWR)) 991 goto wrong_time; 992 993 /* wait for time update to complete */ 994 /* If RTCSA_TUP is zero, we have at least 244us before next update */ 995 while (rtcin(RTC_STATUSA) & RTCSA_TUP); 996 997 days = 0; 998#ifdef USE_RTC_CENTURY 999 year = readrtc(RTC_YEAR) + readrtc(RTC_CENTURY) * 100; 1000#else 1001 year = readrtc(RTC_YEAR) + 1900; 1002 if (year < 1970) 1003 year += 100; 1004#endif 1005 if (year < 1970) 1006 goto wrong_time; 1007 month = readrtc(RTC_MONTH); 1008 for (m = 1; m < month; m++) 1009 days += daysinmonth[m-1]; 1010 if ((month > 2) && LEAPYEAR(year)) 1011 days ++; 1012 days += readrtc(RTC_DAY) - 1; 1013 yd = days; 1014 for (y = 1970; y < year; y++) 1015 days += DAYSPERYEAR + LEAPYEAR(y); 1016 sec = ((( days * 24 + 1017 readrtc(RTC_HRS)) * 60 + 1018 readrtc(RTC_MIN)) * 60 + 1019 readrtc(RTC_SEC)); 1020 /* sec now contains the number of seconds, since Jan 1 1970, 1021 in the local time zone */ 1022#endif 1023 1024 sec += tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0); 1025 1026 s = splclock(); 1027 time.tv_sec = sec; 1028 splx(s); 1029 return; 1030 1031wrong_time: 1032 printf("Invalid time in real time clock.\n"); 1033 printf("Check and reset the date immediately!\n"); 1034} 1035 1036/* 1037 * Write system time back to RTC 1038 */ 1039void 1040resettodr() 1041{ 1042 unsigned long tm; 1043 int y, m, s; 1044#ifdef PC98 1045 int wd; 1046#endif 1047 1048 if (disable_rtc_set) 1049 return; 1050 1051 s = splclock(); 1052 tm = time.tv_sec; 1053 splx(s); 1054 1055#ifdef PC98 1056 rtc_serialcom(0x01); /* Register shift command. */ 1057 1058 /* Calculate local time to put in RTC */ 1059 1060 tm -= tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0); 1061 1062 rtc_outb(bin2bcd(tm%60)); tm /= 60; /* Write back Seconds */ 1063 rtc_outb(bin2bcd(tm%60)); tm /= 60; /* Write back Minutes */ 1064 rtc_outb(bin2bcd(tm%24)); tm /= 24; /* Write back Hours */ 1065 1066 /* We have now the days since 01-01-1970 in tm */ 1067 wd = (tm+4)%7; 1068 for (y = 1970, m = DAYSPERYEAR + LEAPYEAR(y); 1069 tm >= m; 1070 y++, m = DAYSPERYEAR + LEAPYEAR(y)) 1071 tm -= m; 1072 1073 /* Now we have the years in y and the day-of-the-year in tm */ 1074 for (m = 0; ; m++) { 1075 int ml; 1076 1077 ml = daysinmonth[m]; 1078 if (m == 1 && LEAPYEAR(y)) 1079 ml++; 1080 if (tm < ml) 1081 break; 1082 tm -= ml; 1083 } 1084 1085 m++; 1086 rtc_outb(bin2bcd(tm+1)); /* Write back Day */ 1087 rtc_outb((m << 4) | wd); /* Write back Month & Weekday */ 1088 rtc_outb(bin2bcd(y%100)); /* Write back Year */ 1089 1090 rtc_serialcom(0x02); /* Time set & Counter hold command. */ 1091 rtc_serialcom(0x00); /* Register hold command. */ 1092#else 1093 /* Disable RTC updates and interrupts. */ 1094 writertc(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR); 1095 1096 /* Calculate local time to put in RTC */ 1097 1098 tm -= tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0); 1099 1100 writertc(RTC_SEC, bin2bcd(tm%60)); tm /= 60; /* Write back Seconds */ 1101 writertc(RTC_MIN, bin2bcd(tm%60)); tm /= 60; /* Write back Minutes */ 1102 writertc(RTC_HRS, bin2bcd(tm%24)); tm /= 24; /* Write back Hours */ 1103 1104 /* We have now the days since 01-01-1970 in tm */ 1105 writertc(RTC_WDAY, (tm+4)%7); /* Write back Weekday */ 1106 for (y = 1970, m = DAYSPERYEAR + LEAPYEAR(y); 1107 tm >= m; 1108 y++, m = DAYSPERYEAR + LEAPYEAR(y)) 1109 tm -= m; 1110 1111 /* Now we have the years in y and the day-of-the-year in tm */ 1112 writertc(RTC_YEAR, bin2bcd(y%100)); /* Write back Year */ 1113#ifdef USE_RTC_CENTURY 1114 writertc(RTC_CENTURY, bin2bcd(y/100)); /* ... and Century */ 1115#endif 1116 for (m = 0; ; m++) { 1117 int ml; 1118 1119 ml = daysinmonth[m]; 1120 if (m == 1 && LEAPYEAR(y)) 1121 ml++; 1122 if (tm < ml) 1123 break; 1124 tm -= ml; 1125 } 1126 1127 writertc(RTC_MONTH, bin2bcd(m + 1)); /* Write back Month */ 1128 writertc(RTC_DAY, bin2bcd(tm + 1)); /* Write back Month Day */ 1129 1130 /* Reenable RTC updates and interrupts. */ 1131 writertc(RTC_STATUSB, rtc_statusb); 1132#endif 1133} 1134 1135#ifdef APIC_IO 1136/* XXX FIXME: from icu.s: */ 1137extern u_int ivectors[]; 1138extern u_int vec[]; 1139 1140extern void vec8254 __P((void)); 1141extern u_int Xintr8254; 1142extern u_int mask8254; 1143#ifdef DO_RTC_VEC 1144/** XXX FIXME: remove vevRTS stuff after several weeks of no problems */ 1145extern void vecRTC __P((void)); 1146extern u_int XintrRTC; 1147extern u_int maskRTC; 1148#endif /* DO_RTC_VEC */ 1149#endif /* APIC_IO */ 1150 1151/* 1152 * Start both clocks running. 1153 */ 1154void 1155cpu_initclocks() 1156{ 1157#ifdef APIC_IO 1158 int x; 1159#endif /* APIC_IO */ 1160#ifndef PC98 1161 int diag; 1162 1163 if (statclock_disable) { 1164 /* 1165 * The stat interrupt mask is different without the 1166 * statistics clock. Also, don't set the interrupt 1167 * flag which would normally cause the RTC to generate 1168 * interrupts. 1169 */ 1170 stat_imask = HWI_MASK | SWI_MASK; 1171 rtc_statusb = RTCSB_24HR; 1172 } else { 1173 /* Setting stathz to nonzero early helps avoid races. */ 1174 stathz = RTC_NOPROFRATE; 1175 profhz = RTC_PROFRATE; 1176 } 1177#endif 1178 1179 /* Finish initializing 8253 timer 0. */ 1180#ifdef APIC_IO 1181#ifdef APIC_PIN0_TIMER 1182 /* 1183 * Allow 8254 timer to INTerrupt 8259: 1184 * re-initialize master 8259: 1185 * reset; prog 4 bytes, single ICU, edge triggered 1186 */ 1187 outb(IO_ICU1, 0x13); 1188 outb(IO_ICU1 + 1, NRSVIDT); /* start vector */ 1189 outb(IO_ICU1 + 1, 0x00); /* ignore slave */ 1190 outb(IO_ICU1 + 1, 0x03); /* auto EOI, 8086 */ 1191 outb(IO_ICU1 + 1, 0xfe); /* unmask INT0 */ 1192 1193 /* program IO APIC for type 3 INT on INT0 */ 1194 if (ext_int_setup(0, 0) < 0) 1195 panic("8254 redirect via APIC pin0 impossible!"); 1196 1197 register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, 1198 /* XXX */ (inthand2_t *)clkintr, &clk_imask, 1199 /* unit */ 0); 1200 INTREN(IRQ0); 1201#else /* APIC_PIN0_TIMER */ 1202 /* 8254 is traditionally on ISA IRQ0 */ 1203 if ((x = isa_apic_pin(0)) < 0) { 1204 /* bummer, attempt to redirect thru the 8259 */ 1205 if (bootverbose) 1206 printf("APIC missing 8254 connection\n"); 1207 1208 /* allow 8254 timer to INTerrupt 8259 */ 1209#ifdef TEST_ALTTIMER 1210 /* 1211 * re-initialize master 8259: 1212 * reset; prog 4 bytes, single ICU, edge triggered 1213 */ 1214 outb(IO_ICU1, 0x13); 1215 outb(IO_ICU1 + 1, NRSVIDT); /* start vector */ 1216 outb(IO_ICU1 + 1, 0x00); /* ignore slave */ 1217 outb(IO_ICU1 + 1, 0x03); /* auto EOI, 8086 */ 1218 1219 outb(IO_ICU1 + 1, 0xfe); /* unmask INT0 */ 1220#else 1221 x = inb(IO_ICU1 + 1); /* current mask in 8259 */ 1222 x &= ~1; /* clear 8254 timer mask */ 1223 outb(IO_ICU1 + 1, x); /* write new mask */ 1224#endif /* TEST_ALTTIMER */ 1225 1226 /* program IO APIC for type 3 INT on INT0 */ 1227 if (ext_int_setup(0, 0) < 0) 1228 panic("8254 redirect impossible!"); 1229 x = 0; /* 8259 is on 0 */ 1230 } 1231 1232 vec[x] = (u_int)vec8254; 1233 Xintr8254 = (u_int)ivectors[x]; /* XXX might need Xfastintr# */ 1234 mask8254 = (1 << x); 1235 register_intr(/* irq */ x, /* XXX id */ 0, /* flags */ 0, 1236 /* XXX */ (inthand2_t *)clkintr, &clk_imask, 1237 /* unit */ 0); 1238 INTREN(mask8254); 1239#endif /* APIC_PIN0_TIMER */ 1240#else /* APIC_IO */ 1241 register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, 1242 /* XXX */ (inthand2_t *)clkintr, &clk_imask, 1243 /* unit */ 0); 1244 INTREN(IRQ0); 1245#endif /* APIC_IO */ 1246 1247#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) 1248 /* 1249 * Finish setting up anti-jitter measures. 1250 */ 1251 if (i586_ctr_freq != 0) 1252 i586_ctr_bias = rdtsc(); 1253#endif 1254 1255#ifndef PC98 1256 /* Initialize RTC. */ 1257 writertc(RTC_STATUSA, rtc_statusa); 1258 writertc(RTC_STATUSB, RTCSB_24HR); 1259 1260 /* Don't bother enabling the statistics clock. */ 1261 if (statclock_disable) 1262 return; 1263 diag = rtcin(RTC_DIAG); 1264 if (diag != 0) 1265 printf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS); 1266 1267#ifdef APIC_IO 1268 1269#ifdef DO_RTC_VEC 1270 if ((x = isa_apic_pin(8)) < 0) 1271 panic("APIC missing RTC connection"); 1272 vec[x] = (u_int)vecRTC; 1273 XintrRTC = (u_int)ivectors[x]; /* XXX might need Xfastintr# */ 1274 maskRTC = (1 << x); 1275 register_intr(/* irq */ x, /* XXX id */ 1, /* flags */ 0, 1276 /* XXX */ (inthand2_t *)rtcintr, &stat_imask, 1277 /* unit */ 0); 1278 INTREN(maskRTC); 1279#else 1280 if (isa_apic_pin(8) != 8) 1281 panic("APIC RTC != 8"); 1282 register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, 1283 /* XXX */ (inthand2_t *)rtcintr, &stat_imask, 1284 /* unit */ 0); 1285 INTREN(IRQ8); 1286#endif /* DO_RTC_VEC */ 1287 1288#else /* APIC_IO */ 1289 1290 register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, 1291 /* XXX */ (inthand2_t *)rtcintr, &stat_imask, 1292 /* unit */ 0); 1293 INTREN(IRQ8); 1294 1295#endif /* APIC_IO */ 1296 1297 writertc(RTC_STATUSB, rtc_statusb); 1298#endif 1299 1300#ifdef APIC_IO 1301 if (bootverbose) { 1302 printf("SMP: enabled INTs: "); 1303 for (x = 0; x < 24; ++x) 1304 if ((imen & (1 << x)) == 0) 1305 printf("%d, ", x); 1306 printf("imen: 0x%08x\n", imen); 1307 } 1308#endif /* APIC_IO */ 1309} 1310 1311void 1312setstatclockrate(int newhz) 1313{ 1314#ifndef PC98 1315 if (newhz == RTC_PROFRATE) 1316 rtc_statusa = RTCSA_DIVIDER | RTCSA_PROF; 1317 else 1318 rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; 1319 writertc(RTC_STATUSA, rtc_statusa); 1320#endif 1321} 1322 1323static int 1324sysctl_machdep_i8254_freq SYSCTL_HANDLER_ARGS 1325{ 1326 int error; 1327 u_int freq; 1328 1329 /* 1330 * Use `i8254' instead of `timer' in external names because `timer' 1331 * is is too generic. Should use it everywhere. 1332 */ 1333 freq = timer_freq; 1334 error = sysctl_handle_opaque(oidp, &freq, sizeof freq, req); 1335 if (error == 0 && req->newptr != NULL) { 1336 if (timer0_state != 0) 1337 return (EBUSY); /* too much trouble to handle */ 1338 set_timer_freq(freq, hz); 1339#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) 1340 set_i586_ctr_freq(i586_ctr_freq, timer_freq); 1341#endif 1342 } 1343 return (error); 1344} 1345 1346SYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW, 1347 0, sizeof(u_int), sysctl_machdep_i8254_freq, "I", ""); 1348 1349#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) 1350static void 1351set_i586_ctr_freq(u_int i586_freq, u_int i8254_freq) 1352{ 1353 u_int comultiplier, multiplier; 1354 u_long ef; 1355 1356 if (i586_freq == 0) { 1357 i586_ctr_freq = i586_freq; 1358 return; 1359 } 1360 comultiplier = ((unsigned long long)i586_freq 1361 << I586_CTR_COMULTIPLIER_SHIFT) / i8254_freq; 1362 multiplier = (1000000LL << I586_CTR_MULTIPLIER_SHIFT) / i586_freq; 1363 ef = read_eflags(); 1364 disable_intr(); 1365 i586_ctr_freq = i586_freq; 1366 i586_ctr_comultiplier = comultiplier; 1367 i586_ctr_multiplier = multiplier; 1368 write_eflags(ef); 1369} 1370 1371static int 1372sysctl_machdep_i586_freq SYSCTL_HANDLER_ARGS 1373{ 1374 int error; 1375 u_int freq; 1376 1377 if (cpu_class != CPUCLASS_586 && cpu_class != CPUCLASS_686) 1378 return (EOPNOTSUPP); 1379 freq = i586_ctr_freq; 1380 error = sysctl_handle_opaque(oidp, &freq, sizeof freq, req); 1381 if (error == 0 && req->newptr != NULL) 1382 set_i586_ctr_freq(freq, timer_freq); 1383 return (error); 1384} 1385 1386SYSCTL_PROC(_machdep, OID_AUTO, i586_freq, CTLTYPE_INT | CTLFLAG_RW, 1387 0, sizeof(u_int), sysctl_machdep_i586_freq, "I", ""); 1388#endif /* (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) */ 1389