From a8b029c7cfe6220819618eb3e2041a771c97b83b Mon Sep 17 00:00:00 2001 From: mav Date: Sun, 17 Feb 2013 18:42:30 +0000 Subject: MFcalloutng: Microoptimize i8254 one-shot operation mode (disabled by default to allow timecounter functionality) by not writing to mode and MSB registers when it is not required. This saves several microseconds of CPU time per call, reducing minimal measured interrupts interval to 19.5us. --- sys/x86/isa/clock.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/sys/x86/isa/clock.c b/sys/x86/isa/clock.c index a74c11f..42cc448 100644 --- a/sys/x86/isa/clock.c +++ b/sys/x86/isa/clock.c @@ -125,6 +125,8 @@ struct attimer_softc { static struct attimer_softc *attimer_sc = NULL; static int timer0_period = -2; +static int timer0_mode = 0xffff; +static int timer0_last = 0xffff; /* Values for timerX_state: */ #define RELEASED 0 @@ -404,7 +406,7 @@ DELAY(int n) static void set_i8254_freq(int mode, uint32_t period) { - int new_count; + int new_count, new_mode; mtx_lock_spin(&clock_lock); if (mode == MODE_STOP) { @@ -423,21 +425,34 @@ set_i8254_freq(int mode, uint32_t period) timer0_period = (mode == MODE_PERIODIC) ? new_count : -1; switch (mode) { case MODE_STOP: - outb(TIMER_MODE, TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT); + new_mode = TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT; + outb(TIMER_MODE, new_mode); outb(TIMER_CNTR0, 0); outb(TIMER_CNTR0, 0); break; case MODE_PERIODIC: - outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); + new_mode = TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT; + outb(TIMER_MODE, new_mode); outb(TIMER_CNTR0, new_count & 0xff); outb(TIMER_CNTR0, new_count >> 8); break; case MODE_ONESHOT: - outb(TIMER_MODE, TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT); + if (new_count < 256 && timer0_last < 256) { + new_mode = TIMER_SEL0 | TIMER_INTTC | TIMER_LSB; + if (new_mode != timer0_mode) + outb(TIMER_MODE, new_mode); + outb(TIMER_CNTR0, new_count & 0xff); + break; + } + new_mode = TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT; + if (new_mode != timer0_mode) + outb(TIMER_MODE, new_mode); outb(TIMER_CNTR0, new_count & 0xff); outb(TIMER_CNTR0, new_count >> 8); break; } + timer0_mode = new_mode; + timer0_last = new_count; out: mtx_unlock_spin(&clock_lock); } @@ -447,6 +462,8 @@ i8254_restore(void) { timer0_period = -2; + timer0_mode = 0xffff; + timer0_last = 0xffff; if (attimer_sc != NULL) set_i8254_freq(attimer_sc->mode, attimer_sc->period); else -- cgit v1.1