- Fix the locking around the i8254. Values for the TSC clock and lapic

delay function were wildly inaccurate due to multiple CPUs competing
  in DELAY() during calibration, confusing the clock chip.
- Use i8254_delay() explictly in a few more places.
This commit is contained in:
ad 2007-12-04 16:05:34 +00:00
parent 05237843cf
commit 83caeda725
2 changed files with 34 additions and 41 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: clock.c,v 1.13 2007/11/14 17:55:00 ad Exp $ */
/* $NetBSD: clock.c,v 1.14 2007/12/04 16:05:34 ad Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
@ -121,7 +121,7 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.13 2007/11/14 17:55:00 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.14 2007/12/04 16:05:34 ad Exp $");
/* #define CLOCKDEBUG */
/* #define CLOCK_PARANOIA */
@ -257,22 +257,21 @@ static int ticks[6];
static unsigned int
gettick_broken_latch(void)
{
u_long flags;
int v1, v2, v3;
int w1, w2, w3;
int s;
/* Don't want someone screwing with the counter while we're here. */
flags = x86_read_psl();
x86_disable_intr();
s = splhigh();
__cpu_simple_lock(&tmr_lock);
v1 = inb(IO_TIMER1+TIMER_CNTR0);
v1 |= inb(IO_TIMER1+TIMER_CNTR0) << 8;
v2 = inb(IO_TIMER1+TIMER_CNTR0);
v2 |= inb(IO_TIMER1+TIMER_CNTR0) << 8;
v3 = inb(IO_TIMER1+TIMER_CNTR0);
v3 |= inb(IO_TIMER1+TIMER_CNTR0) << 8;
x86_write_psl(flags);
__cpu_simple_unlock(&tmr_lock);
splx(s);
#ifdef CLOCK_PARANOIA
if (clock_debug) {
@ -371,7 +370,7 @@ startrtclock(void)
}
/*
* Must be called at splclock().
* Must be called at splsched().
*/
static void
tickle_tc(void)
@ -418,31 +417,25 @@ u_int
i8254_get_timecount(struct timecounter *tc)
{
u_int count;
u_char high, low;
u_long flags;
uint16_t rdval;
int s;
/* Don't want someone screwing with the counter while we're here. */
flags = x86_read_psl();
x86_disable_intr();
s = splhigh();
__cpu_simple_lock(&tmr_lock);
/* Select timer0 and latch counter value. */
outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
low = inb(IO_TIMER1 + TIMER_CNTR0);
high = inb(IO_TIMER1 + TIMER_CNTR0);
count = rtclock_tval - ((high << 8) | low);
/* insb to make the read atomic */
insb(IO_TIMER1+TIMER_CNTR0, &rdval, 2);
count = rtclock_tval - rdval;
if (rtclock_tval && (count < i8254_lastcount || !i8254_ticked)) {
i8254_ticked = 1;
i8254_offset += rtclock_tval;
}
i8254_lastcount = count;
count += i8254_offset;
__cpu_simple_unlock(&tmr_lock);
x86_write_psl(flags);
splx(s);
return (count);
}
@ -450,21 +443,23 @@ i8254_get_timecount(struct timecounter *tc)
unsigned int
gettick(void)
{
u_long flags;
u_char lo, hi;
uint16_t rdval;
int s;
if (clock_broken_latch)
return (gettick_broken_latch());
/* Don't want someone screwing with the counter while we're here. */
flags = x86_read_psl();
x86_disable_intr();
s = splhigh();
__cpu_simple_lock(&tmr_lock);
/* Select counter 0 and latch it. */
outb(IO_TIMER1+TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
lo = inb(IO_TIMER1+TIMER_CNTR0);
hi = inb(IO_TIMER1+TIMER_CNTR0);
x86_write_psl(flags);
return ((hi << 8) | lo);
/* insb to make the read atomic */
insb(IO_TIMER1+TIMER_CNTR0, &rdval, 2);
__cpu_simple_unlock(&tmr_lock);
splx(s);
return rdval;
}
/*

View File

@ -1,13 +1,11 @@
/* $NetBSD: cpu.c,v 1.10 2007/12/02 20:34:41 ad Exp $ */
/* $NetBSD: cpu.c,v 1.11 2007/12/04 16:05:34 ad Exp $ */
/*-
* Copyright (c) 2000, 2006, 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by RedBack Networks Inc.
*
* Author: Bill Sommerfeld
* by Bill Sommerfeld of RedBack Networks Inc, and by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -71,7 +69,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.10 2007/12/02 20:34:41 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.11 2007/12/04 16:05:34 ad Exp $");
#include "opt_ddb.h"
#include "opt_multiprocessor.h"
@ -576,7 +574,7 @@ cpu_start_secondary(ci)
* wait for it to become ready
*/
for (i = 100000; (!(ci->ci_flags & CPUF_PRESENT)) && i>0;i--) {
delay(10);
i8254_delay(10);
}
if ((ci->ci_flags & CPUF_PRESENT) == 0) {
aprint_error("%s: failed to become ready\n",
@ -598,7 +596,7 @@ cpu_boot_secondary(ci)
atomic_or_32(&ci->ci_flags, CPUF_GO);
for (i = 100000; (!(ci->ci_flags & CPUF_RUNNING)) && i>0;i--) {
DELAY(10);
i8254_delay(10);
}
if ((ci->ci_flags & CPUF_RUNNING) == 0) {
aprint_error("%s: failed to start\n", ci->ci_dev->dv_xname);
@ -829,7 +827,7 @@ mp_cpu_start(struct cpu_info *ci)
if ((error = x86_ipi_init(ci->ci_apicid)) != 0)
return error;
delay(10000);
i8254_delay(10000);
if (cpu_feature & CPUID_APIC) {
@ -837,13 +835,13 @@ mp_cpu_start(struct cpu_info *ci)
ci->ci_apicid,
LAPIC_DLMODE_STARTUP)) != 0)
return error;
delay(200);
i8254_delay(200);
if ((error = x86_ipi(MP_TRAMPOLINE/PAGE_SIZE,
ci->ci_apicid,
LAPIC_DLMODE_STARTUP)) != 0)
return error;
delay(200);
i8254_delay(200);
}
}
#endif