lkml.org 
[lkml]   [2010]   [Nov]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH 1/8] ARM: SCU: Add common routines for secondary CPU bootup
    For CNS3xxx we want to reuse the original ARM approach of booting
    secondary CPUs. This patch factors out VExpress' code into a common
    file, so that now platform code can call these routines.

    Note that this patch doesn't convert VExpress platform to the
    generic routines. Plus, there are also a lot of other platforms
    that might benefit from this change, but we'll convert them via
    separate patches.

    Signed-off-by: Anton Vorontsov <avorontsov@mvista.com>
    ---
    arch/arm/include/asm/smp_scu.h | 9 +++
    arch/arm/kernel/Makefile | 2 +-
    arch/arm/kernel/smp_scu_boot.c | 149 ++++++++++++++++++++++++++++++++++++++++
    arch/arm/kernel/smp_scu_head.S | 40 +++++++++++
    4 files changed, 199 insertions(+), 1 deletions(-)
    create mode 100644 arch/arm/kernel/smp_scu_boot.c
    create mode 100644 arch/arm/kernel/smp_scu_head.S

    diff --git a/arch/arm/include/asm/smp_scu.h b/arch/arm/include/asm/smp_scu.h
    index 2376835..271b252 100644
    --- a/arch/arm/include/asm/smp_scu.h
    +++ b/arch/arm/include/asm/smp_scu.h
    @@ -1,7 +1,16 @@
    #ifndef __ASMARM_ARCH_SCU_H
    #define __ASMARM_ARCH_SCU_H

    +#include <linux/init.h>
    +
    unsigned int scu_get_core_count(void __iomem *);
    void scu_enable(void __iomem *);

    +extern volatile int __cpuinitdata scu_pen_release;
    +void scu_secondary_startup(void);
    +void __cpuinit scu_secondary_init(unsigned int cpu);
    +int __cpuinit scu_boot_secondary(unsigned int cpu, struct task_struct *idle);
    +void __init scu_init_cpus(void __iomem *scu_base);
    +void __init scu_prepare_cpus(void __iomem *scu_base, unsigned int max_cpus);
    +
    #endif
    diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
    index 806d5e1..11d946a 100644
    --- a/arch/arm/kernel/Makefile
    +++ b/arch/arm/kernel/Makefile
    @@ -30,7 +30,7 @@ obj-$(CONFIG_ARTHUR) += arthur.o
    obj-$(CONFIG_ISA_DMA) += dma-isa.o
    obj-$(CONFIG_PCI) += bios32.o isa.o
    obj-$(CONFIG_SMP) += smp.o
    -obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o
    +obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o smp_scu_head.o smp_scu_boot.o
    obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o
    obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
    obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
    diff --git a/arch/arm/kernel/smp_scu_boot.c b/arch/arm/kernel/smp_scu_boot.c
    new file mode 100644
    index 0000000..32a1658
    --- /dev/null
    +++ b/arch/arm/kernel/smp_scu_boot.c
    @@ -0,0 +1,149 @@
    +/*
    + * Copyright (C) 2002 ARM Ltd.
    + * All Rights Reserved
    + *
    + * 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/compiler.h>
    +#include <linux/kernel.h>
    +#include <linux/init.h>
    +#include <linux/io.h>
    +#include <linux/jiffies.h>
    +#include <linux/delay.h>
    +
    +#include <asm/smp_scu.h>
    +#include <asm/localtimer.h>
    +#include <asm/cacheflush.h>
    +
    +/*
    + * control for which core is the next to come out of the secondary
    + * boot "holding pen"
    + */
    +volatile int __cpuinitdata scu_pen_release = -1;
    +
    +static DEFINE_SPINLOCK(boot_lock);
    +
    +void __cpuinit scu_secondary_init(unsigned int cpu)
    +{
    + /*
    + * let the primary processor know we're out of the
    + * pen, then head off into the C entry point
    + */
    + scu_pen_release = -1;
    + smp_wmb();
    +
    + /*
    + * Synchronise with the boot thread.
    + */
    + spin_lock(&boot_lock);
    + spin_unlock(&boot_lock);
    +}
    +
    +int __cpuinit scu_boot_secondary(unsigned int cpu, struct task_struct *idle)
    +{
    + unsigned long timeout;
    +
    + /*
    + * Set synchronisation state between this boot processor
    + * and the secondary one
    + */
    + spin_lock(&boot_lock);
    +
    + /*
    + * This is really belt and braces; we hold unintended secondary
    + * CPUs in the holding pen until we're ready for them. However,
    + * since we haven't sent them a soft interrupt, they shouldn't
    + * be there.
    + */
    + scu_pen_release = cpu;
    + __cpuc_flush_dcache_area((void *)&scu_pen_release,
    + sizeof(scu_pen_release));
    + outer_clean_range(__pa(&scu_pen_release), __pa(&scu_pen_release + 1));
    +
    + /*
    + * Send the secondary CPU a soft interrupt, thereby causing
    + * the boot monitor to read the system wide flags register,
    + * and branch to the address found there.
    + */
    + smp_cross_call(cpumask_of(cpu), 1);
    +
    + timeout = jiffies + (1 * HZ);
    + while (time_before(jiffies, timeout)) {
    + smp_rmb();
    + if (scu_pen_release == -1)
    + break;
    +
    + udelay(10);
    + }
    +
    + /*
    + * now the secondary core is starting up let it run its
    + * calibrations, then wait for it to finish
    + */
    + spin_unlock(&boot_lock);
    +
    + return scu_pen_release != -1 ? -ENOSYS : 0;
    +}
    +
    +/*
    + * Initialise the CPU possible map early - this describes the CPUs
    + * which may be present or become present in the system.
    + */
    +void __init scu_init_cpus(void __iomem *scu_base)
    +{
    + unsigned int ncores = scu_base ? scu_get_core_count(scu_base) : 1;
    + unsigned int i;
    +
    + /* sanity check */
    + if (ncores == 0) {
    + pr_err("%s: strange CM count of 0? Default to 1\n", __func__);
    + ncores = 1;
    + }
    +
    + if (ncores > NR_CPUS) {
    + pr_warn("%s: no. of cores (%d) greater than configured "
    + "maximum of %d - clipping\n", __func__, ncores, NR_CPUS);
    + ncores = NR_CPUS;
    + }
    +
    + for (i = 0; i < ncores; i++)
    + set_cpu_possible(i, true);
    +}
    +
    +void __init scu_prepare_cpus(void __iomem *scu_base, unsigned int max_cpus)
    +{
    + unsigned int ncores = num_possible_cpus();
    + unsigned int cpu = smp_processor_id();
    + int i;
    +
    + smp_store_cpu_info(cpu);
    +
    + /*
    + * are we trying to boot more cores than exist?
    + */
    + if (max_cpus > ncores)
    + max_cpus = ncores;
    +
    + /*
    + * Initialise the present map, which describes the set of CPUs
    + * actually populated at the present time.
    + */
    + for (i = 0; i < max_cpus; i++)
    + set_cpu_present(i, true);
    +
    + /*
    + * Initialise the SCU if there are more than one CPU and let
    + * them know where to start.
    + */
    + if (max_cpus > 1) {
    + /*
    + * Enable the local timer or broadcast device for the
    + * boot CPU, but only if we have more than one CPU.
    + */
    + percpu_timer_setup();
    +
    + scu_enable(scu_base);
    + }
    +}
    diff --git a/arch/arm/kernel/smp_scu_head.S b/arch/arm/kernel/smp_scu_head.S
    new file mode 100644
    index 0000000..e1ceb25
    --- /dev/null
    +++ b/arch/arm/kernel/smp_scu_head.S
    @@ -0,0 +1,40 @@
    +/*
    + * Copyright (c) 2003 ARM Limited
    + * All Rights Reserved
    + *
    + * 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>
    +
    + __INIT
    +
    +/*
    + * SCU specific entry point for secondary CPUs. This provides
    + * a "holding pen" into which all secondary cores are held until we're
    + * ready for them to initialise.
    + */
    +ENTRY(scu_secondary_startup)
    + mrc p15, 0, r0, c0, c0, 5
    + and r0, r0, #15
    + adr r4, 1f
    + ldmia r4, {r5, r6}
    + sub r4, r4, r5
    + add r6, r6, r4
    +#if __LINUX_ARM_ARCH__ >= 7
    + dsb
    +#endif
    +pen: ldr r7, [r6]
    + cmp r7, r0
    + bne pen
    +
    + /*
    + * we've been released from the holding pen: secondary_stack
    + * should now contain the SVC stack for this core
    + */
    + b secondary_startup
    +
    +1: .long .
    + .long scu_pen_release
    --
    1.7.0.5


    \
     
     \ /
      Last update: 2010-11-30 18:41    [W:0.044 / U:128.724 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site