summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2013-02-17 18:42:30 +0000
committermav <mav@FreeBSD.org>2013-02-17 18:42:30 +0000
commita8b029c7cfe6220819618eb3e2041a771c97b83b (patch)
tree510b0e561b28364a36689b25592e08e597967514
parent711b357b3d2aab9c3be4ca2268541fcdf62b796f (diff)
downloadFreeBSD-src-a8b029c7cfe6220819618eb3e2041a771c97b83b.zip
FreeBSD-src-a8b029c7cfe6220819618eb3e2041a771c97b83b.tar.gz
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.
-rw-r--r--sys/x86/isa/clock.c25
1 files 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
OpenPOWER on IntegriCloud