tsc.c revision 48888
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 3748888Sbde * $Id: clock.c,v 1.138 1999/06/27 09:08:48 peter Exp $ 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> 6215508Sbde 634180Sbde#include <machine/clock.h> 6415508Sbde#ifdef CLK_CALIBRATION_LOOP 6515508Sbde#include <machine/cons.h> 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> 7334617Sphk#if NAPM > 0 7434617Sphk#include <machine/apm_bios.h> 7534617Sphk#include <i386/apm/apm_setup.h> 7634617Sphk#endif 7730805Sbde#ifdef APIC_IO 7830805Sbde#include <machine/segments.h> 7930805Sbde#endif 8028921Sfsmp#if defined(SMP) || defined(APIC_IO) 8126949Sfsmp#include <machine/smp.h> 8228921Sfsmp#endif /* SMP || APIC_IO */ 8332054Sphk#include <machine/specialreg.h> 8415508Sbde 852056Swollman#include <i386/isa/icu.h> 862056Swollman#include <i386/isa/isa.h> 8747642Sdfr#include <isa/rtc.h> 882056Swollman#include <i386/isa/timerreg.h> 894Srgrimes 9045897Speter#include <i386/isa/intr_machdep.h> 9128487Sfsmp 9228921Sfsmp#ifdef SMP 9329000Sfsmp#define disable_intr() CLOCK_DISABLE_INTR() 9429000Sfsmp#define enable_intr() CLOCK_ENABLE_INTR() 9534058Stegge 9634571Stegge#ifdef APIC_IO 9734571Stegge#include <i386/isa/intr_machdep.h> 9834058Stegge/* The interrupt triggered by the 8254 (timer) chip */ 9934058Steggeint apic_8254_intr; 10034571Steggestatic u_long read_intr_count __P((int vec)); 10134571Steggestatic void setup_8254_mixed_mode __P((void)); 10234571Stegge#endif 10328921Sfsmp#endif /* SMP */ 10428921Sfsmp 1052873Sbde/* 1062873Sbde * 32-bit time_t's can't reach leap years before 1904 or after 2036, so we 1072873Sbde * can use a simple formula for leap years. 1082873Sbde */ 1092873Sbde#define LEAPYEAR(y) ((u_int)(y) % 4 == 0) 1102913Sache#define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31) 1112873Sbde 11215508Sbde#define TIMER_DIV(x) ((timer_freq + (x) / 2) / (x)) 1134Srgrimes 1144180Sbde/* 1154180Sbde * Time in timer cycles that it takes for microtime() to disable interrupts 1164180Sbde * and latch the count. microtime() currently uses "cli; outb ..." so it 1174180Sbde * normally takes less than 2 timer cycles. Add a few for cache misses. 1184180Sbde * Add a few more to allow for latency in bogus calls to microtime() with 1194180Sbde * interrupts already disabled. 1204180Sbde */ 1214180Sbde#define TIMER0_LATCH_COUNT 20 1224180Sbde 1234180Sbde/* 12417236Sjoerg * Maximum frequency that we are willing to allow for timer0. Must be 12517231Sjoerg * low enough to guarantee that the timer interrupt handler returns 12633690Sphk * before the next timer interrupt. 1274180Sbde */ 12817231Sjoerg#define TIMER0_MAX_FREQ 20000 1294180Sbde 13041787Smckayint adjkerntz; /* local offset from GMT in seconds */ 13147588Sbdeint clkintr_pending; 13215045Sacheint disable_rtc_set; /* disable resettodr() if != 0 */ 13346847Spetervolatile u_int idelayed; 13432052Sphkint statclock_disable; 13532052Sphku_int stat_imask = SWI_CLOCK_MASK; 13633690Sphk#ifndef TIMER_FREQ 13733690Sphk#define TIMER_FREQ 1193182 13833690Sphk#endif 13932052Sphku_int timer_freq = TIMER_FREQ; 14032052Sphkint timer0_max_count; 14132005Sphku_int tsc_freq; 14247592Sphkint tsc_is_broken; 14341787Smckayint wall_cmos_clock; /* wall CMOS clock assumed if != 0 */ 1441390Ssos 1454180Sbdestatic int beeping = 0; 1465291Sbdestatic u_int clk_imask = HWI_MASK | SWI_MASK; 1474180Sbdestatic const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31}; 14819173Sbdestatic u_int hardclock_max_count; 14933690Sphkstatic u_int32_t i8254_lastcount; 15033690Sphkstatic u_int32_t i8254_offset; 15133690Sphkstatic int i8254_ticked; 1524180Sbde/* 1534180Sbde * XXX new_function and timer_func should not handle clockframes, but 1544180Sbde * timer_func currently needs to hold hardclock to handle the 1554180Sbde * timer0_state == 0 case. We should use register_intr()/unregister_intr() 1564180Sbde * to switch between clkintr() and a slightly different timerintr(). 1574180Sbde */ 15819173Sbdestatic void (*new_function) __P((struct clockframe *frame)); 15919173Sbdestatic u_int new_rate; 1604180Sbdestatic u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; 16115345Snatestatic u_char rtc_statusb = RTCSB_24HR | RTCSB_PINTR; 16233690Sphkstatic u_int timer0_prescaler_count; 16317231Sjoerg 16417231Sjoerg/* Values for timerX_state: */ 16517236Sjoerg#define RELEASED 0 16617236Sjoerg#define RELEASE_PENDING 1 16717236Sjoerg#define ACQUIRED 2 16817236Sjoerg#define ACQUIRE_PENDING 3 16917231Sjoerg 17017231Sjoergstatic u_char timer0_state; 17117231Sjoergstatic u_char timer2_state; 17219173Sbdestatic void (*timer_func) __P((struct clockframe *frame)) = hardclock; 17333690Sphkstatic u_int tsc_present; 1744180Sbde 17536719Sphkstatic unsigned i8254_get_timecount __P((struct timecounter *tc)); 17636719Sphkstatic unsigned tsc_get_timecount __P((struct timecounter *tc)); 17721783Sbdestatic void set_timer_freq(u_int freq, int intr_freq); 17817353Sbde 17940610Sphkstatic struct timecounter tsc_timecounter = { 18033690Sphk tsc_get_timecount, /* get_timecount */ 18136741Sphk 0, /* no poll_pps */ 18236198Sphk ~0u, /* counter_mask */ 18333690Sphk 0, /* frequency */ 18433690Sphk "TSC" /* name */ 18533690Sphk}; 18633690Sphk 18733690SphkSYSCTL_OPAQUE(_debug, OID_AUTO, tsc_timecounter, CTLFLAG_RD, 18840610Sphk &tsc_timecounter, sizeof(tsc_timecounter), "S,timecounter", ""); 18933690Sphk 19040610Sphkstatic struct timecounter i8254_timecounter = { 19133690Sphk i8254_get_timecount, /* get_timecount */ 19236741Sphk 0, /* no poll_pps */ 19336198Sphk ~0u, /* counter_mask */ 19433690Sphk 0, /* frequency */ 19533690Sphk "i8254" /* name */ 19633690Sphk}; 19733690Sphk 19833690SphkSYSCTL_OPAQUE(_debug, OID_AUTO, i8254_timecounter, CTLFLAG_RD, 19940610Sphk &i8254_timecounter, sizeof(i8254_timecounter), "S,timecounter", ""); 20033690Sphk 20112724Sphkstatic void 2023185Ssosclkintr(struct clockframe frame) 2032074Swollman{ 20439503Sbde if (timecounter->tc_get_timecount == i8254_get_timecount) { 20547588Sbde disable_intr(); 20647588Sbde if (i8254_ticked) 20739503Sbde i8254_ticked = 0; 20847588Sbde else { 20939503Sbde i8254_offset += timer0_max_count; 21039503Sbde i8254_lastcount = 0; 21139503Sbde } 21247588Sbde clkintr_pending = 0; 21347588Sbde enable_intr(); 21439503Sbde } 2151549Srgrimes timer_func(&frame); 2161442Ssos switch (timer0_state) { 21717236Sjoerg 21817231Sjoerg case RELEASED: 2198448Sbde setdelayed(); 2201442Ssos break; 22117236Sjoerg 22217231Sjoerg case ACQUIRED: 2234180Sbde if ((timer0_prescaler_count += timer0_max_count) 2244180Sbde >= hardclock_max_count) { 22533309Sbde timer0_prescaler_count -= hardclock_max_count; 2261549Srgrimes hardclock(&frame); 2278448Sbde setdelayed(); 2281390Ssos } 2291442Ssos break; 23017236Sjoerg 23117231Sjoerg case ACQUIRE_PENDING: 2328448Sbde setdelayed(); 2334180Sbde timer0_max_count = TIMER_DIV(new_rate); 23429000Sfsmp disable_intr(); 2354180Sbde outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 2364180Sbde outb(TIMER_CNTR0, timer0_max_count & 0xff); 2374180Sbde outb(TIMER_CNTR0, timer0_max_count >> 8); 23829000Sfsmp enable_intr(); 2394180Sbde timer0_prescaler_count = 0; 2401442Ssos timer_func = new_function; 24117231Sjoerg timer0_state = ACQUIRED; 2421442Ssos break; 24317236Sjoerg 24417231Sjoerg case RELEASE_PENDING: 2454180Sbde if ((timer0_prescaler_count += timer0_max_count) 2464180Sbde >= hardclock_max_count) { 24733309Sbde timer0_prescaler_count -= hardclock_max_count; 24834961Sphk#ifdef FIXME 24933309Sbde /* 25034961Sphk * XXX: This magic doesn't work, but It shouldn't be 25134961Sphk * needed now anyway since we will not be able to 25234961Sphk * aquire the i8254 if it is used for timecounting. 25334961Sphk */ 25434961Sphk /* 25533309Sbde * See microtime.s for this magic. 25633309Sbde */ 25733309Sbde time.tv_usec += (27465 * timer0_prescaler_count) >> 15; 25833309Sbde if (time.tv_usec >= 1000000) 25933309Sbde time.tv_usec -= 1000000; 26034961Sphk#endif 2611549Srgrimes hardclock(&frame); 2628448Sbde setdelayed(); 2635291Sbde timer0_max_count = hardclock_max_count; 26429000Sfsmp disable_intr(); 2654180Sbde outb(TIMER_MODE, 2664180Sbde TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 2674180Sbde outb(TIMER_CNTR0, timer0_max_count & 0xff); 2684180Sbde outb(TIMER_CNTR0, timer0_max_count >> 8); 26929000Sfsmp enable_intr(); 2704180Sbde timer0_prescaler_count = 0; 27117231Sjoerg timer_func = hardclock; 27217231Sjoerg timer0_state = RELEASED; 2731442Ssos } 2741442Ssos break; 2751442Ssos } 2761390Ssos} 2771390Ssos 27817231Sjoerg/* 27917236Sjoerg * The acquire and release functions must be called at ipl >= splclock(). 28017231Sjoerg */ 2811390Ssosint 2824180Sbdeacquire_timer0(int rate, void (*function) __P((struct clockframe *frame))) 2831390Ssos{ 28417231Sjoerg static int old_rate; 28517231Sjoerg 28617231Sjoerg if (rate <= 0 || rate > TIMER0_MAX_FREQ) 28717231Sjoerg return (-1); 28836810Sphk if (strcmp(timecounter->tc_name, "i8254") == 0) 28933690Sphk return (-1); 29017231Sjoerg switch (timer0_state) { 29117231Sjoerg 29217236Sjoerg case RELEASED: 29317236Sjoerg timer0_state = ACQUIRE_PENDING; 29417236Sjoerg break; 29517231Sjoerg 29617236Sjoerg case RELEASE_PENDING: 29717236Sjoerg if (rate != old_rate) 29817236Sjoerg return (-1); 29917236Sjoerg /* 30017236Sjoerg * The timer has been released recently, but is being 30117236Sjoerg * re-acquired before the release completed. In this 30217236Sjoerg * case, we simply reclaim it as if it had not been 30317236Sjoerg * released at all. 30417236Sjoerg */ 30517236Sjoerg timer0_state = ACQUIRED; 30617236Sjoerg break; 30717236Sjoerg 30817236Sjoerg default: 30917236Sjoerg return (-1); /* busy */ 31017231Sjoerg } 3111442Ssos new_function = function; 31217231Sjoerg old_rate = new_rate = rate; 31317231Sjoerg return (0); 3141390Ssos} 3151390Ssos 3161390Ssosint 3171390Ssosacquire_timer2(int mode) 3181390Ssos{ 31917231Sjoerg 32017231Sjoerg if (timer2_state != RELEASED) 32117231Sjoerg return (-1); 32217231Sjoerg timer2_state = ACQUIRED; 32317236Sjoerg 32417236Sjoerg /* 32517236Sjoerg * This access to the timer registers is as atomic as possible 32617236Sjoerg * because it is a single instruction. We could do better if we 32717236Sjoerg * knew the rate. Use of splclock() limits glitches to 10-100us, 32817236Sjoerg * and this is probably good enough for timer2, so we aren't as 32917236Sjoerg * careful with it as with timer0. 33017236Sjoerg */ 33117236Sjoerg outb(TIMER_MODE, TIMER_SEL2 | (mode & 0x3f)); 33217236Sjoerg 33317231Sjoerg return (0); 3341390Ssos} 3351390Ssos 3361390Ssosint 3371390Ssosrelease_timer0() 3381390Ssos{ 33917231Sjoerg switch (timer0_state) { 34017231Sjoerg 34117236Sjoerg case ACQUIRED: 34217236Sjoerg timer0_state = RELEASE_PENDING; 34317236Sjoerg break; 34417231Sjoerg 34517236Sjoerg case ACQUIRE_PENDING: 34617236Sjoerg /* Nothing happened yet, release quickly. */ 34717236Sjoerg timer0_state = RELEASED; 34817236Sjoerg break; 34917236Sjoerg 35017236Sjoerg default: 35117236Sjoerg return (-1); 35217231Sjoerg } 35317231Sjoerg return (0); 3541390Ssos} 3551390Ssos 3561390Ssosint 3571390Ssosrelease_timer2() 3581390Ssos{ 35917231Sjoerg 36017231Sjoerg if (timer2_state != ACQUIRED) 36117231Sjoerg return (-1); 36217231Sjoerg timer2_state = RELEASED; 36317236Sjoerg outb(TIMER_MODE, TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT); 36417231Sjoerg return (0); 3651390Ssos} 3661390Ssos 3673185Ssos/* 3683185Ssos * This routine receives statistical clock interrupts from the RTC. 3693185Ssos * As explained above, these occur at 128 interrupts per second. 3703185Ssos * When profiling, we receive interrupts at a rate of 1024 Hz. 3713185Ssos * 3723185Ssos * This does not actually add as much overhead as it sounds, because 3733185Ssos * when the statistical clock is active, the hardclock driver no longer 3743185Ssos * needs to keep (inaccurate) statistics on its own. This decouples 3753185Ssos * statistics gathering from scheduling interrupts. 3763185Ssos * 3773185Ssos * The RTC chip requires that we read status register C (RTC_INTR) 3783185Ssos * to acknowledge an interrupt, before it will generate the next one. 37924676Smckay * Under high interrupt load, rtcintr() can be indefinitely delayed and 38024676Smckay * the clock can tick immediately after the read from RTC_INTR. In this 38124676Smckay * case, the mc146818A interrupt signal will not drop for long enough 38224676Smckay * to register with the 8259 PIC. If an interrupt is missed, the stat 38324676Smckay * clock will halt, considerably degrading system performance. This is 38424676Smckay * why we use 'while' rather than a more straightforward 'if' below. 38524676Smckay * Stat clock ticks can still be lost, causing minor loss of accuracy 38624676Smckay * in the statistics, but the stat clock will no longer stop. 3873185Ssos */ 38812724Sphkstatic void 3893185Ssosrtcintr(struct clockframe frame) 3903185Ssos{ 39124676Smckay while (rtcin(RTC_INTR) & RTCIR_PERIOD) 3923185Ssos statclock(&frame); 3933185Ssos} 3941390Ssos 39518297Sbde#include "opt_ddb.h" 3965291Sbde#ifdef DDB 39718297Sbde#include <ddb/ddb.h> 39818297Sbde 39918297SbdeDB_SHOW_COMMAND(rtc, rtc) 4003185Ssos{ 4015291Sbde printf("%02x/%02x/%02x %02x:%02x:%02x, A = %02x, B = %02x, C = %02x\n", 4025291Sbde rtcin(RTC_YEAR), rtcin(RTC_MONTH), rtcin(RTC_DAY), 4035291Sbde rtcin(RTC_HRS), rtcin(RTC_MIN), rtcin(RTC_SEC), 4045291Sbde rtcin(RTC_STATUSA), rtcin(RTC_STATUSB), rtcin(RTC_INTR)); 4053185Ssos} 40618297Sbde#endif /* DDB */ 4073185Ssos 4081390Ssosstatic int 40910268Sbdegetit(void) 4101390Ssos{ 41116428Sbde u_long ef; 4121390Ssos int high, low; 4131390Ssos 41416428Sbde ef = read_eflags(); 41529000Sfsmp disable_intr(); 41616428Sbde 41716428Sbde /* Select timer0 and latch counter value. */ 41819173Sbde outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 41916428Sbde 4201390Ssos low = inb(TIMER_CNTR0); 4211390Ssos high = inb(TIMER_CNTR0); 42216428Sbde 42328921Sfsmp CLOCK_UNLOCK(); 42416428Sbde write_eflags(ef); 4251390Ssos return ((high << 8) | low); 4261390Ssos} 4271390Ssos 4282017Swollman/* 4291390Ssos * Wait "n" microseconds. 43015508Sbde * Relies on timer 1 counting down from (timer_freq / hz) 4311390Ssos * Note: timer had better have been programmed before this is first used! 4321390Ssos */ 4331390Ssosvoid 4341390SsosDELAY(int n) 4351390Ssos{ 43622106Sbde int delta, prev_tick, tick, ticks_left; 4371390Ssos 4381390Ssos#ifdef DELAYDEBUG 4391390Ssos int getit_calls = 1; 4401390Ssos int n1; 4411390Ssos static int state = 0; 4421390Ssos 4431390Ssos if (state == 0) { 4441390Ssos state = 1; 4451390Ssos for (n1 = 1; n1 <= 10000000; n1 *= 10) 4461390Ssos DELAY(n1); 4471390Ssos state = 2; 4481390Ssos } 4491390Ssos if (state == 1) 4501390Ssos printf("DELAY(%d)...", n); 4511390Ssos#endif 4521390Ssos /* 45321783Sbde * Guard against the timer being uninitialized if we are called 45421783Sbde * early for console i/o. 45521783Sbde */ 45621783Sbde if (timer0_max_count == 0) 45721783Sbde set_timer_freq(timer_freq, hz); 45821783Sbde 45921783Sbde /* 4601390Ssos * Read the counter first, so that the rest of the setup overhead is 4611390Ssos * counted. Guess the initial overhead is 20 usec (on most systems it 4621390Ssos * takes about 1.5 usec for each of the i/o's in getit(). The loop 4631390Ssos * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The 4641390Ssos * multiplications and divisions to scale the count take a while). 4651390Ssos */ 46610268Sbde prev_tick = getit(); 46722106Sbde n -= 0; /* XXX actually guess no initial overhead */ 4681390Ssos /* 46915508Sbde * Calculate (n * (timer_freq / 1e6)) without using floating point 4701390Ssos * and without any avoidable overflows. 4711390Ssos */ 47222106Sbde if (n <= 0) 47322106Sbde ticks_left = 0; 47422106Sbde else if (n < 256) 47522106Sbde /* 47622106Sbde * Use fixed point to avoid a slow division by 1000000. 47722106Sbde * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest. 47822106Sbde * 2^15 is the first power of 2 that gives exact results 47922106Sbde * for n between 0 and 256. 48022106Sbde */ 48122106Sbde ticks_left = ((u_int)n * 39099 + (1 << 15) - 1) >> 15; 48222106Sbde else 48322106Sbde /* 48422106Sbde * Don't bother using fixed point, although gcc-2.7.2 48522106Sbde * generates particularly poor code for the long long 48622106Sbde * division, since even the slow way will complete long 48722106Sbde * before the delay is up (unless we're interrupted). 48822106Sbde */ 48922106Sbde ticks_left = ((u_int)n * (long long)timer_freq + 999999) 49022106Sbde / 1000000; 4911390Ssos 4921390Ssos while (ticks_left > 0) { 49310268Sbde tick = getit(); 4941390Ssos#ifdef DELAYDEBUG 4951390Ssos ++getit_calls; 4961390Ssos#endif 49721783Sbde delta = prev_tick - tick; 4981390Ssos prev_tick = tick; 49921783Sbde if (delta < 0) { 50021783Sbde delta += timer0_max_count; 50121783Sbde /* 50221783Sbde * Guard against timer0_max_count being wrong. 50321783Sbde * This shouldn't happen in normal operation, 50421783Sbde * but it may happen if set_timer_freq() is 50521783Sbde * traced. 50621783Sbde */ 50721783Sbde if (delta < 0) 50821783Sbde delta = 0; 50921783Sbde } 51021783Sbde ticks_left -= delta; 5111390Ssos } 5121390Ssos#ifdef DELAYDEBUG 5131390Ssos if (state == 1) 5141390Ssos printf(" %d calls to getit() at %d usec each\n", 5151390Ssos getit_calls, (n + 5) / getit_calls); 5161390Ssos#endif 5171390Ssos} 5181390Ssos 5191390Ssosstatic void 5203185Ssossysbeepstop(void *chan) 5211390Ssos{ 5221390Ssos outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */ 5231390Ssos release_timer2(); 5241390Ssos beeping = 0; 5251390Ssos} 5261390Ssos 5278876Srgrimesint 5281390Ssossysbeep(int pitch, int period) 5291390Ssos{ 53017231Sjoerg int x = splclock(); 5311390Ssos 5328876Srgrimes if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT)) 53317231Sjoerg if (!beeping) { 53417231Sjoerg /* Something else owns it. */ 53517231Sjoerg splx(x); 53617231Sjoerg return (-1); /* XXX Should be EBUSY, but nobody cares anyway. */ 53717231Sjoerg } 53829000Sfsmp disable_intr(); 5391390Ssos outb(TIMER_CNTR2, pitch); 5401390Ssos outb(TIMER_CNTR2, (pitch>>8)); 54129000Sfsmp enable_intr(); 5421390Ssos if (!beeping) { 54317231Sjoerg /* enable counter2 output to speaker */ 54417231Sjoerg outb(IO_PPI, inb(IO_PPI) | 3); 5451390Ssos beeping = period; 5462873Sbde timeout(sysbeepstop, (void *)NULL, period); 5471390Ssos } 54817231Sjoerg splx(x); 54917231Sjoerg return (0); 5501390Ssos} 5511390Ssos 5522913Sache/* 5532913Sache * RTC support routines 5542913Sache */ 5552913Sache 55614943Sbdeint 55714943Sbdertcin(reg) 55814943Sbde int reg; 55914943Sbde{ 56014943Sbde u_char val; 56114943Sbde 56214943Sbde outb(IO_RTC, reg); 56314943Sbde inb(0x84); 56414943Sbde val = inb(IO_RTC + 1); 56514943Sbde inb(0x84); 56614943Sbde return (val); 56714943Sbde} 56814943Sbde 56913445Sphkstatic __inline void 5705291Sbdewritertc(u_char reg, u_char val) 5712913Sache{ 57233309Sbde inb(0x84); 5735291Sbde outb(IO_RTC, reg); 57433309Sbde inb(0x84); 5755291Sbde outb(IO_RTC + 1, val); 57633309Sbde inb(0x84); /* XXX work around wrong order in rtcin() */ 5772913Sache} 5782913Sache 57913445Sphkstatic __inline int 5802913Sachereadrtc(int port) 5812913Sache{ 58213445Sphk return(bcd2bin(rtcin(port))); 5832913Sache} 5842913Sache 58515508Sbdestatic u_int 58615508Sbdecalibrate_clocks(void) 58715508Sbde{ 58848160Sgreen u_int64_t old_tsc; 58915508Sbde u_int count, prev_count, tot_count; 59015508Sbde int sec, start_sec, timeout; 59115508Sbde 59223393Sbde if (bootverbose) 59323393Sbde printf("Calibrating clock(s) ... "); 59415508Sbde if (!(rtcin(RTC_STATUSD) & RTCSD_PWR)) 59515508Sbde goto fail; 59615508Sbde timeout = 100000000; 59715508Sbde 59815508Sbde /* Read the mc146818A seconds counter. */ 59915508Sbde for (;;) { 60015508Sbde if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) { 60115508Sbde sec = rtcin(RTC_SEC); 60215508Sbde break; 60315508Sbde } 60415508Sbde if (--timeout == 0) 60515508Sbde goto fail; 60615508Sbde } 60715508Sbde 60815508Sbde /* Wait for the mC146818A seconds counter to change. */ 60915508Sbde start_sec = sec; 61015508Sbde for (;;) { 61115508Sbde if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) { 61215508Sbde sec = rtcin(RTC_SEC); 61315508Sbde if (sec != start_sec) 61415508Sbde break; 61515508Sbde } 61615508Sbde if (--timeout == 0) 61715508Sbde goto fail; 61815508Sbde } 61915508Sbde 62015508Sbde /* Start keeping track of the i8254 counter. */ 62115508Sbde prev_count = getit(); 62215508Sbde if (prev_count == 0 || prev_count > timer0_max_count) 62315508Sbde goto fail; 62415508Sbde tot_count = 0; 62515508Sbde 62632054Sphk if (tsc_present) 62748160Sgreen old_tsc = rdtsc(); 62848266Speter else 62948266Speter old_tsc = 0; /* shut up gcc */ 63015508Sbde 63115508Sbde /* 63215508Sbde * Wait for the mc146818A seconds counter to change. Read the i8254 63315508Sbde * counter for each iteration since this is convenient and only 63415508Sbde * costs a few usec of inaccuracy. The timing of the final reads 63515508Sbde * of the counters almost matches the timing of the initial reads, 63615508Sbde * so the main cause of inaccuracy is the varying latency from 63715508Sbde * inside getit() or rtcin(RTC_STATUSA) to the beginning of the 63815508Sbde * rtcin(RTC_SEC) that returns a changed seconds count. The 63915508Sbde * maximum inaccuracy from this cause is < 10 usec on 486's. 64015508Sbde */ 64115508Sbde start_sec = sec; 64215508Sbde for (;;) { 64315508Sbde if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) 64415508Sbde sec = rtcin(RTC_SEC); 64515508Sbde count = getit(); 64615508Sbde if (count == 0 || count > timer0_max_count) 64715508Sbde goto fail; 64815508Sbde if (count > prev_count) 64915508Sbde tot_count += prev_count - (count - timer0_max_count); 65015508Sbde else 65115508Sbde tot_count += prev_count - count; 65215508Sbde prev_count = count; 65315508Sbde if (sec != start_sec) 65415508Sbde break; 65515508Sbde if (--timeout == 0) 65615508Sbde goto fail; 65715508Sbde } 65815508Sbde 65915508Sbde /* 66015508Sbde * Read the cpu cycle counter. The timing considerations are 66115508Sbde * similar to those for the i8254 clock. 66215508Sbde */ 66333690Sphk if (tsc_present) 66448160Sgreen tsc_freq = rdtsc() - old_tsc; 66533690Sphk 66633690Sphk if (bootverbose) { 66733690Sphk if (tsc_present) 66832005Sphk printf("TSC clock: %u Hz, ", tsc_freq); 66933929Sphk printf("i8254 clock: %u Hz\n", tot_count); 67015508Sbde } 67115508Sbde return (tot_count); 67215508Sbde 67315508Sbdefail: 67423393Sbde if (bootverbose) 67523393Sbde printf("failed, using default i8254 clock of %u Hz\n", 67623393Sbde timer_freq); 67715508Sbde return (timer_freq); 67815508Sbde} 67915508Sbde 68015508Sbdestatic void 68115508Sbdeset_timer_freq(u_int freq, int intr_freq) 68215508Sbde{ 68316874Sbde u_long ef; 68433309Sbde int new_timer0_max_count; 68515508Sbde 68615508Sbde ef = read_eflags(); 68729000Sfsmp disable_intr(); 68815508Sbde timer_freq = freq; 68933309Sbde new_timer0_max_count = hardclock_max_count = TIMER_DIV(intr_freq); 69033309Sbde if (new_timer0_max_count != timer0_max_count) { 69133309Sbde timer0_max_count = new_timer0_max_count; 69233309Sbde outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 69333309Sbde outb(TIMER_CNTR0, timer0_max_count & 0xff); 69433309Sbde outb(TIMER_CNTR0, timer0_max_count >> 8); 69533309Sbde } 69628921Sfsmp CLOCK_UNLOCK(); 69715508Sbde write_eflags(ef); 69815508Sbde} 69915508Sbde 7005291Sbde/* 70133690Sphk * Initialize 8254 timer 0 early so that it can be used in DELAY(). 7025291Sbde * XXX initialization of other timers is unintentionally left blank. 7035291Sbde */ 7041390Ssosvoid 7058876Srgrimesstartrtclock() 706798Swollman{ 70715508Sbde u_int delta, freq; 70815508Sbde 70932054Sphk if (cpu_feature & CPUID_TSC) 71032054Sphk tsc_present = 1; 71132054Sphk else 71232054Sphk tsc_present = 0; 71332054Sphk 71415508Sbde writertc(RTC_STATUSA, rtc_statusa); 71515508Sbde writertc(RTC_STATUSB, RTCSB_24HR); 71615508Sbde 71716874Sbde set_timer_freq(timer_freq, hz); 71815508Sbde freq = calibrate_clocks(); 71915508Sbde#ifdef CLK_CALIBRATION_LOOP 72015508Sbde if (bootverbose) { 72115508Sbde printf( 72215508Sbde "Press a key on the console to abort clock calibration\n"); 72318288Sbde while (cncheckc() == -1) 72415508Sbde calibrate_clocks(); 72515508Sbde } 72615508Sbde#endif 72715508Sbde 72815508Sbde /* 72915508Sbde * Use the calibrated i8254 frequency if it seems reasonable. 73015508Sbde * Otherwise use the default, and don't use the calibrated i586 73115508Sbde * frequency. 73215508Sbde */ 73315508Sbde delta = freq > timer_freq ? freq - timer_freq : timer_freq - freq; 73415508Sbde if (delta < timer_freq / 100) { 73515508Sbde#ifndef CLK_USE_I8254_CALIBRATION 73616300Spst if (bootverbose) 73719173Sbde printf( 73815508Sbde"CLK_USE_I8254_CALIBRATION not specified - using default frequency\n"); 73915508Sbde freq = timer_freq; 74015508Sbde#endif 74115508Sbde timer_freq = freq; 74215508Sbde } else { 74323393Sbde if (bootverbose) 74423393Sbde printf( 74523393Sbde "%d Hz differs from default of %d Hz by more than 1%%\n", 74623393Sbde freq, timer_freq); 74732005Sphk tsc_freq = 0; 74815508Sbde } 74915508Sbde 75015508Sbde set_timer_freq(timer_freq, hz); 75140610Sphk i8254_timecounter.tc_frequency = timer_freq; 75240610Sphk init_timecounter(&i8254_timecounter); 75315508Sbde 75432005Sphk#ifndef CLK_USE_TSC_CALIBRATION 75532005Sphk if (tsc_freq != 0) { 75616300Spst if (bootverbose) 75719173Sbde printf( 75832005Sphk"CLK_USE_TSC_CALIBRATION not specified - using old calibration method\n"); 75932005Sphk tsc_freq = 0; 76015508Sbde } 76115508Sbde#endif 76232054Sphk if (tsc_present && tsc_freq == 0) { 76315508Sbde /* 76415508Sbde * Calibration of the i586 clock relative to the mc146818A 76515508Sbde * clock failed. Do a less accurate calibration relative 76615508Sbde * to the i8254 clock. 76715508Sbde */ 76848160Sgreen u_int64_t old_tsc = rdtsc(); 76948160Sgreen 77015508Sbde DELAY(1000000); 77148160Sgreen tsc_freq = rdtsc() - old_tsc; 77232054Sphk#ifdef CLK_USE_TSC_CALIBRATION 77323393Sbde if (bootverbose) 77433690Sphk printf("TSC clock: %u Hz (Method B)\n", tsc_freq); 77516300Spst#endif 77615508Sbde } 77734617Sphk 77834617Sphk#if !defined(SMP) 77934617Sphk /* 78034617Sphk * We can not use the TSC in SMP mode, until we figure out a 78134617Sphk * cheap (impossible), reliable and precise (yeah right!) way 78234617Sphk * to synchronize the TSCs of all the CPUs. 78334617Sphk * Curse Intel for leaving the counter out of the I/O APIC. 78434617Sphk */ 78534617Sphk 78634617Sphk#if NAPM > 0 78734617Sphk /* 78834617Sphk * We can not use the TSC if we found an APM bios. Too many 78934617Sphk * of them lie about their ability&intention to fiddle the CPU 79034617Sphk * clock for us to rely on this. Precise timekeeping on an 79134617Sphk * APM'ed machine is at best a fools pursuit anyway, since 79234617Sphk * any and all of the time spent in various SMM code can't 79334617Sphk * be reliably accounted for. Reading the RTC is your only 79434617Sphk * source of reliable time info. The i8254 looses too of course 79534617Sphk * but we need to have some kind of time... 79634617Sphk */ 79734617Sphk if (apm_version != APMINI_CANTFIND) 79834617Sphk return; 79934617Sphk#endif /* NAPM > 0 */ 80034617Sphk 80147592Sphk if (tsc_present && tsc_freq != 0 && !tsc_is_broken) { 80240610Sphk tsc_timecounter.tc_frequency = tsc_freq; 80340610Sphk init_timecounter(&tsc_timecounter); 80433690Sphk } 80534617Sphk 80634617Sphk#endif /* !defined(SMP) */ 8074Srgrimes} 8084Srgrimes 8092913Sache/* 81041787Smckay * Initialize the time of day register, based on the time base which is, e.g. 81141787Smckay * from a filesystem. 8122913Sache */ 8132913Sachevoid 8143185Ssosinittodr(time_t base) 8154Srgrimes{ 8162913Sache unsigned long sec, days; 8172913Sache int yd; 8182913Sache int year, month; 8192913Sache int y, m, s; 82033690Sphk struct timespec ts; 8214Srgrimes 82232850Sphk if (base) { 82332850Sphk s = splclock(); 82433690Sphk ts.tv_sec = base; 82533690Sphk ts.tv_nsec = 0; 82633690Sphk set_timecounter(&ts); 82732850Sphk splx(s); 82832850Sphk } 8291390Ssos 83041787Smckay /* Look if we have a RTC present and the time is valid */ 8319202Srgrimes if (!(rtcin(RTC_STATUSD) & RTCSD_PWR)) 8322913Sache goto wrong_time; 8334Srgrimes 83441787Smckay /* wait for time update to complete */ 83541787Smckay /* If RTCSA_TUP is zero, we have at least 244us before next update */ 8362913Sache while (rtcin(RTC_STATUSA) & RTCSA_TUP); 8374Srgrimes 8382913Sache days = 0; 8393355Sache#ifdef USE_RTC_CENTURY 84041787Smckay year = readrtc(RTC_YEAR) + readrtc(RTC_CENTURY) * 100; 8413355Sache#else 8423355Sache year = readrtc(RTC_YEAR) + 1900; 8432913Sache if (year < 1970) 8443355Sache year += 100; 8453355Sache#endif 8463355Sache if (year < 1970) 8472913Sache goto wrong_time; 84841787Smckay month = readrtc(RTC_MONTH); 84941787Smckay for (m = 1; m < month; m++) 85041787Smckay days += daysinmonth[m-1]; 85141787Smckay if ((month > 2) && LEAPYEAR(year)) 8522913Sache days ++; 85341787Smckay days += readrtc(RTC_DAY) - 1; 8542913Sache yd = days; 8552913Sache for (y = 1970; y < year; y++) 85641787Smckay days += DAYSPERYEAR + LEAPYEAR(y); 8572913Sache sec = ((( days * 24 + 8582913Sache readrtc(RTC_HRS)) * 60 + 8592913Sache readrtc(RTC_MIN)) * 60 + 8602913Sache readrtc(RTC_SEC)); 86141787Smckay /* sec now contains the number of seconds, since Jan 1 1970, 86241787Smckay in the local time zone */ 8631390Ssos 86415054Sache sec += tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0); 8654Srgrimes 86634961Sphk y = time_second - sec; 86733690Sphk if (y <= -2 || y >= 2) { 86833690Sphk /* badly off, adjust it */ 86933690Sphk s = splclock(); 87033690Sphk ts.tv_sec = sec; 87133690Sphk ts.tv_nsec = 0; 87233690Sphk set_timecounter(&ts); 87333690Sphk splx(s); 87433690Sphk } 8752913Sache return; 8762913Sache 8772913Sachewrong_time: 87841787Smckay printf("Invalid time in real time clock.\n"); 87941787Smckay printf("Check and reset the date immediately!\n"); 8804Srgrimes} 8814Srgrimes 8824Srgrimes/* 88341787Smckay * Write system time back to RTC 8844Srgrimes */ 8854180Sbdevoid 8864180Sbderesettodr() 8874Srgrimes{ 8882913Sache unsigned long tm; 88911872Sphk int y, m, s; 8904Srgrimes 8913366Sache if (disable_rtc_set) 8923366Sache return; 8933366Sache 8942913Sache s = splclock(); 89534961Sphk tm = time_second; 8962913Sache splx(s); 8974Srgrimes 8985291Sbde /* Disable RTC updates and interrupts. */ 8992913Sache writertc(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR); 9004Srgrimes 90141787Smckay /* Calculate local time to put in RTC */ 9021390Ssos 90315054Sache tm -= tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0); 9042913Sache 90513445Sphk writertc(RTC_SEC, bin2bcd(tm%60)); tm /= 60; /* Write back Seconds */ 90613445Sphk writertc(RTC_MIN, bin2bcd(tm%60)); tm /= 60; /* Write back Minutes */ 90713445Sphk writertc(RTC_HRS, bin2bcd(tm%24)); tm /= 24; /* Write back Hours */ 9082913Sache 90941787Smckay /* We have now the days since 01-01-1970 in tm */ 9102913Sache writertc(RTC_WDAY, (tm+4)%7); /* Write back Weekday */ 91113350Sache for (y = 1970, m = DAYSPERYEAR + LEAPYEAR(y); 91213350Sache tm >= m; 91313350Sache y++, m = DAYSPERYEAR + LEAPYEAR(y)) 91413350Sache tm -= m; 9152913Sache 9162913Sache /* Now we have the years in y and the day-of-the-year in tm */ 91713453Sache writertc(RTC_YEAR, bin2bcd(y%100)); /* Write back Year */ 91813350Sache#ifdef USE_RTC_CENTURY 91913445Sphk writertc(RTC_CENTURY, bin2bcd(y/100)); /* ... and Century */ 9203355Sache#endif 92113402Sbde for (m = 0; ; m++) { 92213402Sbde int ml; 9232913Sache 92413402Sbde ml = daysinmonth[m]; 92513402Sbde if (m == 1 && LEAPYEAR(y)) 92613402Sbde ml++; 92713402Sbde if (tm < ml) 92813402Sbde break; 92913402Sbde tm -= ml; 93013402Sbde } 93113402Sbde 93213445Sphk writertc(RTC_MONTH, bin2bcd(m + 1)); /* Write back Month */ 93313445Sphk writertc(RTC_DAY, bin2bcd(tm + 1)); /* Write back Month Day */ 9342913Sache 9355291Sbde /* Reenable RTC updates and interrupts. */ 93615345Snate writertc(RTC_STATUSB, rtc_statusb); 9374Srgrimes} 9384Srgrimes 93927560Sfsmp 9404Srgrimes/* 9415291Sbde * Start both clocks running. 9424Srgrimes */ 9435291Sbdevoid 9445291Sbdecpu_initclocks() 9454Srgrimes{ 9465291Sbde int diag; 94726949Sfsmp#ifdef APIC_IO 94834571Stegge int apic_8254_trial; 94945900Speter struct intrec *clkdesc; 95025164Speter#endif /* APIC_IO */ 9514Srgrimes 95215345Snate if (statclock_disable) { 95315345Snate /* 95415345Snate * The stat interrupt mask is different without the 95515345Snate * statistics clock. Also, don't set the interrupt 95615345Snate * flag which would normally cause the RTC to generate 95715345Snate * interrupts. 95815345Snate */ 95915345Snate stat_imask = HWI_MASK | SWI_MASK; 96015345Snate rtc_statusb = RTCSB_24HR; 96115345Snate } else { 96215345Snate /* Setting stathz to nonzero early helps avoid races. */ 96315345Snate stathz = RTC_NOPROFRATE; 96415345Snate profhz = RTC_PROFRATE; 96515345Snate } 9664Srgrimes 9675291Sbde /* Finish initializing 8253 timer 0. */ 96826949Sfsmp#ifdef APIC_IO 96927563Sfsmp 97038888Stegge apic_8254_intr = isa_apic_irq(0); 97134571Stegge apic_8254_trial = 0; 97234571Stegge if (apic_8254_intr >= 0 ) { 97334571Stegge if (apic_int_type(0, 0) == 3) 97434571Stegge apic_8254_trial = 1; 97534571Stegge } else { 97634571Stegge /* look for ExtInt on pin 0 */ 97734571Stegge if (apic_int_type(0, 0) == 3) { 97834571Stegge apic_8254_intr = 0; 97934571Stegge setup_8254_mixed_mode(); 98034571Stegge } else 98134571Stegge panic("APIC_IO: Cannot route 8254 interrupt to CPU"); 98227563Sfsmp } 98327563Sfsmp 98445897Speter clkdesc = inthand_add("clk", apic_8254_intr, (inthand2_t *)clkintr, 98545897Speter NULL, &clk_imask, INTR_EXCL); 98634571Stegge INTREN(1 << apic_8254_intr); 98734571Stegge 98827696Sfsmp#else /* APIC_IO */ 98927563Sfsmp 99045897Speter inthand_add("clk", 0, (inthand2_t *)clkintr, NULL, &clk_imask, 99145897Speter INTR_EXCL); 9924Srgrimes INTREN(IRQ0); 99327696Sfsmp 99425164Speter#endif /* APIC_IO */ 99526949Sfsmp 9965291Sbde /* Initialize RTC. */ 9975291Sbde writertc(RTC_STATUSA, rtc_statusa); 9985291Sbde writertc(RTC_STATUSB, RTCSB_24HR); 99915345Snate 100015345Snate /* Don't bother enabling the statistics clock. */ 100115345Snate if (statclock_disable) 100215345Snate return; 10035291Sbde diag = rtcin(RTC_DIAG); 10045291Sbde if (diag != 0) 10055291Sbde printf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS); 100627520Sfsmp 100726949Sfsmp#ifdef APIC_IO 100838888Stegge if (isa_apic_irq(8) != 8) 100927520Sfsmp panic("APIC RTC != 8"); 101027563Sfsmp#endif /* APIC_IO */ 101128487Sfsmp 101245897Speter inthand_add("rtc", 8, (inthand2_t *)rtcintr, NULL, &stat_imask, 101345897Speter INTR_EXCL); 101428487Sfsmp 101527616Sfsmp#ifdef APIC_IO 101627616Sfsmp INTREN(APIC_IRQ8); 101727616Sfsmp#else 10182074Swollman INTREN(IRQ8); 101927616Sfsmp#endif /* APIC_IO */ 102027520Sfsmp 102115345Snate writertc(RTC_STATUSB, rtc_statusb); 102234571Stegge 102334571Stegge#ifdef APIC_IO 102434571Stegge if (apic_8254_trial) { 102534571Stegge 102634571Stegge printf("APIC_IO: Testing 8254 interrupt delivery\n"); 102734571Stegge while (read_intr_count(8) < 6) 102835035Stegge ; /* nothing */ 102934571Stegge if (read_intr_count(apic_8254_intr) < 3) { 103034571Stegge /* 103134571Stegge * The MP table is broken. 103234571Stegge * The 8254 was not connected to the specified pin 103334571Stegge * on the IO APIC. 103434571Stegge * Workaround: Limited variant of mixed mode. 103534571Stegge */ 103634571Stegge INTRDIS(1 << apic_8254_intr); 103745897Speter inthand_remove(clkdesc); 103834571Stegge printf("APIC_IO: Broken MP table detected: " 103934571Stegge "8254 is not connected to IO APIC int pin %d\n", 104034571Stegge apic_8254_intr); 104134571Stegge 104234571Stegge apic_8254_intr = 0; 104334571Stegge setup_8254_mixed_mode(); 104445897Speter inthand_add("clk", apic_8254_intr,(inthand2_t *)clkintr, 104545897Speter NULL, &clk_imask, INTR_EXCL); 104634571Stegge INTREN(1 << apic_8254_intr); 104734571Stegge } 104834571Stegge 104934571Stegge } 105034571Stegge if (apic_8254_intr) 105134571Stegge printf("APIC_IO: routing 8254 via pin %d\n",apic_8254_intr); 105234571Stegge else 105334571Stegge printf("APIC_IO: routing 8254 via 8259 on pin 0\n"); 105434571Stegge#endif 105534571Stegge 10564Srgrimes} 10574Srgrimes 105834571Stegge#ifdef APIC_IO 105934571Steggestatic u_long 106034571Steggeread_intr_count(int vec) 106134571Stegge{ 106234571Stegge u_long *up; 106334571Stegge up = intr_countp[vec]; 106434571Stegge if (up) 106534571Stegge return *up; 106634571Stegge return 0UL; 106734571Stegge} 106834571Stegge 106934571Steggestatic void 107034571Steggesetup_8254_mixed_mode() 107134571Stegge{ 107234571Stegge /* 107334571Stegge * Allow 8254 timer to INTerrupt 8259: 107434571Stegge * re-initialize master 8259: 107534571Stegge * reset; prog 4 bytes, single ICU, edge triggered 107634571Stegge */ 107734571Stegge outb(IO_ICU1, 0x13); 107834571Stegge outb(IO_ICU1 + 1, NRSVIDT); /* start vector (unused) */ 107934571Stegge outb(IO_ICU1 + 1, 0x00); /* ignore slave */ 108034571Stegge outb(IO_ICU1 + 1, 0x03); /* auto EOI, 8086 */ 108134571Stegge outb(IO_ICU1 + 1, 0xfe); /* unmask INT0 */ 108234571Stegge 108334571Stegge /* program IO APIC for type 3 INT on INT0 */ 108434571Stegge if (ext_int_setup(0, 0) < 0) 108534571Stegge panic("8254 redirect via APIC pin0 impossible!"); 108634571Stegge} 108734571Stegge#endif 108834571Stegge 10894Srgrimesvoid 10901549Srgrimessetstatclockrate(int newhz) 10911549Srgrimes{ 10925291Sbde if (newhz == RTC_PROFRATE) 10932074Swollman rtc_statusa = RTCSA_DIVIDER | RTCSA_PROF; 10945291Sbde else 10952074Swollman rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; 10965291Sbde writertc(RTC_STATUSA, rtc_statusa); 10971549Srgrimes} 109815508Sbde 109915508Sbdestatic int 110015508Sbdesysctl_machdep_i8254_freq SYSCTL_HANDLER_ARGS 110115508Sbde{ 110215508Sbde int error; 110315508Sbde u_int freq; 110415508Sbde 110515508Sbde /* 110615508Sbde * Use `i8254' instead of `timer' in external names because `timer' 110715508Sbde * is is too generic. Should use it everywhere. 110815508Sbde */ 110915508Sbde freq = timer_freq; 111048888Sbde error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); 111117353Sbde if (error == 0 && req->newptr != NULL) { 111233690Sphk if (timer0_state != RELEASED) 111315508Sbde return (EBUSY); /* too much trouble to handle */ 111415508Sbde set_timer_freq(freq, hz); 111540610Sphk i8254_timecounter.tc_frequency = freq; 111646054Sphk update_timecounter(&i8254_timecounter); 111715508Sbde } 111815508Sbde return (error); 111915508Sbde} 112015508Sbde 112115508SbdeSYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW, 112248888Sbde 0, sizeof(u_int), sysctl_machdep_i8254_freq, "I", ""); 112315508Sbde 112415508Sbdestatic int 112532054Sphksysctl_machdep_tsc_freq SYSCTL_HANDLER_ARGS 112615508Sbde{ 112715508Sbde int error; 112815508Sbde u_int freq; 112915508Sbde 113048888Sbde if (tsc_timecounter.tc_frequency == 0) 113115508Sbde return (EOPNOTSUPP); 113232005Sphk freq = tsc_freq; 113348888Sbde error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); 113433690Sphk if (error == 0 && req->newptr != NULL) { 113533690Sphk tsc_freq = freq; 113640610Sphk tsc_timecounter.tc_frequency = tsc_freq; 113746054Sphk update_timecounter(&tsc_timecounter); 113833690Sphk } 113915508Sbde return (error); 114015508Sbde} 114115508Sbde 114232054SphkSYSCTL_PROC(_machdep, OID_AUTO, tsc_freq, CTLTYPE_INT | CTLFLAG_RW, 114348888Sbde 0, sizeof(u_int), sysctl_machdep_tsc_freq, "I", ""); 114433690Sphk 114536441Sphkstatic unsigned 114636719Sphki8254_get_timecount(struct timecounter *tc) 114733690Sphk{ 114836198Sphk u_int count; 114933690Sphk u_long ef; 115033690Sphk u_int high, low; 115133690Sphk 115233690Sphk ef = read_eflags(); 115333690Sphk disable_intr(); 115433690Sphk 115533690Sphk /* Select timer0 and latch counter value. */ 115633690Sphk outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 115733690Sphk 115833690Sphk low = inb(TIMER_CNTR0); 115933690Sphk high = inb(TIMER_CNTR0); 116047588Sbde count = timer0_max_count - ((high << 8) | low); 116147588Sbde if (count < i8254_lastcount || 116247588Sbde (!i8254_ticked && (clkintr_pending || 116347588Sbde ((count < 20 || (!(ef & PSL_I) && count < timer0_max_count / 2u)) && 116447588Sbde#ifdef APIC_IO 116547588Sbde#define lapic_irr1 ((volatile u_int *)&lapic)[0x210 / 4] /* XXX XXX */ 116647588Sbde /* XXX this assumes that apic_8254_intr is < 24. */ 116747588Sbde (lapic_irr1 & (1 << apic_8254_intr)))) 116847588Sbde#else 116947588Sbde (inb(IO_ICU1) & 1))) 117047588Sbde#endif 117147588Sbde )) { 117233690Sphk i8254_ticked = 1; 117347588Sbde i8254_offset += timer0_max_count; 117433690Sphk } 117533690Sphk i8254_lastcount = count; 117633690Sphk count += i8254_offset; 117733727Sjkh CLOCK_UNLOCK(); 117833690Sphk write_eflags(ef); 117933690Sphk return (count); 118033690Sphk} 118133690Sphk 118236441Sphkstatic unsigned 118336719Sphktsc_get_timecount(struct timecounter *tc) 118433690Sphk{ 118536198Sphk return (rdtsc()); 118633690Sphk} 1187