SparcStation 5 has 1 timer and 1 per-cpu interrupt controller. SparcStation 10/20 has 4 timers and 4 per-cpu interrupt controllers, independently from the number of CPUs installed.
Timer and interrupt controller properties are set accordingly. This is what Sun's OpenBOOT does and having only 1 timer/interrupt declared on SS5 is necessary for NextSTEP.
Signed-off-by: Olivier Danet odanet@caramail.com =================================================================== --- arch/sparc32/openbios.c (révision 1257) +++ arch/sparc32/openbios.c (copie de travail) @@ -41,6 +41,7 @@ unsigned long aux1_offset, aux2_offset; uint64_t dma_base, esp_base, le_base; uint64_t tcx_base; + int intr_ncpu; int mid_offset; int machine_id_low, machine_id_high; }; @@ -57,6 +58,7 @@ .fd_offset = 0x00400000, .counter_offset = 0x00d00000, .intr_offset = 0x00e00000, + .intr_ncpu = 1, .aux1_offset = 0x00900000, .aux2_offset = 0x00910000, .dma_base = 0x78400000, @@ -66,7 +68,7 @@ .machine_id_low = 32, .machine_id_high = 63, }, - /* SS-10 */ + /* SS-10, SS-20 */ { .iommu_base = 0xfe0000000ULL, .tcx_base = 0xe20000000ULL, @@ -77,6 +79,7 @@ .fd_offset = 0x00700000, // 0xff1700000ULL, .counter_offset = 0x00300000, // 0xff1300000ULL, .intr_offset = 0x00400000, // 0xff1400000ULL, + .intr_ncpu = 4, .aux1_offset = 0x00800000, // 0xff1800000ULL, .aux2_offset = 0x00a01000, // 0xff1a01000ULL, .dma_base = 0xef0400000ULL, @@ -97,6 +100,7 @@ .fd_offset = -1, .counter_offset = 0x00300000, // 0xff1300000ULL, .intr_offset = 0x00400000, // 0xff1400000ULL, + .intr_ncpu = 4, .aux1_offset = 0x00800000, // 0xff1800000ULL, .aux2_offset = 0x00a01000, // 0xff1a01000ULL, XXX should not exist .dma_base = 0xef0081000ULL, @@ -837,7 +841,7 @@ #ifdef CONFIG_DRIVER_OBIO mem_size = fw_cfg_read_i32(FW_CFG_RAM_SIZE); ob_obio_init(hwdef->slavio_base, hwdef->fd_offset, - hwdef->counter_offset, hwdef->intr_offset, + hwdef->counter_offset, hwdef->intr_offset, hwdef->intr_ncpu, hwdef->aux1_offset, hwdef->aux2_offset, mem_size);
=================================================================== --- include/drivers/drivers.h (révision 1257) +++ include/drivers/drivers.h (copie de travail) @@ -63,7 +63,7 @@ /* drivers/obio.c */ int ob_obio_init(uint64_t slavio_base, unsigned long fd_offset, unsigned long counter_offset, unsigned long intr_offset, - unsigned long aux1_offset, unsigned long aux2_offset, + int intr_ncpu, unsigned long aux1_offset, unsigned long aux2_offset, unsigned long mem_size); int start_cpu(unsigned int pc, unsigned int context_ptr, unsigned int context, int cpu); =================================================================== --- drivers/obio.c (révision 1257) +++ drivers/obio.c (copie de travail) @@ -26,14 +26,6 @@ #define PROMDEV_SCREEN 0 /* output to screen */ #define PROMDEV_TTYA 1 /* in/out to ttya */
-/* "NCPU" is an historical name that's now a bit of a misnomer. The sun4m - * architecture registers NCPU CPU-specific interrupts along with one - * system-wide interrupt, regardless of the number of actual CPUs installed. - * See the comment on "NCPU" at <http://stuff.mit.edu/afs/athena/astaff/ - * project/opssrc/sys.sunos/sun4m/devaddr.h>. - */ -#define SUN4M_NCPU 4 - /* DECLARE data structures for the nodes. */ DECLARE_UNNAMED_NODE( ob_obio, INSTALL_OPEN, sizeof(int) );
@@ -262,13 +254,13 @@ volatile struct sun4m_timer_regs *counter_regs;
static void -ob_counter_init(uint64_t base, unsigned long offset) +ob_counter_init(uint64_t base, unsigned long offset, int ncpu) { int i;
ob_new_obio_device("counter", NULL);
- for (i = 0; i < SUN4M_NCPU; i++) { + for (i = 0; i < ncpu; i++) { PUSH(0); fword("encode-int"); if (i != 0) fword("encode+"); @@ -300,7 +292,7 @@ counter_regs->cpu_timers[0].l14_timer_limit = 0x9c4000; /* see comment in obio.h */ counter_regs->cpu_timers[0].cntrl = 1;
- for (i = 0; i < SUN4M_NCPU; i++) { + for (i = 0; i < ncpu; i++) { PUSH((unsigned long)&counter_regs->cpu_timers[i]); fword("encode-int"); if (i != 0) @@ -318,13 +310,13 @@ static volatile struct sun4m_intregs *intregs;
static void -ob_interrupt_init(uint64_t base, unsigned long offset) +ob_interrupt_init(uint64_t base, unsigned long offset, int ncpu) { int i;
ob_new_obio_device("interrupt", NULL);
- for (i = 0; i < SUN4M_NCPU; i++) { + for (i = 0; i < ncpu; i++) { PUSH(0); fword("encode-int"); if (i != 0) fword("encode+"); @@ -353,7 +345,7 @@ intregs->clear = ~SUN4M_INT_MASKALL; intregs->cpu_intregs[0].clear = ~0x17fff;
- for (i = 0; i < SUN4M_NCPU; i++) { + for (i = 0; i < ncpu; i++) { PUSH((unsigned long)&intregs->cpu_intregs[i]); fword("encode-int"); if (i != 0) @@ -491,7 +483,7 @@ int ob_obio_init(uint64_t slavio_base, unsigned long fd_offset, unsigned long counter_offset, unsigned long intr_offset, - unsigned long aux1_offset, unsigned long aux2_offset, + int intr_ncpu, unsigned long aux1_offset, unsigned long aux2_offset, unsigned long mem_size) {
@@ -523,9 +515,9 @@ if (aux2_offset != (unsigned long) -1) ob_aux2_reset_init(slavio_base, aux2_offset, AUXIO2_INTR);
- ob_counter_init(slavio_base, counter_offset); + ob_counter_init(slavio_base, counter_offset, intr_ncpu);
- ob_interrupt_init(slavio_base, intr_offset); + ob_interrupt_init(slavio_base, intr_offset, intr_ncpu);
ob_smp_init(mem_size);
===================================================================
On 01/02/14 20:54, Olivier Danet wrote:
SparcStation 5 has 1 timer and 1 per-cpu interrupt controller. SparcStation 10/20 has 4 timers and 4 per-cpu interrupt controllers, independently from the number of CPUs installed.
Timer and interrupt controller properties are set accordingly. This is what Sun's OpenBOOT does and having only 1 timer/interrupt declared on SS5 is necessary for NextSTEP.
Signed-off-by: Olivier Danet odanet@caramail.com
--- arch/sparc32/openbios.c (révision 1257) +++ arch/sparc32/openbios.c (copie de travail) @@ -41,6 +41,7 @@ unsigned long aux1_offset, aux2_offset; uint64_t dma_base, esp_base, le_base; uint64_t tcx_base;
- int intr_ncpu;
int mid_offset; int machine_id_low, machine_id_high; }; @@ -57,6 +58,7 @@ .fd_offset = 0x00400000, .counter_offset = 0x00d00000, .intr_offset = 0x00e00000,
- .intr_ncpu = 1,
.aux1_offset = 0x00900000, .aux2_offset = 0x00910000, .dma_base = 0x78400000, @@ -66,7 +68,7 @@ .machine_id_low = 32, .machine_id_high = 63, },
- /* SS-10 */
- /* SS-10, SS-20 */
{ .iommu_base = 0xfe0000000ULL, .tcx_base = 0xe20000000ULL, @@ -77,6 +79,7 @@ .fd_offset = 0x00700000, // 0xff1700000ULL, .counter_offset = 0x00300000, // 0xff1300000ULL, .intr_offset = 0x00400000, // 0xff1400000ULL,
- .intr_ncpu = 4,
.aux1_offset = 0x00800000, // 0xff1800000ULL, .aux2_offset = 0x00a01000, // 0xff1a01000ULL, .dma_base = 0xef0400000ULL, @@ -97,6 +100,7 @@ .fd_offset = -1, .counter_offset = 0x00300000, // 0xff1300000ULL, .intr_offset = 0x00400000, // 0xff1400000ULL,
- .intr_ncpu = 4,
.aux1_offset = 0x00800000, // 0xff1800000ULL, .aux2_offset = 0x00a01000, // 0xff1a01000ULL, XXX should not exist .dma_base = 0xef0081000ULL, @@ -837,7 +841,7 @@ #ifdef CONFIG_DRIVER_OBIO mem_size = fw_cfg_read_i32(FW_CFG_RAM_SIZE); ob_obio_init(hwdef->slavio_base, hwdef->fd_offset,
- hwdef->counter_offset, hwdef->intr_offset,
- hwdef->counter_offset, hwdef->intr_offset, hwdef->intr_ncpu,
hwdef->aux1_offset, hwdef->aux2_offset, mem_size);
=================================================================== --- include/drivers/drivers.h (révision 1257) +++ include/drivers/drivers.h (copie de travail) @@ -63,7 +63,7 @@ /* drivers/obio.c */ int ob_obio_init(uint64_t slavio_base, unsigned long fd_offset, unsigned long counter_offset, unsigned long intr_offset,
- unsigned long aux1_offset, unsigned long aux2_offset,
- int intr_ncpu, unsigned long aux1_offset, unsigned long aux2_offset,
unsigned long mem_size); int start_cpu(unsigned int pc, unsigned int context_ptr, unsigned int context, int cpu); =================================================================== --- drivers/obio.c (révision 1257) +++ drivers/obio.c (copie de travail) @@ -26,14 +26,6 @@ #define PROMDEV_SCREEN 0 /* output to screen */ #define PROMDEV_TTYA 1 /* in/out to ttya */
-/* "NCPU" is an historical name that's now a bit of a misnomer. The sun4m
- architecture registers NCPU CPU-specific interrupts along with one
- system-wide interrupt, regardless of the number of actual CPUs
installed.
- See the comment on "NCPU" at <http://stuff.mit.edu/afs/athena/astaff/
- project/opssrc/sys.sunos/sun4m/devaddr.h>.
- */
-#define SUN4M_NCPU 4
/* DECLARE data structures for the nodes. */ DECLARE_UNNAMED_NODE( ob_obio, INSTALL_OPEN, sizeof(int) );
@@ -262,13 +254,13 @@ volatile struct sun4m_timer_regs *counter_regs;
static void -ob_counter_init(uint64_t base, unsigned long offset) +ob_counter_init(uint64_t base, unsigned long offset, int ncpu) { int i;
ob_new_obio_device("counter", NULL);
- for (i = 0; i < SUN4M_NCPU; i++) {
- for (i = 0; i < ncpu; i++) {
PUSH(0); fword("encode-int"); if (i != 0) fword("encode+"); @@ -300,7 +292,7 @@ counter_regs->cpu_timers[0].l14_timer_limit = 0x9c4000; /* see comment in obio.h */ counter_regs->cpu_timers[0].cntrl = 1;
Should there not be some initialisation for counter_regs->cpu_timers[i] for i > 0 here somewhere? For example, should each CPU timer have a non-zero value and should it be running or not?
- for (i = 0; i < SUN4M_NCPU; i++) {
- for (i = 0; i < ncpu; i++) {
PUSH((unsigned long)&counter_regs->cpu_timers[i]); fword("encode-int"); if (i != 0) @@ -318,13 +310,13 @@ static volatile struct sun4m_intregs *intregs;
static void -ob_interrupt_init(uint64_t base, unsigned long offset) +ob_interrupt_init(uint64_t base, unsigned long offset, int ncpu) { int i;
ob_new_obio_device("interrupt", NULL);
- for (i = 0; i < SUN4M_NCPU; i++) {
- for (i = 0; i < ncpu; i++) {
PUSH(0); fword("encode-int"); if (i != 0) fword("encode+"); @@ -353,7 +345,7 @@ intregs->clear = ~SUN4M_INT_MASKALL; intregs->cpu_intregs[0].clear = ~0x17fff;
- for (i = 0; i < SUN4M_NCPU; i++) {
- for (i = 0; i < ncpu; i++) {
PUSH((unsigned long)&intregs->cpu_intregs[i]); fword("encode-int"); if (i != 0) @@ -491,7 +483,7 @@ int ob_obio_init(uint64_t slavio_base, unsigned long fd_offset, unsigned long counter_offset, unsigned long intr_offset,
- unsigned long aux1_offset, unsigned long aux2_offset,
- int intr_ncpu, unsigned long aux1_offset, unsigned long aux2_offset,
unsigned long mem_size) {
@@ -523,9 +515,9 @@ if (aux2_offset != (unsigned long) -1) ob_aux2_reset_init(slavio_base, aux2_offset, AUXIO2_INTR);
- ob_counter_init(slavio_base, counter_offset);
- ob_counter_init(slavio_base, counter_offset, intr_ncpu);
- ob_interrupt_init(slavio_base, intr_offset);
- ob_interrupt_init(slavio_base, intr_offset, intr_ncpu);
ob_smp_init(mem_size);
===================================================================
ATB,
Mark.
On 05/02/2014 00:35, Mark Cave-Ayland wrote:
On 01/02/14 20:54, Olivier Danet wrote:
SparcStation 5 has 1 timer and 1 per-cpu interrupt controller. SparcStation 10/20 has 4 timers and 4 per-cpu interrupt controllers, independently from the number of CPUs installed.
Timer and interrupt controller properties are set accordingly. This is what Sun's OpenBOOT does and having only 1 timer/interrupt declared on SS5 is necessary for NextSTEP.
Signed-off-by: Olivier Danet odanet@caramail.com
--- arch/sparc32/openbios.c (révision 1257) +++ arch/sparc32/openbios.c (copie de travail) @@ -41,6 +41,7 @@ unsigned long aux1_offset, aux2_offset; uint64_t dma_base, esp_base, le_base; uint64_t tcx_base;
- int intr_ncpu;
int mid_offset; int machine_id_low, machine_id_high; }; @@ -57,6 +58,7 @@ .fd_offset = 0x00400000, .counter_offset = 0x00d00000, .intr_offset = 0x00e00000,
- .intr_ncpu = 1,
.aux1_offset = 0x00900000, .aux2_offset = 0x00910000, .dma_base = 0x78400000, @@ -66,7 +68,7 @@ .machine_id_low = 32, .machine_id_high = 63, },
- /* SS-10 */
- /* SS-10, SS-20 */
{ .iommu_base = 0xfe0000000ULL, .tcx_base = 0xe20000000ULL, @@ -77,6 +79,7 @@ .fd_offset = 0x00700000, // 0xff1700000ULL, .counter_offset = 0x00300000, // 0xff1300000ULL, .intr_offset = 0x00400000, // 0xff1400000ULL,
- .intr_ncpu = 4,
.aux1_offset = 0x00800000, // 0xff1800000ULL, .aux2_offset = 0x00a01000, // 0xff1a01000ULL, .dma_base = 0xef0400000ULL, @@ -97,6 +100,7 @@ .fd_offset = -1, .counter_offset = 0x00300000, // 0xff1300000ULL, .intr_offset = 0x00400000, // 0xff1400000ULL,
- .intr_ncpu = 4,
.aux1_offset = 0x00800000, // 0xff1800000ULL, .aux2_offset = 0x00a01000, // 0xff1a01000ULL, XXX should not exist .dma_base = 0xef0081000ULL, @@ -837,7 +841,7 @@ #ifdef CONFIG_DRIVER_OBIO mem_size = fw_cfg_read_i32(FW_CFG_RAM_SIZE); ob_obio_init(hwdef->slavio_base, hwdef->fd_offset,
- hwdef->counter_offset, hwdef->intr_offset,
- hwdef->counter_offset, hwdef->intr_offset, hwdef->intr_ncpu,
hwdef->aux1_offset, hwdef->aux2_offset, mem_size);
=================================================================== --- include/drivers/drivers.h (révision 1257) +++ include/drivers/drivers.h (copie de travail) @@ -63,7 +63,7 @@ /* drivers/obio.c */ int ob_obio_init(uint64_t slavio_base, unsigned long fd_offset, unsigned long counter_offset, unsigned long intr_offset,
- unsigned long aux1_offset, unsigned long aux2_offset,
- int intr_ncpu, unsigned long aux1_offset, unsigned long aux2_offset,
unsigned long mem_size); int start_cpu(unsigned int pc, unsigned int context_ptr, unsigned int context, int cpu); =================================================================== --- drivers/obio.c (révision 1257) +++ drivers/obio.c (copie de travail) @@ -26,14 +26,6 @@ #define PROMDEV_SCREEN 0 /* output to screen */ #define PROMDEV_TTYA 1 /* in/out to ttya */
-/* "NCPU" is an historical name that's now a bit of a misnomer. The sun4m
- architecture registers NCPU CPU-specific interrupts along with one
- system-wide interrupt, regardless of the number of actual CPUs
installed.
- See the comment on "NCPU" at
<http://stuff.mit.edu/afs/athena/astaff/
- project/opssrc/sys.sunos/sun4m/devaddr.h>.
- */
-#define SUN4M_NCPU 4
/* DECLARE data structures for the nodes. */ DECLARE_UNNAMED_NODE( ob_obio, INSTALL_OPEN, sizeof(int) );
@@ -262,13 +254,13 @@ volatile struct sun4m_timer_regs *counter_regs;
static void -ob_counter_init(uint64_t base, unsigned long offset) +ob_counter_init(uint64_t base, unsigned long offset, int ncpu) { int i;
ob_new_obio_device("counter", NULL);
- for (i = 0; i < SUN4M_NCPU; i++) {
- for (i = 0; i < ncpu; i++) {
PUSH(0); fword("encode-int"); if (i != 0) fword("encode+"); @@ -300,7 +292,7 @@ counter_regs->cpu_timers[0].l14_timer_limit = 0x9c4000; /* see comment in obio.h */ counter_regs->cpu_timers[0].cntrl = 1;
Should there not be some initialisation for counter_regs->cpu_timers[i] for i > 0 here somewhere? For example, should each CPU timer have a non-zero value and should it be running or not?
- for (i = 0; i < SUN4M_NCPU; i++) {
- for (i = 0; i < ncpu; i++) {
PUSH((unsigned long)&counter_regs->cpu_timers[i]); fword("encode-int"); if (i != 0) @@ -318,13 +310,13 @@ static volatile struct sun4m_intregs *intregs;
static void -ob_interrupt_init(uint64_t base, unsigned long offset) +ob_interrupt_init(uint64_t base, unsigned long offset, int ncpu) { int i;
ob_new_obio_device("interrupt", NULL);
- for (i = 0; i < SUN4M_NCPU; i++) {
- for (i = 0; i < ncpu; i++) {
PUSH(0); fword("encode-int"); if (i != 0) fword("encode+"); @@ -353,7 +345,7 @@ intregs->clear = ~SUN4M_INT_MASKALL; intregs->cpu_intregs[0].clear = ~0x17fff;
- for (i = 0; i < SUN4M_NCPU; i++) {
- for (i = 0; i < ncpu; i++) {
PUSH((unsigned long)&intregs->cpu_intregs[i]); fword("encode-int"); if (i != 0) @@ -491,7 +483,7 @@ int ob_obio_init(uint64_t slavio_base, unsigned long fd_offset, unsigned long counter_offset, unsigned long intr_offset,
- unsigned long aux1_offset, unsigned long aux2_offset,
- int intr_ncpu, unsigned long aux1_offset, unsigned long aux2_offset,
unsigned long mem_size) {
@@ -523,9 +515,9 @@ if (aux2_offset != (unsigned long) -1) ob_aux2_reset_init(slavio_base, aux2_offset, AUXIO2_INTR);
- ob_counter_init(slavio_base, counter_offset);
- ob_counter_init(slavio_base, counter_offset, intr_ncpu);
- ob_interrupt_init(slavio_base, intr_offset);
- ob_interrupt_init(slavio_base, intr_offset, intr_ncpu);
ob_smp_init(mem_size);
===================================================================
ATB,
Mark.
Timers are initialized in QEMU : hw/timer/slavio_timer.c : static void slavio_timer_reset(DeviceState *d)
According to the document "Sun-4M System Architecture" (which was once on Sun's website) "Upon power–on reset all four sets are configured as counter–timers. " = 0 "Upon reset all limit registers are set to 0x00000000. ". The zeroing made by QEMU seems correct.
There are many parts where the initialisation is incertain between QEMU and OpenBIOS.
For example, I have found two days ago that the Sun4m keyboard/mouse UART is never initialised by OpenBIOS, QEMU does not really care about the initialisation, and the specification says nothing about the default power-on state.
Olivier
On 06/02/14 00:11, Olivier Danet wrote:
Timers are initialized in QEMU : hw/timer/slavio_timer.c : static void slavio_timer_reset(DeviceState *d)
According to the document "Sun-4M System Architecture" (which was once on Sun's website) "Upon power–on reset all four sets are configured as counter–timers. " = 0 "Upon reset all limit registers are set to 0x00000000. ". The zeroing made by QEMU seems correct.
There are many parts where the initialisation is incertain between QEMU and OpenBIOS.
For example, I have found two days ago that the Sun4m keyboard/mouse UART is never initialised by OpenBIOS, QEMU does not really care about the initialisation, and the specification says nothing about the default power-on state.
That wouldn't surprise me at all; there are some printenv variables somewhere which control the default serial port configuration but I can easily believe they are not used.
In terms of the the timer, I see the following comment in sun4m_irq.c from Linux:
/* For SMP we use the level 14 ticker, however the bootup code * has copied the firmware's level 14 vector into the boot cpu's * trap table, we must fix this now or we get squashed. */
This implies that OBP uses the level 14 timer itself (presumably part of this would increment the value of the get-msecs word) which should be fairly easy to emulate. Is anyone good enough with OBP/QEMU in order to tell if the level 14 timer is actually being programmed for the romvec ticks register?
For the other CPU timers, for now should we just explicitly set their control register to zero just to make sure they are disabled?
ATB,
Mark.
On 07/02/2014 19:31, Mark Cave-Ayland wrote:
On 06/02/14 00:11, Olivier Danet wrote:
Timers are initialized in QEMU : hw/timer/slavio_timer.c : static void slavio_timer_reset(DeviceState *d)
According to the document "Sun-4M System Architecture" (which was once on Sun's website) "Upon power–on reset all four sets are configured as counter–timers. " = 0 "Upon reset all limit registers are set to 0x00000000. ". The zeroing made by QEMU seems correct.
There are many parts where the initialisation is incertain between QEMU and OpenBIOS.
For example, I have found two days ago that the Sun4m keyboard/mouse UART is never initialised by OpenBIOS, QEMU does not really care about the initialisation, and the specification says nothing about the default power-on state.
That wouldn't surprise me at all; there are some printenv variables somewhere which control the default serial port configuration but I can easily believe they are not used.
In terms of the the timer, I see the following comment in sun4m_irq.c from Linux:
/* For SMP we use the level 14 ticker, however the bootup code
- has copied the firmware's level 14 vector into the boot cpu's
- trap table, we must fix this now or we get squashed.
*/
This implies that OBP uses the level 14 timer itself (presumably part of this would increment the value of the get-msecs word) which should be fairly easy to emulate. Is anyone good enough with OBP/QEMU in order to tell if the level 14 timer is actually being programmed for the romvec ticks register?
For the other CPU timers, for now should we just explicitly set their control register to zero just to make sure they are disabled?
ATB,
Mark.
Yes indeed, the CPU timer is used for the tick counter, tracing timers registers accesses shows it.
I have a patch for the tick timer. It was much simpler than what I feared when writing the "dummy counter" stuff.
I need to look at that "get-msecs" command though...
Olivier.