tsc.c revision 50477
14Srgrimes/*- 24Srgrimes * Copyright (c) 1990 The Regents of the University of California. 34Srgrimes * All rights reserved. 44Srgrimes * 54Srgrimes * This code is derived from software contributed to Berkeley by 64Srgrimes * William Jolitz and Don Ahn. 74Srgrimes * 84Srgrimes * Redistribution and use in source and binary forms, with or without 94Srgrimes * modification, are permitted provided that the following conditions 104Srgrimes * are met: 114Srgrimes * 1. Redistributions of source code must retain the above copyright 124Srgrimes * notice, this list of conditions and the following disclaimer. 134Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 144Srgrimes * notice, this list of conditions and the following disclaimer in the 154Srgrimes * documentation and/or other materials provided with the distribution. 164Srgrimes * 3. All advertising materials mentioning features or use of this software 174Srgrimes * must display the following acknowledgement: 184Srgrimes * This product includes software developed by the University of 194Srgrimes * California, Berkeley and its contributors. 204Srgrimes * 4. Neither the name of the University nor the names of its contributors 214Srgrimes * may be used to endorse or promote products derived from this software 224Srgrimes * without specific prior written permission. 234Srgrimes * 244Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 254Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 264Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 274Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 284Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 294Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 304Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 314Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 324Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 334Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 344Srgrimes * SUCH DAMAGE. 354Srgrimes * 36619Srgrimes * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 3750477Speter * $FreeBSD: head/sys/i386/i386/tsc.c 50477 1999-08-28 01:08:13Z peter $ 384Srgrimes */ 394Srgrimes 403185Ssos/* 4119173Sbde * Routines to handle clock hardware. 4219173Sbde */ 4319173Sbde 4419173Sbde/* 453185Ssos * inittodr, settodr and support routines written 463185Ssos * by Christoph Robitschko <chmr@edvz.tu-graz.ac.at> 473185Ssos * 483185Ssos * reintroduced and updated by Chris Stenton <chris@gnome.co.uk> 8/10/94 492913Sache */ 502913Sache 5116299Spst#include "opt_clock.h" 5233929Sphk#include "apm.h" 5313228Swollman 542056Swollman#include <sys/param.h> 552056Swollman#include <sys/systm.h> 562056Swollman#include <sys/time.h> 572056Swollman#include <sys/kernel.h> 5831253Sbde#ifndef SMP 5931253Sbde#include <sys/lock.h> 6031253Sbde#endif 6115508Sbde#include <sys/sysctl.h> 6249558Sphk#include <sys/cons.h> 6315508Sbde 644180Sbde#include <machine/clock.h> 6515508Sbde#ifdef CLK_CALIBRATION_LOOP 6615508Sbde#endif 6730805Sbde#include <machine/cputypes.h> 682056Swollman#include <machine/frame.h> 6926309Speter#include <machine/ipl.h> 7028551Sbde#include <machine/limits.h> 7132054Sphk#include <machine/md_var.h> 7247588Sbde#include <machine/psl.h> 7330805Sbde#ifdef APIC_IO 7430805Sbde#include <machine/segments.h> 7530805Sbde#endif 7628921Sfsmp#if defined(SMP) || defined(APIC_IO) 7726949Sfsmp#include <machine/smp.h> 7828921Sfsmp#endif /* SMP || APIC_IO */ 7932054Sphk#include <machine/specialreg.h> 8015508Sbde 812056Swollman#include <i386/isa/icu.h> 822056Swollman#include <i386/isa/isa.h> 8347642Sdfr#include <isa/rtc.h> 842056Swollman#include <i386/isa/timerreg.h> 854Srgrimes 8645897Speter#include <i386/isa/intr_machdep.h> 8728487Sfsmp 8828921Sfsmp#ifdef SMP 8929000Sfsmp#define disable_intr() CLOCK_DISABLE_INTR() 9029000Sfsmp#define enable_intr() CLOCK_ENABLE_INTR() 9134058Stegge 9234571Stegge#ifdef APIC_IO 9334571Stegge#include <i386/isa/intr_machdep.h> 9434058Stegge/* The interrupt triggered by the 8254 (timer) chip */ 9534058Steggeint apic_8254_intr; 9634571Steggestatic u_long read_intr_count __P((int vec)); 9734571Steggestatic void setup_8254_mixed_mode __P((void)); 9834571Stegge#endif 9928921Sfsmp#endif /* SMP */ 10028921Sfsmp 1012873Sbde/* 1022873Sbde * 32-bit time_t's can't reach leap years before 1904 or after 2036, so we 1032873Sbde * can use a simple formula for leap years. 1042873Sbde */ 1052873Sbde#define LEAPYEAR(y) ((u_int)(y) % 4 == 0) 1062913Sache#define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31) 1072873Sbde 10815508Sbde#define TIMER_DIV(x) ((timer_freq + (x) / 2) / (x)) 1094Srgrimes 1104180Sbde/* 1114180Sbde * Time in timer cycles that it takes for microtime() to disable interrupts 1124180Sbde * and latch the count. microtime() currently uses "cli; outb ..." so it 1134180Sbde * normally takes less than 2 timer cycles. Add a few for cache misses. 1144180Sbde * Add a few more to allow for latency in bogus calls to microtime() with 1154180Sbde * interrupts already disabled. 1164180Sbde */ 1174180Sbde#define TIMER0_LATCH_COUNT 20 1184180Sbde 1194180Sbde/* 12017236Sjoerg * Maximum frequency that we are willing to allow for timer0. Must be 12117231Sjoerg * low enough to guarantee that the timer interrupt handler returns 12233690Sphk * before the next timer interrupt. 1234180Sbde */ 12417231Sjoerg#define TIMER0_MAX_FREQ 20000 1254180Sbde 12641787Smckayint adjkerntz; /* local offset from GMT in seconds */ 12747588Sbdeint clkintr_pending; 12815045Sacheint disable_rtc_set; /* disable resettodr() if != 0 */ 12946847Spetervolatile u_int idelayed; 13032052Sphkint statclock_disable; 13132052Sphku_int stat_imask = SWI_CLOCK_MASK; 13233690Sphk#ifndef TIMER_FREQ 13333690Sphk#define TIMER_FREQ 1193182 13433690Sphk#endif 13532052Sphku_int timer_freq = TIMER_FREQ; 13632052Sphkint timer0_max_count; 13732005Sphku_int tsc_freq; 13847592Sphkint tsc_is_broken; 13941787Smckayint wall_cmos_clock; /* wall CMOS clock assumed if != 0 */ 1401390Ssos 1414180Sbdestatic int beeping = 0; 1425291Sbdestatic u_int clk_imask = HWI_MASK | SWI_MASK; 1434180Sbdestatic const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31}; 14419173Sbdestatic u_int hardclock_max_count; 14533690Sphkstatic u_int32_t i8254_lastcount; 14633690Sphkstatic u_int32_t i8254_offset; 14733690Sphkstatic int i8254_ticked; 1484180Sbde/* 1494180Sbde * XXX new_function and timer_func should not handle clockframes, but 1504180Sbde * timer_func currently needs to hold hardclock to handle the 1514180Sbde * timer0_state == 0 case. We should use register_intr()/unregister_intr() 1524180Sbde * to switch between clkintr() and a slightly different timerintr(). 1534180Sbde */ 15419173Sbdestatic void (*new_function) __P((struct clockframe *frame)); 15519173Sbdestatic u_int new_rate; 1564180Sbdestatic u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; 15715345Snatestatic u_char rtc_statusb = RTCSB_24HR | RTCSB_PINTR; 15833690Sphkstatic u_int timer0_prescaler_count; 15917231Sjoerg 16017231Sjoerg/* Values for timerX_state: */ 16117236Sjoerg#define RELEASED 0 16217236Sjoerg#define RELEASE_PENDING 1 16317236Sjoerg#define ACQUIRED 2 16417236Sjoerg#define ACQUIRE_PENDING 3 16517231Sjoerg 16617231Sjoergstatic u_char timer0_state; 16717231Sjoergstatic u_char timer2_state; 16819173Sbdestatic void (*timer_func) __P((struct clockframe *frame)) = hardclock; 16933690Sphkstatic u_int tsc_present; 1704180Sbde 17136719Sphkstatic unsigned i8254_get_timecount __P((struct timecounter *tc)); 17236719Sphkstatic unsigned tsc_get_timecount __P((struct timecounter *tc)); 17321783Sbdestatic void set_timer_freq(u_int freq, int intr_freq); 17417353Sbde 17540610Sphkstatic struct timecounter tsc_timecounter = { 17633690Sphk tsc_get_timecount, /* get_timecount */ 17736741Sphk 0, /* no poll_pps */ 17836198Sphk ~0u, /* counter_mask */ 17933690Sphk 0, /* frequency */ 18033690Sphk "TSC" /* name */ 18133690Sphk}; 18233690Sphk 18333690SphkSYSCTL_OPAQUE(_debug, OID_AUTO, tsc_timecounter, CTLFLAG_RD, 18440610Sphk &tsc_timecounter, sizeof(tsc_timecounter), "S,timecounter", ""); 18533690Sphk 18640610Sphkstatic struct timecounter i8254_timecounter = { 18733690Sphk i8254_get_timecount, /* get_timecount */ 18836741Sphk 0, /* no poll_pps */ 18936198Sphk ~0u, /* counter_mask */ 19033690Sphk 0, /* frequency */ 19133690Sphk "i8254" /* name */ 19233690Sphk}; 19333690Sphk 19433690SphkSYSCTL_OPAQUE(_debug, OID_AUTO, i8254_timecounter, CTLFLAG_RD, 19540610Sphk &i8254_timecounter, sizeof(i8254_timecounter), "S,timecounter", ""); 19633690Sphk 19712724Sphkstatic void 1983185Ssosclkintr(struct clockframe frame) 1992074Swollman{ 20039503Sbde if (timecounter->tc_get_timecount == i8254_get_timecount) { 20147588Sbde disable_intr(); 20247588Sbde if (i8254_ticked) 20339503Sbde i8254_ticked = 0; 20447588Sbde else { 20539503Sbde i8254_offset += timer0_max_count; 20639503Sbde i8254_lastcount = 0; 20739503Sbde } 20847588Sbde clkintr_pending = 0; 20947588Sbde enable_intr(); 21039503Sbde } 2111549Srgrimes timer_func(&frame); 2121442Ssos switch (timer0_state) { 21317236Sjoerg 21417231Sjoerg case RELEASED: 2158448Sbde setdelayed(); 2161442Ssos break; 21717236Sjoerg 21817231Sjoerg case ACQUIRED: 2194180Sbde if ((timer0_prescaler_count += timer0_max_count) 2204180Sbde >= hardclock_max_count) { 22133309Sbde timer0_prescaler_count -= hardclock_max_count; 2221549Srgrimes hardclock(&frame); 2238448Sbde setdelayed(); 2241390Ssos } 2251442Ssos break; 22617236Sjoerg 22717231Sjoerg case ACQUIRE_PENDING: 22848889Sbde disable_intr(); 22948889Sbde i8254_offset = i8254_get_timecount(NULL); 23048889Sbde i8254_lastcount = 0; 2314180Sbde timer0_max_count = TIMER_DIV(new_rate); 2324180Sbde outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 2334180Sbde outb(TIMER_CNTR0, timer0_max_count & 0xff); 2344180Sbde outb(TIMER_CNTR0, timer0_max_count >> 8); 23529000Sfsmp enable_intr(); 2361442Ssos timer_func = new_function; 23717231Sjoerg timer0_state = ACQUIRED; 23848889Sbde setdelayed(); 2391442Ssos break; 24017236Sjoerg 24117231Sjoerg case RELEASE_PENDING: 2424180Sbde if ((timer0_prescaler_count += timer0_max_count) 2434180Sbde >= hardclock_max_count) { 24448889Sbde disable_intr(); 24548889Sbde i8254_offset = i8254_get_timecount(NULL); 24648889Sbde i8254_lastcount = 0; 2475291Sbde timer0_max_count = hardclock_max_count; 2484180Sbde outb(TIMER_MODE, 2494180Sbde TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 2504180Sbde outb(TIMER_CNTR0, timer0_max_count & 0xff); 2514180Sbde outb(TIMER_CNTR0, timer0_max_count >> 8); 25229000Sfsmp enable_intr(); 2534180Sbde timer0_prescaler_count = 0; 25417231Sjoerg timer_func = hardclock; 25517231Sjoerg timer0_state = RELEASED; 25648889Sbde hardclock(&frame); 25748889Sbde setdelayed(); 2581442Ssos } 2591442Ssos break; 2601442Ssos } 2611390Ssos} 2621390Ssos 26317231Sjoerg/* 26417236Sjoerg * The acquire and release functions must be called at ipl >= splclock(). 26517231Sjoerg */ 2661390Ssosint 2674180Sbdeacquire_timer0(int rate, void (*function) __P((struct clockframe *frame))) 2681390Ssos{ 26917231Sjoerg static int old_rate; 27017231Sjoerg 27117231Sjoerg if (rate <= 0 || rate > TIMER0_MAX_FREQ) 27217231Sjoerg return (-1); 27317231Sjoerg switch (timer0_state) { 27417231Sjoerg 27517236Sjoerg case RELEASED: 27617236Sjoerg timer0_state = ACQUIRE_PENDING; 27717236Sjoerg break; 27817231Sjoerg 27917236Sjoerg case RELEASE_PENDING: 28017236Sjoerg if (rate != old_rate) 28117236Sjoerg return (-1); 28217236Sjoerg /* 28317236Sjoerg * The timer has been released recently, but is being 28417236Sjoerg * re-acquired before the release completed. In this 28517236Sjoerg * case, we simply reclaim it as if it had not been 28617236Sjoerg * released at all. 28717236Sjoerg */ 28817236Sjoerg timer0_state = ACQUIRED; 28917236Sjoerg break; 29017236Sjoerg 29117236Sjoerg default: 29217236Sjoerg return (-1); /* busy */ 29317231Sjoerg } 2941442Ssos new_function = function; 29517231Sjoerg old_rate = new_rate = rate; 29617231Sjoerg return (0); 2971390Ssos} 2981390Ssos 2991390Ssosint 3001390Ssosacquire_timer2(int mode) 3011390Ssos{ 30217231Sjoerg 30317231Sjoerg if (timer2_state != RELEASED) 30417231Sjoerg return (-1); 30517231Sjoerg timer2_state = ACQUIRED; 30617236Sjoerg 30717236Sjoerg /* 30817236Sjoerg * This access to the timer registers is as atomic as possible 30917236Sjoerg * because it is a single instruction. We could do better if we 31017236Sjoerg * knew the rate. Use of splclock() limits glitches to 10-100us, 31117236Sjoerg * and this is probably good enough for timer2, so we aren't as 31217236Sjoerg * careful with it as with timer0. 31317236Sjoerg */ 31417236Sjoerg outb(TIMER_MODE, TIMER_SEL2 | (mode & 0x3f)); 31517236Sjoerg 31617231Sjoerg return (0); 3171390Ssos} 3181390Ssos 3191390Ssosint 3201390Ssosrelease_timer0() 3211390Ssos{ 32217231Sjoerg switch (timer0_state) { 32317231Sjoerg 32417236Sjoerg case ACQUIRED: 32517236Sjoerg timer0_state = RELEASE_PENDING; 32617236Sjoerg break; 32717231Sjoerg 32817236Sjoerg case ACQUIRE_PENDING: 32917236Sjoerg /* Nothing happened yet, release quickly. */ 33017236Sjoerg timer0_state = RELEASED; 33117236Sjoerg break; 33217236Sjoerg 33317236Sjoerg default: 33417236Sjoerg return (-1); 33517231Sjoerg } 33617231Sjoerg return (0); 3371390Ssos} 3381390Ssos 3391390Ssosint 3401390Ssosrelease_timer2() 3411390Ssos{ 34217231Sjoerg 34317231Sjoerg if (timer2_state != ACQUIRED) 34417231Sjoerg return (-1); 34517231Sjoerg timer2_state = RELEASED; 34617236Sjoerg outb(TIMER_MODE, TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT); 34717231Sjoerg return (0); 3481390Ssos} 3491390Ssos 3503185Ssos/* 3513185Ssos * This routine receives statistical clock interrupts from the RTC. 3523185Ssos * As explained above, these occur at 128 interrupts per second. 3533185Ssos * When profiling, we receive interrupts at a rate of 1024 Hz. 3543185Ssos * 3553185Ssos * This does not actually add as much overhead as it sounds, because 3563185Ssos * when the statistical clock is active, the hardclock driver no longer 3573185Ssos * needs to keep (inaccurate) statistics on its own. This decouples 3583185Ssos * statistics gathering from scheduling interrupts. 3593185Ssos * 3603185Ssos * The RTC chip requires that we read status register C (RTC_INTR) 3613185Ssos * to acknowledge an interrupt, before it will generate the next one. 36224676Smckay * Under high interrupt load, rtcintr() can be indefinitely delayed and 36324676Smckay * the clock can tick immediately after the read from RTC_INTR. In this 36424676Smckay * case, the mc146818A interrupt signal will not drop for long enough 36524676Smckay * to register with the 8259 PIC. If an interrupt is missed, the stat 36624676Smckay * clock will halt, considerably degrading system performance. This is 36724676Smckay * why we use 'while' rather than a more straightforward 'if' below. 36824676Smckay * Stat clock ticks can still be lost, causing minor loss of accuracy 36924676Smckay * in the statistics, but the stat clock will no longer stop. 3703185Ssos */ 37112724Sphkstatic void 3723185Ssosrtcintr(struct clockframe frame) 3733185Ssos{ 37424676Smckay while (rtcin(RTC_INTR) & RTCIR_PERIOD) 3753185Ssos statclock(&frame); 3763185Ssos} 3771390Ssos 37818297Sbde#include "opt_ddb.h" 3795291Sbde#ifdef DDB 38018297Sbde#include <ddb/ddb.h> 38118297Sbde 38218297SbdeDB_SHOW_COMMAND(rtc, rtc) 3833185Ssos{ 3845291Sbde printf("%02x/%02x/%02x %02x:%02x:%02x, A = %02x, B = %02x, C = %02x\n", 3855291Sbde rtcin(RTC_YEAR), rtcin(RTC_MONTH), rtcin(RTC_DAY), 3865291Sbde rtcin(RTC_HRS), rtcin(RTC_MIN), rtcin(RTC_SEC), 3875291Sbde rtcin(RTC_STATUSA), rtcin(RTC_STATUSB), rtcin(RTC_INTR)); 3883185Ssos} 38918297Sbde#endif /* DDB */ 3903185Ssos 3911390Ssosstatic int 39210268Sbdegetit(void) 3931390Ssos{ 39416428Sbde u_long ef; 3951390Ssos int high, low; 3961390Ssos 39716428Sbde ef = read_eflags(); 39829000Sfsmp disable_intr(); 39916428Sbde 40016428Sbde /* Select timer0 and latch counter value. */ 40119173Sbde outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 40216428Sbde 4031390Ssos low = inb(TIMER_CNTR0); 4041390Ssos high = inb(TIMER_CNTR0); 40516428Sbde 40628921Sfsmp CLOCK_UNLOCK(); 40716428Sbde write_eflags(ef); 4081390Ssos return ((high << 8) | low); 4091390Ssos} 4101390Ssos 4112017Swollman/* 4121390Ssos * Wait "n" microseconds. 41315508Sbde * Relies on timer 1 counting down from (timer_freq / hz) 4141390Ssos * Note: timer had better have been programmed before this is first used! 4151390Ssos */ 4161390Ssosvoid 4171390SsosDELAY(int n) 4181390Ssos{ 41922106Sbde int delta, prev_tick, tick, ticks_left; 4201390Ssos 4211390Ssos#ifdef DELAYDEBUG 4221390Ssos int getit_calls = 1; 4231390Ssos int n1; 4241390Ssos static int state = 0; 4251390Ssos 4261390Ssos if (state == 0) { 4271390Ssos state = 1; 4281390Ssos for (n1 = 1; n1 <= 10000000; n1 *= 10) 4291390Ssos DELAY(n1); 4301390Ssos state = 2; 4311390Ssos } 4321390Ssos if (state == 1) 4331390Ssos printf("DELAY(%d)...", n); 4341390Ssos#endif 4351390Ssos /* 43621783Sbde * Guard against the timer being uninitialized if we are called 43721783Sbde * early for console i/o. 43821783Sbde */ 43921783Sbde if (timer0_max_count == 0) 44021783Sbde set_timer_freq(timer_freq, hz); 44121783Sbde 44221783Sbde /* 4431390Ssos * Read the counter first, so that the rest of the setup overhead is 4441390Ssos * counted. Guess the initial overhead is 20 usec (on most systems it 4451390Ssos * takes about 1.5 usec for each of the i/o's in getit(). The loop 4461390Ssos * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The 4471390Ssos * multiplications and divisions to scale the count take a while). 4481390Ssos */ 44910268Sbde prev_tick = getit(); 45022106Sbde n -= 0; /* XXX actually guess no initial overhead */ 4511390Ssos /* 45215508Sbde * Calculate (n * (timer_freq / 1e6)) without using floating point 4531390Ssos * and without any avoidable overflows. 4541390Ssos */ 45522106Sbde if (n <= 0) 45622106Sbde ticks_left = 0; 45722106Sbde else if (n < 256) 45822106Sbde /* 45922106Sbde * Use fixed point to avoid a slow division by 1000000. 46022106Sbde * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest. 46122106Sbde * 2^15 is the first power of 2 that gives exact results 46222106Sbde * for n between 0 and 256. 46322106Sbde */ 46422106Sbde ticks_left = ((u_int)n * 39099 + (1 << 15) - 1) >> 15; 46522106Sbde else 46622106Sbde /* 46722106Sbde * Don't bother using fixed point, although gcc-2.7.2 46822106Sbde * generates particularly poor code for the long long 46922106Sbde * division, since even the slow way will complete long 47022106Sbde * before the delay is up (unless we're interrupted). 47122106Sbde */ 47222106Sbde ticks_left = ((u_int)n * (long long)timer_freq + 999999) 47322106Sbde / 1000000; 4741390Ssos 4751390Ssos while (ticks_left > 0) { 47610268Sbde tick = getit(); 4771390Ssos#ifdef DELAYDEBUG 4781390Ssos ++getit_calls; 4791390Ssos#endif 48021783Sbde delta = prev_tick - tick; 4811390Ssos prev_tick = tick; 48221783Sbde if (delta < 0) { 48321783Sbde delta += timer0_max_count; 48421783Sbde /* 48521783Sbde * Guard against timer0_max_count being wrong. 48621783Sbde * This shouldn't happen in normal operation, 48721783Sbde * but it may happen if set_timer_freq() is 48821783Sbde * traced. 48921783Sbde */ 49021783Sbde if (delta < 0) 49121783Sbde delta = 0; 49221783Sbde } 49321783Sbde ticks_left -= delta; 4941390Ssos } 4951390Ssos#ifdef DELAYDEBUG 4961390Ssos if (state == 1) 4971390Ssos printf(" %d calls to getit() at %d usec each\n", 4981390Ssos getit_calls, (n + 5) / getit_calls); 4991390Ssos#endif 5001390Ssos} 5011390Ssos 5021390Ssosstatic void 5033185Ssossysbeepstop(void *chan) 5041390Ssos{ 5051390Ssos outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */ 5061390Ssos release_timer2(); 5071390Ssos beeping = 0; 5081390Ssos} 5091390Ssos 5108876Srgrimesint 5111390Ssossysbeep(int pitch, int period) 5121390Ssos{ 51317231Sjoerg int x = splclock(); 5141390Ssos 5158876Srgrimes if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT)) 51617231Sjoerg if (!beeping) { 51717231Sjoerg /* Something else owns it. */ 51817231Sjoerg splx(x); 51917231Sjoerg return (-1); /* XXX Should be EBUSY, but nobody cares anyway. */ 52017231Sjoerg } 52129000Sfsmp disable_intr(); 5221390Ssos outb(TIMER_CNTR2, pitch); 5231390Ssos outb(TIMER_CNTR2, (pitch>>8)); 52429000Sfsmp enable_intr(); 5251390Ssos if (!beeping) { 52617231Sjoerg /* enable counter2 output to speaker */ 52717231Sjoerg outb(IO_PPI, inb(IO_PPI) | 3); 5281390Ssos beeping = period; 5292873Sbde timeout(sysbeepstop, (void *)NULL, period); 5301390Ssos } 53117231Sjoerg splx(x); 53217231Sjoerg return (0); 5331390Ssos} 5341390Ssos 5352913Sache/* 5362913Sache * RTC support routines 5372913Sache */ 5382913Sache 53914943Sbdeint 54014943Sbdertcin(reg) 54114943Sbde int reg; 54214943Sbde{ 54314943Sbde u_char val; 54414943Sbde 54514943Sbde outb(IO_RTC, reg); 54614943Sbde inb(0x84); 54714943Sbde val = inb(IO_RTC + 1); 54814943Sbde inb(0x84); 54914943Sbde return (val); 55014943Sbde} 55114943Sbde 55213445Sphkstatic __inline void 5535291Sbdewritertc(u_char reg, u_char val) 5542913Sache{ 55533309Sbde inb(0x84); 5565291Sbde outb(IO_RTC, reg); 55733309Sbde inb(0x84); 5585291Sbde outb(IO_RTC + 1, val); 55933309Sbde inb(0x84); /* XXX work around wrong order in rtcin() */ 5602913Sache} 5612913Sache 56213445Sphkstatic __inline int 5632913Sachereadrtc(int port) 5642913Sache{ 56513445Sphk return(bcd2bin(rtcin(port))); 5662913Sache} 5672913Sache 56815508Sbdestatic u_int 56915508Sbdecalibrate_clocks(void) 57015508Sbde{ 57148160Sgreen u_int64_t old_tsc; 57215508Sbde u_int count, prev_count, tot_count; 57315508Sbde int sec, start_sec, timeout; 57415508Sbde 57523393Sbde if (bootverbose) 57623393Sbde printf("Calibrating clock(s) ... "); 57715508Sbde if (!(rtcin(RTC_STATUSD) & RTCSD_PWR)) 57815508Sbde goto fail; 57915508Sbde timeout = 100000000; 58015508Sbde 58115508Sbde /* Read the mc146818A seconds counter. */ 58215508Sbde for (;;) { 58315508Sbde if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) { 58415508Sbde sec = rtcin(RTC_SEC); 58515508Sbde break; 58615508Sbde } 58715508Sbde if (--timeout == 0) 58815508Sbde goto fail; 58915508Sbde } 59015508Sbde 59115508Sbde /* Wait for the mC146818A seconds counter to change. */ 59215508Sbde start_sec = sec; 59315508Sbde for (;;) { 59415508Sbde if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) { 59515508Sbde sec = rtcin(RTC_SEC); 59615508Sbde if (sec != start_sec) 59715508Sbde break; 59815508Sbde } 59915508Sbde if (--timeout == 0) 60015508Sbde goto fail; 60115508Sbde } 60215508Sbde 60315508Sbde /* Start keeping track of the i8254 counter. */ 60415508Sbde prev_count = getit(); 60515508Sbde if (prev_count == 0 || prev_count > timer0_max_count) 60615508Sbde goto fail; 60715508Sbde tot_count = 0; 60815508Sbde 60932054Sphk if (tsc_present) 61048160Sgreen old_tsc = rdtsc(); 61148266Speter else 61248266Speter old_tsc = 0; /* shut up gcc */ 61315508Sbde 61415508Sbde /* 61515508Sbde * Wait for the mc146818A seconds counter to change. Read the i8254 61615508Sbde * counter for each iteration since this is convenient and only 61715508Sbde * costs a few usec of inaccuracy. The timing of the final reads 61815508Sbde * of the counters almost matches the timing of the initial reads, 61915508Sbde * so the main cause of inaccuracy is the varying latency from 62015508Sbde * inside getit() or rtcin(RTC_STATUSA) to the beginning of the 62115508Sbde * rtcin(RTC_SEC) that returns a changed seconds count. The 62215508Sbde * maximum inaccuracy from this cause is < 10 usec on 486's. 62315508Sbde */ 62415508Sbde start_sec = sec; 62515508Sbde for (;;) { 62615508Sbde if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) 62715508Sbde sec = rtcin(RTC_SEC); 62815508Sbde count = getit(); 62915508Sbde if (count == 0 || count > timer0_max_count) 63015508Sbde goto fail; 63115508Sbde if (count > prev_count) 63215508Sbde tot_count += prev_count - (count - timer0_max_count); 63315508Sbde else 63415508Sbde tot_count += prev_count - count; 63515508Sbde prev_count = count; 63615508Sbde if (sec != start_sec) 63715508Sbde break; 63815508Sbde if (--timeout == 0) 63915508Sbde goto fail; 64015508Sbde } 64115508Sbde 64215508Sbde /* 64315508Sbde * Read the cpu cycle counter. The timing considerations are 64415508Sbde * similar to those for the i8254 clock. 64515508Sbde */ 64633690Sphk if (tsc_present) 64748160Sgreen tsc_freq = rdtsc() - old_tsc; 64833690Sphk 64933690Sphk if (bootverbose) { 65033690Sphk if (tsc_present) 65132005Sphk printf("TSC clock: %u Hz, ", tsc_freq); 65233929Sphk printf("i8254 clock: %u Hz\n", tot_count); 65315508Sbde } 65415508Sbde return (tot_count); 65515508Sbde 65615508Sbdefail: 65723393Sbde if (bootverbose) 65823393Sbde printf("failed, using default i8254 clock of %u Hz\n", 65923393Sbde timer_freq); 66015508Sbde return (timer_freq); 66115508Sbde} 66215508Sbde 66315508Sbdestatic void 66415508Sbdeset_timer_freq(u_int freq, int intr_freq) 66515508Sbde{ 66616874Sbde u_long ef; 66733309Sbde int new_timer0_max_count; 66815508Sbde 66915508Sbde ef = read_eflags(); 67029000Sfsmp disable_intr(); 67115508Sbde timer_freq = freq; 67233309Sbde new_timer0_max_count = hardclock_max_count = TIMER_DIV(intr_freq); 67333309Sbde if (new_timer0_max_count != timer0_max_count) { 67433309Sbde timer0_max_count = new_timer0_max_count; 67533309Sbde outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 67633309Sbde outb(TIMER_CNTR0, timer0_max_count & 0xff); 67733309Sbde outb(TIMER_CNTR0, timer0_max_count >> 8); 67833309Sbde } 67928921Sfsmp CLOCK_UNLOCK(); 68015508Sbde write_eflags(ef); 68115508Sbde} 68215508Sbde 6835291Sbde/* 68433690Sphk * Initialize 8254 timer 0 early so that it can be used in DELAY(). 6855291Sbde * XXX initialization of other timers is unintentionally left blank. 6865291Sbde */ 6871390Ssosvoid 6888876Srgrimesstartrtclock() 689798Swollman{ 69015508Sbde u_int delta, freq; 69115508Sbde 69232054Sphk if (cpu_feature & CPUID_TSC) 69332054Sphk tsc_present = 1; 69432054Sphk else 69532054Sphk tsc_present = 0; 69632054Sphk 69715508Sbde writertc(RTC_STATUSA, rtc_statusa); 69815508Sbde writertc(RTC_STATUSB, RTCSB_24HR); 69915508Sbde 70016874Sbde set_timer_freq(timer_freq, hz); 70115508Sbde freq = calibrate_clocks(); 70215508Sbde#ifdef CLK_CALIBRATION_LOOP 70315508Sbde if (bootverbose) { 70415508Sbde printf( 70515508Sbde "Press a key on the console to abort clock calibration\n"); 70618288Sbde while (cncheckc() == -1) 70715508Sbde calibrate_clocks(); 70815508Sbde } 70915508Sbde#endif 71015508Sbde 71115508Sbde /* 71215508Sbde * Use the calibrated i8254 frequency if it seems reasonable. 71315508Sbde * Otherwise use the default, and don't use the calibrated i586 71415508Sbde * frequency. 71515508Sbde */ 71615508Sbde delta = freq > timer_freq ? freq - timer_freq : timer_freq - freq; 71715508Sbde if (delta < timer_freq / 100) { 71815508Sbde#ifndef CLK_USE_I8254_CALIBRATION 71916300Spst if (bootverbose) 72019173Sbde printf( 72115508Sbde"CLK_USE_I8254_CALIBRATION not specified - using default frequency\n"); 72215508Sbde freq = timer_freq; 72315508Sbde#endif 72415508Sbde timer_freq = freq; 72515508Sbde } else { 72623393Sbde if (bootverbose) 72723393Sbde printf( 72823393Sbde "%d Hz differs from default of %d Hz by more than 1%%\n", 72923393Sbde freq, timer_freq); 73032005Sphk tsc_freq = 0; 73115508Sbde } 73215508Sbde 73315508Sbde set_timer_freq(timer_freq, hz); 73440610Sphk i8254_timecounter.tc_frequency = timer_freq; 73540610Sphk init_timecounter(&i8254_timecounter); 73615508Sbde 73732005Sphk#ifndef CLK_USE_TSC_CALIBRATION 73832005Sphk if (tsc_freq != 0) { 73916300Spst if (bootverbose) 74019173Sbde printf( 74132005Sphk"CLK_USE_TSC_CALIBRATION not specified - using old calibration method\n"); 74232005Sphk tsc_freq = 0; 74315508Sbde } 74415508Sbde#endif 74532054Sphk if (tsc_present && tsc_freq == 0) { 74615508Sbde /* 74715508Sbde * Calibration of the i586 clock relative to the mc146818A 74815508Sbde * clock failed. Do a less accurate calibration relative 74915508Sbde * to the i8254 clock. 75015508Sbde */ 75148160Sgreen u_int64_t old_tsc = rdtsc(); 75248160Sgreen 75315508Sbde DELAY(1000000); 75448160Sgreen tsc_freq = rdtsc() - old_tsc; 75532054Sphk#ifdef CLK_USE_TSC_CALIBRATION 75623393Sbde if (bootverbose) 75733690Sphk printf("TSC clock: %u Hz (Method B)\n", tsc_freq); 75816300Spst#endif 75915508Sbde } 76034617Sphk 76134617Sphk#if !defined(SMP) 76234617Sphk /* 76334617Sphk * We can not use the TSC in SMP mode, until we figure out a 76434617Sphk * cheap (impossible), reliable and precise (yeah right!) way 76534617Sphk * to synchronize the TSCs of all the CPUs. 76634617Sphk * Curse Intel for leaving the counter out of the I/O APIC. 76734617Sphk */ 76834617Sphk 76934617Sphk#if NAPM > 0 77034617Sphk /* 77149186Smsmith * We can not use the TSC if we support APM. Precise timekeeping 77249186Smsmith * on an APM'ed machine is at best a fools pursuit, since 77334617Sphk * any and all of the time spent in various SMM code can't 77434617Sphk * be reliably accounted for. Reading the RTC is your only 77534617Sphk * source of reliable time info. The i8254 looses too of course 77634617Sphk * but we need to have some kind of time... 77749186Smsmith * We don't know at this point whether APM is going to be used 77849186Smsmith * or not, nor when it might be activated. Play it safe. 77934617Sphk */ 78049186Smsmith return; 78134617Sphk#endif /* NAPM > 0 */ 78234617Sphk 78347592Sphk if (tsc_present && tsc_freq != 0 && !tsc_is_broken) { 78440610Sphk tsc_timecounter.tc_frequency = tsc_freq; 78540610Sphk init_timecounter(&tsc_timecounter); 78633690Sphk } 78734617Sphk 78834617Sphk#endif /* !defined(SMP) */ 7894Srgrimes} 7904Srgrimes 7912913Sache/* 79241787Smckay * Initialize the time of day register, based on the time base which is, e.g. 79341787Smckay * from a filesystem. 7942913Sache */ 7952913Sachevoid 7963185Ssosinittodr(time_t base) 7974Srgrimes{ 7982913Sache unsigned long sec, days; 7992913Sache int yd; 8002913Sache int year, month; 8012913Sache int y, m, s; 80233690Sphk struct timespec ts; 8034Srgrimes 80432850Sphk if (base) { 80532850Sphk s = splclock(); 80633690Sphk ts.tv_sec = base; 80733690Sphk ts.tv_nsec = 0; 80833690Sphk set_timecounter(&ts); 80932850Sphk splx(s); 81032850Sphk } 8111390Ssos 81241787Smckay /* Look if we have a RTC present and the time is valid */ 8139202Srgrimes if (!(rtcin(RTC_STATUSD) & RTCSD_PWR)) 8142913Sache goto wrong_time; 8154Srgrimes 81641787Smckay /* wait for time update to complete */ 81741787Smckay /* If RTCSA_TUP is zero, we have at least 244us before next update */ 8182913Sache while (rtcin(RTC_STATUSA) & RTCSA_TUP); 8194Srgrimes 8202913Sache days = 0; 8213355Sache#ifdef USE_RTC_CENTURY 82241787Smckay year = readrtc(RTC_YEAR) + readrtc(RTC_CENTURY) * 100; 8233355Sache#else 8243355Sache year = readrtc(RTC_YEAR) + 1900; 8252913Sache if (year < 1970) 8263355Sache year += 100; 8273355Sache#endif 8283355Sache if (year < 1970) 8292913Sache goto wrong_time; 83041787Smckay month = readrtc(RTC_MONTH); 83141787Smckay for (m = 1; m < month; m++) 83241787Smckay days += daysinmonth[m-1]; 83341787Smckay if ((month > 2) && LEAPYEAR(year)) 8342913Sache days ++; 83541787Smckay days += readrtc(RTC_DAY) - 1; 8362913Sache yd = days; 8372913Sache for (y = 1970; y < year; y++) 83841787Smckay days += DAYSPERYEAR + LEAPYEAR(y); 8392913Sache sec = ((( days * 24 + 8402913Sache readrtc(RTC_HRS)) * 60 + 8412913Sache readrtc(RTC_MIN)) * 60 + 8422913Sache readrtc(RTC_SEC)); 84341787Smckay /* sec now contains the number of seconds, since Jan 1 1970, 84441787Smckay in the local time zone */ 8451390Ssos 84615054Sache sec += tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0); 8474Srgrimes 84834961Sphk y = time_second - sec; 84933690Sphk if (y <= -2 || y >= 2) { 85033690Sphk /* badly off, adjust it */ 85133690Sphk s = splclock(); 85233690Sphk ts.tv_sec = sec; 85333690Sphk ts.tv_nsec = 0; 85433690Sphk set_timecounter(&ts); 85533690Sphk splx(s); 85633690Sphk } 8572913Sache return; 8582913Sache 8592913Sachewrong_time: 86041787Smckay printf("Invalid time in real time clock.\n"); 86141787Smckay printf("Check and reset the date immediately!\n"); 8624Srgrimes} 8634Srgrimes 8644Srgrimes/* 86541787Smckay * Write system time back to RTC 8664Srgrimes */ 8674180Sbdevoid 8684180Sbderesettodr() 8694Srgrimes{ 8702913Sache unsigned long tm; 87111872Sphk int y, m, s; 8724Srgrimes 8733366Sache if (disable_rtc_set) 8743366Sache return; 8753366Sache 8762913Sache s = splclock(); 87734961Sphk tm = time_second; 8782913Sache splx(s); 8794Srgrimes 8805291Sbde /* Disable RTC updates and interrupts. */ 8812913Sache writertc(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR); 8824Srgrimes 88341787Smckay /* Calculate local time to put in RTC */ 8841390Ssos 88515054Sache tm -= tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0); 8862913Sache 88713445Sphk writertc(RTC_SEC, bin2bcd(tm%60)); tm /= 60; /* Write back Seconds */ 88813445Sphk writertc(RTC_MIN, bin2bcd(tm%60)); tm /= 60; /* Write back Minutes */ 88913445Sphk writertc(RTC_HRS, bin2bcd(tm%24)); tm /= 24; /* Write back Hours */ 8902913Sache 89141787Smckay /* We have now the days since 01-01-1970 in tm */ 8922913Sache writertc(RTC_WDAY, (tm+4)%7); /* Write back Weekday */ 89313350Sache for (y = 1970, m = DAYSPERYEAR + LEAPYEAR(y); 89413350Sache tm >= m; 89513350Sache y++, m = DAYSPERYEAR + LEAPYEAR(y)) 89613350Sache tm -= m; 8972913Sache 8982913Sache /* Now we have the years in y and the day-of-the-year in tm */ 89913453Sache writertc(RTC_YEAR, bin2bcd(y%100)); /* Write back Year */ 90013350Sache#ifdef USE_RTC_CENTURY 90113445Sphk writertc(RTC_CENTURY, bin2bcd(y/100)); /* ... and Century */ 9023355Sache#endif 90313402Sbde for (m = 0; ; m++) { 90413402Sbde int ml; 9052913Sache 90613402Sbde ml = daysinmonth[m]; 90713402Sbde if (m == 1 && LEAPYEAR(y)) 90813402Sbde ml++; 90913402Sbde if (tm < ml) 91013402Sbde break; 91113402Sbde tm -= ml; 91213402Sbde } 91313402Sbde 91413445Sphk writertc(RTC_MONTH, bin2bcd(m + 1)); /* Write back Month */ 91513445Sphk writertc(RTC_DAY, bin2bcd(tm + 1)); /* Write back Month Day */ 9162913Sache 9175291Sbde /* Reenable RTC updates and interrupts. */ 91815345Snate writertc(RTC_STATUSB, rtc_statusb); 9194Srgrimes} 9204Srgrimes 92127560Sfsmp 9224Srgrimes/* 9235291Sbde * Start both clocks running. 9244Srgrimes */ 9255291Sbdevoid 9265291Sbdecpu_initclocks() 9274Srgrimes{ 9285291Sbde int diag; 92926949Sfsmp#ifdef APIC_IO 93034571Stegge int apic_8254_trial; 93145900Speter struct intrec *clkdesc; 93225164Speter#endif /* APIC_IO */ 9334Srgrimes 93415345Snate if (statclock_disable) { 93515345Snate /* 93615345Snate * The stat interrupt mask is different without the 93715345Snate * statistics clock. Also, don't set the interrupt 93815345Snate * flag which would normally cause the RTC to generate 93915345Snate * interrupts. 94015345Snate */ 94115345Snate stat_imask = HWI_MASK | SWI_MASK; 94215345Snate rtc_statusb = RTCSB_24HR; 94315345Snate } else { 94415345Snate /* Setting stathz to nonzero early helps avoid races. */ 94515345Snate stathz = RTC_NOPROFRATE; 94615345Snate profhz = RTC_PROFRATE; 94715345Snate } 9484Srgrimes 9495291Sbde /* Finish initializing 8253 timer 0. */ 95026949Sfsmp#ifdef APIC_IO 95127563Sfsmp 95238888Stegge apic_8254_intr = isa_apic_irq(0); 95334571Stegge apic_8254_trial = 0; 95434571Stegge if (apic_8254_intr >= 0 ) { 95534571Stegge if (apic_int_type(0, 0) == 3) 95634571Stegge apic_8254_trial = 1; 95734571Stegge } else { 95834571Stegge /* look for ExtInt on pin 0 */ 95934571Stegge if (apic_int_type(0, 0) == 3) { 96034571Stegge apic_8254_intr = 0; 96134571Stegge setup_8254_mixed_mode(); 96234571Stegge } else 96334571Stegge panic("APIC_IO: Cannot route 8254 interrupt to CPU"); 96427563Sfsmp } 96527563Sfsmp 96645897Speter clkdesc = inthand_add("clk", apic_8254_intr, (inthand2_t *)clkintr, 96745897Speter NULL, &clk_imask, INTR_EXCL); 96834571Stegge INTREN(1 << apic_8254_intr); 96934571Stegge 97027696Sfsmp#else /* APIC_IO */ 97127563Sfsmp 97245897Speter inthand_add("clk", 0, (inthand2_t *)clkintr, NULL, &clk_imask, 97345897Speter INTR_EXCL); 9744Srgrimes INTREN(IRQ0); 97527696Sfsmp 97625164Speter#endif /* APIC_IO */ 97726949Sfsmp 9785291Sbde /* Initialize RTC. */ 9795291Sbde writertc(RTC_STATUSA, rtc_statusa); 9805291Sbde writertc(RTC_STATUSB, RTCSB_24HR); 98115345Snate 98215345Snate /* Don't bother enabling the statistics clock. */ 98315345Snate if (statclock_disable) 98415345Snate return; 9855291Sbde diag = rtcin(RTC_DIAG); 9865291Sbde if (diag != 0) 9875291Sbde printf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS); 98827520Sfsmp 98926949Sfsmp#ifdef APIC_IO 99038888Stegge if (isa_apic_irq(8) != 8) 99127520Sfsmp panic("APIC RTC != 8"); 99227563Sfsmp#endif /* APIC_IO */ 99328487Sfsmp 99445897Speter inthand_add("rtc", 8, (inthand2_t *)rtcintr, NULL, &stat_imask, 99545897Speter INTR_EXCL); 99628487Sfsmp 99727616Sfsmp#ifdef APIC_IO 99827616Sfsmp INTREN(APIC_IRQ8); 99927616Sfsmp#else 10002074Swollman INTREN(IRQ8); 100127616Sfsmp#endif /* APIC_IO */ 100227520Sfsmp 100315345Snate writertc(RTC_STATUSB, rtc_statusb); 100434571Stegge 100534571Stegge#ifdef APIC_IO 100634571Stegge if (apic_8254_trial) { 100734571Stegge 100834571Stegge printf("APIC_IO: Testing 8254 interrupt delivery\n"); 100934571Stegge while (read_intr_count(8) < 6) 101035035Stegge ; /* nothing */ 101134571Stegge if (read_intr_count(apic_8254_intr) < 3) { 101234571Stegge /* 101334571Stegge * The MP table is broken. 101434571Stegge * The 8254 was not connected to the specified pin 101534571Stegge * on the IO APIC. 101634571Stegge * Workaround: Limited variant of mixed mode. 101734571Stegge */ 101834571Stegge INTRDIS(1 << apic_8254_intr); 101945897Speter inthand_remove(clkdesc); 102034571Stegge printf("APIC_IO: Broken MP table detected: " 102134571Stegge "8254 is not connected to IO APIC int pin %d\n", 102234571Stegge apic_8254_intr); 102334571Stegge 102434571Stegge apic_8254_intr = 0; 102534571Stegge setup_8254_mixed_mode(); 102645897Speter inthand_add("clk", apic_8254_intr,(inthand2_t *)clkintr, 102745897Speter NULL, &clk_imask, INTR_EXCL); 102834571Stegge INTREN(1 << apic_8254_intr); 102934571Stegge } 103034571Stegge 103134571Stegge } 103234571Stegge if (apic_8254_intr) 103334571Stegge printf("APIC_IO: routing 8254 via pin %d\n",apic_8254_intr); 103434571Stegge else 103534571Stegge printf("APIC_IO: routing 8254 via 8259 on pin 0\n"); 103634571Stegge#endif 103734571Stegge 10384Srgrimes} 10394Srgrimes 104034571Stegge#ifdef APIC_IO 104134571Steggestatic u_long 104234571Steggeread_intr_count(int vec) 104334571Stegge{ 104434571Stegge u_long *up; 104534571Stegge up = intr_countp[vec]; 104634571Stegge if (up) 104734571Stegge return *up; 104834571Stegge return 0UL; 104934571Stegge} 105034571Stegge 105134571Steggestatic void 105234571Steggesetup_8254_mixed_mode() 105334571Stegge{ 105434571Stegge /* 105534571Stegge * Allow 8254 timer to INTerrupt 8259: 105634571Stegge * re-initialize master 8259: 105734571Stegge * reset; prog 4 bytes, single ICU, edge triggered 105834571Stegge */ 105934571Stegge outb(IO_ICU1, 0x13); 106034571Stegge outb(IO_ICU1 + 1, NRSVIDT); /* start vector (unused) */ 106134571Stegge outb(IO_ICU1 + 1, 0x00); /* ignore slave */ 106234571Stegge outb(IO_ICU1 + 1, 0x03); /* auto EOI, 8086 */ 106334571Stegge outb(IO_ICU1 + 1, 0xfe); /* unmask INT0 */ 106434571Stegge 106534571Stegge /* program IO APIC for type 3 INT on INT0 */ 106634571Stegge if (ext_int_setup(0, 0) < 0) 106734571Stegge panic("8254 redirect via APIC pin0 impossible!"); 106834571Stegge} 106934571Stegge#endif 107034571Stegge 10714Srgrimesvoid 10721549Srgrimessetstatclockrate(int newhz) 10731549Srgrimes{ 10745291Sbde if (newhz == RTC_PROFRATE) 10752074Swollman rtc_statusa = RTCSA_DIVIDER | RTCSA_PROF; 10765291Sbde else 10772074Swollman rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; 10785291Sbde writertc(RTC_STATUSA, rtc_statusa); 10791549Srgrimes} 108015508Sbde 108115508Sbdestatic int 108215508Sbdesysctl_machdep_i8254_freq SYSCTL_HANDLER_ARGS 108315508Sbde{ 108415508Sbde int error; 108515508Sbde u_int freq; 108615508Sbde 108715508Sbde /* 108815508Sbde * Use `i8254' instead of `timer' in external names because `timer' 108915508Sbde * is is too generic. Should use it everywhere. 109015508Sbde */ 109115508Sbde freq = timer_freq; 109248888Sbde error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); 109317353Sbde if (error == 0 && req->newptr != NULL) { 109433690Sphk if (timer0_state != RELEASED) 109515508Sbde return (EBUSY); /* too much trouble to handle */ 109615508Sbde set_timer_freq(freq, hz); 109740610Sphk i8254_timecounter.tc_frequency = freq; 109846054Sphk update_timecounter(&i8254_timecounter); 109915508Sbde } 110015508Sbde return (error); 110115508Sbde} 110215508Sbde 110315508SbdeSYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW, 110448888Sbde 0, sizeof(u_int), sysctl_machdep_i8254_freq, "I", ""); 110515508Sbde 110615508Sbdestatic int 110732054Sphksysctl_machdep_tsc_freq SYSCTL_HANDLER_ARGS 110815508Sbde{ 110915508Sbde int error; 111015508Sbde u_int freq; 111115508Sbde 111248888Sbde if (tsc_timecounter.tc_frequency == 0) 111315508Sbde return (EOPNOTSUPP); 111432005Sphk freq = tsc_freq; 111548888Sbde error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); 111633690Sphk if (error == 0 && req->newptr != NULL) { 111733690Sphk tsc_freq = freq; 111840610Sphk tsc_timecounter.tc_frequency = tsc_freq; 111946054Sphk update_timecounter(&tsc_timecounter); 112033690Sphk } 112115508Sbde return (error); 112215508Sbde} 112315508Sbde 112432054SphkSYSCTL_PROC(_machdep, OID_AUTO, tsc_freq, CTLTYPE_INT | CTLFLAG_RW, 112548888Sbde 0, sizeof(u_int), sysctl_machdep_tsc_freq, "I", ""); 112633690Sphk 112736441Sphkstatic unsigned 112836719Sphki8254_get_timecount(struct timecounter *tc) 112933690Sphk{ 113036198Sphk u_int count; 113133690Sphk u_long ef; 113233690Sphk u_int high, low; 113333690Sphk 113433690Sphk ef = read_eflags(); 113533690Sphk disable_intr(); 113633690Sphk 113733690Sphk /* Select timer0 and latch counter value. */ 113833690Sphk outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 113933690Sphk 114033690Sphk low = inb(TIMER_CNTR0); 114133690Sphk high = inb(TIMER_CNTR0); 114247588Sbde count = timer0_max_count - ((high << 8) | low); 114347588Sbde if (count < i8254_lastcount || 114447588Sbde (!i8254_ticked && (clkintr_pending || 114547588Sbde ((count < 20 || (!(ef & PSL_I) && count < timer0_max_count / 2u)) && 114647588Sbde#ifdef APIC_IO 114747588Sbde#define lapic_irr1 ((volatile u_int *)&lapic)[0x210 / 4] /* XXX XXX */ 114847588Sbde /* XXX this assumes that apic_8254_intr is < 24. */ 114947588Sbde (lapic_irr1 & (1 << apic_8254_intr)))) 115047588Sbde#else 115147588Sbde (inb(IO_ICU1) & 1))) 115247588Sbde#endif 115347588Sbde )) { 115433690Sphk i8254_ticked = 1; 115547588Sbde i8254_offset += timer0_max_count; 115633690Sphk } 115733690Sphk i8254_lastcount = count; 115833690Sphk count += i8254_offset; 115933727Sjkh CLOCK_UNLOCK(); 116033690Sphk write_eflags(ef); 116133690Sphk return (count); 116233690Sphk} 116333690Sphk 116436441Sphkstatic unsigned 116536719Sphktsc_get_timecount(struct timecounter *tc) 116633690Sphk{ 116736198Sphk return (rdtsc()); 116833690Sphk} 1169