Signed-off-by: Daniel Hellstrom <dan...@gaisler.com>
---
 arch/sparc/cpu/leon3/Makefile           |    2 +-
 arch/sparc/cpu/leon3/cpu.c              |   10 ++-
 arch/sparc/cpu/leon3/cpu_mp.c           |   87 +++++++++++++++
 arch/sparc/cpu/leon3/prom.c             |   32 +++---
 arch/sparc/cpu/leon3/start.S            |   70 ++++++++++++
 arch/sparc/include/asm/boot_mp.h        |   70 ++++++++++++
 arch/sparc/lib/Makefile                 |    2 +-
 arch/sparc/lib/boot_mp.c                |  177 +++++++++++++++++++++++++++++++
 arch/sparc/lib/bootm.c                  |   57 ++++++++--
 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 ++
 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 ++-
 17 files changed, 547 insertions(+), 38 deletions(-)
 create mode 100644 arch/sparc/cpu/leon3/cpu_mp.c
 create mode 100644 arch/sparc/include/asm/boot_mp.h
 create mode 100644 arch/sparc/lib/boot_mp.c

diff --git a/arch/sparc/cpu/leon3/Makefile b/arch/sparc/cpu/leon3/Makefile
index f1bb808..4d36061 100644
--- a/arch/sparc/cpu/leon3/Makefile
+++ b/arch/sparc/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/arch/sparc/cpu/leon3/cpu.c b/arch/sparc/cpu/leon3/cpu.c
index 5cc9513..13d3dd7 100644
--- a/arch/sparc/cpu/leon3/cpu.c
+++ b/arch/sparc/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/arch/sparc/cpu/leon3/cpu_mp.c b/arch/sparc/cpu/leon3/cpu_mp.c
new file mode 100644
index 0000000..9074149
--- /dev/null
+++ b/arch/sparc/cpu/leon3/cpu_mp.c
@@ -0,0 +1,87 @@
+/* Interface implementation for cmd_mp.c on multi processor LEON
+ * CPUs
+ *
+ * (C) Copyright 2010
+ * Daniel Hellstrom, Gaisler Research, dan...@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_disable(int nr)
+{
+       printf("LEON CPU disable not available\n");
+
+       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/arch/sparc/cpu/leon3/prom.c b/arch/sparc/cpu/leon3/prom.c
index e0a69af..eb7350b 100644
--- a/arch/sparc/cpu/leon3/prom.c
+++ b/arch/sparc/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/arch/sparc/cpu/leon3/start.S b/arch/sparc/cpu/leon3/start.S
index a9c49d9..050f604 100644
--- a/arch/sparc/cpu/leon3/start.S
+++ b/arch/sparc/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/arch/sparc/include/asm/boot_mp.h b/arch/sparc/include/asm/boot_mp.h
new file mode 100644
index 0000000..e033b9c
--- /dev/null
+++ b/arch/sparc/include/asm/boot_mp.h
@@ -0,0 +1,70 @@
+/* Multiprocessor boot setup functions.
+ *
+ * (C) Copyright 2010
+ * Daniel Hellstrom, Gaisler Research, dan...@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/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index 040ca10..3860fdc 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/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/arch/sparc/lib/boot_mp.c b/arch/sparc/lib/boot_mp.c
new file mode 100644
index 0000000..3b4dcd0
--- /dev/null
+++ b/arch/sparc/lib/boot_mp.c
@@ -0,0 +1,177 @@
+/* SPARC Multi-Processor initialization
+ *
+ * (C) Copyright 2010
+ * Daniel Hellstrom, Aeroflex Gaisler, dan...@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/arch/sparc/lib/bootm.c b/arch/sparc/lib/bootm.c
index f517325..3d25bf7 100644
--- a/arch/sparc/lib/bootm.c
+++ b/arch/sparc/lib/bootm.c
@@ -28,11 +28,12 @@
 #include <asm/prom.h>
 #include <asm/cache.h>
 #include <image.h>
+#include <asm/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
diff --git a/board/gaisler/gr_cpci_ax2000/u-boot.lds 
b/board/gaisler/gr_cpci_ax2000/u-boot.lds
index 2282682..4f116a1 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 0ca2651..7c2d82c 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 67222ac..769df44 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 681fd8d..c25d533 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/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)
-- 
1.5.4

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to