Re: Using %stick where available
Michael <[email protected]>
| Newsgroups | gmane.os.netbsd.ports.sparc64 |
|---|---|
| Message-ID | <[email protected]> |
Hello, On Nov 7, 2012, at 7:04 AM, Takeshi Nakayama wrote: >>>> Michael <[email protected]> wrote > >> 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. > > It looks ok to me, but as Eric reported it needs some fix. Yeah, I have no US-IIe hardware so I couldn't test it there, which is one of the reasons why I posted the patch here first. >> + struct cpu_info *ci = curcpu(); > > Replace the following curcpu()s with ci. Done. > I think the following is better for consistency. > > - long clk; > + long clk, sclk; Yeah, I left it an int because that's what we get from the PROM, but you're right, they should be the same type. >> + sclk = prom_getpropint(findroot(), "stick-frequency", 0); >> + ci->ci_system_clockrate[0] = sclk; >> + ci->ci_system_clockrate[1] = sclk / 1000000; > > US-IIe has system tick register, but its implementation is > different to US-III one. It can be used via memory mapped system > registers, not via ancillary state register (%asr24). Seriously? I expected trouble with US-IIe but not quite like that. > So, I suggest not to use it on US-IIe as below. > > if (!CPU_IS_HUMMINGBIRD()) { > sclk = prom_getpropint(findroot(), "stick-frequency", 0); > ci->ci_system_clockrate[0] = sclk; > ci->ci_system_clockrate[1] = sclk / 1000000; > } Done, slightly changed to make sure ci_system_clockrate[] is 0 if we don't have %stick. > And, put the following into include/psl.h. > > #define CPU_IS_HUMMINGBIRD() (GETVER_CPU_IMPL() == IMPL_HUMMINGBIRD) >> 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) > > CI_SYSCLOCKRATE is unused. I put it there because CI_CLOCKRATE is used in delay() which we may want to adapt to %stick / CI_SYSCLOCKRATE at some point. I'll leave it out in the revised patch. >> +/* >> + * setstick(long) >> + */ >> +ENTRY(setstick) >> + retl >> + wr %o0, STICK >> + >> +/* >> + * long getstick(void) >> + */ >> +ENTRY(getstick) >> + retl >> + rd STICK, %o0 > > I'll replace them with inline functions like settick/gettick after > you commited. I put them there because I couldn't get the inline assembler to do what I want ( serious lack of practice on my part ) > BB_ERRATA_1 is an errata of US-II, so #ifdef BB_ERRATA_1 cases are > unnecessary. Removed them. Attached is the revised patch, thanks for looking at this! have fun Michael
stick_2.patch
(application/octet-stream, 11.2 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 7 Nov 2012 17:26:57 -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 7 Nov 2012 17:26:58 -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: include/psl.h
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/include/psl.h,v
retrieving revision 1.49
diff -u -w -r1.49 psl.h
--- include/psl.h 12 Jul 2011 07:51:34 -0000 1.49
+++ include/psl.h 7 Nov 2012 17:26:58 -0000
@@ -330,6 +330,7 @@
#define GETVER_CPU_IMPL() ((getver() & VER_IMPL) >> VER_IMPL_SHIFT)
#define GETVER_CPU_MANUF() ((getver() & VER_MANUF) >> VER_MANUF_SHIFT)
#define CPU_IS_SPITFIRE() (GETVER_CPU_IMPL() == IMPL_SPITFIRE)
+#define CPU_IS_HUMMINGBIRD() (GETVER_CPU_IMPL() == IMPL_HUMMINGBIRD)
#define CPU_IS_USIIIi() ((GETVER_CPU_IMPL() == IMPL_JALAPENO) || \
(GETVER_CPU_IMPL() == IMPL_SERRANO))
#define CPU_IS_USIII_UP() (GETVER_CPU_IMPL() >= IMPL_CHEETAH)
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 7 Nov 2012 17:26:58 -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
@@ -361,17 +402,24 @@
}
/* Make sure we have a sane cpu_clockrate -- we'll need it */
- if (!curcpu()->ci_cpu_clockrate[0]) {
+ if (!ci->ci_cpu_clockrate[0]) {
/* Default to 200MHz clock XXXXX */
- curcpu()->ci_cpu_clockrate[0] = 200000000;
- curcpu()->ci_cpu_clockrate[1] = 200000000 / 1000000;
+ ci->ci_cpu_clockrate[0] = 200000000;
+ ci->ci_cpu_clockrate[1] = 200000000 / 1000000;
}
/* 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 =
+ ci->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)ci->ci_system_clockrate[1]);
+ /* We don't have a counter-timer -- use %stick */
+ 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 7 Nov 2012 17:26:58 -0000
@@ -242,7 +242,7 @@
cpu_attach(device_t parent, device_t dev, void *aux)
{
int node;
- long clk;
+ long clk, sclk = 0;
struct mainbus_attach_args *ma = aux;
struct cpu_info *ci;
const char *sep;
@@ -299,12 +299,23 @@
ci->ci_cpu_clockrate[1] = clk / 1000000;
}
+ if (!CPU_IS_HUMMINGBIRD()) {
+ 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 +463,8 @@
sync_tick = 1;
membar_Sync();
settick(0);
+ if (ci->ci_system_clockrate[0] != 0)
+ setstick(0);
setpstate(pstate);
@@ -480,8 +493,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/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 7 Nov 2012 17:26:59 -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,77 @@
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
+ retl
+ wr %o2, STICK_CMPR
+
+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
+ retl
+ wr %o2, STICK_CMPR
ENTRY(setjmp)
save %sp, -CC64FSZ, %sp ! Need a frame to return to.
PGP.sig
(application/pgp-signature, 518 B) - not displayed