pcrtc.c revision 72792
119304Speter/*- 219304Speter * Copyright (c) 1990 The Regents of the University of California. 319304Speter * All rights reserved. 419304Speter * 519304Speter * This code is derived from software contributed to Berkeley by 619304Speter * William Jolitz and Don Ahn. 719304Speter * 819304Speter * Redistribution and use in source and binary forms, with or without 919304Speter * modification, are permitted provided that the following conditions 1019304Speter * are met: 1119304Speter * 1. Redistributions of source code must retain the above copyright 1219304Speter * notice, this list of conditions and the following disclaimer. 13254225Speter * 2. Redistributions in binary form must reproduce the above copyright 1419304Speter * notice, this list of conditions and the following disclaimer in the 1519304Speter * documentation and/or other materials provided with the distribution. 1619304Speter * 3. All advertising materials mentioning features or use of this software 1719304Speter * must display the following acknowledgement: 1819304Speter * This product includes software developed by the University of 1919304Speter * California, Berkeley and its contributors. 2019304Speter * 4. Neither the name of the University nor the names of its contributors 2119304Speter * may be used to endorse or promote products derived from this software 2219304Speter * without specific prior written permission. 2319304Speter * 2419304Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2519304Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2619304Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2719304Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2819304Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2919304Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3019304Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3119304Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3219304Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3319304Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3419304Speter * SUCH DAMAGE. 35254225Speter * 3619304Speter * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 3719304Speter * $FreeBSD: head/sys/pc98/cbus/pcrtc.c 72792 2001-02-21 10:22:22Z kato $ 38254225Speter */ 39254225Speter 40254225Speter/* 41254225Speter * Routines to handle clock hardware. 42254225Speter */ 43254225Speter 4419304Speter/* 4519304Speter * inittodr, settodr and support routines written 4619304Speter * by Christoph Robitschko <chmr@edvz.tu-graz.ac.at> 4719304Speter * 4819304Speter * reintroduced and updated by Chris Stenton <chris@gnome.co.uk> 8/10/94 4919304Speter */ 5019304Speter 5119304Speter/* 5219304Speter * modified for PC98 by Kakefuda 5319304Speter */ 5419304Speter 5519304Speter#include "opt_clock.h" 5619304Speter#include "opt_apm.h" 5719304Speter#include "opt_mca.h" 5819304Speter 5919304Speter#include <sys/param.h> 6019304Speter#include <sys/systm.h> 6119304Speter#include <sys/bus.h> 6219304Speter#include <sys/ipl.h> 63254225Speter#include <sys/mutex.h> 6419304Speter#include <sys/proc.h> 6519304Speter#include <sys/time.h> 6619304Speter#include <sys/timetc.h> 6719304Speter#include <sys/kernel.h> 6819304Speter#ifndef SMP 6919304Speter#include <sys/lock.h> 7019304Speter#endif 7119304Speter#include <sys/sysctl.h> 7219304Speter#include <sys/cons.h> 7319304Speter 7419304Speter#include <machine/clock.h> 7519304Speter#ifdef CLK_CALIBRATION_LOOP 7619304Speter#endif 7719304Speter#include <machine/cputypes.h> 7819304Speter#include <machine/frame.h> 79254225Speter#include <machine/limits.h> 8019304Speter#include <machine/md_var.h> 8119304Speter#include <machine/psl.h> 82254225Speter#ifdef APIC_IO 83254225Speter#include <machine/segments.h> 84254225Speter#endif 85254225Speter#if defined(SMP) || defined(APIC_IO) 86254225Speter#include <machine/smp.h> 87254225Speter#endif /* SMP || APIC_IO */ 8819304Speter#include <machine/specialreg.h> 8919304Speter 9019304Speter#include <i386/isa/icu.h> 9119304Speter#ifdef PC98 9219304Speter#include <pc98/pc98/pc98.h> 93254225Speter#include <pc98/pc98/pc98_machdep.h> 94254225Speter#include <i386/isa/isa_device.h> 95254225Speter#else 9619304Speter#include <i386/isa/isa.h> 9719304Speter#include <isa/rtc.h> 9819304Speter#endif 9919304Speter#include <isa/isavar.h> 10019304Speter#include <i386/isa/timerreg.h> 10119304Speter 10219304Speter#include <i386/isa/intr_machdep.h> 10319304Speter 10419304Speter#ifdef DEV_MCA 10519304Speter#include <i386/isa/mca_machdep.h> 10619304Speter#endif 10719304Speter 10819304Speter#ifdef APIC_IO 10919304Speter#include <i386/isa/intr_machdep.h> 11019304Speter/* The interrupt triggered by the 8254 (timer) chip */ 11119304Speterint apic_8254_intr; 11219304Speterstatic u_long read_intr_count __P((int vec)); 11319304Speterstatic void setup_8254_mixed_mode __P((void)); 11419304Speter#endif 11519304Speter 11619304Speter/* 11719304Speter * 32-bit time_t's can't reach leap years before 1904 or after 2036, so we 11819304Speter * can use a simple formula for leap years. 119254225Speter */ 120254225Speter#define LEAPYEAR(y) ((u_int)(y) % 4 == 0) 12119304Speter#define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31) 12219304Speter 12319304Speter#define TIMER_DIV(x) ((timer_freq + (x) / 2) / (x)) 12419304Speter 125254225Speter/* 126254225Speter * Time in timer cycles that it takes for microtime() to disable interrupts 12719304Speter * and latch the count. microtime() currently uses "cli; outb ..." so it 12819304Speter * normally takes less than 2 timer cycles. Add a few for cache misses. 12919304Speter * Add a few more to allow for latency in bogus calls to microtime() with 13019304Speter * interrupts already disabled. 13119304Speter */ 13219304Speter#define TIMER0_LATCH_COUNT 20 13319304Speter 13419304Speter/* 13519304Speter * Maximum frequency that we are willing to allow for timer0. Must be 13619304Speter * low enough to guarantee that the timer interrupt handler returns 13719304Speter * before the next timer interrupt. 13819304Speter */ 13919304Speter#define TIMER0_MAX_FREQ 20000 14019304Speter 14119304Speterint adjkerntz; /* local offset from GMT in seconds */ 14219304Speterint clkintr_pending; 14319304Speterint disable_rtc_set; /* disable resettodr() if != 0 */ 14419304Speterint statclock_disable; 14519304Speter#ifndef TIMER_FREQ 14619304Speter#ifdef PC98 14719304Speter#define TIMER_FREQ 2457600; 14819304Speter#else /* IBM-PC */ 14919304Speter#define TIMER_FREQ 1193182; 15019304Speter#endif /* PC98 */ 15119304Speter#endif 15219304Speteru_int timer_freq = TIMER_FREQ; 15319304Speterint timer0_max_count; 15419304Speteru_int tsc_freq; 155254225Speterint tsc_is_broken; 156254225Speteru_int tsc_present; 15719304Speterint wall_cmos_clock; /* wall CMOS clock assumed if != 0 */ 15819304Speterstruct mtx clock_lock; 15919304Speter 16019304Speterstatic int beeping = 0; 161254225Speterstatic const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31}; 16219304Speterstatic u_int hardclock_max_count; 16319304Speterstatic u_int32_t i8254_lastcount; 16419304Speterstatic u_int32_t i8254_offset; 16519304Speterstatic int i8254_ticked; 166254225Speter/* 16719304Speter * XXX new_function and timer_func should not handle clockframes, but 16819304Speter * timer_func currently needs to hold hardclock to handle the 16919304Speter * timer0_state == 0 case. We should use inthand_add()/inthand_remove() 17019304Speter * to switch between clkintr() and a slightly different timerintr(). 17119304Speter */ 172254225Speterstatic void (*new_function) __P((struct clockframe *frame)); 173254225Speterstatic u_int new_rate; 174254225Speter#ifndef PC98 175254225Speterstatic u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; 176254225Speterstatic u_char rtc_statusb = RTCSB_24HR | RTCSB_PINTR; 17719304Speter#endif 17819304Speterstatic u_int timer0_prescaler_count; 179254225Speter 180254225Speter/* Values for timerX_state: */ 181254225Speter#define RELEASED 0 182254225Speter#define RELEASE_PENDING 1 183254225Speter#define ACQUIRED 2 184254225Speter#define ACQUIRE_PENDING 3 185254225Speter 186254225Speterstatic u_char timer0_state; 18719304Speter#ifdef PC98 188254225Speterstatic u_char timer1_state; 189254225Speter#endif 190254225Speterstatic u_char timer2_state; 191254225Speterstatic void (*timer_func) __P((struct clockframe *frame)) = hardclock; 192254225Speter#ifdef PC98 19319304Speterstatic void rtc_serialcombit __P((int)); 194254225Speterstatic void rtc_serialcom __P((int)); 19519304Speterstatic int rtc_inb __P((void)); 19619304Speterstatic void rtc_outb __P((int)); 19719304Speter#endif 19819304Speter 19919304Speterstatic unsigned i8254_get_timecount __P((struct timecounter *tc)); 200254225Speterstatic unsigned tsc_get_timecount __P((struct timecounter *tc)); 20119304Speterstatic void set_timer_freq(u_int freq, int intr_freq); 20219304Speter 20319304Speterstatic struct timecounter tsc_timecounter = { 20419304Speter tsc_get_timecount, /* get_timecount */ 20519304Speter 0, /* no poll_pps */ 20619304Speter ~0u, /* counter_mask */ 20719304Speter 0, /* frequency */ 20819304Speter "TSC" /* name */ 20919304Speter}; 21019304Speter 21119304SpeterSYSCTL_OPAQUE(_debug, OID_AUTO, tsc_timecounter, CTLFLAG_RD, 21219304Speter &tsc_timecounter, sizeof(tsc_timecounter), "S,timecounter", ""); 213254225Speter 214254225Speterstatic struct timecounter i8254_timecounter = { 215254225Speter i8254_get_timecount, /* get_timecount */ 21619304Speter 0, /* no poll_pps */ 21719304Speter ~0u, /* counter_mask */ 21819304Speter 0, /* frequency */ 21919304Speter "i8254" /* name */ 22019304Speter}; 22119304Speter 22219304SpeterSYSCTL_OPAQUE(_debug, OID_AUTO, i8254_timecounter, CTLFLAG_RD, 22319304Speter &i8254_timecounter, sizeof(i8254_timecounter), "S,timecounter", ""); 22419304Speter 22519304Speterstatic void 22619304Speterclkintr(struct clockframe frame) 22719304Speter{ 22819304Speter 22919304Speter if (timecounter->tc_get_timecount == i8254_get_timecount) { 23019304Speter mtx_lock_spin(&clock_lock); 23119304Speter if (i8254_ticked) 23219304Speter i8254_ticked = 0; 23319304Speter else { 23419304Speter i8254_offset += timer0_max_count; 23519304Speter i8254_lastcount = 0; 23619304Speter } 23719304Speter clkintr_pending = 0; 23819304Speter mtx_unlock_spin(&clock_lock); 23919304Speter } 24019304Speter timer_func(&frame); 24119304Speter switch (timer0_state) { 24219304Speter 24319304Speter case RELEASED: 24419304Speter break; 24519304Speter 24619304Speter case ACQUIRED: 24719304Speter if ((timer0_prescaler_count += timer0_max_count) 24819304Speter >= hardclock_max_count) { 24919304Speter timer0_prescaler_count -= hardclock_max_count; 25019304Speter hardclock(&frame); 25119304Speter } 25219304Speter break; 25319304Speter 25419304Speter case ACQUIRE_PENDING: 25519304Speter mtx_lock_spin(&clock_lock); 25619304Speter i8254_offset = i8254_get_timecount(NULL); 25719304Speter i8254_lastcount = 0; 25819304Speter timer0_max_count = TIMER_DIV(new_rate); 25919304Speter outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 26019304Speter outb(TIMER_CNTR0, timer0_max_count & 0xff); 26119304Speter outb(TIMER_CNTR0, timer0_max_count >> 8); 26219304Speter mtx_unlock_spin(&clock_lock); 26319304Speter timer_func = new_function; 26419304Speter timer0_state = ACQUIRED; 26519304Speter break; 26619304Speter 26719304Speter case RELEASE_PENDING: 268254225Speter if ((timer0_prescaler_count += timer0_max_count) 26919304Speter >= hardclock_max_count) { 27019304Speter mtx_lock_spin(&clock_lock); 271254225Speter i8254_offset = i8254_get_timecount(NULL); 272254225Speter i8254_lastcount = 0; 273254225Speter timer0_max_count = hardclock_max_count; 274254225Speter outb(TIMER_MODE, 275254225Speter TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 276254225Speter outb(TIMER_CNTR0, timer0_max_count & 0xff); 27719304Speter outb(TIMER_CNTR0, timer0_max_count >> 8); 27819304Speter mtx_unlock_spin(&clock_lock); 27919304Speter timer0_prescaler_count = 0; 280254225Speter timer_func = hardclock; 281254225Speter timer0_state = RELEASED; 28219304Speter hardclock(&frame); 28319304Speter } 28419304Speter break; 28519304Speter } 28619304Speter#ifdef DEV_MCA 28719304Speter /* Reset clock interrupt by asserting bit 7 of port 0x61 */ 28819304Speter if (MCA_system) 28919304Speter outb(0x61, inb(0x61) | 0x80); 29019304Speter#endif 29119304Speter} 29219304Speter 293254225Speter/* 294254225Speter * The acquire and release functions must be called at ipl >= splclock(). 29519304Speter */ 29619304Speterint 29719304Speteracquire_timer0(int rate, void (*function) __P((struct clockframe *frame))) 298254225Speter{ 299254225Speter static int old_rate; 30019304Speter 30119304Speter if (rate <= 0 || rate > TIMER0_MAX_FREQ) 30219304Speter return (-1); 30319304Speter switch (timer0_state) { 30419304Speter 30519304Speter case RELEASED: 30619304Speter timer0_state = ACQUIRE_PENDING; 30719304Speter break; 30819304Speter 30919304Speter case RELEASE_PENDING: 31019304Speter if (rate != old_rate) 31119304Speter return (-1); 31219304Speter /* 31319304Speter * The timer has been released recently, but is being 31419304Speter * re-acquired before the release completed. In this 31519304Speter * case, we simply reclaim it as if it had not been 31619304Speter * released at all. 31719304Speter */ 31819304Speter timer0_state = ACQUIRED; 31919304Speter break; 32019304Speter 32119304Speter default: 32219304Speter return (-1); /* busy */ 32319304Speter } 32419304Speter new_function = function; 32519304Speter old_rate = new_rate = rate; 32619304Speter return (0); 32719304Speter} 32819304Speter 32919304Speter#ifdef PC98 33019304Speterint 33119304Speteracquire_timer1(int mode) 33219304Speter{ 33319304Speter 33419304Speter if (timer1_state != RELEASED) 33519304Speter return (-1); 33619304Speter timer1_state = ACQUIRED; 33719304Speter 33819304Speter /* 33919304Speter * This access to the timer registers is as atomic as possible 34019304Speter * because it is a single instruction. We could do better if we 34119304Speter * knew the rate. Use of splclock() limits glitches to 10-100us, 34219304Speter * and this is probably good enough for timer2, so we aren't as 34319304Speter * careful with it as with timer0. 34419304Speter */ 34519304Speter outb(TIMER_MODE, TIMER_SEL1 | (mode & 0x3f)); 346254225Speter 34719304Speter return (0); 34819304Speter} 349254225Speter#endif 350254225Speter 351254225Speterint 352254225Speteracquire_timer2(int mode) 353254225Speter{ 35419304Speter 35519304Speter if (timer2_state != RELEASED) 35619304Speter return (-1); 357254225Speter timer2_state = ACQUIRED; 358254225Speter 35919304Speter /* 36019304Speter * This access to the timer registers is as atomic as possible 36119304Speter * because it is a single instruction. We could do better if we 36219304Speter * knew the rate. Use of splclock() limits glitches to 10-100us, 36319304Speter * and this is probably good enough for timer2, so we aren't as 36419304Speter * careful with it as with timer0. 36519304Speter */ 36619304Speter outb(TIMER_MODE, TIMER_SEL2 | (mode & 0x3f)); 36719304Speter 36819304Speter return (0); 36919304Speter} 37019304Speter 371254225Speterint 372254225Speterrelease_timer0() 37319304Speter{ 37419304Speter switch (timer0_state) { 37519304Speter 376254225Speter case ACQUIRED: 377254225Speter timer0_state = RELEASE_PENDING; 37819304Speter break; 37919304Speter 38019304Speter case ACQUIRE_PENDING: 38119304Speter /* Nothing happened yet, release quickly. */ 38219304Speter timer0_state = RELEASED; 38319304Speter break; 38419304Speter 38519304Speter default: 38619304Speter return (-1); 38719304Speter } 38819304Speter return (0); 38919304Speter} 39019304Speter 39119304Speter#ifdef PC98 39219304Speterint 39319304Speterrelease_timer1() 39419304Speter{ 39519304Speter 39619304Speter if (timer1_state != ACQUIRED) 39719304Speter return (-1); 39819304Speter timer1_state = RELEASED; 39919304Speter outb(TIMER_MODE, TIMER_SEL1 | TIMER_SQWAVE | TIMER_16BIT); 40019304Speter return (0); 40119304Speter} 40219304Speter#endif 40319304Speter 40419304Speterint 40519304Speterrelease_timer2() 40619304Speter{ 40719304Speter 40819304Speter if (timer2_state != ACQUIRED) 40919304Speter return (-1); 41019304Speter timer2_state = RELEASED; 41119304Speter outb(TIMER_MODE, TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT); 41219304Speter return (0); 41319304Speter} 41419304Speter 415254225Speter#ifndef PC98 41619304Speter/* 41719304Speter * This routine receives statistical clock interrupts from the RTC. 418254225Speter * As explained above, these occur at 128 interrupts per second. 419254225Speter * When profiling, we receive interrupts at a rate of 1024 Hz. 420254225Speter * 421254225Speter * This does not actually add as much overhead as it sounds, because 422254225Speter * when the statistical clock is active, the hardclock driver no longer 42319304Speter * needs to keep (inaccurate) statistics on its own. This decouples 42419304Speter * statistics gathering from scheduling interrupts. 42519304Speter * 426254225Speter * The RTC chip requires that we read status register C (RTC_INTR) 427254225Speter * to acknowledge an interrupt, before it will generate the next one. 42819304Speter * Under high interrupt load, rtcintr() can be indefinitely delayed and 42919304Speter * the clock can tick immediately after the read from RTC_INTR. In this 43019304Speter * case, the mc146818A interrupt signal will not drop for long enough 43119304Speter * to register with the 8259 PIC. If an interrupt is missed, the stat 43219304Speter * clock will halt, considerably degrading system performance. This is 43319304Speter * why we use 'while' rather than a more straightforward 'if' below. 43419304Speter * Stat clock ticks can still be lost, causing minor loss of accuracy 43519304Speter * in the statistics, but the stat clock will no longer stop. 43619304Speter */ 43719304Speterstatic void 43819304Speterrtcintr(struct clockframe frame) 43919304Speter{ 44019304Speter while (rtcin(RTC_INTR) & RTCIR_PERIOD) 44119304Speter statclock(&frame); 442254225Speter} 443254225Speter 44419304Speter#include "opt_ddb.h" 44519304Speter#ifdef DDB 44619304Speter#include <ddb/ddb.h> 447254225Speter 448254225SpeterDB_SHOW_COMMAND(rtc, rtc) 44919304Speter{ 45019304Speter printf("%02x/%02x/%02x %02x:%02x:%02x, A = %02x, B = %02x, C = %02x\n", 45119304Speter rtcin(RTC_YEAR), rtcin(RTC_MONTH), rtcin(RTC_DAY), 45219304Speter rtcin(RTC_HRS), rtcin(RTC_MIN), rtcin(RTC_SEC), 45319304Speter rtcin(RTC_STATUSA), rtcin(RTC_STATUSB), rtcin(RTC_INTR)); 45419304Speter} 45519304Speter#endif /* DDB */ 45619304Speter#endif /* for PC98 */ 45719304Speter 45819304Speterstatic int 45919304Spetergetit(void) 46019304Speter{ 46119304Speter int high, low; 46219304Speter 46319304Speter mtx_lock_spin(&clock_lock); 46419304Speter 46519304Speter /* Select timer0 and latch counter value. */ 46619304Speter outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 46719304Speter 46819304Speter low = inb(TIMER_CNTR0); 46919304Speter high = inb(TIMER_CNTR0); 47019304Speter 47119304Speter mtx_unlock_spin(&clock_lock); 47219304Speter return ((high << 8) | low); 47319304Speter} 47419304Speter 47519304Speter/* 47619304Speter * Wait "n" microseconds. 47719304Speter * Relies on timer 1 counting down from (timer_freq / hz) 47819304Speter * Note: timer had better have been programmed before this is first used! 47919304Speter */ 480254225Spetervoid 481254225SpeterDELAY(int n) 482254225Speter{ 48319304Speter int delta, prev_tick, tick, ticks_left; 48419304Speter 48519304Speter#ifdef DELAYDEBUG 48619304Speter int getit_calls = 1; 48719304Speter int n1; 48819304Speter static int state = 0; 48919304Speter 49019304Speter if (state == 0) { 49119304Speter state = 1; 49219304Speter for (n1 = 1; n1 <= 10000000; n1 *= 10) 49319304Speter DELAY(n1); 49419304Speter state = 2; 49519304Speter } 49619304Speter if (state == 1) 49719304Speter printf("DELAY(%d)...", n); 49819304Speter#endif 49919304Speter /* 50019304Speter * Guard against the timer being uninitialized if we are called 501254225Speter * early for console i/o. 502254225Speter */ 50319304Speter if (timer0_max_count == 0) 50419304Speter set_timer_freq(timer_freq, hz); 50519304Speter 50619304Speter /* 50719304Speter * Read the counter first, so that the rest of the setup overhead is 50819304Speter * counted. Guess the initial overhead is 20 usec (on most systems it 50919304Speter * takes about 1.5 usec for each of the i/o's in getit(). The loop 51019304Speter * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The 51119304Speter * multiplications and divisions to scale the count take a while). 51219304Speter */ 51319304Speter prev_tick = getit(); 51419304Speter n -= 0; /* XXX actually guess no initial overhead */ 515254225Speter /* 516254225Speter * Calculate (n * (timer_freq / 1e6)) without using floating point 517254225Speter * and without any avoidable overflows. 51819304Speter */ 51919304Speter if (n <= 0) 52019304Speter ticks_left = 0; 52119304Speter else if (n < 256) 522254225Speter /* 523254225Speter * Use fixed point to avoid a slow division by 1000000. 52419304Speter * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest. 52519304Speter * 2^15 is the first power of 2 that gives exact results 52619304Speter * for n between 0 and 256. 52719304Speter */ 52819304Speter ticks_left = ((u_int)n * 39099 + (1 << 15) - 1) >> 15; 52919304Speter else 53019304Speter /* 53119304Speter * Don't bother using fixed point, although gcc-2.7.2 53219304Speter * generates particularly poor code for the long long 53319304Speter * division, since even the slow way will complete long 53419304Speter * before the delay is up (unless we're interrupted). 53519304Speter */ 53619304Speter ticks_left = ((u_int)n * (long long)timer_freq + 999999) 53719304Speter / 1000000; 538254225Speter 539254225Speter while (ticks_left > 0) { 54019304Speter tick = getit(); 54119304Speter#ifdef DELAYDEBUG 54219304Speter ++getit_calls; 54319304Speter#endif 54419304Speter delta = prev_tick - tick; 54519304Speter prev_tick = tick; 54619304Speter if (delta < 0) { 547254225Speter delta += timer0_max_count; 548254225Speter /* 54919304Speter * Guard against timer0_max_count being wrong. 55019304Speter * This shouldn't happen in normal operation, 55119304Speter * but it may happen if set_timer_freq() is 552254225Speter * traced. 55319304Speter */ 55419304Speter if (delta < 0) 555254225Speter delta = 0; 556254225Speter } 55719304Speter ticks_left -= delta; 55819304Speter } 55919304Speter#ifdef DELAYDEBUG 56019304Speter if (state == 1) 561254225Speter printf(" %d calls to getit() at %d usec each\n", 562254225Speter getit_calls, (n + 5) / getit_calls); 563254225Speter#endif 564254225Speter} 565254225Speter 566254225Speterstatic void 567254225Spetersysbeepstop(void *chan) 568254225Speter{ 569254225Speter#ifdef PC98 /* PC98 */ 570254225Speter outb(IO_PPI, inb(IO_PPI)|0x08); /* disable counter1 output to speaker */ 571254225Speter release_timer1(); 572254225Speter#else 573254225Speter outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */ 574254225Speter release_timer2(); 57519304Speter#endif 57619304Speter beeping = 0; 577254225Speter} 578254225Speter 57919304Speterint 58019304Spetersysbeep(int pitch, int period) 58119304Speter{ 58219304Speter int x = splclock(); 583254225Speter 584254225Speter#ifdef PC98 585254225Speter if (acquire_timer1(TIMER_SQWAVE|TIMER_16BIT)) 586254225Speter if (!beeping) { 587254225Speter /* Something else owns it. */ 588254225Speter splx(x); 589254225Speter return (-1); /* XXX Should be EBUSY, but nobody cares anyway. */ 590254225Speter } 591254225Speter disable_intr(); 592254225Speter outb(0x3fdb, pitch); 593254225Speter outb(0x3fdb, (pitch>>8)); 594254225Speter enable_intr(); 595254225Speter if (!beeping) { 596254225Speter /* enable counter1 output to speaker */ 597254225Speter outb(IO_PPI, (inb(IO_PPI) & 0xf7)); 598254225Speter beeping = period; 599254225Speter timeout(sysbeepstop, (void *)NULL, period); 600254225Speter } 601254225Speter#else 602254225Speter if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT)) 603254225Speter if (!beeping) { 604254225Speter /* Something else owns it. */ 605254225Speter splx(x); 606254225Speter return (-1); /* XXX Should be EBUSY, but nobody cares anyway. */ 607254225Speter } 608254225Speter mtx_lock_spin(&clock_lock); 609254225Speter outb(TIMER_CNTR2, pitch); 610254225Speter outb(TIMER_CNTR2, (pitch>>8)); 611254225Speter mtx_unlock_spin(&clock_lock); 612254225Speter if (!beeping) { 613254225Speter /* enable counter2 output to speaker */ 614254225Speter outb(IO_PPI, inb(IO_PPI) | 3); 615254225Speter beeping = period; 616254225Speter timeout(sysbeepstop, (void *)NULL, period); 617254225Speter } 618254225Speter#endif 619254225Speter splx(x); 620254225Speter return (0); 621254225Speter} 622254225Speter 623254225Speter#ifndef PC98 624254225Speter/* 625254225Speter * RTC support routines 626254225Speter */ 627254225Speter 628254225Speterint 629254225Speterrtcin(reg) 630254225Speter int reg; 631254225Speter{ 632254225Speter int s; 633254225Speter u_char val; 634254225Speter 635254225Speter s = splhigh(); 636254225Speter outb(IO_RTC, reg); 637254225Speter inb(0x84); 638254225Speter val = inb(IO_RTC + 1); 639254225Speter inb(0x84); 640254225Speter splx(s); 641254225Speter return (val); 642254225Speter} 643254225Speter 644254225Speterstatic __inline void 645254225Speterwritertc(u_char reg, u_char val) 646254225Speter{ 647254225Speter int s; 648254225Speter 64919304Speter s = splhigh(); 65019304Speter inb(0x84); 65119304Speter outb(IO_RTC, reg); 65219304Speter inb(0x84); 65319304Speter outb(IO_RTC + 1, val); 65419304Speter inb(0x84); /* XXX work around wrong order in rtcin() */ 655254225Speter splx(s); 656254225Speter} 657254225Speter 65819304Speterstatic __inline int 65919304Speterreadrtc(int port) 66019304Speter{ 66119304Speter return(bcd2bin(rtcin(port))); 66219304Speter} 66319304Speter#endif 66419304Speter 66519304Speter#ifdef PC98 66619304Speterunsigned int delaycount; 66719304Speter#define FIRST_GUESS 0x2000 66819304Speterstatic void findcpuspeed(void) 669254225Speter{ 670254225Speter int i; 671254225Speter int remainder; 672254225Speter 673254225Speter /* Put counter in count down mode */ 67419304Speter outb(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN); 67519304Speter outb(TIMER_CNTR0, 0xff); 67619304Speter outb(TIMER_CNTR0, 0xff); 67719304Speter for (i = FIRST_GUESS; i; i--) 67819304Speter ; 67919304Speter remainder = getit(); 68019304Speter delaycount = (FIRST_GUESS * TIMER_DIV(1000)) / (0xffff - remainder); 68119304Speter} 68219304Speter#endif 683254225Speter 68419304Speter#ifdef PC98 68519304Speterstatic u_int 68619304Spetercalibrate_clocks(void) 68719304Speter{ 68819304Speter int timeout; 689 u_int count, prev_count, tot_count; 690 u_short sec, start_sec; 691 692 if (bootverbose) 693 printf("Calibrating clock(s) ... "); 694 /* Check ARTIC. */ 695 if (!(PC98_SYSTEM_PARAMETER(0x458) & 0x80) && 696 !(PC98_SYSTEM_PARAMETER(0x45b) & 0x04)) 697 goto fail; 698 timeout = 100000000; 699 700 /* Read the ARTIC. */ 701 sec = inw(0x5e); 702 703 /* Wait for the ARTIC to changes. */ 704 start_sec = sec; 705 for (;;) { 706 sec = inw(0x5e); 707 if (sec != start_sec) 708 break; 709 if (--timeout == 0) 710 goto fail; 711 } 712 prev_count = getit(); 713 if (prev_count == 0 || prev_count > timer0_max_count) 714 goto fail; 715 tot_count = 0; 716 717 if (tsc_present) 718 wrmsr(0x10, 0LL); /* XXX 0x10 is the MSR for the TSC */ 719 start_sec = sec; 720 for (;;) { 721 sec = inw(0x5e); 722 count = getit(); 723 if (count == 0 || count > timer0_max_count) 724 goto fail; 725 if (count > prev_count) 726 tot_count += prev_count - (count - timer0_max_count); 727 else 728 tot_count += prev_count - count; 729 prev_count = count; 730 if ((sec == start_sec + 1200) || 731 (sec < start_sec && 732 (u_int)sec + 0x10000 == (u_int)start_sec + 1200)) 733 break; 734 if (--timeout == 0) 735 goto fail; 736 } 737 /* 738 * Read the cpu cycle counter. The timing considerations are 739 * similar to those for the i8254 clock. 740 */ 741 if (tsc_present) 742 tsc_freq = rdtsc(); 743 744 if (bootverbose) { 745 if (tsc_present) 746 printf("TSC clock: %u Hz, ", tsc_freq); 747 printf("i8254 clock: %u Hz\n", tot_count); 748 } 749 return (tot_count); 750 751fail: 752 if (bootverbose) 753 printf("failed, using default i8254 clock of %u Hz\n", 754 timer_freq); 755 return (timer_freq); 756} 757#else 758static u_int 759calibrate_clocks(void) 760{ 761 u_int64_t old_tsc; 762 u_int count, prev_count, tot_count; 763 int sec, start_sec, timeout; 764 765 if (bootverbose) 766 printf("Calibrating clock(s) ... "); 767 if (!(rtcin(RTC_STATUSD) & RTCSD_PWR)) 768 goto fail; 769 timeout = 100000000; 770 771 /* Read the mc146818A seconds counter. */ 772 for (;;) { 773 if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) { 774 sec = rtcin(RTC_SEC); 775 break; 776 } 777 if (--timeout == 0) 778 goto fail; 779 } 780 781 /* Wait for the mC146818A seconds counter to change. */ 782 start_sec = sec; 783 for (;;) { 784 if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) { 785 sec = rtcin(RTC_SEC); 786 if (sec != start_sec) 787 break; 788 } 789 if (--timeout == 0) 790 goto fail; 791 } 792 793 /* Start keeping track of the i8254 counter. */ 794 prev_count = getit(); 795 if (prev_count == 0 || prev_count > timer0_max_count) 796 goto fail; 797 tot_count = 0; 798 799 if (tsc_present) 800 old_tsc = rdtsc(); 801 else 802 old_tsc = 0; /* shut up gcc */ 803 804 /* 805 * Wait for the mc146818A seconds counter to change. Read the i8254 806 * counter for each iteration since this is convenient and only 807 * costs a few usec of inaccuracy. The timing of the final reads 808 * of the counters almost matches the timing of the initial reads, 809 * so the main cause of inaccuracy is the varying latency from 810 * inside getit() or rtcin(RTC_STATUSA) to the beginning of the 811 * rtcin(RTC_SEC) that returns a changed seconds count. The 812 * maximum inaccuracy from this cause is < 10 usec on 486's. 813 */ 814 start_sec = sec; 815 for (;;) { 816 if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) 817 sec = rtcin(RTC_SEC); 818 count = getit(); 819 if (count == 0 || count > timer0_max_count) 820 goto fail; 821 if (count > prev_count) 822 tot_count += prev_count - (count - timer0_max_count); 823 else 824 tot_count += prev_count - count; 825 prev_count = count; 826 if (sec != start_sec) 827 break; 828 if (--timeout == 0) 829 goto fail; 830 } 831 832 /* 833 * Read the cpu cycle counter. The timing considerations are 834 * similar to those for the i8254 clock. 835 */ 836 if (tsc_present) 837 tsc_freq = rdtsc() - old_tsc; 838 839 if (bootverbose) { 840 if (tsc_present) 841 printf("TSC clock: %u Hz, ", tsc_freq); 842 printf("i8254 clock: %u Hz\n", tot_count); 843 } 844 return (tot_count); 845 846fail: 847 if (bootverbose) 848 printf("failed, using default i8254 clock of %u Hz\n", 849 timer_freq); 850 return (timer_freq); 851} 852#endif /* !PC98 */ 853 854static void 855set_timer_freq(u_int freq, int intr_freq) 856{ 857 int new_timer0_max_count; 858 859 mtx_lock_spin(&clock_lock); 860 timer_freq = freq; 861 new_timer0_max_count = hardclock_max_count = TIMER_DIV(intr_freq); 862 if (new_timer0_max_count != timer0_max_count) { 863 timer0_max_count = new_timer0_max_count; 864 outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 865 outb(TIMER_CNTR0, timer0_max_count & 0xff); 866 outb(TIMER_CNTR0, timer0_max_count >> 8); 867 } 868 mtx_unlock_spin(&clock_lock); 869} 870 871/* 872 * i8254_restore is called from apm_default_resume() to reload 873 * the countdown register. 874 * this should not be necessary but there are broken laptops that 875 * do not restore the countdown register on resume. 876 * when it happnes, it messes up the hardclock interval and system clock, 877 * which leads to the infamous "calcru: negative time" problem. 878 */ 879void 880i8254_restore(void) 881{ 882 883 mtx_lock_spin(&clock_lock); 884 outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 885 outb(TIMER_CNTR0, timer0_max_count & 0xff); 886 outb(TIMER_CNTR0, timer0_max_count >> 8); 887 mtx_unlock_spin(&clock_lock); 888} 889 890/* 891 * Initialize 8254 timer 0 early so that it can be used in DELAY(). 892 * XXX initialization of other timers is unintentionally left blank. 893 */ 894void 895startrtclock() 896{ 897 u_int delta, freq; 898 899#ifdef PC98 900 findcpuspeed(); 901 if (pc98_machine_type & M_8M) 902 timer_freq = 1996800L; /* 1.9968 MHz */ 903 else 904 timer_freq = 2457600L; /* 2.4576 MHz */ 905#endif /* PC98 */ 906 907 if (cpu_feature & CPUID_TSC) 908 tsc_present = 1; 909 else 910 tsc_present = 0; 911 912#ifndef PC98 913 writertc(RTC_STATUSA, rtc_statusa); 914 writertc(RTC_STATUSB, RTCSB_24HR); 915#endif 916 917 set_timer_freq(timer_freq, hz); 918 freq = calibrate_clocks(); 919#ifdef CLK_CALIBRATION_LOOP 920 if (bootverbose) { 921 printf( 922 "Press a key on the console to abort clock calibration\n"); 923 while (cncheckc() == -1) 924 calibrate_clocks(); 925 } 926#endif 927 928 /* 929 * Use the calibrated i8254 frequency if it seems reasonable. 930 * Otherwise use the default, and don't use the calibrated i586 931 * frequency. 932 */ 933 delta = freq > timer_freq ? freq - timer_freq : timer_freq - freq; 934 if (delta < timer_freq / 100) { 935#ifndef CLK_USE_I8254_CALIBRATION 936 if (bootverbose) 937 printf( 938"CLK_USE_I8254_CALIBRATION not specified - using default frequency\n"); 939 freq = timer_freq; 940#endif 941 timer_freq = freq; 942 } else { 943 if (bootverbose) 944 printf( 945 "%d Hz differs from default of %d Hz by more than 1%%\n", 946 freq, timer_freq); 947 tsc_freq = 0; 948 } 949 950 set_timer_freq(timer_freq, hz); 951 i8254_timecounter.tc_frequency = timer_freq; 952 tc_init(&i8254_timecounter); 953 954#ifndef CLK_USE_TSC_CALIBRATION 955 if (tsc_freq != 0) { 956 if (bootverbose) 957 printf( 958"CLK_USE_TSC_CALIBRATION not specified - using old calibration method\n"); 959 tsc_freq = 0; 960 } 961#endif 962 if (tsc_present && tsc_freq == 0) { 963 /* 964 * Calibration of the i586 clock relative to the mc146818A 965 * clock failed. Do a less accurate calibration relative 966 * to the i8254 clock. 967 */ 968 u_int64_t old_tsc = rdtsc(); 969 970 DELAY(1000000); 971 tsc_freq = rdtsc() - old_tsc; 972#ifdef CLK_USE_TSC_CALIBRATION 973 if (bootverbose) 974 printf("TSC clock: %u Hz (Method B)\n", tsc_freq); 975#endif 976 } 977 978#if !defined(SMP) 979 /* 980 * We can not use the TSC in SMP mode, until we figure out a 981 * cheap (impossible), reliable and precise (yeah right!) way 982 * to synchronize the TSCs of all the CPUs. 983 * Curse Intel for leaving the counter out of the I/O APIC. 984 */ 985 986#ifdef DEV_APM 987 /* 988 * We can not use the TSC if we support APM. Precise timekeeping 989 * on an APM'ed machine is at best a fools pursuit, since 990 * any and all of the time spent in various SMM code can't 991 * be reliably accounted for. Reading the RTC is your only 992 * source of reliable time info. The i8254 looses too of course 993 * but we need to have some kind of time... 994 * We don't know at this point whether APM is going to be used 995 * or not, nor when it might be activated. Play it safe. 996 */ 997 { 998 int disabled = 0; 999 resource_int_value("apm", 0, "disabled", &disabled); 1000 if (disabled == 0) 1001 return; 1002 } 1003#endif /* DEV_APM */ 1004 1005 if (tsc_present && tsc_freq != 0 && !tsc_is_broken) { 1006 tsc_timecounter.tc_frequency = tsc_freq; 1007 tc_init(&tsc_timecounter); 1008 } 1009 1010#endif /* !defined(SMP) */ 1011} 1012 1013#ifdef PC98 1014static void 1015rtc_serialcombit(int i) 1016{ 1017 outb(IO_RTC, ((i&0x01)<<5)|0x07); 1018 DELAY(1); 1019 outb(IO_RTC, ((i&0x01)<<5)|0x17); 1020 DELAY(1); 1021 outb(IO_RTC, ((i&0x01)<<5)|0x07); 1022 DELAY(1); 1023} 1024 1025static void 1026rtc_serialcom(int i) 1027{ 1028 rtc_serialcombit(i&0x01); 1029 rtc_serialcombit((i&0x02)>>1); 1030 rtc_serialcombit((i&0x04)>>2); 1031 rtc_serialcombit((i&0x08)>>3); 1032 outb(IO_RTC, 0x07); 1033 DELAY(1); 1034 outb(IO_RTC, 0x0f); 1035 DELAY(1); 1036 outb(IO_RTC, 0x07); 1037 DELAY(1); 1038} 1039 1040static void 1041rtc_outb(int val) 1042{ 1043 int s; 1044 int sa = 0; 1045 1046 for (s=0;s<8;s++) { 1047 sa = ((val >> s) & 0x01) ? 0x27 : 0x07; 1048 outb(IO_RTC, sa); /* set DI & CLK 0 */ 1049 DELAY(1); 1050 outb(IO_RTC, sa | 0x10); /* CLK 1 */ 1051 DELAY(1); 1052 } 1053 outb(IO_RTC, sa & 0xef); /* CLK 0 */ 1054} 1055 1056static int 1057rtc_inb(void) 1058{ 1059 int s; 1060 int sa = 0; 1061 1062 for (s=0;s<8;s++) { 1063 sa |= ((inb(0x33) & 0x01) << s); 1064 outb(IO_RTC, 0x17); /* CLK 1 */ 1065 DELAY(1); 1066 outb(IO_RTC, 0x07); /* CLK 0 */ 1067 DELAY(2); 1068 } 1069 return sa; 1070} 1071#endif /* PC-98 */ 1072 1073/* 1074 * Initialize the time of day register, based on the time base which is, e.g. 1075 * from a filesystem. 1076 */ 1077void 1078inittodr(time_t base) 1079{ 1080 unsigned long sec, days; 1081#ifndef PC98 1082 int yd; 1083#endif 1084 int year, month; 1085 int y, m, s; 1086 struct timespec ts; 1087#ifdef PC98 1088 int second, min, hour; 1089#endif 1090 1091 if (base) { 1092 s = splclock(); 1093 ts.tv_sec = base; 1094 ts.tv_nsec = 0; 1095 tc_setclock(&ts); 1096 splx(s); 1097 } 1098 1099#ifdef PC98 1100 rtc_serialcom(0x03); /* Time Read */ 1101 rtc_serialcom(0x01); /* Register shift command. */ 1102 DELAY(20); 1103 1104 second = bcd2bin(rtc_inb() & 0xff); /* sec */ 1105 min = bcd2bin(rtc_inb() & 0xff); /* min */ 1106 hour = bcd2bin(rtc_inb() & 0xff); /* hour */ 1107 days = bcd2bin(rtc_inb() & 0xff) - 1; /* date */ 1108 1109 month = (rtc_inb() >> 4) & 0x0f; /* month */ 1110 for (m = 1; m < month; m++) 1111 days += daysinmonth[m-1]; 1112 year = bcd2bin(rtc_inb() & 0xff) + 1900; /* year */ 1113 /* 2000 year problem */ 1114 if (year < 1995) 1115 year += 100; 1116 if (year < 1970) 1117 goto wrong_time; 1118 for (y = 1970; y < year; y++) 1119 days += DAYSPERYEAR + LEAPYEAR(y); 1120 if ((month > 2) && LEAPYEAR(year)) 1121 days ++; 1122 sec = ((( days * 24 + 1123 hour) * 60 + 1124 min) * 60 + 1125 second); 1126 /* sec now contains the number of seconds, since Jan 1 1970, 1127 in the local time zone */ 1128 1129 s = splhigh(); 1130#else /* IBM-PC */ 1131 /* Look if we have a RTC present and the time is valid */ 1132 if (!(rtcin(RTC_STATUSD) & RTCSD_PWR)) 1133 goto wrong_time; 1134 1135 /* wait for time update to complete */ 1136 /* If RTCSA_TUP is zero, we have at least 244us before next update */ 1137 s = splhigh(); 1138 while (rtcin(RTC_STATUSA) & RTCSA_TUP) { 1139 splx(s); 1140 s = splhigh(); 1141 } 1142 1143 days = 0; 1144#ifdef USE_RTC_CENTURY 1145 year = readrtc(RTC_YEAR) + readrtc(RTC_CENTURY) * 100; 1146#else 1147 year = readrtc(RTC_YEAR) + 1900; 1148 if (year < 1970) 1149 year += 100; 1150#endif 1151 if (year < 1970) { 1152 splx(s); 1153 goto wrong_time; 1154 } 1155 month = readrtc(RTC_MONTH); 1156 for (m = 1; m < month; m++) 1157 days += daysinmonth[m-1]; 1158 if ((month > 2) && LEAPYEAR(year)) 1159 days ++; 1160 days += readrtc(RTC_DAY) - 1; 1161 yd = days; 1162 for (y = 1970; y < year; y++) 1163 days += DAYSPERYEAR + LEAPYEAR(y); 1164 sec = ((( days * 24 + 1165 readrtc(RTC_HRS)) * 60 + 1166 readrtc(RTC_MIN)) * 60 + 1167 readrtc(RTC_SEC)); 1168 /* sec now contains the number of seconds, since Jan 1 1970, 1169 in the local time zone */ 1170#endif 1171 1172 sec += tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0); 1173 1174 y = time_second - sec; 1175 if (y <= -2 || y >= 2) { 1176 /* badly off, adjust it */ 1177 ts.tv_sec = sec; 1178 ts.tv_nsec = 0; 1179 tc_setclock(&ts); 1180 } 1181 splx(s); 1182 return; 1183 1184wrong_time: 1185 printf("Invalid time in real time clock.\n"); 1186 printf("Check and reset the date immediately!\n"); 1187} 1188 1189/* 1190 * Write system time back to RTC 1191 */ 1192void 1193resettodr() 1194{ 1195 unsigned long tm; 1196 int y, m, s; 1197#ifdef PC98 1198 int wd; 1199#endif 1200 1201 if (disable_rtc_set) 1202 return; 1203 1204 s = splclock(); 1205 tm = time_second; 1206 splx(s); 1207 1208#ifdef PC98 1209 rtc_serialcom(0x01); /* Register shift command. */ 1210 1211 /* Calculate local time to put in RTC */ 1212 1213 tm -= tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0); 1214 1215 rtc_outb(bin2bcd(tm%60)); tm /= 60; /* Write back Seconds */ 1216 rtc_outb(bin2bcd(tm%60)); tm /= 60; /* Write back Minutes */ 1217 rtc_outb(bin2bcd(tm%24)); tm /= 24; /* Write back Hours */ 1218 1219 /* We have now the days since 01-01-1970 in tm */ 1220 wd = (tm+4)%7; 1221 for (y = 1970, m = DAYSPERYEAR + LEAPYEAR(y); 1222 tm >= m; 1223 y++, m = DAYSPERYEAR + LEAPYEAR(y)) 1224 tm -= m; 1225 1226 /* Now we have the years in y and the day-of-the-year in tm */ 1227 for (m = 0; ; m++) { 1228 int ml; 1229 1230 ml = daysinmonth[m]; 1231 if (m == 1 && LEAPYEAR(y)) 1232 ml++; 1233 if (tm < ml) 1234 break; 1235 tm -= ml; 1236 } 1237 1238 m++; 1239 rtc_outb(bin2bcd(tm+1)); /* Write back Day */ 1240 rtc_outb((m << 4) | wd); /* Write back Month & Weekday */ 1241 rtc_outb(bin2bcd(y%100)); /* Write back Year */ 1242 1243 rtc_serialcom(0x02); /* Time set & Counter hold command. */ 1244 rtc_serialcom(0x00); /* Register hold command. */ 1245#else 1246 /* Disable RTC updates and interrupts. */ 1247 writertc(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR); 1248 1249 /* Calculate local time to put in RTC */ 1250 1251 tm -= tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0); 1252 1253 writertc(RTC_SEC, bin2bcd(tm%60)); tm /= 60; /* Write back Seconds */ 1254 writertc(RTC_MIN, bin2bcd(tm%60)); tm /= 60; /* Write back Minutes */ 1255 writertc(RTC_HRS, bin2bcd(tm%24)); tm /= 24; /* Write back Hours */ 1256 1257 /* We have now the days since 01-01-1970 in tm */ 1258 writertc(RTC_WDAY, (tm+4)%7); /* Write back Weekday */ 1259 for (y = 1970, m = DAYSPERYEAR + LEAPYEAR(y); 1260 tm >= m; 1261 y++, m = DAYSPERYEAR + LEAPYEAR(y)) 1262 tm -= m; 1263 1264 /* Now we have the years in y and the day-of-the-year in tm */ 1265 writertc(RTC_YEAR, bin2bcd(y%100)); /* Write back Year */ 1266#ifdef USE_RTC_CENTURY 1267 writertc(RTC_CENTURY, bin2bcd(y/100)); /* ... and Century */ 1268#endif 1269 for (m = 0; ; m++) { 1270 int ml; 1271 1272 ml = daysinmonth[m]; 1273 if (m == 1 && LEAPYEAR(y)) 1274 ml++; 1275 if (tm < ml) 1276 break; 1277 tm -= ml; 1278 } 1279 1280 writertc(RTC_MONTH, bin2bcd(m + 1)); /* Write back Month */ 1281 writertc(RTC_DAY, bin2bcd(tm + 1)); /* Write back Month Day */ 1282 1283 /* Reenable RTC updates and interrupts. */ 1284 writertc(RTC_STATUSB, rtc_statusb); 1285#endif /* PC98 */ 1286} 1287 1288 1289/* 1290 * Start both clocks running. 1291 */ 1292void 1293cpu_initclocks() 1294{ 1295#ifdef APIC_IO 1296 int apic_8254_trial; 1297 void *clkdesc; 1298#endif /* APIC_IO */ 1299#ifndef PC98 1300 int diag; 1301 1302 if (statclock_disable) { 1303 /* 1304 * The stat interrupt mask is different without the 1305 * statistics clock. Also, don't set the interrupt 1306 * flag which would normally cause the RTC to generate 1307 * interrupts. 1308 */ 1309 rtc_statusb = RTCSB_24HR; 1310 } else { 1311 /* Setting stathz to nonzero early helps avoid races. */ 1312 stathz = RTC_NOPROFRATE; 1313 profhz = RTC_PROFRATE; 1314 } 1315#endif 1316 1317 /* Finish initializing 8253 timer 0. */ 1318#ifdef APIC_IO 1319 1320 apic_8254_intr = isa_apic_irq(0); 1321 apic_8254_trial = 0; 1322 if (apic_8254_intr >= 0 ) { 1323 if (apic_int_type(0, 0) == 3) 1324 apic_8254_trial = 1; 1325 } else { 1326 /* look for ExtInt on pin 0 */ 1327 if (apic_int_type(0, 0) == 3) { 1328 apic_8254_intr = apic_irq(0, 0); 1329 setup_8254_mixed_mode(); 1330 } else 1331 panic("APIC_IO: Cannot route 8254 interrupt to CPU"); 1332 } 1333 1334 inthand_add("clk", apic_8254_intr, (driver_intr_t *)clkintr, NULL, 1335 INTR_TYPE_CLK | INTR_FAST, &clkdesc); 1336 INTREN(1 << apic_8254_intr); 1337 1338#else /* APIC_IO */ 1339 1340 /* 1341 * XXX Check the priority of this interrupt handler. I 1342 * couldn't find anything suitable in the BSD/OS code (grog, 1343 * 19 July 2000). 1344 */ 1345 inthand_add("clk", 0, (driver_intr_t *)clkintr, NULL, 1346 INTR_TYPE_CLK | INTR_FAST, NULL); 1347 INTREN(IRQ0); 1348 1349#endif /* APIC_IO */ 1350 1351#ifndef PC98 1352 /* Initialize RTC. */ 1353 writertc(RTC_STATUSA, rtc_statusa); 1354 writertc(RTC_STATUSB, RTCSB_24HR); 1355 1356 /* Don't bother enabling the statistics clock. */ 1357 if (statclock_disable) 1358 return; 1359 diag = rtcin(RTC_DIAG); 1360 if (diag != 0) 1361 printf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS); 1362#endif /* !PC98 */ 1363 1364#ifndef PC98 1365#ifdef APIC_IO 1366 if (isa_apic_irq(8) != 8) 1367 panic("APIC RTC != 8"); 1368#endif /* APIC_IO */ 1369 1370 inthand_add("rtc", 8, (driver_intr_t *)rtcintr, NULL, 1371 INTR_TYPE_CLK | INTR_FAST, NULL); 1372 1373#ifdef APIC_IO 1374 INTREN(APIC_IRQ8); 1375#else 1376 INTREN(IRQ8); 1377#endif /* APIC_IO */ 1378 1379 writertc(RTC_STATUSB, rtc_statusb); 1380#endif /* PC98 */ 1381 1382#ifdef APIC_IO 1383 if (apic_8254_trial) { 1384 1385 printf("APIC_IO: Testing 8254 interrupt delivery\n"); 1386 while (read_intr_count(8) < 6) 1387 ; /* nothing */ 1388 if (read_intr_count(apic_8254_intr) < 3) { 1389 /* 1390 * The MP table is broken. 1391 * The 8254 was not connected to the specified pin 1392 * on the IO APIC. 1393 * Workaround: Limited variant of mixed mode. 1394 */ 1395 INTRDIS(1 << apic_8254_intr); 1396 inthand_remove(clkdesc); 1397 printf("APIC_IO: Broken MP table detected: " 1398 "8254 is not connected to " 1399 "IOAPIC #%d intpin %d\n", 1400 int_to_apicintpin[apic_8254_intr].ioapic, 1401 int_to_apicintpin[apic_8254_intr].int_pin); 1402 /* 1403 * Revoke current ISA IRQ 0 assignment and 1404 * configure a fallback interrupt routing from 1405 * the 8254 Timer via the 8259 PIC to the 1406 * an ExtInt interrupt line on IOAPIC #0 intpin 0. 1407 * We reuse the low level interrupt handler number. 1408 */ 1409 if (apic_irq(0, 0) < 0) { 1410 revoke_apic_irq(apic_8254_intr); 1411 assign_apic_irq(0, 0, apic_8254_intr); 1412 } 1413 apic_8254_intr = apic_irq(0, 0); 1414 setup_8254_mixed_mode(); 1415 inthand_add("clk", apic_8254_intr, 1416 (driver_intr_t *)clkintr, NULL, 1417 INTR_TYPE_CLK | INTR_FAST, NULL); 1418 INTREN(1 << apic_8254_intr); 1419 } 1420 1421 } 1422 if (apic_int_type(0, 0) != 3 || 1423 int_to_apicintpin[apic_8254_intr].ioapic != 0 || 1424 int_to_apicintpin[apic_8254_intr].int_pin != 0) 1425 printf("APIC_IO: routing 8254 via IOAPIC #%d intpin %d\n", 1426 int_to_apicintpin[apic_8254_intr].ioapic, 1427 int_to_apicintpin[apic_8254_intr].int_pin); 1428 else 1429 printf("APIC_IO: " 1430 "routing 8254 via 8259 and IOAPIC #0 intpin 0\n"); 1431#endif 1432 1433} 1434 1435#ifdef APIC_IO 1436static u_long 1437read_intr_count(int vec) 1438{ 1439 u_long *up; 1440 up = intr_countp[vec]; 1441 if (up) 1442 return *up; 1443 return 0UL; 1444} 1445 1446static void 1447setup_8254_mixed_mode() 1448{ 1449 /* 1450 * Allow 8254 timer to INTerrupt 8259: 1451 * re-initialize master 8259: 1452 * reset; prog 4 bytes, single ICU, edge triggered 1453 */ 1454 outb(IO_ICU1, 0x13); 1455#ifdef PC98 1456 outb(IO_ICU1 + 2, NRSVIDT); /* start vector (unused) */ 1457 outb(IO_ICU1 + 2, 0x00); /* ignore slave */ 1458 outb(IO_ICU1 + 2, 0x03); /* auto EOI, 8086 */ 1459 outb(IO_ICU1 + 2, 0xfe); /* unmask INT0 */ 1460#else 1461 outb(IO_ICU1 + 1, NRSVIDT); /* start vector (unused) */ 1462 outb(IO_ICU1 + 1, 0x00); /* ignore slave */ 1463 outb(IO_ICU1 + 1, 0x03); /* auto EOI, 8086 */ 1464 outb(IO_ICU1 + 1, 0xfe); /* unmask INT0 */ 1465#endif 1466 /* program IO APIC for type 3 INT on INT0 */ 1467 if (ext_int_setup(0, 0) < 0) 1468 panic("8254 redirect via APIC pin0 impossible!"); 1469} 1470#endif 1471 1472void 1473setstatclockrate(int newhz) 1474{ 1475#ifndef PC98 1476 if (newhz == RTC_PROFRATE) 1477 rtc_statusa = RTCSA_DIVIDER | RTCSA_PROF; 1478 else 1479 rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; 1480 writertc(RTC_STATUSA, rtc_statusa); 1481#endif 1482} 1483 1484static int 1485sysctl_machdep_i8254_freq(SYSCTL_HANDLER_ARGS) 1486{ 1487 int error; 1488 u_int freq; 1489 1490 /* 1491 * Use `i8254' instead of `timer' in external names because `timer' 1492 * is is too generic. Should use it everywhere. 1493 */ 1494 freq = timer_freq; 1495 error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); 1496 if (error == 0 && req->newptr != NULL) { 1497 if (timer0_state != RELEASED) 1498 return (EBUSY); /* too much trouble to handle */ 1499 set_timer_freq(freq, hz); 1500 i8254_timecounter.tc_frequency = freq; 1501 tc_update(&i8254_timecounter); 1502 } 1503 return (error); 1504} 1505 1506SYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW, 1507 0, sizeof(u_int), sysctl_machdep_i8254_freq, "I", ""); 1508 1509static int 1510sysctl_machdep_tsc_freq(SYSCTL_HANDLER_ARGS) 1511{ 1512 int error; 1513 u_int freq; 1514 1515 if (tsc_timecounter.tc_frequency == 0) 1516 return (EOPNOTSUPP); 1517 freq = tsc_freq; 1518 error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); 1519 if (error == 0 && req->newptr != NULL) { 1520 tsc_freq = freq; 1521 tsc_timecounter.tc_frequency = tsc_freq; 1522 tc_update(&tsc_timecounter); 1523 } 1524 return (error); 1525} 1526 1527SYSCTL_PROC(_machdep, OID_AUTO, tsc_freq, CTLTYPE_INT | CTLFLAG_RW, 1528 0, sizeof(u_int), sysctl_machdep_tsc_freq, "I", ""); 1529 1530static unsigned 1531i8254_get_timecount(struct timecounter *tc) 1532{ 1533 u_int count; 1534 u_int high, low; 1535 u_int eflags; 1536 1537 eflags = read_eflags(); 1538 mtx_lock_spin(&clock_lock); 1539 1540 /* Select timer0 and latch counter value. */ 1541 outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 1542 1543 low = inb(TIMER_CNTR0); 1544 high = inb(TIMER_CNTR0); 1545 count = timer0_max_count - ((high << 8) | low); 1546 if (count < i8254_lastcount || 1547 (!i8254_ticked && (clkintr_pending || 1548 ((count < 20 || (!(eflags & PSL_I) && count < timer0_max_count / 2u)) && 1549#ifdef APIC_IO 1550#define lapic_irr1 ((volatile u_int *)&lapic)[0x210 / 4] /* XXX XXX */ 1551 /* XXX this assumes that apic_8254_intr is < 24. */ 1552 (lapic_irr1 & (1 << apic_8254_intr)))) 1553#else 1554 (inb(IO_ICU1) & 1))) 1555#endif 1556 )) { 1557 i8254_ticked = 1; 1558 i8254_offset += timer0_max_count; 1559 } 1560 i8254_lastcount = count; 1561 count += i8254_offset; 1562 mtx_unlock_spin(&clock_lock); 1563 return (count); 1564} 1565 1566static unsigned 1567tsc_get_timecount(struct timecounter *tc) 1568{ 1569 return (rdtsc()); 1570} 1571 1572/* 1573 * Attach to the ISA PnP descriptors for the timer and realtime clock. 1574 */ 1575static struct isa_pnp_id attimer_ids[] = { 1576 { 0x0001d041 /* PNP0100 */, "AT timer" }, 1577 { 0x000bd041 /* PNP0B00 */, "AT realtime clock" }, 1578 { 0 } 1579}; 1580 1581static int 1582attimer_probe(device_t dev) 1583{ 1584 int result; 1585 1586 if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, attimer_ids)) <= 0) 1587 device_quiet(dev); 1588 return(result); 1589} 1590 1591static int 1592attimer_attach(device_t dev) 1593{ 1594 return(0); 1595} 1596 1597static device_method_t attimer_methods[] = { 1598 /* Device interface */ 1599 DEVMETHOD(device_probe, attimer_probe), 1600 DEVMETHOD(device_attach, attimer_attach), 1601 DEVMETHOD(device_detach, bus_generic_detach), 1602 DEVMETHOD(device_shutdown, bus_generic_shutdown), 1603 DEVMETHOD(device_suspend, bus_generic_suspend), /* XXX stop statclock? */ 1604 DEVMETHOD(device_resume, bus_generic_resume), /* XXX restart statclock? */ 1605 { 0, 0 } 1606}; 1607 1608static driver_t attimer_driver = { 1609 "attimer", 1610 attimer_methods, 1611 1, /* no softc */ 1612}; 1613 1614static devclass_t attimer_devclass; 1615 1616DRIVER_MODULE(attimer, isa, attimer_driver, attimer_devclass, 0, 0); 1617