tsc.c revision 36441
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 3736441Sphk * $Id: clock.c,v 1.120 1998/05/19 18:48:30 phk 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> 7234617Sphk#if NAPM > 0 7334617Sphk#include <machine/apm_bios.h> 7434617Sphk#include <i386/apm/apm_setup.h> 7534617Sphk#endif 7630805Sbde#ifdef APIC_IO 7730805Sbde#include <machine/segments.h> 7830805Sbde#endif 7928921Sfsmp#if defined(SMP) || defined(APIC_IO) 8026949Sfsmp#include <machine/smp.h> 8128921Sfsmp#endif /* SMP || APIC_IO */ 8232054Sphk#include <machine/specialreg.h> 8315508Sbde 842056Swollman#include <i386/isa/icu.h> 852056Swollman#include <i386/isa/isa.h> 862056Swollman#include <i386/isa/rtc.h> 872056Swollman#include <i386/isa/timerreg.h> 884Srgrimes 8928487Sfsmp#include <sys/interrupt.h> 9028487Sfsmp 9128921Sfsmp#ifdef SMP 9229000Sfsmp#define disable_intr() CLOCK_DISABLE_INTR() 9329000Sfsmp#define enable_intr() CLOCK_ENABLE_INTR() 9434058Stegge 9534571Stegge#ifdef APIC_IO 9634571Stegge#include <i386/isa/intr_machdep.h> 9734058Stegge/* The interrupt triggered by the 8254 (timer) chip */ 9834058Steggeint apic_8254_intr; 9934571Steggestatic u_long read_intr_count __P((int vec)); 10034571Steggestatic void setup_8254_mixed_mode __P((void)); 10134571Stegge#endif 10228921Sfsmp#endif /* SMP */ 10328921Sfsmp 1042873Sbde/* 1052873Sbde * 32-bit time_t's can't reach leap years before 1904 or after 2036, so we 1062873Sbde * can use a simple formula for leap years. 1072873Sbde */ 1082873Sbde#define LEAPYEAR(y) ((u_int)(y) % 4 == 0) 1092913Sache#define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31) 1102873Sbde 11115508Sbde#define TIMER_DIV(x) ((timer_freq + (x) / 2) / (x)) 1124Srgrimes 1134180Sbde/* 1144180Sbde * Time in timer cycles that it takes for microtime() to disable interrupts 1154180Sbde * and latch the count. microtime() currently uses "cli; outb ..." so it 1164180Sbde * normally takes less than 2 timer cycles. Add a few for cache misses. 1174180Sbde * Add a few more to allow for latency in bogus calls to microtime() with 1184180Sbde * interrupts already disabled. 1194180Sbde */ 1204180Sbde#define TIMER0_LATCH_COUNT 20 1214180Sbde 1224180Sbde/* 12317236Sjoerg * Maximum frequency that we are willing to allow for timer0. Must be 12417231Sjoerg * low enough to guarantee that the timer interrupt handler returns 12533690Sphk * before the next timer interrupt. 1264180Sbde */ 12717231Sjoerg#define TIMER0_MAX_FREQ 20000 1284180Sbde 12915045Sacheint adjkerntz; /* local offset from GMT in seconds */ 13015045Sacheint disable_rtc_set; /* disable resettodr() if != 0 */ 1318448Sbdeu_int idelayed; 13232052Sphkint statclock_disable; 13332052Sphku_int stat_imask = SWI_CLOCK_MASK; 13433690Sphk#ifndef TIMER_FREQ 13533690Sphk#define TIMER_FREQ 1193182 13633690Sphk#endif 13732052Sphku_int timer_freq = TIMER_FREQ; 13832052Sphkint timer0_max_count; 13932005Sphku_int tsc_freq; 14019173Sbdeint wall_cmos_clock; /* wall CMOS clock assumed if != 0 */ 1411390Ssos 1424180Sbdestatic int beeping = 0; 1435291Sbdestatic u_int clk_imask = HWI_MASK | SWI_MASK; 1444180Sbdestatic const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31}; 14519173Sbdestatic u_int hardclock_max_count; 14633690Sphkstatic u_int32_t i8254_lastcount; 14733690Sphkstatic u_int32_t i8254_offset; 14833690Sphkstatic int i8254_ticked; 1494180Sbde/* 1504180Sbde * XXX new_function and timer_func should not handle clockframes, but 1514180Sbde * timer_func currently needs to hold hardclock to handle the 1524180Sbde * timer0_state == 0 case. We should use register_intr()/unregister_intr() 1534180Sbde * to switch between clkintr() and a slightly different timerintr(). 1544180Sbde */ 15519173Sbdestatic void (*new_function) __P((struct clockframe *frame)); 15619173Sbdestatic u_int new_rate; 1574180Sbdestatic u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; 15815345Snatestatic u_char rtc_statusb = RTCSB_24HR | RTCSB_PINTR; 15933690Sphkstatic u_int timer0_prescaler_count; 16017231Sjoerg 16117231Sjoerg/* Values for timerX_state: */ 16217236Sjoerg#define RELEASED 0 16317236Sjoerg#define RELEASE_PENDING 1 16417236Sjoerg#define ACQUIRED 2 16517236Sjoerg#define ACQUIRE_PENDING 3 16617231Sjoerg 16717231Sjoergstatic u_char timer0_state; 16817231Sjoergstatic u_char timer2_state; 16919173Sbdestatic void (*timer_func) __P((struct clockframe *frame)) = hardclock; 17033690Sphkstatic u_int tsc_present; 1714180Sbde 17236198Sphkstatic unsigned i8254_get_timecount __P((void)); 17336198Sphkstatic unsigned tsc_get_timecount __P((void)); 17421783Sbdestatic void set_timer_freq(u_int freq, int intr_freq); 17517353Sbde 17633690Sphkstatic struct timecounter tsc_timecounter[3] = { 17733690Sphk tsc_get_timecount, /* get_timecount */ 17836198Sphk ~0u, /* counter_mask */ 17933690Sphk 0, /* frequency */ 18033690Sphk "TSC" /* name */ 18133690Sphk}; 18233690Sphk 18333690SphkSYSCTL_OPAQUE(_debug, OID_AUTO, tsc_timecounter, CTLFLAG_RD, 18433690Sphk tsc_timecounter, sizeof(tsc_timecounter), "S,timecounter", ""); 18533690Sphk 18633690Sphkstatic struct timecounter i8254_timecounter[3] = { 18733690Sphk i8254_get_timecount, /* get_timecount */ 18836198Sphk ~0u, /* counter_mask */ 18933690Sphk 0, /* frequency */ 19033690Sphk "i8254" /* name */ 19133690Sphk}; 19233690Sphk 19333690SphkSYSCTL_OPAQUE(_debug, OID_AUTO, i8254_timecounter, CTLFLAG_RD, 19433690Sphk i8254_timecounter, sizeof(i8254_timecounter), "S,timecounter", ""); 19533690Sphk 19612724Sphkstatic void 1973185Ssosclkintr(struct clockframe frame) 1982074Swollman{ 19933690Sphk if (!i8254_ticked) 20033690Sphk i8254_offset += timer0_max_count; 20133690Sphk else 20233690Sphk i8254_ticked = 0; 20333753Sbde i8254_lastcount = 0; 2041549Srgrimes timer_func(&frame); 2051442Ssos switch (timer0_state) { 20617236Sjoerg 20717231Sjoerg case RELEASED: 2088448Sbde setdelayed(); 2091442Ssos break; 21017236Sjoerg 21117231Sjoerg case ACQUIRED: 2124180Sbde if ((timer0_prescaler_count += timer0_max_count) 2134180Sbde >= hardclock_max_count) { 21433309Sbde timer0_prescaler_count -= hardclock_max_count; 2151549Srgrimes hardclock(&frame); 2168448Sbde setdelayed(); 2171390Ssos } 2181442Ssos break; 21917236Sjoerg 22017231Sjoerg case ACQUIRE_PENDING: 2218448Sbde setdelayed(); 2224180Sbde timer0_max_count = TIMER_DIV(new_rate); 22329000Sfsmp disable_intr(); 2244180Sbde outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 2254180Sbde outb(TIMER_CNTR0, timer0_max_count & 0xff); 2264180Sbde outb(TIMER_CNTR0, timer0_max_count >> 8); 22729000Sfsmp enable_intr(); 2284180Sbde timer0_prescaler_count = 0; 2291442Ssos timer_func = new_function; 23017231Sjoerg timer0_state = ACQUIRED; 2311442Ssos break; 23217236Sjoerg 23317231Sjoerg case RELEASE_PENDING: 2344180Sbde if ((timer0_prescaler_count += timer0_max_count) 2354180Sbde >= hardclock_max_count) { 23633309Sbde timer0_prescaler_count -= hardclock_max_count; 23734961Sphk#ifdef FIXME 23833309Sbde /* 23934961Sphk * XXX: This magic doesn't work, but It shouldn't be 24034961Sphk * needed now anyway since we will not be able to 24134961Sphk * aquire the i8254 if it is used for timecounting. 24234961Sphk */ 24334961Sphk /* 24433309Sbde * See microtime.s for this magic. 24533309Sbde */ 24633309Sbde time.tv_usec += (27465 * timer0_prescaler_count) >> 15; 24733309Sbde if (time.tv_usec >= 1000000) 24833309Sbde time.tv_usec -= 1000000; 24934961Sphk#endif 2501549Srgrimes hardclock(&frame); 2518448Sbde setdelayed(); 2525291Sbde timer0_max_count = hardclock_max_count; 25329000Sfsmp disable_intr(); 2544180Sbde outb(TIMER_MODE, 2554180Sbde TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 2564180Sbde outb(TIMER_CNTR0, timer0_max_count & 0xff); 2574180Sbde outb(TIMER_CNTR0, timer0_max_count >> 8); 25829000Sfsmp enable_intr(); 2594180Sbde timer0_prescaler_count = 0; 26017231Sjoerg timer_func = hardclock; 26117231Sjoerg timer0_state = RELEASED; 2621442Ssos } 2631442Ssos break; 2641442Ssos } 2651390Ssos} 2661390Ssos 26717231Sjoerg/* 26817236Sjoerg * The acquire and release functions must be called at ipl >= splclock(). 26917231Sjoerg */ 2701390Ssosint 2714180Sbdeacquire_timer0(int rate, void (*function) __P((struct clockframe *frame))) 2721390Ssos{ 27317231Sjoerg static int old_rate; 27417231Sjoerg 27517231Sjoerg if (rate <= 0 || rate > TIMER0_MAX_FREQ) 27617231Sjoerg return (-1); 27733690Sphk if (strcmp(timecounter->name, "i8254") == 0) 27833690Sphk return (-1); 27917231Sjoerg switch (timer0_state) { 28017231Sjoerg 28117236Sjoerg case RELEASED: 28217236Sjoerg timer0_state = ACQUIRE_PENDING; 28317236Sjoerg break; 28417231Sjoerg 28517236Sjoerg case RELEASE_PENDING: 28617236Sjoerg if (rate != old_rate) 28717236Sjoerg return (-1); 28817236Sjoerg /* 28917236Sjoerg * The timer has been released recently, but is being 29017236Sjoerg * re-acquired before the release completed. In this 29117236Sjoerg * case, we simply reclaim it as if it had not been 29217236Sjoerg * released at all. 29317236Sjoerg */ 29417236Sjoerg timer0_state = ACQUIRED; 29517236Sjoerg break; 29617236Sjoerg 29717236Sjoerg default: 29817236Sjoerg return (-1); /* busy */ 29917231Sjoerg } 3001442Ssos new_function = function; 30117231Sjoerg old_rate = new_rate = rate; 30217231Sjoerg return (0); 3031390Ssos} 3041390Ssos 3051390Ssosint 3061390Ssosacquire_timer2(int mode) 3071390Ssos{ 30817231Sjoerg 30917231Sjoerg if (timer2_state != RELEASED) 31017231Sjoerg return (-1); 31117231Sjoerg timer2_state = ACQUIRED; 31217236Sjoerg 31317236Sjoerg /* 31417236Sjoerg * This access to the timer registers is as atomic as possible 31517236Sjoerg * because it is a single instruction. We could do better if we 31617236Sjoerg * knew the rate. Use of splclock() limits glitches to 10-100us, 31717236Sjoerg * and this is probably good enough for timer2, so we aren't as 31817236Sjoerg * careful with it as with timer0. 31917236Sjoerg */ 32017236Sjoerg outb(TIMER_MODE, TIMER_SEL2 | (mode & 0x3f)); 32117236Sjoerg 32217231Sjoerg return (0); 3231390Ssos} 3241390Ssos 3251390Ssosint 3261390Ssosrelease_timer0() 3271390Ssos{ 32817231Sjoerg switch (timer0_state) { 32917231Sjoerg 33017236Sjoerg case ACQUIRED: 33117236Sjoerg timer0_state = RELEASE_PENDING; 33217236Sjoerg break; 33317231Sjoerg 33417236Sjoerg case ACQUIRE_PENDING: 33517236Sjoerg /* Nothing happened yet, release quickly. */ 33617236Sjoerg timer0_state = RELEASED; 33717236Sjoerg break; 33817236Sjoerg 33917236Sjoerg default: 34017236Sjoerg return (-1); 34117231Sjoerg } 34217231Sjoerg return (0); 3431390Ssos} 3441390Ssos 3451390Ssosint 3461390Ssosrelease_timer2() 3471390Ssos{ 34817231Sjoerg 34917231Sjoerg if (timer2_state != ACQUIRED) 35017231Sjoerg return (-1); 35117231Sjoerg timer2_state = RELEASED; 35217236Sjoerg outb(TIMER_MODE, TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT); 35317231Sjoerg return (0); 3541390Ssos} 3551390Ssos 3563185Ssos/* 3573185Ssos * This routine receives statistical clock interrupts from the RTC. 3583185Ssos * As explained above, these occur at 128 interrupts per second. 3593185Ssos * When profiling, we receive interrupts at a rate of 1024 Hz. 3603185Ssos * 3613185Ssos * This does not actually add as much overhead as it sounds, because 3623185Ssos * when the statistical clock is active, the hardclock driver no longer 3633185Ssos * needs to keep (inaccurate) statistics on its own. This decouples 3643185Ssos * statistics gathering from scheduling interrupts. 3653185Ssos * 3663185Ssos * The RTC chip requires that we read status register C (RTC_INTR) 3673185Ssos * to acknowledge an interrupt, before it will generate the next one. 36824676Smckay * Under high interrupt load, rtcintr() can be indefinitely delayed and 36924676Smckay * the clock can tick immediately after the read from RTC_INTR. In this 37024676Smckay * case, the mc146818A interrupt signal will not drop for long enough 37124676Smckay * to register with the 8259 PIC. If an interrupt is missed, the stat 37224676Smckay * clock will halt, considerably degrading system performance. This is 37324676Smckay * why we use 'while' rather than a more straightforward 'if' below. 37424676Smckay * Stat clock ticks can still be lost, causing minor loss of accuracy 37524676Smckay * in the statistics, but the stat clock will no longer stop. 3763185Ssos */ 37712724Sphkstatic void 3783185Ssosrtcintr(struct clockframe frame) 3793185Ssos{ 38024676Smckay while (rtcin(RTC_INTR) & RTCIR_PERIOD) 3813185Ssos statclock(&frame); 3823185Ssos} 3831390Ssos 38418297Sbde#include "opt_ddb.h" 3855291Sbde#ifdef DDB 38618297Sbde#include <ddb/ddb.h> 38718297Sbde 38818297SbdeDB_SHOW_COMMAND(rtc, rtc) 3893185Ssos{ 3905291Sbde printf("%02x/%02x/%02x %02x:%02x:%02x, A = %02x, B = %02x, C = %02x\n", 3915291Sbde rtcin(RTC_YEAR), rtcin(RTC_MONTH), rtcin(RTC_DAY), 3925291Sbde rtcin(RTC_HRS), rtcin(RTC_MIN), rtcin(RTC_SEC), 3935291Sbde rtcin(RTC_STATUSA), rtcin(RTC_STATUSB), rtcin(RTC_INTR)); 3943185Ssos} 39518297Sbde#endif /* DDB */ 3963185Ssos 3971390Ssosstatic int 39810268Sbdegetit(void) 3991390Ssos{ 40016428Sbde u_long ef; 4011390Ssos int high, low; 4021390Ssos 40316428Sbde ef = read_eflags(); 40429000Sfsmp disable_intr(); 40516428Sbde 40616428Sbde /* Select timer0 and latch counter value. */ 40719173Sbde outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 40816428Sbde 4091390Ssos low = inb(TIMER_CNTR0); 4101390Ssos high = inb(TIMER_CNTR0); 41116428Sbde 41228921Sfsmp CLOCK_UNLOCK(); 41316428Sbde write_eflags(ef); 4141390Ssos return ((high << 8) | low); 4151390Ssos} 4161390Ssos 4172017Swollman/* 4181390Ssos * Wait "n" microseconds. 41915508Sbde * Relies on timer 1 counting down from (timer_freq / hz) 4201390Ssos * Note: timer had better have been programmed before this is first used! 4211390Ssos */ 4221390Ssosvoid 4231390SsosDELAY(int n) 4241390Ssos{ 42522106Sbde int delta, prev_tick, tick, ticks_left; 4261390Ssos 4271390Ssos#ifdef DELAYDEBUG 4281390Ssos int getit_calls = 1; 4291390Ssos int n1; 4301390Ssos static int state = 0; 4311390Ssos 4321390Ssos if (state == 0) { 4331390Ssos state = 1; 4341390Ssos for (n1 = 1; n1 <= 10000000; n1 *= 10) 4351390Ssos DELAY(n1); 4361390Ssos state = 2; 4371390Ssos } 4381390Ssos if (state == 1) 4391390Ssos printf("DELAY(%d)...", n); 4401390Ssos#endif 4411390Ssos /* 44221783Sbde * Guard against the timer being uninitialized if we are called 44321783Sbde * early for console i/o. 44421783Sbde */ 44521783Sbde if (timer0_max_count == 0) 44621783Sbde set_timer_freq(timer_freq, hz); 44721783Sbde 44821783Sbde /* 4491390Ssos * Read the counter first, so that the rest of the setup overhead is 4501390Ssos * counted. Guess the initial overhead is 20 usec (on most systems it 4511390Ssos * takes about 1.5 usec for each of the i/o's in getit(). The loop 4521390Ssos * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The 4531390Ssos * multiplications and divisions to scale the count take a while). 4541390Ssos */ 45510268Sbde prev_tick = getit(); 45622106Sbde n -= 0; /* XXX actually guess no initial overhead */ 4571390Ssos /* 45815508Sbde * Calculate (n * (timer_freq / 1e6)) without using floating point 4591390Ssos * and without any avoidable overflows. 4601390Ssos */ 46122106Sbde if (n <= 0) 46222106Sbde ticks_left = 0; 46322106Sbde else if (n < 256) 46422106Sbde /* 46522106Sbde * Use fixed point to avoid a slow division by 1000000. 46622106Sbde * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest. 46722106Sbde * 2^15 is the first power of 2 that gives exact results 46822106Sbde * for n between 0 and 256. 46922106Sbde */ 47022106Sbde ticks_left = ((u_int)n * 39099 + (1 << 15) - 1) >> 15; 47122106Sbde else 47222106Sbde /* 47322106Sbde * Don't bother using fixed point, although gcc-2.7.2 47422106Sbde * generates particularly poor code for the long long 47522106Sbde * division, since even the slow way will complete long 47622106Sbde * before the delay is up (unless we're interrupted). 47722106Sbde */ 47822106Sbde ticks_left = ((u_int)n * (long long)timer_freq + 999999) 47922106Sbde / 1000000; 4801390Ssos 4811390Ssos while (ticks_left > 0) { 48210268Sbde tick = getit(); 4831390Ssos#ifdef DELAYDEBUG 4841390Ssos ++getit_calls; 4851390Ssos#endif 48621783Sbde delta = prev_tick - tick; 4871390Ssos prev_tick = tick; 48821783Sbde if (delta < 0) { 48921783Sbde delta += timer0_max_count; 49021783Sbde /* 49121783Sbde * Guard against timer0_max_count being wrong. 49221783Sbde * This shouldn't happen in normal operation, 49321783Sbde * but it may happen if set_timer_freq() is 49421783Sbde * traced. 49521783Sbde */ 49621783Sbde if (delta < 0) 49721783Sbde delta = 0; 49821783Sbde } 49921783Sbde ticks_left -= delta; 5001390Ssos } 5011390Ssos#ifdef DELAYDEBUG 5021390Ssos if (state == 1) 5031390Ssos printf(" %d calls to getit() at %d usec each\n", 5041390Ssos getit_calls, (n + 5) / getit_calls); 5051390Ssos#endif 5061390Ssos} 5071390Ssos 5081390Ssosstatic void 5093185Ssossysbeepstop(void *chan) 5101390Ssos{ 5111390Ssos outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */ 5121390Ssos release_timer2(); 5131390Ssos beeping = 0; 5141390Ssos} 5151390Ssos 5168876Srgrimesint 5171390Ssossysbeep(int pitch, int period) 5181390Ssos{ 51917231Sjoerg int x = splclock(); 5201390Ssos 5218876Srgrimes if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT)) 52217231Sjoerg if (!beeping) { 52317231Sjoerg /* Something else owns it. */ 52417231Sjoerg splx(x); 52517231Sjoerg return (-1); /* XXX Should be EBUSY, but nobody cares anyway. */ 52617231Sjoerg } 52729000Sfsmp disable_intr(); 5281390Ssos outb(TIMER_CNTR2, pitch); 5291390Ssos outb(TIMER_CNTR2, (pitch>>8)); 53029000Sfsmp enable_intr(); 5311390Ssos if (!beeping) { 53217231Sjoerg /* enable counter2 output to speaker */ 53317231Sjoerg outb(IO_PPI, inb(IO_PPI) | 3); 5341390Ssos beeping = period; 5352873Sbde timeout(sysbeepstop, (void *)NULL, period); 5361390Ssos } 53717231Sjoerg splx(x); 53817231Sjoerg return (0); 5391390Ssos} 5401390Ssos 5412913Sache/* 5422913Sache * RTC support routines 5432913Sache */ 5442913Sache 54514943Sbdeint 54614943Sbdertcin(reg) 54714943Sbde int reg; 54814943Sbde{ 54914943Sbde u_char val; 55014943Sbde 55114943Sbde outb(IO_RTC, reg); 55214943Sbde inb(0x84); 55314943Sbde val = inb(IO_RTC + 1); 55414943Sbde inb(0x84); 55514943Sbde return (val); 55614943Sbde} 55714943Sbde 55813445Sphkstatic __inline void 5595291Sbdewritertc(u_char reg, u_char val) 5602913Sache{ 56133309Sbde inb(0x84); 5625291Sbde outb(IO_RTC, reg); 56333309Sbde inb(0x84); 5645291Sbde outb(IO_RTC + 1, val); 56533309Sbde inb(0x84); /* XXX work around wrong order in rtcin() */ 5662913Sache} 5672913Sache 56813445Sphkstatic __inline int 5692913Sachereadrtc(int port) 5702913Sache{ 57113445Sphk return(bcd2bin(rtcin(port))); 5722913Sache} 5732913Sache 57415508Sbdestatic u_int 57515508Sbdecalibrate_clocks(void) 57615508Sbde{ 57715508Sbde u_int count, prev_count, tot_count; 57815508Sbde int sec, start_sec, timeout; 57915508Sbde 58023393Sbde if (bootverbose) 58123393Sbde printf("Calibrating clock(s) ... "); 58215508Sbde if (!(rtcin(RTC_STATUSD) & RTCSD_PWR)) 58315508Sbde goto fail; 58415508Sbde timeout = 100000000; 58515508Sbde 58615508Sbde /* Read the mc146818A seconds counter. */ 58715508Sbde for (;;) { 58815508Sbde if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) { 58915508Sbde sec = rtcin(RTC_SEC); 59015508Sbde break; 59115508Sbde } 59215508Sbde if (--timeout == 0) 59315508Sbde goto fail; 59415508Sbde } 59515508Sbde 59615508Sbde /* Wait for the mC146818A seconds counter to change. */ 59715508Sbde start_sec = sec; 59815508Sbde for (;;) { 59915508Sbde if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) { 60015508Sbde sec = rtcin(RTC_SEC); 60115508Sbde if (sec != start_sec) 60215508Sbde break; 60315508Sbde } 60415508Sbde if (--timeout == 0) 60515508Sbde goto fail; 60615508Sbde } 60715508Sbde 60815508Sbde /* Start keeping track of the i8254 counter. */ 60915508Sbde prev_count = getit(); 61015508Sbde if (prev_count == 0 || prev_count > timer0_max_count) 61115508Sbde goto fail; 61215508Sbde tot_count = 0; 61315508Sbde 61432054Sphk if (tsc_present) 61515508Sbde wrmsr(0x10, 0LL); /* XXX 0x10 is the MSR for the TSC */ 61615508Sbde 61715508Sbde /* 61815508Sbde * Wait for the mc146818A seconds counter to change. Read the i8254 61915508Sbde * counter for each iteration since this is convenient and only 62015508Sbde * costs a few usec of inaccuracy. The timing of the final reads 62115508Sbde * of the counters almost matches the timing of the initial reads, 62215508Sbde * so the main cause of inaccuracy is the varying latency from 62315508Sbde * inside getit() or rtcin(RTC_STATUSA) to the beginning of the 62415508Sbde * rtcin(RTC_SEC) that returns a changed seconds count. The 62515508Sbde * maximum inaccuracy from this cause is < 10 usec on 486's. 62615508Sbde */ 62715508Sbde start_sec = sec; 62815508Sbde for (;;) { 62915508Sbde if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) 63015508Sbde sec = rtcin(RTC_SEC); 63115508Sbde count = getit(); 63215508Sbde if (count == 0 || count > timer0_max_count) 63315508Sbde goto fail; 63415508Sbde if (count > prev_count) 63515508Sbde tot_count += prev_count - (count - timer0_max_count); 63615508Sbde else 63715508Sbde tot_count += prev_count - count; 63815508Sbde prev_count = count; 63915508Sbde if (sec != start_sec) 64015508Sbde break; 64115508Sbde if (--timeout == 0) 64215508Sbde goto fail; 64315508Sbde } 64415508Sbde 64515508Sbde /* 64615508Sbde * Read the cpu cycle counter. The timing considerations are 64715508Sbde * similar to those for the i8254 clock. 64815508Sbde */ 64933690Sphk if (tsc_present) 65033690Sphk tsc_freq = rdtsc(); 65133690Sphk 65233690Sphk if (bootverbose) { 65333690Sphk if (tsc_present) 65432005Sphk printf("TSC clock: %u Hz, ", tsc_freq); 65533929Sphk printf("i8254 clock: %u Hz\n", tot_count); 65615508Sbde } 65715508Sbde return (tot_count); 65815508Sbde 65915508Sbdefail: 66023393Sbde if (bootverbose) 66123393Sbde printf("failed, using default i8254 clock of %u Hz\n", 66223393Sbde timer_freq); 66315508Sbde return (timer_freq); 66415508Sbde} 66515508Sbde 66615508Sbdestatic void 66715508Sbdeset_timer_freq(u_int freq, int intr_freq) 66815508Sbde{ 66916874Sbde u_long ef; 67033309Sbde int new_timer0_max_count; 67115508Sbde 67215508Sbde ef = read_eflags(); 67329000Sfsmp disable_intr(); 67415508Sbde timer_freq = freq; 67533309Sbde new_timer0_max_count = hardclock_max_count = TIMER_DIV(intr_freq); 67633309Sbde if (new_timer0_max_count != timer0_max_count) { 67733309Sbde timer0_max_count = new_timer0_max_count; 67833309Sbde outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 67933309Sbde outb(TIMER_CNTR0, timer0_max_count & 0xff); 68033309Sbde outb(TIMER_CNTR0, timer0_max_count >> 8); 68133309Sbde } 68228921Sfsmp CLOCK_UNLOCK(); 68315508Sbde write_eflags(ef); 68415508Sbde} 68515508Sbde 6865291Sbde/* 68733690Sphk * Initialize 8254 timer 0 early so that it can be used in DELAY(). 6885291Sbde * XXX initialization of other timers is unintentionally left blank. 6895291Sbde */ 6901390Ssosvoid 6918876Srgrimesstartrtclock() 692798Swollman{ 69315508Sbde u_int delta, freq; 69415508Sbde 69532054Sphk if (cpu_feature & CPUID_TSC) 69632054Sphk tsc_present = 1; 69732054Sphk else 69832054Sphk tsc_present = 0; 69932054Sphk 70015508Sbde writertc(RTC_STATUSA, rtc_statusa); 70115508Sbde writertc(RTC_STATUSB, RTCSB_24HR); 70215508Sbde 70316874Sbde set_timer_freq(timer_freq, hz); 70415508Sbde freq = calibrate_clocks(); 70515508Sbde#ifdef CLK_CALIBRATION_LOOP 70615508Sbde if (bootverbose) { 70715508Sbde printf( 70815508Sbde "Press a key on the console to abort clock calibration\n"); 70918288Sbde while (cncheckc() == -1) 71015508Sbde calibrate_clocks(); 71115508Sbde } 71215508Sbde#endif 71315508Sbde 71415508Sbde /* 71515508Sbde * Use the calibrated i8254 frequency if it seems reasonable. 71615508Sbde * Otherwise use the default, and don't use the calibrated i586 71715508Sbde * frequency. 71815508Sbde */ 71915508Sbde delta = freq > timer_freq ? freq - timer_freq : timer_freq - freq; 72015508Sbde if (delta < timer_freq / 100) { 72115508Sbde#ifndef CLK_USE_I8254_CALIBRATION 72216300Spst if (bootverbose) 72319173Sbde printf( 72415508Sbde"CLK_USE_I8254_CALIBRATION not specified - using default frequency\n"); 72515508Sbde freq = timer_freq; 72615508Sbde#endif 72715508Sbde timer_freq = freq; 72815508Sbde } else { 72923393Sbde if (bootverbose) 73023393Sbde printf( 73123393Sbde "%d Hz differs from default of %d Hz by more than 1%%\n", 73223393Sbde freq, timer_freq); 73332005Sphk tsc_freq = 0; 73415508Sbde } 73515508Sbde 73615508Sbde set_timer_freq(timer_freq, hz); 73733690Sphk i8254_timecounter[0].frequency = timer_freq; 73833690Sphk init_timecounter(i8254_timecounter); 73915508Sbde 74032005Sphk#ifndef CLK_USE_TSC_CALIBRATION 74132005Sphk if (tsc_freq != 0) { 74216300Spst if (bootverbose) 74319173Sbde printf( 74432005Sphk"CLK_USE_TSC_CALIBRATION not specified - using old calibration method\n"); 74532005Sphk tsc_freq = 0; 74615508Sbde } 74715508Sbde#endif 74832054Sphk if (tsc_present && tsc_freq == 0) { 74915508Sbde /* 75015508Sbde * Calibration of the i586 clock relative to the mc146818A 75115508Sbde * clock failed. Do a less accurate calibration relative 75215508Sbde * to the i8254 clock. 75315508Sbde */ 75415508Sbde wrmsr(0x10, 0LL); /* XXX */ 75515508Sbde DELAY(1000000); 75633690Sphk tsc_freq = rdtsc(); 75732054Sphk#ifdef CLK_USE_TSC_CALIBRATION 75823393Sbde if (bootverbose) 75933690Sphk printf("TSC clock: %u Hz (Method B)\n", tsc_freq); 76016300Spst#endif 76115508Sbde } 76234617Sphk 76334617Sphk#if !defined(SMP) 76434617Sphk /* 76534617Sphk * We can not use the TSC in SMP mode, until we figure out a 76634617Sphk * cheap (impossible), reliable and precise (yeah right!) way 76734617Sphk * to synchronize the TSCs of all the CPUs. 76834617Sphk * Curse Intel for leaving the counter out of the I/O APIC. 76934617Sphk */ 77034617Sphk 77134617Sphk#if NAPM > 0 77234617Sphk /* 77334617Sphk * We can not use the TSC if we found an APM bios. Too many 77434617Sphk * of them lie about their ability&intention to fiddle the CPU 77534617Sphk * clock for us to rely on this. Precise timekeeping on an 77634617Sphk * APM'ed machine is at best a fools pursuit anyway, since 77734617Sphk * any and all of the time spent in various SMM code can't 77834617Sphk * be reliably accounted for. Reading the RTC is your only 77934617Sphk * source of reliable time info. The i8254 looses too of course 78034617Sphk * but we need to have some kind of time... 78134617Sphk */ 78234617Sphk if (apm_version != APMINI_CANTFIND) 78334617Sphk return; 78434617Sphk#endif /* NAPM > 0 */ 78534617Sphk 78633690Sphk if (tsc_present && tsc_freq != 0) { 78733690Sphk tsc_timecounter[0].frequency = tsc_freq; 78833690Sphk init_timecounter(tsc_timecounter); 78933690Sphk } 79034617Sphk 79134617Sphk#endif /* !defined(SMP) */ 7924Srgrimes} 7934Srgrimes 7942913Sache/* 7952913Sache * Initialize the time of day register, based on the time base which is, e.g. 7962913Sache * from a filesystem. 7972913Sache */ 7982913Sachevoid 7993185Ssosinittodr(time_t base) 8004Srgrimes{ 8012913Sache unsigned long sec, days; 8022913Sache int yd; 8032913Sache int year, month; 8042913Sache int y, m, s; 80533690Sphk struct timespec ts; 8064Srgrimes 80732850Sphk if (base) { 80832850Sphk s = splclock(); 80933690Sphk ts.tv_sec = base; 81033690Sphk ts.tv_nsec = 0; 81133690Sphk set_timecounter(&ts); 81232850Sphk splx(s); 81332850Sphk } 8141390Ssos 8152913Sache /* Look if we have a RTC present and the time is valid */ 8169202Srgrimes if (!(rtcin(RTC_STATUSD) & RTCSD_PWR)) 8172913Sache goto wrong_time; 8184Srgrimes 8192913Sache /* wait for time update to complete */ 8202913Sache /* If RTCSA_TUP is zero, we have at least 244us before next update */ 8212913Sache while (rtcin(RTC_STATUSA) & RTCSA_TUP); 8224Srgrimes 8232913Sache days = 0; 8243355Sache#ifdef USE_RTC_CENTURY 8252913Sache year = readrtc(RTC_YEAR) + readrtc(RTC_CENTURY) * 100; 8263355Sache#else 8273355Sache year = readrtc(RTC_YEAR) + 1900; 8282913Sache if (year < 1970) 8293355Sache year += 100; 8303355Sache#endif 8313355Sache if (year < 1970) 8322913Sache goto wrong_time; 8332913Sache month = readrtc(RTC_MONTH); 8342913Sache for (m = 1; m < month; m++) 8352913Sache days += daysinmonth[m-1]; 8362913Sache if ((month > 2) && LEAPYEAR(year)) 8372913Sache days ++; 8382913Sache days += readrtc(RTC_DAY) - 1; 8392913Sache yd = days; 8402913Sache for (y = 1970; y < year; y++) 8412913Sache days += DAYSPERYEAR + LEAPYEAR(y); 8422913Sache sec = ((( days * 24 + 8432913Sache readrtc(RTC_HRS)) * 60 + 8442913Sache readrtc(RTC_MIN)) * 60 + 8452913Sache readrtc(RTC_SEC)); 8462913Sache /* sec now contains the number of seconds, since Jan 1 1970, 8472913Sache in the local time zone */ 8481390Ssos 84915054Sache sec += tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0); 8504Srgrimes 85134961Sphk y = time_second - sec; 85233690Sphk if (y <= -2 || y >= 2) { 85333690Sphk /* badly off, adjust it */ 85433690Sphk s = splclock(); 85533690Sphk ts.tv_sec = sec; 85633690Sphk ts.tv_nsec = 0; 85733690Sphk set_timecounter(&ts); 85833690Sphk splx(s); 85933690Sphk } 8602913Sache return; 8612913Sache 8622913Sachewrong_time: 8632913Sache printf("Invalid time in real time clock.\n"); 8642913Sache printf("Check and reset the date immediately!\n"); 8654Srgrimes} 8664Srgrimes 8674Srgrimes/* 8682913Sache * Write system time back to RTC 8694Srgrimes */ 8704180Sbdevoid 8714180Sbderesettodr() 8724Srgrimes{ 8732913Sache unsigned long tm; 87411872Sphk int y, m, s; 8754Srgrimes 8763366Sache if (disable_rtc_set) 8773366Sache return; 8783366Sache 8792913Sache s = splclock(); 88034961Sphk tm = time_second; 8812913Sache splx(s); 8824Srgrimes 8835291Sbde /* Disable RTC updates and interrupts. */ 8842913Sache writertc(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR); 8854Srgrimes 8863366Sache /* Calculate local time to put in RTC */ 8871390Ssos 88815054Sache tm -= tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0); 8892913Sache 89013445Sphk writertc(RTC_SEC, bin2bcd(tm%60)); tm /= 60; /* Write back Seconds */ 89113445Sphk writertc(RTC_MIN, bin2bcd(tm%60)); tm /= 60; /* Write back Minutes */ 89213445Sphk writertc(RTC_HRS, bin2bcd(tm%24)); tm /= 24; /* Write back Hours */ 8932913Sache 8942913Sache /* We have now the days since 01-01-1970 in tm */ 8952913Sache writertc(RTC_WDAY, (tm+4)%7); /* Write back Weekday */ 89613350Sache for (y = 1970, m = DAYSPERYEAR + LEAPYEAR(y); 89713350Sache tm >= m; 89813350Sache y++, m = DAYSPERYEAR + LEAPYEAR(y)) 89913350Sache tm -= m; 9002913Sache 9012913Sache /* Now we have the years in y and the day-of-the-year in tm */ 90213453Sache writertc(RTC_YEAR, bin2bcd(y%100)); /* Write back Year */ 90313350Sache#ifdef USE_RTC_CENTURY 90413445Sphk writertc(RTC_CENTURY, bin2bcd(y/100)); /* ... and Century */ 9053355Sache#endif 90613402Sbde for (m = 0; ; m++) { 90713402Sbde int ml; 9082913Sache 90913402Sbde ml = daysinmonth[m]; 91013402Sbde if (m == 1 && LEAPYEAR(y)) 91113402Sbde ml++; 91213402Sbde if (tm < ml) 91313402Sbde break; 91413402Sbde tm -= ml; 91513402Sbde } 91613402Sbde 91713445Sphk writertc(RTC_MONTH, bin2bcd(m + 1)); /* Write back Month */ 91813445Sphk writertc(RTC_DAY, bin2bcd(tm + 1)); /* Write back Month Day */ 9192913Sache 9205291Sbde /* Reenable RTC updates and interrupts. */ 92115345Snate writertc(RTC_STATUSB, rtc_statusb); 9224Srgrimes} 9234Srgrimes 92427560Sfsmp 9254Srgrimes/* 9265291Sbde * Start both clocks running. 9274Srgrimes */ 9285291Sbdevoid 9295291Sbdecpu_initclocks() 9304Srgrimes{ 9315291Sbde int diag; 93226949Sfsmp#ifdef APIC_IO 93334571Stegge int apic_8254_trial; 93425164Speter#endif /* APIC_IO */ 9354Srgrimes 93615345Snate if (statclock_disable) { 93715345Snate /* 93815345Snate * The stat interrupt mask is different without the 93915345Snate * statistics clock. Also, don't set the interrupt 94015345Snate * flag which would normally cause the RTC to generate 94115345Snate * interrupts. 94215345Snate */ 94315345Snate stat_imask = HWI_MASK | SWI_MASK; 94415345Snate rtc_statusb = RTCSB_24HR; 94515345Snate } else { 94615345Snate /* Setting stathz to nonzero early helps avoid races. */ 94715345Snate stathz = RTC_NOPROFRATE; 94815345Snate profhz = RTC_PROFRATE; 94915345Snate } 9504Srgrimes 9515291Sbde /* Finish initializing 8253 timer 0. */ 95226949Sfsmp#ifdef APIC_IO 95327563Sfsmp 95434571Stegge apic_8254_intr = isa_apic_pin(0); 95534571Stegge apic_8254_trial = 0; 95634571Stegge if (apic_8254_intr >= 0 ) { 95734571Stegge if (apic_int_type(0, 0) == 3) 95834571Stegge apic_8254_trial = 1; 95934571Stegge } else { 96034571Stegge /* look for ExtInt on pin 0 */ 96134571Stegge if (apic_int_type(0, 0) == 3) { 96234571Stegge apic_8254_intr = 0; 96334571Stegge setup_8254_mixed_mode(); 96434571Stegge } else 96534571Stegge panic("APIC_IO: Cannot route 8254 interrupt to CPU"); 96627563Sfsmp } 96727563Sfsmp 96834571Stegge register_intr(/* irq */ apic_8254_intr, /* XXX id */ 0, /* flags */ 0, 96925164Speter /* XXX */ (inthand2_t *)clkintr, &clk_imask, 97025164Speter /* unit */ 0); 97134571Stegge INTREN(1 << apic_8254_intr); 97234571Stegge 97327696Sfsmp#else /* APIC_IO */ 97427563Sfsmp 9757090Sbde register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, 9767090Sbde /* XXX */ (inthand2_t *)clkintr, &clk_imask, 9777090Sbde /* unit */ 0); 9784Srgrimes INTREN(IRQ0); 97927696Sfsmp 98025164Speter#endif /* APIC_IO */ 98126949Sfsmp 9825291Sbde /* Initialize RTC. */ 9835291Sbde writertc(RTC_STATUSA, rtc_statusa); 9845291Sbde writertc(RTC_STATUSB, RTCSB_24HR); 98515345Snate 98615345Snate /* Don't bother enabling the statistics clock. */ 98715345Snate if (statclock_disable) 98815345Snate return; 9895291Sbde diag = rtcin(RTC_DIAG); 9905291Sbde if (diag != 0) 9915291Sbde printf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS); 99227520Sfsmp 99326949Sfsmp#ifdef APIC_IO 99427520Sfsmp if (isa_apic_pin(8) != 8) 99527520Sfsmp panic("APIC RTC != 8"); 99627563Sfsmp#endif /* APIC_IO */ 99728487Sfsmp 9987090Sbde register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, 9997090Sbde /* XXX */ (inthand2_t *)rtcintr, &stat_imask, 10007090Sbde /* unit */ 0); 100128487Sfsmp 100227616Sfsmp#ifdef APIC_IO 100327616Sfsmp INTREN(APIC_IRQ8); 100427616Sfsmp#else 10052074Swollman INTREN(IRQ8); 100627616Sfsmp#endif /* APIC_IO */ 100727520Sfsmp 100815345Snate writertc(RTC_STATUSB, rtc_statusb); 100934571Stegge 101034571Stegge#ifdef APIC_IO 101134571Stegge if (apic_8254_trial) { 101234571Stegge 101334571Stegge printf("APIC_IO: Testing 8254 interrupt delivery\n"); 101434571Stegge while (read_intr_count(8) < 6) 101535035Stegge ; /* nothing */ 101634571Stegge if (read_intr_count(apic_8254_intr) < 3) { 101734571Stegge /* 101834571Stegge * The MP table is broken. 101934571Stegge * The 8254 was not connected to the specified pin 102034571Stegge * on the IO APIC. 102134571Stegge * Workaround: Limited variant of mixed mode. 102234571Stegge */ 102334571Stegge INTRDIS(1 << apic_8254_intr); 102434571Stegge unregister_intr(apic_8254_intr, 102534571Stegge /* XXX */ (inthand2_t *) clkintr); 102634571Stegge printf("APIC_IO: Broken MP table detected: " 102734571Stegge "8254 is not connected to IO APIC int pin %d\n", 102834571Stegge apic_8254_intr); 102934571Stegge 103034571Stegge apic_8254_intr = 0; 103134571Stegge setup_8254_mixed_mode(); 103234571Stegge register_intr(/* irq */ apic_8254_intr, /* XXX id */ 0, /* flags */ 0, 103334571Stegge /* XXX */ (inthand2_t *)clkintr, &clk_imask, 103434571Stegge /* unit */ 0); 103534571Stegge INTREN(1 << apic_8254_intr); 103634571Stegge } 103734571Stegge 103834571Stegge } 103934571Stegge if (apic_8254_intr) 104034571Stegge printf("APIC_IO: routing 8254 via pin %d\n",apic_8254_intr); 104134571Stegge else 104234571Stegge printf("APIC_IO: routing 8254 via 8259 on pin 0\n"); 104334571Stegge#endif 104434571Stegge 10454Srgrimes} 10464Srgrimes 104734571Stegge#ifdef APIC_IO 104834571Steggestatic u_long 104934571Steggeread_intr_count(int vec) 105034571Stegge{ 105134571Stegge u_long *up; 105234571Stegge up = intr_countp[vec]; 105334571Stegge if (up) 105434571Stegge return *up; 105534571Stegge return 0UL; 105634571Stegge} 105734571Stegge 105834571Steggestatic void 105934571Steggesetup_8254_mixed_mode() 106034571Stegge{ 106134571Stegge /* 106234571Stegge * Allow 8254 timer to INTerrupt 8259: 106334571Stegge * re-initialize master 8259: 106434571Stegge * reset; prog 4 bytes, single ICU, edge triggered 106534571Stegge */ 106634571Stegge outb(IO_ICU1, 0x13); 106734571Stegge outb(IO_ICU1 + 1, NRSVIDT); /* start vector (unused) */ 106834571Stegge outb(IO_ICU1 + 1, 0x00); /* ignore slave */ 106934571Stegge outb(IO_ICU1 + 1, 0x03); /* auto EOI, 8086 */ 107034571Stegge outb(IO_ICU1 + 1, 0xfe); /* unmask INT0 */ 107134571Stegge 107234571Stegge /* program IO APIC for type 3 INT on INT0 */ 107334571Stegge if (ext_int_setup(0, 0) < 0) 107434571Stegge panic("8254 redirect via APIC pin0 impossible!"); 107534571Stegge} 107634571Stegge#endif 107734571Stegge 10784Srgrimesvoid 10791549Srgrimessetstatclockrate(int newhz) 10801549Srgrimes{ 10815291Sbde if (newhz == RTC_PROFRATE) 10822074Swollman rtc_statusa = RTCSA_DIVIDER | RTCSA_PROF; 10835291Sbde else 10842074Swollman rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; 10855291Sbde writertc(RTC_STATUSA, rtc_statusa); 10861549Srgrimes} 108715508Sbde 108815508Sbdestatic int 108915508Sbdesysctl_machdep_i8254_freq SYSCTL_HANDLER_ARGS 109015508Sbde{ 109115508Sbde int error; 109215508Sbde u_int freq; 109315508Sbde 109415508Sbde /* 109515508Sbde * Use `i8254' instead of `timer' in external names because `timer' 109615508Sbde * is is too generic. Should use it everywhere. 109715508Sbde */ 109815508Sbde freq = timer_freq; 109915508Sbde error = sysctl_handle_opaque(oidp, &freq, sizeof freq, req); 110017353Sbde if (error == 0 && req->newptr != NULL) { 110133690Sphk if (timer0_state != RELEASED) 110215508Sbde return (EBUSY); /* too much trouble to handle */ 110315508Sbde set_timer_freq(freq, hz); 110433690Sphk i8254_timecounter[0].frequency = freq; 110515508Sbde } 110615508Sbde return (error); 110715508Sbde} 110815508Sbde 110915508SbdeSYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW, 111015508Sbde 0, sizeof(u_int), sysctl_machdep_i8254_freq, "I", ""); 111115508Sbde 111215508Sbdestatic int 111332054Sphksysctl_machdep_tsc_freq SYSCTL_HANDLER_ARGS 111415508Sbde{ 111515508Sbde int error; 111615508Sbde u_int freq; 111715508Sbde 111832054Sphk if (!tsc_present) 111915508Sbde return (EOPNOTSUPP); 112032005Sphk freq = tsc_freq; 112115508Sbde error = sysctl_handle_opaque(oidp, &freq, sizeof freq, req); 112233690Sphk if (error == 0 && req->newptr != NULL) { 112333690Sphk tsc_freq = freq; 112433690Sphk tsc_timecounter[0].frequency = tsc_freq; 112533690Sphk } 112615508Sbde return (error); 112715508Sbde} 112815508Sbde 112932054SphkSYSCTL_PROC(_machdep, OID_AUTO, tsc_freq, CTLTYPE_INT | CTLFLAG_RW, 113032054Sphk 0, sizeof(u_int), sysctl_machdep_tsc_freq, "I", ""); 113133690Sphk 113236441Sphkstatic unsigned 113333690Sphki8254_get_timecount(void) 113433690Sphk{ 113536198Sphk u_int count; 113633690Sphk u_long ef; 113733690Sphk u_int high, low; 113833690Sphk 113933690Sphk ef = read_eflags(); 114033690Sphk disable_intr(); 114133690Sphk 114233690Sphk /* Select timer0 and latch counter value. */ 114333690Sphk outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 114433690Sphk 114533690Sphk low = inb(TIMER_CNTR0); 114633690Sphk high = inb(TIMER_CNTR0); 114733690Sphk 114833690Sphk count = hardclock_max_count - ((high << 8) | low); 114933690Sphk if (count < i8254_lastcount) { 115033690Sphk i8254_ticked = 1; 115133690Sphk i8254_offset += hardclock_max_count; 115233690Sphk } 115333690Sphk 115433690Sphk i8254_lastcount = count; 115533690Sphk count += i8254_offset; 115633727Sjkh CLOCK_UNLOCK(); 115733690Sphk write_eflags(ef); 115833690Sphk return (count); 115933690Sphk} 116033690Sphk 116136441Sphkstatic unsigned 116233690Sphktsc_get_timecount(void) 116333690Sphk{ 116436198Sphk return (rdtsc()); 116533690Sphk} 1166