Commit 704cfd7f authored by Patrice Chotard's avatar Patrice Chotard

ARM: sti: remove pen_release and boot_lock

The pen_release implementation was created for Versatile platforms to
work around boot loaders that did not differentiate between the
various different secondary CPUs on this ARM development platform.
This should not be true of modern platforms where we send IPIs to
specific CPUs to wake them up.  Remove the pen_release stuff from
SoCs that make use of the per-CPU IPI mechanism.

The boot_lock is something that was required for ARM development
platforms to ensure that the delay calibration worked properly.  This
is not necessary for modern platforms that have better bus bandwidth
and do not need to calibrate the delay loop for secondary cores.
Remove the boot_lock entirely.

Due to pen_release and boot_lock removal, .smp_prepare_cpus and
.smp_boot_secondary STi callbacks must be reworked properly to
allow secondary CPU bring up.

Secondary CPU is initialized and started by a U-BOOTROM firmware.
Secondary CPU is spinning and waiting for a write at cpu_strt_ptr.
Writing secondary_startup address at cpu_strt_ptr makes it to
jump directly to secondary_startup().

This write must be done in .smp_boot_secondary callback and not
in .smp_prepare_cpus as previously, this insures that secondary_data
struct is populated in __cpu_up() (stack, pgdir and swapper_pg_dir fields).

The IPI in sti_boot_secondary() is useless, so remove it.

This patch is the merged of Russell's patch [1] and the rework of
.smp_prepare_cpus and .smp_boot_secondary STi callbacks [2].

[1] https://patchwork.kernel.org/patch/10729435/
[2] https://patchwork.kernel.org/patch/10735795/Signed-off-by: default avatarRussell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarPatrice Chotard <patrice.chotard@st.com>
parent 65102238
obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_ARCH_STI) += board-dt.o obj-$(CONFIG_ARCH_STI) += board-dt.o
/*
* arch/arm/mach-sti/headsmp.S
*
* Copyright (C) 2013 STMicroelectronics (R&D) Limited.
* http://www.st.com
*
* Cloned from linux/arch/arm/mach-vexpress/headsmp.S
*
* 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>
/*
* ST 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(sti_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
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
ENDPROC(sti_secondary_startup)
1: .long .
.long pen_release
...@@ -28,82 +28,33 @@ ...@@ -28,82 +28,33 @@
#include "smp.h" #include "smp.h"
static void write_pen_release(int val) static u32 __iomem *cpu_strt_ptr;
{
pen_release = val;
smp_wmb();
sync_cache_w(&pen_release);
}
static DEFINE_SPINLOCK(boot_lock);
static void sti_secondary_init(unsigned int cpu)
{
/*
* let the primary processor know we're out of the
* pen, then head off into the C entry point
*/
write_pen_release(-1);
/*
* Synchronise with the boot thread.
*/
spin_lock(&boot_lock);
spin_unlock(&boot_lock);
}
static int sti_boot_secondary(unsigned int cpu, struct task_struct *idle) static int sti_boot_secondary(unsigned int cpu, struct task_struct *idle)
{ {
unsigned long timeout; unsigned long entry_pa = __pa_symbol(secondary_startup);
/*
* set synchronisation state between this boot processor
* and the secondary one
*/
spin_lock(&boot_lock);
/* /*
* The secondary processor is waiting to be released from * Secondary CPU is initialised and started by a U-BOOTROM firmware.
* the holding pen - release it, then wait for it to flag * Secondary CPU is spinning and waiting for a write at cpu_strt_ptr.
* that it has been released by resetting pen_release. * Writing secondary_startup address at cpu_strt_ptr makes it to
* * jump directly to secondary_startup().
* Note that "pen_release" is the hardware CPU ID, whereas
* "cpu" is Linux's internal ID.
*/ */
write_pen_release(cpu_logical_map(cpu)); __raw_writel(entry_pa, cpu_strt_ptr);
/* /* wmb so that data is actually written before cache flush is done */
* Send the secondary CPU a soft interrupt, thereby causing smp_wmb();
* it to jump to the secondary entrypoint. sync_cache_w(cpu_strt_ptr);
*/
arch_send_wakeup_ipi_mask(cpumask_of(cpu));
timeout = jiffies + (1 * HZ);
while (time_before(jiffies, timeout)) {
smp_rmb();
if (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 pen_release != -1 ? -ENOSYS : 0; return 0;
} }
static void __init sti_smp_prepare_cpus(unsigned int max_cpus) static void __init sti_smp_prepare_cpus(unsigned int max_cpus)
{ {
struct device_node *np; struct device_node *np;
void __iomem *scu_base; void __iomem *scu_base;
u32 __iomem *cpu_strt_ptr;
u32 release_phys; u32 release_phys;
int cpu; int cpu;
unsigned long entry_pa = __pa_symbol(sti_secondary_startup);
np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
...@@ -131,8 +82,8 @@ static void __init sti_smp_prepare_cpus(unsigned int max_cpus) ...@@ -131,8 +82,8 @@ static void __init sti_smp_prepare_cpus(unsigned int max_cpus)
} }
/* /*
* holding pen is usually configured in SBC DMEM but can also be * cpu-release-addr is usually configured in SBC DMEM but can
* in RAM. * also be in RAM.
*/ */
if (!memblock_is_memory(release_phys)) if (!memblock_is_memory(release_phys))
...@@ -142,22 +93,11 @@ static void __init sti_smp_prepare_cpus(unsigned int max_cpus) ...@@ -142,22 +93,11 @@ static void __init sti_smp_prepare_cpus(unsigned int max_cpus)
cpu_strt_ptr = cpu_strt_ptr =
(u32 __iomem *)phys_to_virt(release_phys); (u32 __iomem *)phys_to_virt(release_phys);
__raw_writel(entry_pa, cpu_strt_ptr); set_cpu_possible(cpu, true);
/*
* wmb so that data is actually written
* before cache flush is done
*/
smp_wmb();
sync_cache_w(cpu_strt_ptr);
if (!memblock_is_memory(release_phys))
iounmap(cpu_strt_ptr);
} }
} }
const struct smp_operations sti_smp_ops __initconst = { const struct smp_operations sti_smp_ops __initconst = {
.smp_prepare_cpus = sti_smp_prepare_cpus, .smp_prepare_cpus = sti_smp_prepare_cpus,
.smp_secondary_init = sti_secondary_init,
.smp_boot_secondary = sti_boot_secondary, .smp_boot_secondary = sti_boot_secondary,
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment