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