From d1747d99343973bfb8d64254147b2e1b0ac5ab63 Mon Sep 17 00:00:00 2001 From: wollman Date: Mon, 15 Aug 1994 03:15:20 +0000 Subject: Enable use of the RTC chip for the statistical clock. While this does not provide the full accuracy of a randomized statistical clock, it does provide greater accuracy than the previous method, while not significantly increasing overhead. It also provides profiling support at 1024 Hz. You must re-compile config before making a new kernel, or you will end up with unresolved symbols. Reviewed uy: Bruce evans said it worked for him. --- sys/i386/i386/tsc.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++---- sys/i386/include/spl.h | 5 +++-- sys/i386/isa/clock.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++---- sys/i386/isa/icu.s | 4 +++- sys/i386/isa/rtc.h | 20 ++++++++++++++++- 5 files changed, 137 insertions(+), 12 deletions(-) (limited to 'sys/i386') diff --git a/sys/i386/i386/tsc.c b/sys/i386/i386/tsc.c index cf0a7f6..35f2e42 100644 --- a/sys/i386/i386/tsc.c +++ b/sys/i386/i386/tsc.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.12 1994/08/11 00:28:24 wollman Exp $ + * $Id: clock.c,v 1.13 1994/08/13 03:49:56 wollman Exp $ */ /* @@ -60,6 +60,7 @@ #define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x)) void hardclock(); +void statclock(); static int beeping; int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */ u_int timer0_prescale; @@ -102,6 +103,44 @@ clkintr(frame) hardclock(&frame); } +static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; + +/* + * This routine receives statistical clock interrupts from the RTC. + * As explained above, these occur at 128 interrupts per second. + * When profiling, we receive interrupts at a rate of 1024 Hz. + * + * This does not actually add as much overhead as it sounds, because + * when the statistical clock is active, the hardclock driver no longer + * needs to keep (inaccurate) statistics on its own. This decouples + * statistics gathering from scheduling interrupts. + * + * The RTC chip requires that we read status register C (RTC_INTR) + * to acknowledge an interrupt, before it will generate the next one. + */ +void +rtcintr(struct clockframe frame) +{ + u_char stat; + stat = rtcin(RTC_INTR); + if(stat & RTCIR_PERIOD) { + statclock(&frame); + } +} + +#ifdef DEBUG +void +printrtc(void) +{ + outb(IO_RTC, RTC_STATUSA); + printf("RTC status A = %x", inb(IO_RTC+1)); + outb(IO_RTC, RTC_STATUSB); + printf(", B = %x", inb(IO_RTC+1)); + outb(IO_RTC, RTC_INTR); + printf(", C = %x\n", inb(IO_RTC+1)); +} +#endif + #if 0 void timerintr(struct clockframe frame) @@ -338,9 +377,9 @@ startrtclock() /* initialize brain-dead battery powered clock */ outb (IO_RTC, RTC_STATUSA); - outb (IO_RTC+1, 0x26); + outb (IO_RTC+1, rtc_statusa); outb (IO_RTC, RTC_STATUSB); - outb (IO_RTC+1, 2); + outb (IO_RTC+1, RTCSB_24HR); outb (IO_RTC, RTC_DIAG); if (s = inb (IO_RTC+1)) @@ -460,13 +499,17 @@ test_inittodr(time_t base) */ #define V(s) __CONCAT(V, s) extern void V(clk)(); - +extern void V(rtc)(); void enablertclock() { setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL); INTREN(IRQ0); + setidt(ICU_OFFSET+8, &V(rtc), SDT_SYS386IGT, SEL_KPL); + INTREN(IRQ8); + outb(IO_RTC, RTC_STATUSB); + outb(IO_RTC+1, RTCSB_PINTR | RTCSB_24HR); } @@ -482,10 +525,19 @@ spinwait(int millisecs) void cpu_initclocks() { + stathz = RTC_NOPROFRATE; + profhz = RTC_PROFRATE; enablertclock(); } void setstatclockrate(int newhz) { + if(newhz == RTC_PROFRATE) { + rtc_statusa = RTCSA_DIVIDER | RTCSA_PROF; + } else { + rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; + } + outb(IO_RTC, RTC_STATUSA); + outb(IO_RTC+1, rtc_statusa); } diff --git a/sys/i386/include/spl.h b/sys/i386/include/spl.h index 739fc20..2a9c1dc 100644 --- a/sys/i386/include/spl.h +++ b/sys/i386/include/spl.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: spl.h,v 1.3 1994/08/02 07:39:06 davidg Exp $ */ #ifndef _MACHINE_IPL_H_ @@ -79,6 +79,7 @@ extern unsigned net_imask; /* group of interrupts masked with splimp() */ extern volatile unsigned ipending; /* active interrupts masked by cpl */ extern volatile unsigned netisr; extern unsigned tty_imask; /* group of interrupts masked with spltty() */ +extern unsigned stat_imask; /* interrupts masked with splstatclock() */ /* * ipending has to be volatile so that it is read every time it is accessed @@ -110,7 +111,7 @@ static __inline int name(void) \ GENSPL(splbio, cpl |= bio_imask) GENSPL(splclock, cpl = HWI_MASK | SWI_MASK) GENSPL(splhigh, cpl = HWI_MASK | SWI_MASK) -GENSPL(splstatclock, cpl = HWI_MASK | SWI_MASK) +GENSPL(splstatclock, cpl |= stat_imask | SWI_CLOCK_MASK) GENSPL(splimp, cpl |= net_imask) GENSPL(splnet, cpl |= SWI_NET_MASK) GENSPL(splsoftclock, cpl = SWI_CLOCK_MASK) diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c index cf0a7f6..35f2e42 100644 --- a/sys/i386/isa/clock.c +++ b/sys/i386/isa/clock.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.12 1994/08/11 00:28:24 wollman Exp $ + * $Id: clock.c,v 1.13 1994/08/13 03:49:56 wollman Exp $ */ /* @@ -60,6 +60,7 @@ #define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x)) void hardclock(); +void statclock(); static int beeping; int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */ u_int timer0_prescale; @@ -102,6 +103,44 @@ clkintr(frame) hardclock(&frame); } +static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; + +/* + * This routine receives statistical clock interrupts from the RTC. + * As explained above, these occur at 128 interrupts per second. + * When profiling, we receive interrupts at a rate of 1024 Hz. + * + * This does not actually add as much overhead as it sounds, because + * when the statistical clock is active, the hardclock driver no longer + * needs to keep (inaccurate) statistics on its own. This decouples + * statistics gathering from scheduling interrupts. + * + * The RTC chip requires that we read status register C (RTC_INTR) + * to acknowledge an interrupt, before it will generate the next one. + */ +void +rtcintr(struct clockframe frame) +{ + u_char stat; + stat = rtcin(RTC_INTR); + if(stat & RTCIR_PERIOD) { + statclock(&frame); + } +} + +#ifdef DEBUG +void +printrtc(void) +{ + outb(IO_RTC, RTC_STATUSA); + printf("RTC status A = %x", inb(IO_RTC+1)); + outb(IO_RTC, RTC_STATUSB); + printf(", B = %x", inb(IO_RTC+1)); + outb(IO_RTC, RTC_INTR); + printf(", C = %x\n", inb(IO_RTC+1)); +} +#endif + #if 0 void timerintr(struct clockframe frame) @@ -338,9 +377,9 @@ startrtclock() /* initialize brain-dead battery powered clock */ outb (IO_RTC, RTC_STATUSA); - outb (IO_RTC+1, 0x26); + outb (IO_RTC+1, rtc_statusa); outb (IO_RTC, RTC_STATUSB); - outb (IO_RTC+1, 2); + outb (IO_RTC+1, RTCSB_24HR); outb (IO_RTC, RTC_DIAG); if (s = inb (IO_RTC+1)) @@ -460,13 +499,17 @@ test_inittodr(time_t base) */ #define V(s) __CONCAT(V, s) extern void V(clk)(); - +extern void V(rtc)(); void enablertclock() { setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL); INTREN(IRQ0); + setidt(ICU_OFFSET+8, &V(rtc), SDT_SYS386IGT, SEL_KPL); + INTREN(IRQ8); + outb(IO_RTC, RTC_STATUSB); + outb(IO_RTC+1, RTCSB_PINTR | RTCSB_24HR); } @@ -482,10 +525,19 @@ spinwait(int millisecs) void cpu_initclocks() { + stathz = RTC_NOPROFRATE; + profhz = RTC_PROFRATE; enablertclock(); } void setstatclockrate(int newhz) { + if(newhz == RTC_PROFRATE) { + rtc_statusa = RTCSA_DIVIDER | RTCSA_PROF; + } else { + rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; + } + outb(IO_RTC, RTC_STATUSA); + outb(IO_RTC+1, rtc_statusa); } diff --git a/sys/i386/isa/icu.s b/sys/i386/isa/icu.s index 6d897d7..735eeda 100644 --- a/sys/i386/isa/icu.s +++ b/sys/i386/isa/icu.s @@ -36,7 +36,7 @@ * * @(#)icu.s 7.2 (Berkeley) 5/21/91 * - * $Id: icu.s,v 1.9 1994/05/25 08:58:55 rgrimes Exp $ + * $Id: icu.s,v 1.10 1994/08/13 03:50:01 wollman Exp $ */ /* @@ -58,6 +58,8 @@ _cpl: .long HWI_MASK | SWI_MASK /* current priority (all off) */ .globl _imen _imen: .long HWI_MASK /* interrupt mask enable (all h/w off) */ _high_imask: .long HWI_MASK | SWI_MASK + .globl _stat_imask +_stat_imask: .long (1 << 8) .globl _tty_imask _tty_imask: .long 0 .globl _bio_imask diff --git a/sys/i386/isa/rtc.h b/sys/i386/isa/rtc.h index ba008b6..9c0f501 100644 --- a/sys/i386/isa/rtc.h +++ b/sys/i386/isa/rtc.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)rtc.h 7.1 (Berkeley) 5/12/91 - * $Id: rtc.h,v 1.3 1993/11/07 17:44:34 wollman Exp $ + * $Id: rtc.h,v 1.4 1993/12/18 01:12:47 ache Exp $ */ #ifndef _I386_ISA_RTC_H_ @@ -54,10 +54,28 @@ #define RTC_DAY 0x07 /* day of month */ #define RTC_MONTH 0x08 /* month of year */ #define RTC_YEAR 0x09 /* month of year */ + #define RTC_STATUSA 0x0a /* status register A */ #define RTCSA_TUP 0x80 /* time update, don't look now */ +#define RTCSA_DIVIDER 0x20 /* divider correct for 32768 Hz */ +#define RTCSA_8192 0x03 +#define RTCSA_4096 0x04 +#define RTCSA_2048 0x05 +#define RTCSA_1024 0x06 /* default for profiling */ +#define RTCSA_PROF RTCSA_1024 +#define RTC_PROFRATE 1024 +#define RTCSA_512 0x07 +#define RTCSA_256 0x08 +#define RTCSA_128 0x09 +#define RTCSA_NOPROF RTCSA_128 +#define RTC_NOPROFRATE 128 +#define RTCSA_64 0x0a +#define RTCSA_32 0x0b #define RTC_STATUSB 0x0b /* status register B */ +#define RTCSB_HALT 0x80 /* stop clock updates */ +#define RTCSB_PINTR 0x40 /* periodic clock interrupt */ +#define RTCSB_24HR 0x02 /* 24-hour mode */ #define RTC_INTR 0x0c /* status register C (R) interrupt source */ #define RTCIR_UPDATE 0x10 /* update intr */ -- cgit v1.1