summaryrefslogtreecommitdiff
path: root/sys/arch/i386/isa/clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/i386/isa/clock.c')
-rw-r--r--sys/arch/i386/isa/clock.c70
1 files changed, 58 insertions, 12 deletions
diff --git a/sys/arch/i386/isa/clock.c b/sys/arch/i386/isa/clock.c
index aed8f785522..0d1a0e7440f 100644
--- a/sys/arch/i386/isa/clock.c
+++ b/sys/arch/i386/isa/clock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clock.c,v 1.21 2000/01/29 04:27:48 mickey Exp $ */
+/* $OpenBSD: clock.c,v 1.22 2001/02/13 17:19:12 ho Exp $ */
/* $NetBSD: clock.c,v 1.39 1996/05/12 23:11:54 mycroft Exp $ */
/*-
@@ -89,11 +89,13 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/*
* Primitive clock interrupt routines.
*/
+#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/kernel.h>
#include <sys/device.h>
+#include <sys/timeout.h>
#include <machine/cpu.h>
#include <machine/intr.h>
@@ -141,6 +143,7 @@ void rtcput __P((mc_todregs *));
int hexdectodec __P((int));
int dectohexdec __P((int));
int rtcintr __P((void *));
+void rtcdrain __P((void *));
__inline u_int mc146818_read __P((void *, u_int));
__inline void mc146818_write __P((void *, u_int, u_int));
@@ -157,9 +160,16 @@ mc146818_read(sc, reg)
void *sc; /* XXX use it? */
u_int reg;
{
+ int s;
+ u_char v;
+ s = splhigh();
outb(IO_RTC, reg);
- return (inb(IO_RTC+1));
+ DELAY(1);
+ v = inb(IO_RTC+1);
+ DELAY(1);
+ splx(s);
+ return (v);
}
__inline void
@@ -167,9 +177,14 @@ mc146818_write(sc, reg, datum)
void *sc; /* XXX use it? */
u_int reg, datum;
{
+ int s;
+ s = splhigh();
outb(IO_RTC, reg);
+ DELAY(1);
outb(IO_RTC+1, datum);
+ DELAY(1);
+ splx(s);
}
void
@@ -188,6 +203,21 @@ startrtclock()
}
void
+rtcdrain(void *v)
+{
+ struct timeout *to = (struct timeout *)v;
+
+ timeout_del(to);
+
+ /*
+ * Drain any un-acknowledged RTC interrupts.
+ * See comment in cpu_initclocks().
+ */
+ while (mc146818_read(NULL, MC_REGC) & MC_REGC_PF)
+ ; /* Nothing. */
+}
+
+void
initrtclock()
{
/* initialize 8253 clock */
@@ -205,7 +235,7 @@ clockintr(arg)
struct clockframe *frame = arg; /* not strictly necessary */
hardclock(frame);
- return 1;
+ return (1);
}
int
@@ -213,14 +243,17 @@ rtcintr(arg)
void *arg;
{
struct clockframe *frame = arg; /* not strictly neccecary */
- u_int stat;
+ u_int stat = 0;
- stat = mc146818_read(NULL, MC_REGC);
- if (stat & MC_REGC_PF) {
+ /*
+ * If rtcintr is 'late', next intr may happen immediately.
+ * Get them all. (Also, see comment in cpu_initclocks().)
+ */
+ while (mc146818_read(NULL, MC_REGC) & MC_REGC_PF) {
statclock(frame);
- return 1;
+ stat = 1;
}
- return 0;
+ return (stat);
}
int
@@ -381,6 +414,7 @@ calibrate_cyclecounter()
void
cpu_initclocks()
{
+ static struct timeout rtcdrain_timeout;
stathz = 128;
profhz = 1024;
@@ -395,6 +429,18 @@ cpu_initclocks()
mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_128_Hz);
mc146818_write(NULL, MC_REGB, MC_REGB_24HR | MC_REGB_PIE);
+
+ /*
+ * On a number of i386 systems, the rtc will fail to start when booting
+ * the system. This is due to us missing to acknowledge an interrupt
+ * during early stages of the boot process. If we do not acknowledge
+ * the interrupt, the rtc clock will not generate further interrupts.
+ * To solve this, once interrupts are enabled, use a timeout (once)
+ * to drain any un-acknowledged rtc interrupt(s).
+ */
+
+ timeout_set(&rtcdrain_timeout, rtcdrain, (void *)&rtcdrain_timeout);
+ timeout_add(&rtcdrain_timeout, 1);
}
int
@@ -436,8 +482,8 @@ static int timeset;
* check whether the CMOS layout is "standard"-like (ie, not PS/2-like),
* to be called at splclock()
*/
-static int cmoscheck __P((void));
-static int
+int cmoscheck __P((void));
+int
cmoscheck()
{
int i;
@@ -463,8 +509,8 @@ int rtc_update_century = 0;
* into full width.
* Being here, deal with the CMOS century byte.
*/
-static int clock_expandyear __P((int));
-static int
+int clock_expandyear __P((int));
+int
clock_expandyear(clockyear)
int clockyear;
{