-/* $OpenBSD: cpu.h,v 1.64 2008/08/07 18:46:04 kettenis Exp $ */
+/* $OpenBSD: cpu.h,v 1.65 2008/08/07 21:25:48 kettenis Exp $ */
/* $NetBSD: cpu.h,v 1.28 2001/06/14 22:56:58 thorpej Exp $ */
/*
#define CLKF_PC(framep) ((framep)->t.tf_pc)
#define CLKF_INTR(framep) ((framep)->saved_intr_level != 0)
+extern void (*cpu_start_clock)(void);
+
void setsoftnet(void);
#define aston(p) ((p)->p_md.md_astpending = 1)
/* 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 *);
-/* $OpenBSD: ctlreg.h,v 1.19 2008/07/12 07:37:25 kettenis Exp $ */
+/* $OpenBSD: ctlreg.h,v 1.20 2008/08/07 21:25:48 kettenis Exp $ */
/* $NetBSD: ctlreg.h,v 1.28 2001/08/06 23:55:34 eeh Exp $ */
/*
GEN_RD(asi);
GEN_RD(asr22);
+GEN_RD(sys_tick);
+GEN_RD(sys_tick_cmpr);
GEN_RDPR(cwp);
GEN_RDPR(tick);
GEN_RDPR(pstate);
: "memory");
}
-/* read 64-bit %tick register */
+/* 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 void tickcmpr_set(u_int64_t);
+extern void sys_tickcmpr_set(u_int64_t);
#endif /* _LOCORE */
#endif /* _SPARC64_CTLREG_ */
-/* $OpenBSD: clock.c,v 1.45 2008/08/07 18:46:04 kettenis Exp $ */
+/* $OpenBSD: clock.c,v 1.46 2008/08/07 21:25:47 kettenis Exp $ */
/* $NetBSD: clock.c,v 1.41 2001/07/24 19:29:25 eeh Exp $ */
/*
strlcpy(level0.ih_name, "clock", sizeof(level0.ih_name));
intr_establish(10, &level0);
+ /* We only have one timer so we have no statclock */
+ stathz = 0;
+
+ if (sys_tick_rate > 0 && impl != IMPL_HUMMINGBIRD) {
+ tick_increment = sys_tick_rate / hz;
+ level0.ih_fun = sys_tickintr;
+ cpu_start_clock = sys_tick_start;
+ } else {
+ /* set the next interrupt time */
+ tick_increment = cpu_clockrate / hz;
+ level0.ih_fun = tickintr;
+ cpu_start_clock = tick_start;
+ }
+
for (ci = cpus; ci != NULL; ci = ci->ci_next)
memcpy(&ci->ci_tickintr, &level0, sizeof(level0));
- /* We only have one timer so we have no statclock */
- stathz = 0;
+ cpu_start_clock();
- /* set the next interrupt time */
- tick_increment = cpu_clockrate / hz;
-#ifdef DEBUG
- printf("Using %%tick -- intr in %ld cycles...",
- tick_increment);
-#endif
- tick_start();
-#ifdef DEBUG
- printf("done.\n");
-#endif
return;
}
return (1);
}
+int
+sys_tickintr(cap)
+ void *cap;
+{
+ struct cpu_info *ci = curcpu();
+ u_int64_t s;
+
+ /*
+ * Do we need to worry about overflow here?
+ */
+ while (ci->ci_tick < sys_tick()) {
+ ci->ci_tick += tick_increment;
+ hardclock((struct clockframe *)cap);
+ level0.ih_count.ec_count++;
+ }
+
+ /* Reset the interrupt. */
+ s = intr_disable();
+ sys_tickcmpr_set(ci->ci_tick);
+ intr_restore(s);
+
+ return (1);
+}
+
/*
* Level 14 (stat clock) interrupt handler.
*/
intr_restore(s);
}
+void
+sys_tick_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(sys_tick(), tick_increment);
+ sys_tickcmpr_set(ci->ci_tick);
+ intr_restore(s);
+}
+
u_int
tick_get_timecount(struct timecounter *tc)
{
-/* $OpenBSD: cpu.c,v 1.45 2008/07/21 13:30:05 art Exp $ */
+/* $OpenBSD: cpu.c,v 1.46 2008/08/07 21:25:47 kettenis Exp $ */
/* $NetBSD: cpu.c,v 1.13 2001/05/26 21:27:15 chs Exp $ */
/*
us_dcache_flush_page
};
+void (*cpu_start_clock)(void);
+
/* Linked list of all CPUs in system. */
struct cpu_info *cpus = NULL;
microuptime(&ci->ci_schedstate.spc_runtime);
splx(s);
- tick_start();
+ cpu_start_clock();
SCHED_LOCK(s);
cpu_switchto(NULL, sched_chooseproc());
-/* $OpenBSD: locore.s,v 1.150 2008/08/07 18:46:04 kettenis Exp $ */
+/* $OpenBSD: locore.s,v 1.151 2008/08/07 21:25:47 kettenis Exp $ */
/* $NetBSD: locore.s,v 1.137 2001/08/13 06:10:10 jdolecek Exp $ */
/*
* If this is a %tick softint, clear it then call interrupt_vector.
*/
rd SOFTINT, %g1
- btst TICK_INT, %g1
+ set (TICK_INT|STICK_INT), %g2
+ andcc %g2, %g1, %g2
bz,pt %icc, 0f
GET_CPUINFO_VA(%g7)
- wr %g0, TICK_INT, CLEAR_SOFTINT
+ wr %g2, 0, CLEAR_SOFTINT
ba,pt %icc, setup_sparcintr
add %g7, CI_TICKINTR, %g5
0:
retl
nop
+ENTRY(sys_tickcmpr_set)
+ ba 1f
+ mov 8, %o2 ! Initial step size
+ .align 64
+1: wr %o0, 0, %sys_tick_cmpr
+ rd %sys_tick_cmpr, %g0
+
+ rd %sys_tick, %o1 ! Read current %sys_tick
+ sllx %o1, 1, %o1
+ srlx %o1, 1, %o1
+
+ cmp %o0, %o1 ! Make sure the value we wrote to
+ bg,pt %xcc, 2f ! %sys_tick_cmpr 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