summaryrefslogtreecommitdiffstats
path: root/sys/isa/atrtc.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2005-07-01 15:47:27 +0000
committerjhb <jhb@FreeBSD.org>2005-07-01 15:47:27 +0000
commit6228a1d064d22e837bd55ad6ca80cd1544908ebc (patch)
tree0a073e8b0a2263c44c677d50a0e161dda5bb47e3 /sys/isa/atrtc.c
parent2523f635902c1b1743e4cd1ca9c7d84b95bcc692 (diff)
downloadFreeBSD-src-6228a1d064d22e837bd55ad6ca80cd1544908ebc.zip
FreeBSD-src-6228a1d064d22e837bd55ad6ca80cd1544908ebc.tar.gz
Use a simpler implementation for the i8254 timecounter when using the lapic
timer since irq0 isn't being driven at hz in that case and we don't need to try to handle edge cases with rollover, etc. that require irq0 to be firing for the timecounter to actually work. Submitted by: phk Tested by: schweikh Approved by: re (scottl)
Diffstat (limited to 'sys/isa/atrtc.c')
-rw-r--r--sys/isa/atrtc.c47
1 files changed, 35 insertions, 12 deletions
diff --git a/sys/isa/atrtc.c b/sys/isa/atrtc.c
index 5350c79..e2358e4 100644
--- a/sys/isa/atrtc.c
+++ b/sys/isa/atrtc.c
@@ -136,6 +136,7 @@ static u_char rtc_statusb = RTCSB_24HR;
static u_char timer2_state;
static unsigned i8254_get_timecount(struct timecounter *tc);
+static unsigned i8254_simple_get_timecount(struct timecounter *tc);
static void set_timer_freq(u_int freq, int intr_freq);
static struct timecounter i8254_timecounter = {
@@ -532,10 +533,15 @@ set_timer_freq(u_int freq, int intr_freq)
{
int new_timer0_max_count;
+ i8254_timecounter.tc_frequency = freq;
mtx_lock_spin(&clock_lock);
timer_freq = freq;
new_timer0_max_count = hardclock_max_count = TIMER_DIV(intr_freq);
- if (new_timer0_max_count != timer0_max_count) {
+ if (using_lapic_timer) {
+ outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
+ outb(TIMER_CNTR0, 0);
+ outb(TIMER_CNTR0, 0);
+ } else if (new_timer0_max_count != timer0_max_count) {
timer0_max_count = new_timer0_max_count;
outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, timer0_max_count & 0xff);
@@ -548,11 +554,7 @@ static void
i8254_restore(void)
{
- mtx_lock_spin(&clock_lock);
- outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
- outb(TIMER_CNTR0, timer0_max_count & 0xff);
- outb(TIMER_CNTR0, timer0_max_count >> 8);
- mtx_unlock_spin(&clock_lock);
+ set_timer_freq(timer_freq, hz);
}
static void
@@ -627,7 +629,6 @@ startrtclock()
}
set_timer_freq(timer_freq, hz);
- i8254_timecounter.tc_frequency = timer_freq;
tc_init(&i8254_timecounter);
init_TSC();
@@ -782,15 +783,21 @@ cpu_initclocks()
/*
* If we aren't using the local APIC timer to drive the kernel
* clocks, setup the interrupt handler for the 8254 timer 0 so
- * that it can drive hardclock().
+ * that it can drive hardclock(). Otherwise, change the 8254
+ * timecounter to user a simpler algorithm.
*/
- if (!using_lapic_timer) {
+ if (!using_lapic_timer || 1) {
intr_add_handler("clk", 0, (driver_intr_t *)clkintr, NULL,
INTR_TYPE_CLK | INTR_FAST, NULL);
i8254_intsrc = intr_lookup_source(0);
if (i8254_intsrc != NULL)
i8254_pending =
i8254_intsrc->is_pic->pic_source_pending;
+ } else {
+ i8254_timecounter.tc_get_timecount =
+ i8254_simple_get_timecount;
+ i8254_timecounter.tc_counter_mask = 0xffff;
+ set_timer_freq(timer_freq, hz);
}
/* Initialize RTC. */
@@ -858,10 +865,8 @@ sysctl_machdep_i8254_freq(SYSCTL_HANDLER_ARGS)
*/
freq = timer_freq;
error = sysctl_handle_int(oidp, &freq, sizeof(freq), req);
- if (error == 0 && req->newptr != NULL) {
+ if (error == 0 && req->newptr != NULL)
set_timer_freq(freq, hz);
- i8254_timecounter.tc_frequency = freq;
- }
return (error);
}
@@ -869,6 +874,24 @@ SYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW,
0, sizeof(u_int), sysctl_machdep_i8254_freq, "IU", "");
static unsigned
+i8254_simple_get_timecount(struct timecounter *tc)
+{
+ u_int count;
+ u_int high, low;
+
+ mtx_lock_spin(&clock_lock);
+
+ /* Select timer0 and latch counter value. */
+ outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
+
+ low = inb(TIMER_CNTR0);
+ high = inb(TIMER_CNTR0);
+ count = 0xffff - ((high << 8) | low);
+ mtx_unlock_spin(&clock_lock);
+ return (count);
+}
+
+static unsigned
i8254_get_timecount(struct timecounter *tc)
{
u_int count;
OpenPOWER on IntegriCloud