summaryrefslogtreecommitdiff
path: root/sys/arch/sparc64
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2008-08-10 14:13:06 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2008-08-10 14:13:06 +0000
commitf04415c248c8f15e080efacac20317cd1a919148 (patch)
treebdef1ca85515291edba0beddd09ca20d37a79048 /sys/arch/sparc64
parentc31485f39d2672744106d3bd06b2bf41d61b682c (diff)
Use the STICK logic on UltraSPARC-IIe to generate clock interrupts.
Diffstat (limited to 'sys/arch/sparc64')
-rw-r--r--sys/arch/sparc64/include/cpu.h6
-rw-r--r--sys/arch/sparc64/include/ctlreg.h4
-rw-r--r--sys/arch/sparc64/sparc64/clock.c64
-rw-r--r--sys/arch/sparc64/sparc64/locore.s54
4 files changed, 116 insertions, 12 deletions
diff --git a/sys/arch/sparc64/include/cpu.h b/sys/arch/sparc64/include/cpu.h
index de4057bd262..4fa56d7688f 100644
--- a/sys/arch/sparc64/include/cpu.h
+++ b/sys/arch/sparc64/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.65 2008/08/07 21:25:48 kettenis Exp $ */
+/* $OpenBSD: cpu.h,v 1.66 2008/08/10 14:13:05 kettenis Exp $ */
/* $NetBSD: cpu.h,v 1.28 2001/06/14 22:56:58 thorpej Exp $ */
/*
@@ -250,12 +250,8 @@ void dumpconf(void);
caddr_t reserve_dumppages(caddr_t);
/* clock.c */
struct timeval;
-int tickintr(void *); /* level 10 (tick) interrupt code */
-int sys_tickintr(void *); /* level 10 (sys_tick) interrupt code */
int clockintr(void *);/* level 10 (clock) interrupt code */
int statintr(void *); /* level 14 (statclock) interrupt code */
-void tick_start(void);
-void sys_tick_start(void);
/* locore.s */
struct fpstate64;
void savefpstate(struct fpstate64 *);
diff --git a/sys/arch/sparc64/include/ctlreg.h b/sys/arch/sparc64/include/ctlreg.h
index 68b13fcf01b..0a9cc50bca4 100644
--- a/sys/arch/sparc64/include/ctlreg.h
+++ b/sys/arch/sparc64/include/ctlreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ctlreg.h,v 1.20 2008/08/07 21:25:48 kettenis Exp $ */
+/* $OpenBSD: ctlreg.h,v 1.21 2008/08/10 14:13:05 kettenis Exp $ */
/* $NetBSD: ctlreg.h,v 1.28 2001/08/06 23:55:34 eeh Exp $ */
/*
@@ -728,9 +728,11 @@ void flush(void *p)
/* Read 64-bit %tick and %sys_tick registers. */
#define tick() (sparc_rdpr(tick) & TICK_TICKS)
#define sys_tick() (sparc_rd(sys_tick) & TICK_TICKS)
+extern u_int64_t stick(void);
extern void tickcmpr_set(u_int64_t);
extern void sys_tickcmpr_set(u_int64_t);
+extern void stickcmpr_set(u_int64_t);
#endif /* _LOCORE */
#endif /* _SPARC64_CTLREG_ */
diff --git a/sys/arch/sparc64/sparc64/clock.c b/sys/arch/sparc64/sparc64/clock.c
index 329cf66cc83..8dc5674c559 100644
--- a/sys/arch/sparc64/sparc64/clock.c
+++ b/sys/arch/sparc64/sparc64/clock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clock.c,v 1.46 2008/08/07 21:25:47 kettenis Exp $ */
+/* $OpenBSD: clock.c,v 1.47 2008/08/10 14:13:05 kettenis Exp $ */
/* $NetBSD: clock.c,v 1.41 2001/07/24 19:29:25 eeh Exp $ */
/*
@@ -132,7 +132,15 @@ int statvar = 8192;
int statmin; /* statclock interval - 1/2*variance */
static long tick_increment;
-int schedintr(void *);
+
+void tick_start(void);
+void sys_tick_start(void);
+void stick_start(void);
+
+int tickintr(void *);
+int sys_tickintr(void *);
+int stickintr(void *);
+int schedintr(void *);
static struct intrhand level10 = { clockintr };
static struct intrhand level0 = { tickintr };
@@ -615,10 +623,15 @@ cpu_initclocks(void)
/* We only have one timer so we have no statclock */
stathz = 0;
- if (sys_tick_rate > 0 && impl != IMPL_HUMMINGBIRD) {
+ if (sys_tick_rate > 0) {
tick_increment = sys_tick_rate / hz;
- level0.ih_fun = sys_tickintr;
- cpu_start_clock = sys_tick_start;
+ if (impl == IMPL_HUMMINGBIRD) {
+ level0.ih_fun = stickintr;
+ cpu_start_clock = stick_start;
+ } else {
+ level0.ih_fun = sys_tickintr;
+ cpu_start_clock = sys_tick_start;
+ }
} else {
/* set the next interrupt time */
tick_increment = cpu_clockrate / hz;
@@ -799,6 +812,30 @@ sys_tickintr(cap)
return (1);
}
+int
+stickintr(cap)
+ void *cap;
+{
+ struct cpu_info *ci = curcpu();
+ u_int64_t s;
+
+ /*
+ * Do we need to worry about overflow here?
+ */
+ while (ci->ci_tick < stick()) {
+ ci->ci_tick += tick_increment;
+ hardclock((struct clockframe *)cap);
+ level0.ih_count.ec_count++;
+ }
+
+ /* Reset the interrupt. */
+ s = intr_disable();
+ stickcmpr_set(ci->ci_tick);
+ intr_restore(s);
+
+ return (1);
+}
+
/*
* Level 14 (stat clock) interrupt handler.
*/
@@ -974,6 +1011,23 @@ sys_tick_start(void)
intr_restore(s);
}
+void
+stick_start(void)
+{
+ struct cpu_info *ci = curcpu();
+ u_int64_t s;
+
+ /*
+ * Try to make the tick interrupts as synchronously as possible on
+ * all CPUs to avoid inaccuracies for migrating processes.
+ */
+
+ s = intr_disable();
+ ci->ci_tick = roundup(stick(), tick_increment);
+ stickcmpr_set(ci->ci_tick);
+ intr_restore(s);
+}
+
u_int
tick_get_timecount(struct timecounter *tc)
{
diff --git a/sys/arch/sparc64/sparc64/locore.s b/sys/arch/sparc64/sparc64/locore.s
index f996fa7d13f..4b1a0d47d08 100644
--- a/sys/arch/sparc64/sparc64/locore.s
+++ b/sys/arch/sparc64/sparc64/locore.s
@@ -1,4 +1,4 @@
-/* $OpenBSD: locore.s,v 1.151 2008/08/07 21:25:47 kettenis Exp $ */
+/* $OpenBSD: locore.s,v 1.152 2008/08/10 14:13:05 kettenis Exp $ */
/* $NetBSD: locore.s,v 1.137 2001/08/13 06:10:10 jdolecek Exp $ */
/*
@@ -8939,6 +8939,58 @@ ENTRY(sys_tickcmpr_set)
retl
nop
+/*
+ * Support for the STICK logic found on the integrated PCI host bridge
+ * of Hummingbird (UltraSPARC-IIe). The chip designers made the
+ * brilliant decision to split the 64-bit counters into two 64-bit
+ * aligned 32-bit registers, making atomic access impossible. This
+ * means we have to check for wraparound in various places. Sigh.
+ */
+
+#define STICK_CMP_LOW 0x1fe0000f060
+#define STICK_CMP_HIGH 0x1fe0000f068
+#define STICK_REG_LOW 0x1fe0000f070
+#define STICK_REG_HIGH 0x1fe0000f078
+
+ENTRY(stick)
+ setx STICK_REG_LOW, %o1, %o3
+0:
+ ldxa [%o3] ASI_PHYS_NON_CACHED, %o0
+ add %o3, (STICK_REG_HIGH - STICK_REG_LOW), %o4
+ ldxa [%o4] ASI_PHYS_NON_CACHED, %o1
+ ldxa [%o3] ASI_PHYS_NON_CACHED, %o2
+ cmp %o2, %o0 ! Check for wraparound
+ blu,pn %icc, 0b
+ sllx %o1, 33, %o1 ! Clear the MSB
+ srlx %o1, 1, %o1
+ retl
+ or %o2, %o1, %o0
+
+ENTRY(stickcmpr_set)
+ setx STICK_CMP_HIGH, %o1, %o3
+ mov 8, %o2 ! Initial step size
+1:
+ srlx %o0, 32, %o1
+ stxa %o1, [%o3] ASI_PHYS_NON_CACHED
+ add %o3, (STICK_CMP_LOW - STICK_CMP_HIGH), %o4
+ stxa %o0, [%o4] ASI_PHYS_NON_CACHED
+
+ add %o3, (STICK_REG_LOW - STICK_CMP_HIGH), %o4
+ ldxa [%o4] ASI_PHYS_NON_CACHED, %o1
+ add %o3, (STICK_REG_HIGH - STICK_CMP_HIGH), %o4
+ ldxa [%o4] ASI_PHYS_NON_CACHED, %o5
+ sllx %o5, 32, %o5
+ or %o1, %o5, %o1
+
+ cmp %o0, %o1 ! Make sure the value we wrote
+ bg,pt %xcc, 2f ! was in the future
+ add %o0, %o2, %o0 ! If not, add the step size, double
+ ba,pt %xcc, 1b ! the step size and try again.
+ sllx %o2, 1, %o2
+2:
+ retl
+ nop
+
#define MICROPERSEC (1000000)
.data
.align 16