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