[PATCH v2 08/10] arm: zynq: Add smp support

Michal Simek monstr at monstr.eu
Wed Mar 27 04:59:51 EDT 2013


2013/3/26 Michal Simek <michal.simek at xilinx.com>:
> Zynq is dual core Cortex A9 which starts always
> at zero. Using simple trampoline ensure long jump
> to secondary_startup code.
>
> Signed-off-by: Michal Simek <michal.simek at xilinx.com>
> Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
> ---
> v2: Remove boot_lock from secondary_init
>     Incorporate Steffen changes in smp code
>     Use flush range instead of simple flush
>     Add HAVE_SMP
>     Add support for the booting kernels with
>       non zero starting address
> ---
>  arch/arm/mach-zynq/Kconfig   |    1 +
>  arch/arm/mach-zynq/Makefile  |    1 +
>  arch/arm/mach-zynq/common.c  |    1 +
>  arch/arm/mach-zynq/common.h  |   11 ++++
>  arch/arm/mach-zynq/headsmp.S |   24 +++++++
>  arch/arm/mach-zynq/platsmp.c |  149 ++++++++++++++++++++++++++++++++++++++++++
>  arch/arm/mach-zynq/slcr.c    |   29 ++++++++
>  7 files changed, 216 insertions(+)
>  create mode 100644 arch/arm/mach-zynq/headsmp.S
>  create mode 100644 arch/arm/mach-zynq/platsmp.c
>
> diff --git a/arch/arm/mach-zynq/Kconfig b/arch/arm/mach-zynq/Kconfig
> index d70651e..f4a7e63 100644
> --- a/arch/arm/mach-zynq/Kconfig
> +++ b/arch/arm/mach-zynq/Kconfig
> @@ -8,6 +8,7 @@ config ARCH_ZYNQ
>         select ICST
>         select MIGHT_HAVE_CACHE_L2X0
>         select USE_OF
> +       select HAVE_SMP
>         select SPARSE_IRQ
>         select CADENCE_TTC_TIMER
>         help
> diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile
> index 13ee09b..b595d22 100644
> --- a/arch/arm/mach-zynq/Makefile
> +++ b/arch/arm/mach-zynq/Makefile
> @@ -4,3 +4,4 @@
>
>  # Common support
>  obj-y                          := common.o slcr.o
> +obj-$(CONFIG_SMP)              += headsmp.o platsmp.o
> diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c
> index 4ad3560..da93957 100644
> --- a/arch/arm/mach-zynq/common.c
> +++ b/arch/arm/mach-zynq/common.c
> @@ -104,6 +104,7 @@ static const char *xilinx_dt_match[] = {
>  };
>
>  MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform")
> +       .smp            = smp_ops(zynq_smp_ops),
>         .map_io         = xilinx_map_io,
>         .init_irq       = irqchip_init,
>         .init_machine   = xilinx_init_machine,
> diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h
> index e5628f7..33cdc23 100644
> --- a/arch/arm/mach-zynq/common.h
> +++ b/arch/arm/mach-zynq/common.h
> @@ -19,6 +19,17 @@
>
>  extern int slcr_init(void);
>  extern void slcr_system_reset(void);
> +extern void slcr_cpu_stop(int cpu);
> +extern void slcr_cpu_start(int cpu);
> +
> +#ifdef CONFIG_SMP
> +extern void secondary_startup(void);
> +extern char zynq_secondary_trampoline;
> +extern char zynq_secondary_trampoline_jump;
> +extern char zynq_secondary_trampoline_end;
> +extern int __cpuinit zynq_cpun_start(u32 address, int cpu);
> +extern struct smp_operations zynq_smp_ops __initdata;
> +#endif
>
>  extern void __iomem *zynq_slcr_base;
>  extern void __iomem *scu_base;
> diff --git a/arch/arm/mach-zynq/headsmp.S b/arch/arm/mach-zynq/headsmp.S
> new file mode 100644
> index 0000000..d183cd2
> --- /dev/null
> +++ b/arch/arm/mach-zynq/headsmp.S
> @@ -0,0 +1,24 @@
> +/*
> + * Copyright (c) 2013 Steffen Trumtrar <s.trumtrar at pengutronix.de>
> + * Copyright (c) 2012-2013 Xilinx
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#include <linux/linkage.h>
> +#include <linux/init.h>
> +
> +       __CPUINIT
> +
> +ENTRY(zynq_secondary_trampoline)
> +       ldr     r0, [pc]
> +       bx      r0
> +.globl zynq_secondary_trampoline_jump
> +zynq_secondary_trampoline_jump:
> +       /* Space for jumping address */
> +       .word   /* cpu 1 */
> +.globl zynq_secondary_trampoline_end
> +zynq_secondary_trampoline_end:
> +
> +ENDPROC(zynq_secondary_trampoline)
> diff --git a/arch/arm/mach-zynq/platsmp.c b/arch/arm/mach-zynq/platsmp.c
> new file mode 100644
> index 0000000..062b319
> --- /dev/null
> +++ b/arch/arm/mach-zynq/platsmp.c
> @@ -0,0 +1,149 @@
> +/*
> + * This file contains Xilinx specific SMP code, used to start up
> + * the second processor.
> + *
> + * Copyright (C) 2011-2013 Xilinx
> + *
> + * based on linux/arch/arm/mach-realview/platsmp.c
> + *
> + * Copyright (C) 2002 ARM Ltd.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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.
> + */
> +
> +#include <linux/export.h>
> +#include <linux/jiffies.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <asm/cacheflush.h>
> +#include <asm/smp_scu.h>
> +#include <linux/irqchip/arm-gic.h>
> +#include "common.h"
> +
> +/*
> + * Store number of cores in the system
> + * Because of scu_get_core_count() must be in __init section and can't
> + * be called from zynq_cpun_start() because it is in __cpuinit section.
> + */
> +static int ncores;
> +
> +/* Secondary CPU kernel startup is a 2 step process. The primary CPU
> + * starts the secondary CPU by giving it the address of the kernel and
> + * then sending it an event to wake it up. The secondary CPU then
> + * starts the kernel and tells the primary CPU it's up and running.
> + */
> +static void __cpuinit zynq_secondary_init(unsigned int cpu)
> +{
> +       /*
> +        * if any interrupts are already enabled for the primary
> +        * core (e.g. timer irq), then they will not have been enabled
> +        * for us: do so
> +        */
> +       gic_secondary_init(0);
> +}
> +
> +int __cpuinit zynq_cpun_start(u32 address, int cpu)
> +{
> +       u32 trampoline_code_size = &zynq_secondary_trampoline_end -
> +                                               &zynq_secondary_trampoline;
> +
> +       if (cpu > ncores) {
> +               pr_warn("CPU No. is not available in the system\n");
> +               return -1;
> +       }
> +
> +       /* MS: Expectation that SLCR are directly map and accessible */
> +       /* Not possible to jump to non aligned address */
> +       if (!(address & 3) && (!address || (address >= trampoline_code_size))) {
> +               /* Store pointer to ioremap area which points to address 0x0 */
> +               static u8 __iomem *zero;
> +               u32 trampoline_size = &zynq_secondary_trampoline_jump -
> +                                               &zynq_secondary_trampoline;
> +
> +               slcr_cpu_stop(cpu);
> +
> +               if (__pa(PAGE_OFFSET)) {
> +                       zero = ioremap(0, trampoline_code_size);
> +                       if (!zero) {
> +                               pr_warn("BOOTUP jump vectors not accessible\n");
> +                               return -1;
> +                       }
> +               } else {
> +                       zero = (__force u8 __iomem *)PAGE_OFFSET;
> +               }
> +
> +               /*
> +                * This is elegant way how to jump to any address
> +                * 0x0: Load address at 0x8 to r0
> +                * 0x4: Jump by mov instruction
> +                * 0x8: Jumping address
> +                */
> +               memcpy((__force void *)zero, &zynq_secondary_trampoline,
> +                                               trampoline_size);
> +               writel(address, zero + trampoline_size + sizeof(int));

Please remove this  + sizeof(int). I forget to remove it from this version.
Because I tested Rob's idea to have jump table based on cpu id.

Thanks,
Michal


-- 
Michal Simek, Ing. (M.Eng)
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/
Maintainer of Linux kernel - Xilinx Zynq ARM architecture
Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform



More information about the linux-arm-kernel mailing list