[U-Boot] [PATCH 17/17] SPARC, LEON3: added support for multiprocessing, tested Linux 2.6.21.1 SMP and RTEMS-4.10 AMP.
Daniel Hellstrom
daniel at gaisler.com
Thu Jan 28 13:16:36 CET 2010
Signed-off-by: Daniel Hellstrom <daniel at gaisler.com>
---
board/gaisler/gr_cpci_ax2000/u-boot.lds | 7 ++
board/gaisler/gr_ep2s60/u-boot.lds | 7 ++
board/gaisler/gr_xc3s_1500/u-boot.lds | 7 ++
board/gaisler/grsim/u-boot.lds | 7 ++
cpu/leon3/Makefile | 2 +-
cpu/leon3/cpu.c | 10 ++-
cpu/leon3/cpu_mp.c | 80 ++++++++++++++
cpu/leon3/prom.c | 32 +++---
cpu/leon3/start.S | 70 ++++++++++++
include/asm-sparc/boot_mp.h | 70 ++++++++++++
include/configs/gr_cpci_ax2000.h | 12 ++-
include/configs/gr_ep2s60.h | 12 ++-
include/configs/gr_xc3s_1500.h | 14 ++-
include/configs/grsim.h | 12 ++-
lib_sparc/Makefile | 2 +-
lib_sparc/boot_mp.c | 177 +++++++++++++++++++++++++++++++
lib_sparc/bootm.c | 57 ++++++++--
17 files changed, 540 insertions(+), 38 deletions(-)
create mode 100644 cpu/leon3/cpu_mp.c
create mode 100644 include/asm-sparc/boot_mp.h
create mode 100644 lib_sparc/boot_mp.c
diff --git a/board/gaisler/gr_cpci_ax2000/u-boot.lds b/board/gaisler/gr_cpci_ax2000/u-boot.lds
index d5d7842..17a0fc3 100644
--- a/board/gaisler/gr_cpci_ax2000/u-boot.lds
+++ b/board/gaisler/gr_cpci_ax2000/u-boot.lds
@@ -72,6 +72,13 @@ SECTIONS
*(.prom.text)
. = ALIGN(16);
__prom_end = .;
+ /* Align MP section to the same as the MAX size of the MP section */
+ . = ALIGN(512);
+ __mp_start = .;
+ *(.mp.data)
+ *(.mp.text)
+ . = ALIGN(16);
+ __mp_end = .;
*(.text)
*(.fixup)
*(.gnu.warning)
diff --git a/board/gaisler/gr_ep2s60/u-boot.lds b/board/gaisler/gr_ep2s60/u-boot.lds
index 99aa0ad..c02a6d2 100644
--- a/board/gaisler/gr_ep2s60/u-boot.lds
+++ b/board/gaisler/gr_ep2s60/u-boot.lds
@@ -72,6 +72,13 @@ SECTIONS
*(.prom.text)
. = ALIGN(16);
__prom_end = .;
+ /* Align MP section to the same as the MAX size of the MP section */
+ . = ALIGN(512);
+ __mp_start = .;
+ *(.mp.data)
+ *(.mp.text)
+ . = ALIGN(16);
+ __mp_end = .;
*(.text)
*(.fixup)
*(.gnu.warning)
diff --git a/board/gaisler/gr_xc3s_1500/u-boot.lds b/board/gaisler/gr_xc3s_1500/u-boot.lds
index 3b13190..de7ea6b 100644
--- a/board/gaisler/gr_xc3s_1500/u-boot.lds
+++ b/board/gaisler/gr_xc3s_1500/u-boot.lds
@@ -72,6 +72,13 @@ SECTIONS
*(.prom.text)
. = ALIGN(16);
__prom_end = .;
+ /* Align MP section to the same as the MAX size of the MP section */
+ . = ALIGN(512);
+ __mp_start = .;
+ *(.mp.data)
+ *(.mp.text)
+ . = ALIGN(16);
+ __mp_end = .;
*(.text)
*(.fixup)
*(.gnu.warning)
diff --git a/board/gaisler/grsim/u-boot.lds b/board/gaisler/grsim/u-boot.lds
index 0fa6627..ac7dbec 100644
--- a/board/gaisler/grsim/u-boot.lds
+++ b/board/gaisler/grsim/u-boot.lds
@@ -71,6 +71,13 @@ SECTIONS
*(.prom.text)
. = ALIGN(16);
__prom_end = .;
+ /* Align MP section to the same as the MAX size of the MP section */
+ . = ALIGN(512);
+ __mp_start = .;
+ *(.mp.data)
+ *(.mp.text)
+ . = ALIGN(16);
+ __mp_end = .;
*(.text)
*(.fixup)
*(.gnu.warning)
diff --git a/cpu/leon3/Makefile b/cpu/leon3/Makefile
index f1bb808..4d36061 100644
--- a/cpu/leon3/Makefile
+++ b/cpu/leon3/Makefile
@@ -28,7 +28,7 @@ LIB = $(obj)lib$(CPU).a
START = start.o
SOBJS = ambapp_low.o ambapp_low_c.o memcfg_low.o
COBJS = cpu_init.o serial.o cpu.o ambapp.o interrupts.o prom.o usb_uhci.o \
- memcfg.o
+ memcfg.o cpu_mp.o
SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
diff --git a/cpu/leon3/cpu.c b/cpu/leon3/cpu.c
index 5cc9513..13d3dd7 100644
--- a/cpu/leon3/cpu.c
+++ b/cpu/leon3/cpu.c
@@ -83,8 +83,14 @@ int checkcpu(void)
/* ------------------------------------------------------------------------- */
-void cpu_reset(void)
+int cpu_reset(int nr)
{
+ if ( nr > 0 ) {
+ puts(" CPU[N] RESET NOT SUPPORTED BY ARCHITECTURE (N>0), "
+ "SYSTEM RESET IS POSSIBLE.");
+ return -1;
+ }
+
/* Interrupts off */
disable_interrupts();
@@ -94,7 +100,7 @@ void cpu_reset(void)
int do_reset(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
- cpu_reset();
+ cpu_reset(0);
return 1;
diff --git a/cpu/leon3/cpu_mp.c b/cpu/leon3/cpu_mp.c
new file mode 100644
index 0000000..5cd5a6a
--- /dev/null
+++ b/cpu/leon3/cpu_mp.c
@@ -0,0 +1,80 @@
+/* Interface implementation for cmd_mp.c on multi processor LEON
+ * CPUs
+ *
+ * (C) Copyright 2010
+ * Daniel Hellstrom, Gaisler Research, daniel at gaisler.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+
+#ifdef CONFIG_MP
+
+#include <grlib/irqmp.h>
+
+extern int leon_cpu_cnt;
+extern ambapp_dev_irqmp *irqmp;
+
+int cpu_numcores(void)
+{
+ return leon_cpu_cnt;
+}
+
+int cpu_status(int nr)
+{
+ printf("LEON CPUs available: %d\n", leon_cpu_cnt);
+
+ return 0;
+}
+
+int cpu_release(int nr, int argc, char *argv[])
+{
+ unsigned int ep, stack, arg0, arg1;
+
+ /* Get entry point, stack and argument */
+ if ( argc < 2 ) {
+ printf( " At least 5 arguments must be given.\n"
+ " Argument 4 is entry point\n"
+ " Argument 5 is stack\n"
+ " Argument 6-7 is kernel arg 0 and 1 (OPTIONAL)\n");
+ return -1;
+ }
+ ep = simple_strtoul(argv[0], NULL, 16);
+ stack = simple_strtoul(argv[1], NULL, 16);
+ arg0 = arg1 = 0;
+
+ if ( argc > 2 ) {
+ arg0 = simple_strtoul(argv[2], NULL, 16);
+ }
+ if ( argc > 3 ) {
+ arg1 = simple_strtoul(argv[3], NULL, 16);
+ }
+
+ /* Register CPU start up options into MP table */
+ boot_mp_cpu_setup(nr, ep, stack, (void *)arg0, (void *)arg1);
+
+ /* Release CPU by writing to IRQ controller MP register */
+ irqmp->mstatus = (1<<nr);
+
+ return 0;
+}
+
+#endif
diff --git a/cpu/leon3/prom.c b/cpu/leon3/prom.c
index 6cd2281..2a4fc2d 100644
--- a/cpu/leon3/prom.c
+++ b/cpu/leon3/prom.c
@@ -31,6 +31,7 @@
#include <asm/processor.h>
#include <asm/irq.h>
#include <asm/leon.h>
+#include <asm/boot_mp.h>
#include <ambapp.h>
#include <grlib/apbuart.h>
#include <grlib/irqmp.h>
@@ -931,21 +932,9 @@ void leon_prom_init(struct leon_prom_info *pspi)
/* Set the pointer to the Console UART in romvec */
pspi->reloc_funcs.leon3_apbuart = leon3_apbuart;
- {
- int j = 1;
-#ifdef CONFIG_SMP
- ambapp_dev_irqmp *b;
- b = (ambapp_dev_irqmp *) leon3_getapbbase(VENDOR_GAISLER,
- GAISLER_IRQMP);
- if (b) {
- j = 1 + ((LEON3_BYPASS_LOAD_PA(&(b->mpstatus))
- >> LEON3_IRQMPSTATUS_CPUNR) & 0xf);
- }
-#endif
#undef nodes
- pspi->nodes[2 + j].level = -1;
- pspi->nodes[2 + j].properties = __va(spi.root_properties + 3);
- }
+ pspi->nodes[2 + leon_cpu_cnt].level = -1;
+ pspi->nodes[2 + leon_cpu_cnt].properties = __va(spi.root_properties + 3);
/* Set Ethernet MAC address from environment */
if ((addr_str = getenv("ethaddr")) != NULL) {
@@ -1024,7 +1013,7 @@ void prepare_bootargs(char *bootargs)
}
}
-void srmmu_init_cpu(unsigned int entry)
+void srmmu_init(unsigned int entry)
{
sparc_srmmu_setup *psrmmu_tables = (void *)
((((unsigned int)&srmmu_tables) & PROM_SIZE_MASK) +
@@ -1079,6 +1068,19 @@ void srmmu_init_cpu(unsigned int entry)
/* convert rom vec pointer to virtual address */
kernel_arg_promvec = (struct linux_romvec *)
(((unsigned int)kernel_arg_promvec & 0x0fffffff) | 0xf0000000);
+}
+
+#ifdef CONFIG_MP
+/* This function must be located in the MP or PROM part of the application because
+ * it will be called from CPU1, CPU2 ... after CPU0 has made it into the kernel
+ * and started the other CPUs
+ */
+void MP_TEXT boot_mp_linux_cpu_preinit(int cpu)
+#else
+void boot_mp_linux_cpu_preinit(int cpu)
+#endif
+{
+ sparc_srmmu_setup *psrmmu_tables = (void *)CONFIG_SYS_PROM_OFFSET;
/* Set Context pointer to point to context table
* 256 contexts supported.
diff --git a/cpu/leon3/start.S b/cpu/leon3/start.S
index d9faa86..1f30150 100644
--- a/cpu/leon3/start.S
+++ b/cpu/leon3/start.S
@@ -27,6 +27,7 @@
#include <asm/psr.h>
#include <asm/stack.h>
#include <asm/leon.h>
+#include <asm/boot_mp.h>
#include <timestamp.h>
#include <version.h>
#include <ambapp.h>
@@ -258,6 +259,20 @@ wininit:
set WIM_INIT, %g3
mov %g3, %wim
+#ifdef CONFIG_MP
+/* In a multi CPU system (and the slave CPUs have been started) the slaves
+ * have a special boot up sequence. It is expected that CPU0 has already run
+ * u-boot and it has loaded an OS which now have activated one or more slave
+ * CPUs.
+ */
+multi_cpu_detect:
+ rd %asr17, %g3
+ srl %g3, 28, %g3
+ cmp %g3, %g0
+ bne slave_cpu_init
+ nop
+#endif
+
stackp:
set CONFIG_SYS_INIT_SP_OFFSET, %fp
andn %fp, 0x0f, %fp
@@ -386,6 +401,23 @@ prom_relocate_loop:
bne prom_relocate_loop
inc 16,%g4
+#ifdef CONFIG_MP
+mp_relocate:
+ set __mp_start, %g2
+ set __mp_end, %g3
+ set CONFIG_SYS_MP_OFFSET, %g4
+
+mp_relocate_loop:
+ ldd [%g2],%l0
+ ldd [%g2+8],%l2
+ std %l0,[%g4]
+ std %l2,[%g4+8]
+ inc 16,%g2
+ subcc %g3,%g2,%g0
+ bne mp_relocate_loop
+ inc 16,%g4
+#endif
+
/* Trap table has been moved, lets tell CPU about
* the new trap table address
*/
@@ -651,3 +683,41 @@ _reset_reloc:
set start, %l0
call %l0
nop
+
+#ifdef CONFIG_MP
+/* Slave CPUs reach here */
+slave_cpu_init:
+
+ /* Get Index into cpu slave struct */
+ sll %g3, 4, %i0
+
+ set (CONFIG_SYS_MP_OFFSET+0x4), %o1 /* cpu_table is mp_data+0x4 */
+ add %i0, %o1, %i0
+
+ /* Setup Stack Pointer from config */
+ ld [%i0 + BOOT_MP_CPU_STACK], %fp
+ andn %fp, 0x0f, %fp
+ sub %fp, 64, %sp
+
+ /* Call OS-dependent CPU init routine */
+ set CONFIG_SYS_MP_OFFSET, %o1 /* cpu_table is mp_data+0x0 */
+ ld [%o1], %o1
+ cmp %o1, 0
+ beq slave_cpu_boot_kernel
+ nop
+ call %o1
+ clr %o0
+
+ /* Call Kernel */
+slave_cpu_boot_kernel:
+ ld [%i0 + BOOT_MP_CPU_ARG0], %o0 /* ARG0 */
+ ld [%i0 + BOOT_MP_CPU_ARG1], %o1 /* ARG1 */
+ ld [%i0 + BOOT_MP_CPU_EP], %o3 /* ENTRY POINT */
+ call %o3
+ clr %o2
+
+dead_slave:
+ /* Kernel Failed or no support for MP */
+ ta 0x1
+ nop
+#endif
diff --git a/include/asm-sparc/boot_mp.h b/include/asm-sparc/boot_mp.h
new file mode 100644
index 0000000..e033b9c
--- /dev/null
+++ b/include/asm-sparc/boot_mp.h
@@ -0,0 +1,70 @@
+/* Multiprocessor boot setup functions.
+ *
+ * (C) Copyright 2010
+ * Daniel Hellstrom, Gaisler Research, daniel at gaisler.com.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#ifndef __ASM_SPARC_BOOT_MP_H__
+#define __ASM_SPARC_BOOT_MP_H__
+
+#define MP_TEXT __attribute__ ((__section__ (".mp.text")))
+#define MP_DATA __attribute__ ((__section__ (".mp.data")))
+
+#define BOOT_MP_CPU_EP 0x00
+#define BOOT_MP_CPU_STACK 0x04
+#define BOOT_MP_CPU_ARG0 0x08
+#define BOOT_MP_CPU_ARG1 0x0C
+
+#ifndef __ASSEMBLER__
+
+/* Allow for arch specific CPU initialization before RTEMS boot */
+extern void boot_mp_rtems_cpu_preinit(int cpu);
+
+/* Allow for arch specific CPU initialization before VxWorks boot */
+extern void boot_mp_vxworks_cpu_preinit(int cpu);
+
+/* Allow for arch specific CPU initialization before Linux boot */
+extern void boot_mp_linux_cpu_preinit(int cpu);
+
+struct boot_mp_cpu {
+ unsigned int entry_point;
+ unsigned int stack;
+ void *arg0;
+ void *arg1;
+};
+
+/* All CPU entry points and stacks */
+extern struct boot_mp_cpu boot_mp_cpu_table[];
+
+extern void boot_mp_os_setup(int os);
+
+extern void boot_mp_cpu_setup(
+ int cpu,
+ unsigned int entry_point,
+ unsigned int stack,
+ void *arg0,
+ void *arg1
+ );
+
+/* Init a CPU before entering the kernel */
+extern void boot_mp_cpu_preinit(int cpu);
+
+#endif
+
+#endif
diff --git a/include/configs/gr_cpci_ax2000.h b/include/configs/gr_cpci_ax2000.h
index b9d45dd..a6d669d 100644
--- a/include/configs/gr_cpci_ax2000.h
+++ b/include/configs/gr_cpci_ax2000.h
@@ -264,8 +264,16 @@
#define CONFIG_SYS_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */
#define CONFIG_SYS_GBL_DATA_OFFSET (CONFIG_SYS_RAM_END - CONFIG_SYS_GBL_DATA_SIZE)
-#define CONFIG_SYS_PROM_SIZE (8192-CONFIG_SYS_GBL_DATA_SIZE)
-#define CONFIG_SYS_PROM_OFFSET (CONFIG_SYS_GBL_DATA_OFFSET-CONFIG_SYS_PROM_SIZE)
+#ifdef CONFIG_MP
+#define CONFIG_SYS_MP_SIZE 512
+#define CONFIG_SYS_MP_OFFSET (CONFIG_SYS_GBL_DATA_OFFSET-CONFIG_SYS_MP_SIZE)
+#else
+#define CONFIG_SYS_MP_SIZE 0
+#define CONFIG_SYS_MP_OFFSET CONFIG_SYS_GBL_DATA_OFFSET
+#endif
+
+#define CONFIG_SYS_PROM_SIZE (8192-CONFIG_SYS_MP_SIZE-CONFIG_SYS_GBL_DATA_SIZE)
+#define CONFIG_SYS_PROM_OFFSET (CONFIG_SYS_MP_OFFSET-CONFIG_SYS_PROM_SIZE)
#define CONFIG_SYS_INIT_SP_OFFSET (CONFIG_SYS_PROM_OFFSET-32)
#define CONFIG_SYS_STACK_SIZE (0x10000-32)
diff --git a/include/configs/gr_ep2s60.h b/include/configs/gr_ep2s60.h
index 6edb92c..10afca2 100644
--- a/include/configs/gr_ep2s60.h
+++ b/include/configs/gr_ep2s60.h
@@ -232,8 +232,16 @@
#define CONFIG_SYS_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */
#define CONFIG_SYS_GBL_DATA_OFFSET (CONFIG_SYS_SDRAM_END - CONFIG_SYS_GBL_DATA_SIZE)
-#define CONFIG_SYS_PROM_SIZE (8192-CONFIG_SYS_GBL_DATA_SIZE)
-#define CONFIG_SYS_PROM_OFFSET (CONFIG_SYS_GBL_DATA_OFFSET-CONFIG_SYS_PROM_SIZE)
+#ifdef CONFIG_MP
+#define CONFIG_SYS_MP_SIZE 512
+#define CONFIG_SYS_MP_OFFSET (CONFIG_SYS_GBL_DATA_OFFSET-CONFIG_SYS_MP_SIZE)
+#else
+#define CONFIG_SYS_MP_SIZE 0
+#define CONFIG_SYS_MP_OFFSET CONFIG_SYS_GBL_DATA_OFFSET
+#endif
+
+#define CONFIG_SYS_PROM_SIZE (8192-CONFIG_SYS_MP_SIZE-CONFIG_SYS_GBL_DATA_SIZE)
+#define CONFIG_SYS_PROM_OFFSET (CONFIG_SYS_MP_OFFSET-CONFIG_SYS_PROM_SIZE)
#define CONFIG_SYS_INIT_SP_OFFSET (CONFIG_SYS_PROM_OFFSET-32)
#define CONFIG_SYS_STACK_SIZE (0x10000-32)
diff --git a/include/configs/gr_xc3s_1500.h b/include/configs/gr_xc3s_1500.h
index 1f9dd4a..b57640a 100644
--- a/include/configs/gr_xc3s_1500.h
+++ b/include/configs/gr_xc3s_1500.h
@@ -54,6 +54,8 @@
#define CONFIG_DOS_PARTITION
#define CONFIG_MAC_PARTITION
#define CONFIG_ISO_PARTITION
+#define CONFIG_MP
+#define CONFIG_MP_MAX_CPUS 4
/*
* Supported commands
@@ -209,8 +211,16 @@
#define CONFIG_SYS_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */
#define CONFIG_SYS_GBL_DATA_OFFSET (CONFIG_SYS_RAM_END - CONFIG_SYS_GBL_DATA_SIZE)
-#define CONFIG_SYS_PROM_SIZE (8192-CONFIG_SYS_GBL_DATA_SIZE)
-#define CONFIG_SYS_PROM_OFFSET (CONFIG_SYS_GBL_DATA_OFFSET-CONFIG_SYS_PROM_SIZE)
+#ifdef CONFIG_MP
+#define CONFIG_SYS_MP_SIZE 512
+#define CONFIG_SYS_MP_OFFSET (CONFIG_SYS_GBL_DATA_OFFSET-CONFIG_SYS_MP_SIZE)
+#else
+#define CONFIG_SYS_MP_SIZE 0
+#define CONFIG_SYS_MP_OFFSET CONFIG_SYS_GBL_DATA_OFFSET
+#endif
+
+#define CONFIG_SYS_PROM_SIZE (8192-CONFIG_SYS_MP_SIZE-CONFIG_SYS_GBL_DATA_SIZE)
+#define CONFIG_SYS_PROM_OFFSET (CONFIG_SYS_MP_OFFSET-CONFIG_SYS_PROM_SIZE)
#define CONFIG_SYS_INIT_SP_OFFSET (CONFIG_SYS_PROM_OFFSET-32)
#define CONFIG_SYS_STACK_SIZE (0x10000-32)
diff --git a/include/configs/grsim.h b/include/configs/grsim.h
index f815672..9e177e6 100644
--- a/include/configs/grsim.h
+++ b/include/configs/grsim.h
@@ -234,8 +234,16 @@
#define CONFIG_SYS_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */
#define CONFIG_SYS_GBL_DATA_OFFSET (CONFIG_SYS_RAM_END - CONFIG_SYS_GBL_DATA_SIZE)
-#define CONFIG_SYS_PROM_SIZE (8192-CONFIG_SYS_GBL_DATA_SIZE)
-#define CONFIG_SYS_PROM_OFFSET (CONFIG_SYS_GBL_DATA_OFFSET-CONFIG_SYS_PROM_SIZE)
+#ifdef CONFIG_MP
+#define CONFIG_SYS_MP_SIZE 512
+#define CONFIG_SYS_MP_OFFSET (CONFIG_SYS_GBL_DATA_OFFSET-CONFIG_SYS_MP_SIZE)
+#else
+#define CONFIG_SYS_MP_SIZE 0
+#define CONFIG_SYS_MP_OFFSET CONFIG_SYS_GBL_DATA_OFFSET
+#endif
+
+#define CONFIG_SYS_PROM_SIZE (8192-CONFIG_SYS_MP_SIZE-CONFIG_SYS_GBL_DATA_SIZE)
+#define CONFIG_SYS_PROM_OFFSET (CONFIG_SYS_MP_OFFSET-CONFIG_SYS_PROM_SIZE)
#define CONFIG_SYS_INIT_SP_OFFSET (CONFIG_SYS_PROM_OFFSET-32)
#define CONFIG_SYS_STACK_SIZE (0x10000-32)
diff --git a/lib_sparc/Makefile b/lib_sparc/Makefile
index 040ca10..3860fdc 100644
--- a/lib_sparc/Makefile
+++ b/lib_sparc/Makefile
@@ -27,7 +27,7 @@ LIB = $(obj)lib$(ARCH).a
SOBJS =
-COBJS = board.o cache.o interrupts.o time.o bootm.o
+COBJS = board.o cache.o interrupts.o time.o bootm.o boot_mp.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
diff --git a/lib_sparc/boot_mp.c b/lib_sparc/boot_mp.c
new file mode 100644
index 0000000..3154fd1
--- /dev/null
+++ b/lib_sparc/boot_mp.c
@@ -0,0 +1,177 @@
+/* SPARC Multi-Processor initialization
+ *
+ * (C) Copyright 2010
+ * Daniel Hellstrom, Aeroflex Gaisler, daniel at gaisler.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/boot_mp.h>
+#include <config.h>
+
+#ifdef CONFIG_MP
+
+#ifndef CONFIG_MP_MAX_CPUS
+ #error CONFIG_MP_MAX_CPUS must be defined
+#endif
+
+typedef int (*cpu_preinit_func) (int cpu);
+
+/* Structure of all MP DATA section */
+struct boot_mp_data {
+ /* Function called for each CPU before entering kernel */
+ cpu_preinit_func func;
+
+ /* All CPU entry points and so on */
+ struct boot_mp_cpu cpu_table[CONFIG_MP_MAX_CPUS];
+
+ /* OS to boot */
+ int os;
+};
+
+struct boot_mp_data MP_DATA mp_data;
+
+/* Allow for specific RTEMS CPU initialization before RTEMS AMP boot */
+void MP_TEXT __boot_mp_rtems_cpu_preinit(int cpu)
+{
+
+}
+void boot_mp_rtems_cpu_preinit(int cpu)
+ __attribute__((weak, alias("__boot_mp_rtems_cpu_preinit")));
+
+/* Allow for specific VxWorks CPU initialization before slave CPUs boot */
+void MP_TEXT __boot_mp_vxworks_cpu_preinit(int cpu)
+{
+
+}
+void boot_mp_vxworks_cpu_preinit(int cpu)
+ __attribute__((weak, alias("__boot_mp_vxworks_cpu_preinit")));
+
+/* Allow for specific Linux CPU initialization before slave CPUs boot */
+void MP_TEXT __boot_mp_linux_cpu_preinit(int cpu)
+{
+
+}
+void boot_mp_linux_cpu_preinit(int cpu)
+ __attribute__((weak, alias("__boot_mp_linux_cpu_preinit")));
+
+static cpu_preinit_func os_cpu_preinit[] =
+{
+ [IH_OS_LINUX] = boot_mp_linux_cpu_preinit,
+ [IH_OS_RTEMS] = boot_mp_rtems_cpu_preinit,
+ [IH_OS_VXWORKS] = boot_mp_vxworks_cpu_preinit,
+};
+
+void boot_mp_os_setup(int os)
+{
+ struct boot_mp_data *mpd = (void *)CONFIG_SYS_MP_OFFSET;
+ unsigned int func;
+
+ mpd->os = os;
+
+ func = (unsigned int)os_cpu_preinit[os];
+ if ( func == 0 ) {
+ /* We assume that the OS booting does not support MP and will
+ * therefore not start the other CPUs.
+ */
+ mpd->func = 0;
+ } else {
+ mpd->func = CONFIG_SYS_MP_OFFSET + (func & (CONFIG_SYS_MP_SIZE-1));
+ }
+
+ debug("boot_mp_os_setup: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
+ os,
+ os_cpu_preinit,
+ &os_cpu_preinit[os],
+ (unsigned int)os_cpu_preinit[os],
+ CONFIG_SYS_MP_SIZE,
+ ((unsigned int)os_cpu_preinit[os] & (CONFIG_SYS_MP_SIZE-1))
+ );
+}
+
+void boot_mp_cpu_setup(
+ int cpu,
+ unsigned int entry_point,
+ unsigned int stack,
+ void *arg0,
+ void *arg1
+ )
+{
+ struct boot_mp_data *mpd = (void *)CONFIG_SYS_MP_OFFSET;
+
+ if ( cpu >= CONFIG_MP_MAX_CPUS )
+ return;
+
+ mpd->cpu_table[cpu].entry_point = entry_point;
+ mpd->cpu_table[cpu].stack = stack;
+ mpd->cpu_table[cpu].arg0 = arg0;
+ mpd->cpu_table[cpu].arg1 = arg1;
+
+ debug("boot_mp_cpu_setup(%d): ep=0x%x stack=0x%x, arg=[0x%x,0x%x]\n",
+ cpu, entry_point, stack, arg0, arg1);
+}
+
+/* In a RTEMS AMP system all CPUs have different entry points and stacks,
+ * the addresses are taken from the environment variables:
+ * cpu0_entry and cpu0_stack
+ */
+void boot_mp_rtems_setup(void)
+{
+ char *str;
+ char env_str[16];
+ int cpu;
+ unsigned int entry, stack;
+
+ for(cpu=0; cpu<CONFIG_MP_MAX_CPUS; cpu++) {
+
+ entry = 0;
+ stack = 0;
+
+ strcpy(env_str, "cpuX_entry");
+ env_str[3] = '0' + cpu;
+ if ( (str = getenv(env_str)) != NULL ) {
+ entry = simple_strtoul(str, NULL, 16);
+ }
+
+ strcpy(env_str, "cpuX_stack");
+ env_str[3] = '0' + cpu;
+ if ( (str = getenv(env_str)) != NULL ) {
+ stack = simple_strtoul(str, NULL, 16);
+ }
+
+ boot_mp_cpu_setup(
+ cpu,
+ (unsigned int)entry,
+ (unsigned int)stack,
+ NULL,
+ NULL);
+ }
+}
+
+/* Prepare boot, called from bootm */
+void arch_preboot_os(int os)
+{
+ boot_mp_os_setup(os);
+
+ if ( os == IH_OS_RTEMS )
+ boot_mp_rtems_setup();
+}
+
+#endif
diff --git a/lib_sparc/bootm.c b/lib_sparc/bootm.c
index f517325..428ad97 100644
--- a/lib_sparc/bootm.c
+++ b/lib_sparc/bootm.c
@@ -28,11 +28,12 @@
#include <asm/prom.h>
#include <asm/cache.h>
#include <image.h>
+#include <asm-sparc/boot_mp.h>
#define PRINT_KERNEL_HEADER
extern image_header_t header;
-extern void srmmu_init_cpu(unsigned int entry);
+extern void srmmu_init(unsigned int entry);
extern void prepare_bootargs(char *bootargs);
/* sparc kernel argument (the ROM vector) */
@@ -43,7 +44,8 @@ struct linux_romvec *kernel_arg_promvec;
#define RAMDISK_IMAGE_START_MASK 0x07FF
#define RAMDISK_PROMPT_FLAG 0x8000
#define RAMDISK_LOAD_FLAG 0x4000
-struct __attribute__ ((packed)) {
+/* Linux Single CPU Header */
+struct linux_up_hdr {
char traptable[PAGE_SIZE];
char swapper_pg_dir[PAGE_SIZE];
char pg0[PAGE_SIZE];
@@ -73,7 +75,13 @@ struct __attribute__ ((packed)) {
unsigned int end;
} ver_0203;
} hdr_input;
-} *linux_hdr;
+} __attribute__ ((packed)) ;
+
+/* Linux SMP Header */
+struct linux_smp_hdr {
+ char traptable[3][PAGE_SIZE];
+ struct linux_up_hdr single_hdr;
+} __attribute__ ((packed));
/* temporary initrd image holder */
image_header_t ihdr;
@@ -98,23 +106,34 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t * images)
void (*kernel) (struct linux_romvec *, void *);
struct lmb *lmb = &images->lmb;
int ret;
+ int i;
+ struct linux_up_hdr *linux_hdr;
+ struct linux_smp_hdr *linux_smp_hdr;
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
- /* Get virtual address of kernel start */
- linux_hdr = (void *)images->os.load;
-
- /* */
+ /* Kernel Entry Point */
kernel = (void (*)(struct linux_romvec *, void *))images->ep;
+ /* Get virtual address of kernel start */
+ linux_hdr = (struct linux_up_hdr *)images->os.load;
+
/* check for a SPARC kernel */
if ((linux_hdr->hdr[0] != 'H') ||
(linux_hdr->hdr[1] != 'd') ||
(linux_hdr->hdr[2] != 'r') || (linux_hdr->hdr[3] != 'S')) {
- puts("Error reading header of SPARC Linux kernel, aborting\n");
- goto error;
+ /* Not a valid Linux Header, check if Linux SMP header */
+ linux_smp_hdr = (struct linux_smp_hdr *)images->os.load;
+ linux_hdr = (struct linux_up_hdr *)&linux_smp_hdr->single_hdr;
+ if ((linux_hdr->hdr[0] != 'H') ||
+ (linux_hdr->hdr[1] != 'd') ||
+ (linux_hdr->hdr[2] != 'r') || (linux_hdr->hdr[3] != 'S')) {
+ puts("Error reading header of SPARC Linux kernel, aborting\n");
+ goto error;
+ }
}
+
#ifdef PRINT_KERNEL_HEADER
printf("## Found SPARC Linux kernel %d.%d.%d ...\n",
linux_hdr->linuxver_major,
@@ -164,8 +183,24 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t * images)
bootargs = getenv("bootargs");
prepare_bootargs(bootargs);
- /* turn on mmu & setup context table & page table for process 0 (kernel) */
- srmmu_init_cpu((unsigned int)kernel);
+ /* Init MMU table of SRMMU and more */
+ srmmu_init((unsigned int)kernel);
+
+#ifdef CONFIG_MP
+ for(i=0; i<CONFIG_MP_MAX_CPUS; i++) {
+ boot_mp_cpu_setup(
+ i,
+ (unsigned int)kernel,
+ (unsigned int)CONFIG_SYS_INIT_SP_OFFSET,
+ kernel_arg_promvec,
+ NULL);
+ }
+#endif
+
+ /* turn on mmu & setup context table & page table for process 0 (kernel).
+ * This function is later called by each CPU in a multiprocessor system.
+ */
+ boot_mp_linux_cpu_preinit(0);
/* Enter SPARC Linux kernel
* From now on the only code in u-boot that will be
--
1.5.4
More information about the U-Boot
mailing list