diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2008-08-10 14:13:06 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2008-08-10 14:13:06 +0000 |
commit | f04415c248c8f15e080efacac20317cd1a919148 (patch) | |
tree | bdef1ca85515291edba0beddd09ca20d37a79048 /sys/arch/sparc64 | |
parent | c31485f39d2672744106d3bd06b2bf41d61b682c (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.h | 6 | ||||
-rw-r--r-- | sys/arch/sparc64/include/ctlreg.h | 4 | ||||
-rw-r--r-- | sys/arch/sparc64/sparc64/clock.c | 64 | ||||
-rw-r--r-- | sys/arch/sparc64/sparc64/locore.s | 54 |
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 |