romvec.pvtime is a pointer to an 'uptime' counter, calibrated in millisecond.
We use the [1st] CPU timer, running at 100Hz, to increment (+10) the counter.
This counter is used by NextStep to measure the 10 seconds delay during boot, when asking about boot options.
Signed-off-by: Olivier Danet odanet@caramail.com
--------------------------------------------------------------- diff a/arch/sparc32/romvec.c b/arch/sparc32/romvec.c --- a/arch/sparc32/romvec.c 2014-02-07 18:23:59.761220839 +0100 +++ b/arch/sparc32/romvec.c 2014-02-07 18:39:38.728186578 +0100 @@ -479,6 +479,7 @@ init_openprom(void) romvec0.pv_reboot = obp_reboot_handler; romvec0.pv_printf = obp_printf_handler; romvec0.pv_abort = obp_abort_handler; + romvec0.pv_ticks = &obp_ticks; romvec0.pv_halt = obp_halt_handler; romvec0.pv_synchook = &sync_hook; romvec0.pv_v0bootargs = &obp_argp; diff -rup a/arch/sparc32/vectors.S b/arch/sparc32/vectors.S --- a/arch/sparc32/vectors.S 2014-02-07 18:22:20.063224477 +0100 +++ b/arch/sparc32/vectors.S 2014-02-07 18:40:44.161184191 +0100 @@ -207,6 +207,10 @@ irq_entry14: sethi %hi(counter_regs), %l7 ld [%l7 + %lo(counter_regs)], %l7 ld [%l7], %g0 + sethi %hi(obp_ticks), %l7 + ld [%l7 + %lo(obp_ticks)], %l6 + add %l6, 10, %l6 + st %l6, [%l7 + %lo(obp_ticks)] jmp %l1 rett %l2
diff a/drivers/obio.c b/drivers/obio.c --- a/drivers/obio.c 2014-02-07 18:25:08.050218348 +0100 +++ b/drivers/obio.c 2014-02-07 18:56:54.126148798 +0100 @@ -253,6 +253,8 @@ ob_aux2_reset_init(uint64_t base, uint64
volatile struct sun4m_timer_regs *counter_regs;
+volatile int32_t obp_ticks; + static void ob_counter_init(uint64_t base, unsigned long offset, int ncpu) { @@ -287,7 +289,7 @@ ob_counter_init(uint64_t base, unsigned
counter_regs = (struct sun4m_timer_regs *)ofmem_map_io(base + (uint64_t)offset, sizeof(*counter_regs)); - counter_regs->cfg = 0xffffffff; + counter_regs->cfg = 0xfffffffe; counter_regs->l10_timer_limit = 0; counter_regs->cpu_timers[0].l14_timer_limit = 0x9c4000; /* see comment in obio.h */ counter_regs->cpu_timers[0].cntrl = 1; @@ -304,6 +306,8 @@ ob_counter_init(uint64_t base, unsigned push_str("address"); fword("property");
+ obp_ticks = 0; + fword("finish-device"); }
diff a/drivers/obio.h b/drivers/obio.h --- a/drivers/obio.h 2014-02-07 18:22:20.276224469 +0100 +++ b/drivers/obio.h 2014-02-07 18:45:46.417173162 +0100 @@ -88,7 +88,7 @@ struct sun4m_timer_regs { * Registers of hardware timer in sun4m. */ struct sun4m_timer_percpu { - volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */ + volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000 = 10ms period*/ volatile unsigned int l14_cur_count; };
diff a/include/drivers/drivers.h b/include/drivers/drivers.h --- a/include/drivers/drivers.h 2014-02-07 18:25:08.053218348 +0100 +++ b/include/drivers/drivers.h 2014-02-07 18:43:25.598178300 +0100 @@ -81,6 +81,7 @@ extern uint16_t graphic_depth; extern volatile unsigned char *power_reg; extern volatile unsigned int *reset_reg; extern volatile struct sun4m_timer_regs *counter_regs; +extern volatile int32_t obp_ticks;
void ob_new_obio_device(const char *name, const char *type); unsigned long ob_reg(uint64_t base, uint64_t offset, unsigned long size, int map); ---------------------------------------------------------------
On 09/02/14 17:24, Olivier Danet wrote:
romvec.pvtime is a pointer to an 'uptime' counter, calibrated in millisecond.
We use the [1st] CPU timer, running at 100Hz, to increment (+10) the counter.
This counter is used by NextStep to measure the 10 seconds delay during boot, when asking about boot options.
Signed-off-by: Olivier Danet odanet@caramail.com
diff a/arch/sparc32/romvec.c b/arch/sparc32/romvec.c --- a/arch/sparc32/romvec.c 2014-02-07 18:23:59.761220839 +0100 +++ b/arch/sparc32/romvec.c 2014-02-07 18:39:38.728186578 +0100 @@ -479,6 +479,7 @@ init_openprom(void) romvec0.pv_reboot = obp_reboot_handler; romvec0.pv_printf = obp_printf_handler; romvec0.pv_abort = obp_abort_handler;
- romvec0.pv_ticks = &obp_ticks;
romvec0.pv_halt = obp_halt_handler; romvec0.pv_synchook = &sync_hook; romvec0.pv_v0bootargs = &obp_argp; diff -rup a/arch/sparc32/vectors.S b/arch/sparc32/vectors.S --- a/arch/sparc32/vectors.S 2014-02-07 18:22:20.063224477 +0100 +++ b/arch/sparc32/vectors.S 2014-02-07 18:40:44.161184191 +0100 @@ -207,6 +207,10 @@ irq_entry14: sethi %hi(counter_regs), %l7 ld [%l7 + %lo(counter_regs)], %l7 ld [%l7], %g0
- sethi %hi(obp_ticks), %l7
- ld [%l7 + %lo(obp_ticks)], %l6
- add %l6, 10, %l6
- st %l6, [%l7 + %lo(obp_ticks)]
jmp %l1 rett %l2
diff a/drivers/obio.c b/drivers/obio.c --- a/drivers/obio.c 2014-02-07 18:25:08.050218348 +0100 +++ b/drivers/obio.c 2014-02-07 18:56:54.126148798 +0100 @@ -253,6 +253,8 @@ ob_aux2_reset_init(uint64_t base, uint64
volatile struct sun4m_timer_regs *counter_regs;
+volatile int32_t obp_ticks;
static void ob_counter_init(uint64_t base, unsigned long offset, int ncpu) { @@ -287,7 +289,7 @@ ob_counter_init(uint64_t base, unsigned
counter_regs = (struct sun4m_timer_regs *)ofmem_map_io(base + (uint64_t)offset, sizeof(*counter_regs));
- counter_regs->cfg = 0xffffffff;
- counter_regs->cfg = 0xfffffffe;
counter_regs->l10_timer_limit = 0; counter_regs->cpu_timers[0].l14_timer_limit = 0x9c4000; /* see comment in obio.h */ counter_regs->cpu_timers[0].cntrl = 1; @@ -304,6 +306,8 @@ ob_counter_init(uint64_t base, unsigned push_str("address"); fword("property");
- obp_ticks = 0;
fword("finish-device"); }
diff a/drivers/obio.h b/drivers/obio.h --- a/drivers/obio.h 2014-02-07 18:22:20.276224469 +0100 +++ b/drivers/obio.h 2014-02-07 18:45:46.417173162 +0100 @@ -88,7 +88,7 @@ struct sun4m_timer_regs {
- Registers of hardware timer in sun4m.
*/ struct sun4m_timer_percpu {
- volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */
- volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000
= 10ms period*/ volatile unsigned int l14_cur_count; };
diff a/include/drivers/drivers.h b/include/drivers/drivers.h --- a/include/drivers/drivers.h 2014-02-07 18:25:08.053218348 +0100 +++ b/include/drivers/drivers.h 2014-02-07 18:43:25.598178300 +0100 @@ -81,6 +81,7 @@ extern uint16_t graphic_depth; extern volatile unsigned char *power_reg; extern volatile unsigned int *reset_reg; extern volatile struct sun4m_timer_regs *counter_regs; +extern volatile int32_t obp_ticks;
void ob_new_obio_device(const char *name, const char *type); unsigned long ob_reg(uint64_t base, uint64_t offset, unsigned long size, int map);
Hi Olivier,
The basic patch looks like it's a good starting point, however if use the QEMU gdbstub to set a breakpoint on irq_entry14 for the timer interrupt then it never triggers whilst in OpenBIOS.
If I let the boot continue into the Solaris kernel then it does break eventually, which makes me think that the timer initialisation in ob_interrupt_init() needs some extra modifications.
Can you double-check your complete patchset and confirm whether or not there are any changes to the timer mask registers at all?
ATB,
Mark.
On 10/02/2014 02:25, Mark Cave-Ayland wrote:
On 09/02/14 17:24, Olivier Danet wrote:
Hi Olivier,
The basic patch looks like it's a good starting point, however if use the QEMU gdbstub to set a breakpoint on irq_entry14 for the timer interrupt then it never triggers whilst in OpenBIOS.
If I let the boot continue into the Solaris kernel then it does break eventually, which makes me think that the timer initialisation in ob_interrupt_init() needs some extra modifications.
Can you double-check your complete patchset and confirm whether or not there are any changes to the timer mask registers at all?
ATB,
Mark.
I had tested with NextSTEP, which, afaik, is the only user of this damn counter...
In OpenBIOS, the CPU "PSR.PIL" register masked all interrupts. Here is a version which enable the interrupt level 14, used by the timer. It is not optimal because the psr_get/set functions are also declared in arch/sparc32/psr.h, maybe it should be moved to include/arch/sparc32...
Index: arch/sparc32/romvec.c =================================================================== --- arch/sparc32/romvec.c (révision 1260) +++ arch/sparc32/romvec.c (copie de travail) @@ -479,6 +479,7 @@ romvec0.pv_reboot = obp_reboot_handler; romvec0.pv_printf = obp_printf_handler; romvec0.pv_abort = obp_abort_handler; + romvec0.pv_ticks = &obp_ticks; romvec0.pv_halt = obp_halt_handler; romvec0.pv_synchook = &sync_hook; romvec0.pv_v0bootargs = &obp_argp; Index: arch/sparc32/vectors.S =================================================================== --- arch/sparc32/vectors.S (révision 1260) +++ arch/sparc32/vectors.S (copie de travail) @@ -207,6 +207,10 @@ sethi %hi(counter_regs), %l7 ld [%l7 + %lo(counter_regs)], %l7 ld [%l7], %g0 + sethi %hi(obp_ticks), %l7 + ld [%l7 + %lo(obp_ticks)], %l6 + add %l6, 10, %l6 + st %l6, [%l7 + %lo(obp_ticks)] jmp %l1 rett %l2
Index: drivers/obio.c =================================================================== --- drivers/obio.c (révision 1260) +++ drivers/obio.c (copie de travail) @@ -34,6 +34,33 @@ */ #define SUN4M_NCPU 4
+static __inline__ unsigned int get_psr(void) +{ + unsigned int psr; + __asm__ __volatile__( + "rd %%psr, %0\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + : "=r" (psr) + : /* no inputs */ + : "memory"); + + return psr; +} + +static __inline__ void put_psr(unsigned int new_psr) +{ + __asm__ __volatile__( + "wr %0, 0x0, %%psr\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + : /* no outputs */ + : "r" (new_psr) + : "memory", "cc"); +} + /* DECLARE data structures for the nodes. */ DECLARE_UNNAMED_NODE( ob_obio, INSTALL_OPEN, sizeof(int) );
@@ -261,10 +288,13 @@
volatile struct sun4m_timer_regs *counter_regs;
+volatile int32_t obp_ticks; + static void ob_counter_init(uint64_t base, unsigned long offset) { int i; + uint32_t psr;
ob_new_obio_device("counter", NULL);
@@ -294,12 +324,18 @@ fword("property");
+ obp_ticks = 0; + counter_regs = (struct sun4m_timer_regs *)ofmem_map_io(base + (uint64_t)offset, sizeof(*counter_regs)); - counter_regs->cfg = 0xffffffff; + counter_regs->cfg = 0xfffffffe; counter_regs->l10_timer_limit = 0; counter_regs->cpu_timers[0].l14_timer_limit = 0x9c4000; /* see comment in obio.h */ counter_regs->cpu_timers[0].cntrl = 1;
+ psr=get_psr(); + psr=(psr & ~0xF00) | (13 << 8); /* Enable CPU timer interrupt (level 14) */ + put_psr(psr); + for (i = 0; i < SUN4M_NCPU; i++) { PUSH((unsigned long)&counter_regs->cpu_timers[i]); fword("encode-int"); Index: drivers/obio.h =================================================================== --- drivers/obio.h (révision 1260) +++ drivers/obio.h (copie de travail) @@ -88,7 +88,7 @@ * Registers of hardware timer in sun4m. */ struct sun4m_timer_percpu { - volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */ + volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000 = 10ms period */ volatile unsigned int l14_cur_count; };
Index: include/drivers/drivers.h =================================================================== --- include/drivers/drivers.h (révision 1260) +++ include/drivers/drivers.h (copie de travail) @@ -81,6 +81,7 @@ extern volatile unsigned char *power_reg; extern volatile unsigned int *reset_reg; extern volatile struct sun4m_timer_regs *counter_regs; +extern volatile int32_t obp_ticks;
void ob_new_obio_device(const char *name, const char *type); unsigned long ob_reg(uint64_t base, uint64_t offset, unsigned long size, int map); ===================================================================
On 11/02/14 00:43, Olivier Danet wrote:
I had tested with NextSTEP, which, afaik, is the only user of this damn counter...
In OpenBIOS, the CPU "PSR.PIL" register masked all interrupts. Here is a version which enable the interrupt level 14, used by the timer. It is not optimal because the psr_get/set functions are also declared in arch/sparc32/psr.h, maybe it should be moved to include/arch/sparc32...
Aha so that was the part I was missing! Please find attached a squashed reworked version of your patch which makes the following changes:
- Fixes up psr.h and friends so we can use the constants/functions that are already there
- Change obp_ticks from int32_t obp_ticks to uint32_t *obp_ticks (this is so we can reference it in Forth too)
- Add an implementation of get-msecs in Forth which is surrounded by [IFDEF] CONFIG_SPARC32 ... [THEN] guards which references the value from the above pointer
This appears to work for me, and most importantly it doesn't appear to affect Solaris 8 boot (which is good, as Solaris is generally the most sensitive OS when changing things in OpenBIOS).
Welcome to OpenBIOS v1.1 built on Feb 11 2014 19:37 Type 'help' for detailed information
0 > get-msecs u. 1bd0 ok 0 > get-msecs u. 2ada ok 0 > get-msecs u. 389a ok 0 >
Can you test on NextStep and let me know if it looks okay to you too?
ATB,
Mark.
On 11/02/2014 21:02, Mark Cave-Ayland wrote:
On 11/02/14 00:43, Olivier Danet wrote:
I had tested with NextSTEP, which, afaik, is the only user of this damn counter...
In OpenBIOS, the CPU "PSR.PIL" register masked all interrupts. Here is a version which enable the interrupt level 14, used by the timer. It is not optimal because the psr_get/set functions are also declared in arch/sparc32/psr.h, maybe it should be moved to include/arch/sparc32...
Aha so that was the part I was missing! Please find attached a squashed reworked version of your patch which makes the following changes:
- Fixes up psr.h and friends so we can use the constants/functions
that are already there
- Change obp_ticks from int32_t obp_ticks to uint32_t *obp_ticks (this
is so we can reference it in Forth too)
- Add an implementation of get-msecs in Forth which is surrounded by
[IFDEF] CONFIG_SPARC32 ... [THEN] guards which references the value from the above pointer
This appears to work for me, and most importantly it doesn't appear to affect Solaris 8 boot (which is good, as Solaris is generally the most sensitive OS when changing things in OpenBIOS).
Welcome to OpenBIOS v1.1 built on Feb 11 2014 19:37 Type 'help' for detailed information
0 > get-msecs u. 1bd0 ok 0 > get-msecs u. 2ada ok 0 > get-msecs u. 389a ok 0 >
Can you test on NextStep and let me know if it looks okay to you too?
ATB,
Mark.
Your patch works great !
BTW, this should not change anything :
- intregs->cpu_intregs[0].clear = ~0x17fff; + intregs->cpu_intregs[0].clear = 0xffffffff;
The per-CPU clear mask is marked as "reserved" for hard ints, bits 16 and 14..0, so ~0x17fff should be enough. (Sun4M sys. arch, page 31, §5.7.1.2)
Solaris 8 is very sensitive indeed. I have tried a genuine CD in an authentic SparcStation and it keeps hanging during install ;-)
Olivier