summaryrefslogtreecommitdiffstats
path: root/sys/x86
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2010-09-18 07:36:43 +0000
committermav <mav@FreeBSD.org>2010-09-18 07:36:43 +0000
commitbbf7bbb468fbaeed9848ed2787aede299cb1f8fd (patch)
treec597b381b4f810cf282bb3b732d0413e9f53fa6c /sys/x86
parenta1682974694d69a29fe86e5c0eb7a45c603e97ef (diff)
downloadFreeBSD-src-bbf7bbb468fbaeed9848ed2787aede299cb1f8fd.zip
FreeBSD-src-bbf7bbb468fbaeed9848ed2787aede299cb1f8fd.tar.gz
Restore pre-r212778 optimization, skipping timer reprogramming when it is
not neccessary. It allows to avoid time counter jump of up to 1/18s, when base frequency slightly tuned via machdep.i8254_freq sysctl. Fix few style things. Suggested by: bde
Diffstat (limited to 'sys/x86')
-rw-r--r--sys/x86/isa/clock.c46
1 files changed, 27 insertions, 19 deletions
diff --git a/sys/x86/isa/clock.c b/sys/x86/isa/clock.c
index 4fb41d8..5e917c1 100644
--- a/sys/x86/isa/clock.c
+++ b/sys/x86/isa/clock.c
@@ -124,6 +124,8 @@ struct attimer_softc {
};
static struct attimer_softc *attimer_sc = NULL;
+static int timer0_period = -2;
+
/* Values for timerX_state: */
#define RELEASED 0
#define RELEASE_PENDING 1
@@ -367,36 +369,41 @@ DELAY(int n)
static void
set_i8254_freq(int mode, uint32_t period)
{
- int val;
+ int new_count;
mtx_lock_spin(&clock_lock);
- if (period == 0)
- val = 0x10000;
- else
- val = min(((uint64_t)i8254_freq * period) >> 32, 0x10000);
- if (val == 0x10000)
- i8254_max_count = 0xffff;
- else
- i8254_max_count = val;
- if (mode == MODE_STOP && i8254_timecounter)
- mode = MODE_PERIODIC;
+ if (mode == MODE_STOP) {
+ if (i8254_timecounter) {
+ mode = MODE_PERIODIC;
+ new_count = 0x10000;
+ } else
+ new_count = -1;
+ } else {
+ new_count = min(((uint64_t)i8254_freq * period +
+ 0x80000000LLU) >> 32, 0x10000);
+ }
+ if (new_count == timer0_period)
+ goto out;
+ i8254_max_count = ((new_count & ~0xffff) != 0) ? 0xffff : new_count;
+ timer0_period = (mode == MODE_PERIODIC) ? new_count : -1;
switch (mode) {
case MODE_STOP:
outb(TIMER_MODE, TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT);
- outb(TIMER_CNTR0, 0xff);
- outb(TIMER_CNTR0, 0xff);
+ outb(TIMER_CNTR0, 0);
+ outb(TIMER_CNTR0, 0);
break;
case MODE_PERIODIC:
outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
- outb(TIMER_CNTR0, val & 0xff);
- outb(TIMER_CNTR0, val >> 8);
+ 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);
- outb(TIMER_CNTR0, val & 0xff);
- outb(TIMER_CNTR0, val >> 8);
+ outb(TIMER_CNTR0, new_count & 0xff);
+ outb(TIMER_CNTR0, new_count >> 8);
break;
}
+out:
mtx_unlock_spin(&clock_lock);
}
@@ -404,7 +411,8 @@ static void
i8254_restore(void)
{
- if (attimer_sc)
+ timer0_period = -2;
+ if (attimer_sc != NULL)
set_i8254_freq(attimer_sc->mode, attimer_sc->period);
else
set_i8254_freq(0, 0);
@@ -473,7 +481,7 @@ sysctl_machdep_i8254_freq(SYSCTL_HANDLER_ARGS)
error = sysctl_handle_int(oidp, &freq, 0, req);
if (error == 0 && req->newptr != NULL) {
i8254_freq = freq;
- if (attimer_sc) {
+ if (attimer_sc != NULL) {
set_i8254_freq(attimer_sc->mode, attimer_sc->period);
attimer_sc->tc.tc_frequency = freq;
} else {
OpenPOWER on IntegriCloud