Using %stick where available

Michael <[email protected]>
Newsgroups gmane.os.netbsd.ports.sparc64
Message-ID <[email protected]>
Hello,

the attached patch adds support for the system timer interrupt present  
in UltraSPARC-III and some later II ( like IIe and IIi with on chip  
ecache ). It hasn't seen much testing beyond 'works on my Blade 2500'.  
The purpose is to have a timer interrupt / time counter that's  
independent of the CPU's clock rate, so we can change it without  
worrying about time keeping.

cpu0 at mainbus0: SUNW,UltraSPARC-IIIi @ 1280 MHz, UPA id 0
cpu0: system tick frequency 12 MHz
cpu0: 32K instruction (32 b/l), 64K data (32 b/l), 1024K external (64  
b/l)
...
timecounter: Timecounter "stick-counter" frequency 12000000 Hz quality  
100
No counter-timer -- using %stick at 12MHz as system clock.

have fun
Michael
stick.patch (application/octet-stream, 11 KB)
Index: include/cpu.h
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/include/cpu.h,v
retrieving revision 1.98
diff -u -w -r1.98 cpu.h
--- include/cpu.h	30 Jul 2011 19:29:12 -0000	1.98
+++ include/cpu.h	6 Nov 2012 19:20:24 -0000
@@ -128,7 +128,8 @@
 
 	/* %tick and cpu frequency information */
 	u_long			ci_tick_increment;
-	uint64_t		ci_cpu_clockrate[2];
+	uint64_t		ci_cpu_clockrate[2];	/* %tick */
+	uint64_t		ci_system_clockrate[2];	/* %stick */
 
 	/* Interrupts */
 	struct intrhand		*ci_intrpending[16];
@@ -351,10 +352,12 @@
 /* clock.c */
 struct timeval;
 int	tickintr(void *);	/* level 10/14 (tick) interrupt code */
+int	stickintr(void *);	/* system tick interrupt code */
 int	clockintr(void *);	/* level 10 (clock) interrupt code */
 int	statintr(void *);	/* level 14 (statclock) interrupt code */
 int	schedintr(void *);	/* level 10 (schedclock) interrupt code */
 void	tickintr_establish(int, int (*)(void *));
+void	stickintr_establish(int, int (*)(void *));
 /* locore.s */
 struct fpstate64;
 void	savefpstate(struct fpstate64 *);
@@ -372,6 +375,10 @@
 void	switchtoctx_us(int);
 void	switchtoctx_usiii(int);
 void	next_tick(long);
+void	next_stick(long);
+void	setstick(long);
+long	getstick(void);
+
 /* trap.c */
 void	cpu_vmspace_exec(struct lwp *, vaddr_t, vaddr_t);
 int	rwindow_save(struct lwp *);
Index: include/ctlreg.h
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/include/ctlreg.h,v
retrieving revision 1.56
diff -u -w -r1.56 ctlreg.h
--- include/ctlreg.h	8 Oct 2011 08:49:07 -0000	1.56
+++ include/ctlreg.h	6 Nov 2012 19:20:24 -0000
@@ -415,6 +415,8 @@
 #define	CLEAR_SOFTINT	%asr21	/* Clears these bits */
 #define	SOFTINT		%asr22	/* Reads the register */
 #define	TICK_CMPR	%asr23
+#define	STICK		%asr24
+#define	STICK_CMPR	%asr25
 
 #define	TICK_INT	0x01	/* level-14 clock tick */
 #define	SOFTINT1	(0x1<<1)
@@ -432,6 +434,7 @@
 #define	SOFTINT13	(0x1<<13)
 #define	SOFTINT14	(0x1<<14)
 #define	SOFTINT15	(0x1<<15)
+#define	STICK_INTR	(0x1<<16)	/* system tick */
 
 /* Interrupt Dispatch -- usually reserved for cross-calls */
 #define	ASR_IDSR	0x48 /* Interrupt dispatch status reg */
Index: sparc64/clock.c
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/sparc64/clock.c,v
retrieving revision 1.106
diff -u -w -r1.106 clock.c
--- sparc64/clock.c	4 Sep 2011 12:17:46 -0000	1.106
+++ sparc64/clock.c	6 Nov 2012 19:20:24 -0000
@@ -99,6 +99,7 @@
  *  counter-timer	 timer#0	 timer#1	 %tick
  *  counter-timer + SMP	 timer#0/%tick	 -		 timer#1 or %tick
  *  no counter-timer	 %tick		 -		 %tick
+ *  US-IIIi		 %stick		 -		 %stick
  */
 
 /*
@@ -137,6 +138,7 @@
 int timerblurb = 10; /* Guess a value; used before clock is attached */
 
 static u_int tick_get_timecount(struct timecounter *);
+static u_int stick_get_timecount(struct timecounter *);
 
 /*
  * define timecounter "tick-counter"
@@ -153,6 +155,17 @@
 	NULL			/* next timecounter */
 };
 
+static struct timecounter stick_timecounter = {
+	stick_get_timecount,	/* get_timecount */
+	0,			/* no poll_pps */
+	~0u,			/* counter_mask */
+	0,                      /* frequency - set at initialisation */
+	"stick-counter",	/* name */
+	100,			/* quality */
+	0,			/* private reference - UNUSED */
+	NULL			/* next timecounter */
+};
+
 /*
  * tick_get_timecount provide current tick counter value
  */
@@ -162,6 +175,12 @@
 	return cpu_counter();
 }
 
+static u_int
+stick_get_timecount(struct timecounter *tc)
+{
+	return getstick();
+}
+
 #ifdef MULTIPROCESSOR
 static u_int counter_get_timecount(struct timecounter *);
 
@@ -329,6 +348,27 @@
 	intr_restore(s);
 }
 
+void
+stickintr_establish(int pil, int (*fun)(void *))
+{
+	int s;
+	struct intrhand *ih;
+	struct cpu_info *ci = curcpu();
+
+	ih = sparc_softintr_establish(pil, fun, NULL);
+	ih->ih_number = 1;
+	if (CPU_IS_PRIMARY(ci))
+		intr_establish(pil, true, ih);
+	ci->ci_tick_ih = ih;
+
+	/* set the next interrupt time */
+	ci->ci_tick_increment = ci->ci_system_clockrate[0] / hz;
+
+	s = intr_disable();
+	next_stick(ci->ci_tick_increment);
+	intr_restore(s);
+}
+
 /*
  * Set up the real-time and statistics clocks.  Leave stathz 0 only if
  * no alternative timer is available.
@@ -338,6 +378,7 @@
 void
 cpu_initclocks(void)
 {
+	struct cpu_info *ci = curcpu();
 #ifndef MULTIPROCESSOR
 	int statint, minint;
 #endif
@@ -370,8 +411,15 @@
 	/* Initialize the %tick register */
 	settick(0);
 
+	if (ci->ci_system_clockrate[0] == 0) {
 	tick_timecounter.tc_frequency = curcpu()->ci_cpu_clockrate[0];
 	tc_init(&tick_timecounter);
+	} else {
+		setstick(0);
+		stick_timecounter.tc_frequency = 
+		    curcpu()->ci_system_clockrate[0];
+		tc_init(&stick_timecounter);
+	}
 
 	/*
 	 * Now handle machines w/o counter-timers.
@@ -379,13 +427,21 @@
 
 	if (!timerreg_4u.t_timer || !timerreg_4u.t_clrintr) {
 
-		aprint_normal("No counter-timer -- using %%tick at %luMHz as "
-			"system clock.\n",
+		if (ci->ci_system_clockrate[0] == 0) {
+			aprint_normal("No counter-timer -- using %%tick "
+			    "at %luMHz as system clock.\n",
 			(unsigned long)curcpu()->ci_cpu_clockrate[1]);
 
 		/* We don't have a counter-timer -- use %tick */
 		tickintr_establish(PIL_CLOCK, tickintr);
+		} else {
+			aprint_normal("No counter-timer -- using %%stick "
+			    "at %luMHz as system clock.\n",
+			    (unsigned long)curcpu()->ci_system_clockrate[1]);
 
+			/* We don't have a counter-timer -- use %tick */
+			stickintr_establish(PIL_CLOCK, stickintr);
+		}
 		/* We only have one timer so we have no statclock */
 		stathz = 0;
 
@@ -525,6 +581,22 @@
 	return (1);
 }
 
+int
+stickintr(void *cap)
+{
+	int s;
+
+	hardclock((struct clockframe *)cap);
+
+	s = intr_disable();
+	/* Reset the interrupt */
+	next_stick(curcpu()->ci_tick_increment);
+	intr_restore(s);
+	curcpu()->ci_tick_evcnt.ev_count++;
+
+	return (1);
+}
+
 #ifndef MULTIPROCESSOR
 /*
  * Level 14 (stat clock) interrupt handler.
Index: sparc64/cpu.c
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/sparc64/cpu.c,v
retrieving revision 1.102
diff -u -w -r1.102 cpu.c
--- sparc64/cpu.c	27 Oct 2012 17:18:12 -0000	1.102
+++ sparc64/cpu.c	6 Nov 2012 19:20:24 -0000
@@ -250,7 +250,7 @@
 	int bigcache, cachesize;
 	char buf[100];
 	int 	totalsize = 0;
-	int 	linesize, dcachesize, icachesize;
+	int 	linesize, dcachesize, icachesize, sclk;
 
 	/* tell them what we have */
 	node = ma->ma_node;
@@ -299,12 +299,21 @@
 		ci->ci_cpu_clockrate[1] = clk / 1000000;
 	}
 
+	sclk = prom_getpropint(findroot(), "stick-frequency", 0);
+	ci->ci_system_clockrate[0] = sclk;
+	ci->ci_system_clockrate[1] = sclk / 1000000;
+
 	snprintf(buf, sizeof buf, "%s @ %s MHz",
 		prom_getpropstring(node, "name"), clockfreq(clk));
 	snprintf(cpu_model, sizeof cpu_model, "%s (%s)", machine_model, buf);
 
 	aprint_normal(": %s, UPA id %d\n", buf, ci->ci_cpuid);
 	aprint_naive("\n");
+
+	if (ci->ci_system_clockrate[0] != 0) {
+		aprint_normal_dev(dev, "system tick frequency %d MHz\n", 
+		    (int)ci->ci_system_clockrate[1]);
+	}
 	aprint_normal_dev(dev, "");
 
 	bigcache = 0;
@@ -452,6 +461,8 @@
 		sync_tick = 1;
 		membar_Sync();
 		settick(0);
+		if (ci->ci_system_clockrate[0] != 0)
+			setstick(0);
 
 		setpstate(pstate);
 
@@ -480,8 +491,12 @@
 		/* we do nothing here */
 	}
 	settick(0);
-
+	if (curcpu()->ci_system_clockrate[0] != 0) {
+		setstick(0);
+		stickintr_establish(PIL_CLOCK, stickintr);
+	} else {
 	tickintr_establish(PIL_CLOCK, tickintr);
+	}
 	spl0();
 }
 #endif /* MULTIPROCESSOR */
Index: sparc64/genassym.cf
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/sparc64/genassym.cf,v
retrieving revision 1.66
diff -u -w -r1.66 genassym.cf
--- sparc64/genassym.cf	20 Jul 2011 12:06:00 -0000	1.66
+++ sparc64/genassym.cf	6 Nov 2012 19:20:24 -0000
@@ -157,6 +157,7 @@
 define	CI_NFAULT	offsetof(struct cpu_info, ci_data.cpu_nfault)
 define	CI_NINTR	offsetof(struct cpu_info, ci_data.cpu_nintr)
 define	CI_CLOCKRATE	offsetof(struct cpu_info, ci_cpu_clockrate)
+define	CI_SYSCLOCKRATE	offsetof(struct cpu_info, ci_system_clockrate)
 define	CI_IDEPTH	offsetof(struct cpu_info, ci_idepth)
 define	CI_INTRPENDING	offsetof(struct cpu_info, ci_intrpending)
 define	CI_TICK_IH	offsetof(struct cpu_info, ci_tick_ih)
Index: sparc64/locore.s
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/sparc64/locore.s,v
retrieving revision 1.341
diff -u -w -r1.341 locore.s
--- sparc64/locore.s	17 Mar 2012 22:19:53 -0000	1.341
+++ sparc64/locore.s	6 Nov 2012 19:20:25 -0000
@@ -3270,13 +3270,18 @@
 	wrpr	%g0, PSTATE_KERN|PSTATE_IG, %pstate	! DEBUG
 #endif
 	/*
-	 * If this is a %tick softint, clear it then call interrupt_vector.
+	 * If this is a %tick or %stick softint, clear it then call
+	 * interrupt_vector. Only one of them should be enabled at any given
+	 * time.
 	 */
 	rd	SOFTINT, %g1
-	btst	1, %g1
+	mov	1, %g5
+	sllx	%g5, 16, %g3
+	or	%g5, %g3, %g5
+	andcc	%g5, %g1, %g5
 	bz,pt	%icc, 0f
 	 sethi	%hi(CPUINFO_VA+CI_TICK_IH), %g3
-	wr	%g0, 1, CLEAR_SOFTINT
+	wr	%g0, %g5, CLEAR_SOFTINT
 	ba,pt	%icc, setup_sparcintr
 	 LDPTR	[%g3 + %lo(CPUINFO_VA+CI_TICK_IH)], %g5
 0:
@@ -6058,6 +6063,93 @@
 	 wr	%o2, TICK_CMPR
 #endif
 
+/*
+ * setstick(long)
+ */
+ENTRY(setstick)
+	retl
+	 wr %o0, STICK
+
+/*
+ * long getstick(void)
+ */
+ENTRY(getstick)
+	retl
+	 rd STICK, %o0
+
+/*
+ * next_stick(long increment)
+ *
+ * Sets the %stick_cmpr register to fire off in `increment' machine
+ * cycles in the future.  Also handles %stick wraparound.  In 32-bit
+ * mode we're limited to a 32-bit increment.
+ */
+ENTRY(next_stick)
+	rd	STICK_CMPR, %o2
+	rd	STICK, %o1
+
+	mov	1, %o3		! Mask off high bits of these registers
+	sllx	%o3, 63, %o3
+	andn	%o1, %o3, %o1
+	andn	%o2, %o3, %o2
+	cmp	%o1, %o2	! Did we wrap?  (tick < tick_cmpr)
+	bgt,pt	%icc, 1f
+	 add	%o1, 1000, %o1	! Need some slack so we don't lose intrs.
+
+	/*
+	 * Handle the unlikely case of %stick wrapping.
+	 *
+	 * This should only happen every 10 years or more.
+	 *
+	 * We need to increment the time base by the size of %stick in
+	 * microseconds.  This will require some divides and multiplies
+	 * which can take time.  So we re-read %stick.
+	 *
+	 */
+
+	/* XXXXX NOT IMPLEMENTED */
+
+
+
+1:
+	add	%o2, %o0, %o2
+	andn	%o2, %o3, %o4
+	brlz,pn	%o4, Lstick_ovflw
+	 cmp	%o2, %o1	! Has this stick passed?
+	blt,pn	%xcc, 1b	! Yes
+	 nop
+
+#ifdef BB_ERRATA_1
+	ba,a	2f
+	 nop
+#else
+	retl
+	 wr	%o2, STICK_CMPR
+#endif
+
+Lstick_ovflw:
+/*
+ * When we get here tick_cmpr has wrapped, but we don't know if %stick
+ * has wrapped.  If bit 62 is set then we have not wrapped and we can
+ * use the current value of %o4 as %stick.  Otherwise we need to return
+ * to our loop with %o4 as %stick_cmpr (%o2).
+ */
+	srlx	%o3, 1, %o5
+	btst	%o5, %o1
+	bz,pn	%xcc, 1b
+	 mov	%o4, %o2
+#ifdef BB_ERRATA_1
+	ba,a	2f
+	 nop
+	.align	64
+2:	wr	%o2, STICK_CMPR
+	rd	STICK_CMPR, %g0
+	retl
+	 nop
+#else
+	retl
+	 wr	%o2, STICK_CMPR
+#endif
 
 ENTRY(setjmp)
 	save	%sp, -CC64FSZ, %sp	! Need a frame to return to.
PGP.sig (application/pgp-signature, 518 B) - not displayed
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.