2010-11-30 17:38:30

by Anton Vorontsov

[permalink] [raw]
Subject: [PATCH v4 0/8] SMP support for CNS3xxx + some SMP SCU cleanups

Hello everyone,

This is a reincarnation of my old series that was posted some time
ago, i.e. http://www.spinics.net/lists/arm-kernel/msg94291.html

The main change is that boot protocol routines were split into
its own file, i.e. smp_scu_boot.c. And now there are all platforms
converted to the common SCU routines (where possible).

Russell suggested to get rid of the holding pen thing, I believe
this is doable, but for now I don't want to change code behaviour.
Just consolidate it as much as possible.

For convenience, the patches are available in GIT repository (based
on Russell's devel tree):

git://git.infradead.org/users/cbou/linux-cns3xxx.git smp

Diffstat looks quite good, I think. Especially, considering that
the series contains SMP addition for a platform, :-)

arch/arm/Kconfig | 2 +-
arch/arm/include/asm/smp_scu.h | 9 +
arch/arm/kernel/Makefile | 2 +-
arch/arm/kernel/smp_scu_boot.c | 149 ++++++++++++++++++
.../headsmp.S => kernel/smp_scu_head.S} | 11 +-
arch/arm/mach-cns3xxx/Kconfig | 1 +
arch/arm/mach-cns3xxx/Makefile | 1 +
arch/arm/mach-cns3xxx/include/mach/smp.h | 28 ++++
arch/arm/mach-cns3xxx/platsmp.c | 69 +++++++++
arch/arm/mach-omap2/omap-smp.c | 64 +--------
arch/arm/mach-realview/Makefile | 2 +-
arch/arm/mach-realview/hotplug.c | 5 +-
arch/arm/mach-realview/platsmp.c | 161 ++------------------
arch/arm/mach-s5pv310/Makefile | 2 +-
arch/arm/mach-s5pv310/headsmp.S | 41 -----
arch/arm/mach-s5pv310/hotplug.c | 5 +-
arch/arm/mach-s5pv310/platsmp.c | 125 +---------------
arch/arm/mach-tegra/platsmp.c | 36 +----
arch/arm/mach-ux500/Makefile | 2 +-
arch/arm/mach-ux500/headsmp.S | 38 -----
arch/arm/mach-ux500/hotplug.c | 5 +-
arch/arm/mach-ux500/include/mach/smp.h | 3 -
arch/arm/mach-ux500/platsmp.c | 115 +-------------
arch/arm/mach-vexpress/Makefile | 2 +-
arch/arm/mach-vexpress/headsmp.S | 39 -----
arch/arm/mach-vexpress/platsmp.c | 150 ++-----------------
26 files changed, 318 insertions(+), 749 deletions(-)
create mode 100644 arch/arm/kernel/smp_scu_boot.c
rename arch/arm/{mach-realview/headsmp.S => kernel/smp_scu_head.S} (81%)
create mode 100644 arch/arm/mach-cns3xxx/include/mach/smp.h
create mode 100644 arch/arm/mach-cns3xxx/platsmp.c
delete mode 100644 arch/arm/mach-s5pv310/headsmp.S
delete mode 100644 arch/arm/mach-ux500/headsmp.S
delete mode 100644 arch/arm/mach-vexpress/headsmp.S


2010-11-30 17:38:35

by Anton Vorontsov

[permalink] [raw]
Subject: [PATCH 3/8] ARM: VExpress: Switch to generic SCU routines

This shrinks platform-specific code quite a bit.

Signed-off-by: Anton Vorontsov <[email protected]>
---
arch/arm/mach-vexpress/Makefile | 2 +-
arch/arm/mach-vexpress/headsmp.S | 39 ----------
arch/arm/mach-vexpress/platsmp.c | 150 ++++----------------------------------
3 files changed, 15 insertions(+), 176 deletions(-)
delete mode 100644 arch/arm/mach-vexpress/headsmp.S

diff --git a/arch/arm/mach-vexpress/Makefile b/arch/arm/mach-vexpress/Makefile
index 1b71b77..6533d11 100644
--- a/arch/arm/mach-vexpress/Makefile
+++ b/arch/arm/mach-vexpress/Makefile
@@ -4,5 +4,5 @@

obj-y := v2m.o
obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o
-obj-$(CONFIG_SMP) += platsmp.o headsmp.o
+obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
diff --git a/arch/arm/mach-vexpress/headsmp.S b/arch/arm/mach-vexpress/headsmp.S
deleted file mode 100644
index 8a78ff6..0000000
--- a/arch/arm/mach-vexpress/headsmp.S
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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>
-
- __INIT
-
-/*
- * Versatile Express 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(vexpress_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
-
-1: .long .
- .long pen_release
diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c
index 276f916..2d4146f 100644
--- a/arch/arm/mach-vexpress/platsmp.c
+++ b/arch/arm/mach-vexpress/platsmp.c
@@ -9,15 +9,9 @@
* published by the Free Software Foundation.
*/
#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/jiffies.h>
#include <linux/smp.h>
#include <linux/io.h>

-#include <asm/cacheflush.h>
-#include <asm/localtimer.h>
#include <asm/smp_scu.h>
#include <asm/unified.h>

@@ -27,21 +21,11 @@

#include "core.h"

-extern void vexpress_secondary_startup(void);
-
-/*
- * control for which core is the next to come out of the secondary
- * boot "holding pen"
- */
-volatile int __cpuinitdata pen_release = -1;
-
static void __iomem *scu_base_addr(void)
{
return MMIO_P2V(A9_MPCORE_SCU);
}

-static DEFINE_SPINLOCK(boot_lock);
-
void __cpuinit platform_secondary_init(unsigned int cpu)
{
trace_hardirqs_off();
@@ -53,138 +37,32 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
*/
gic_cpu_init(0, gic_cpu_base_addr);

- /*
- * let the primary processor know we're out of the
- * pen, then head off into the C entry point
- */
- pen_release = -1;
- smp_wmb();
-
- /*
- * Synchronise with the boot thread.
- */
- spin_lock(&boot_lock);
- spin_unlock(&boot_lock);
+ scu_secondary_init(cpu);
}

int __cpuinit 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.
- */
- pen_release = cpu;
- __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
- outer_clean_range(__pa(&pen_release), __pa(&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 (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 scu_boot_secondary(cpu, idle);
}

-/*
- * Initialise the CPU possible map early - this describes the CPUs
- * which may be present or become present in the system.
- */
void __init smp_init_cpus(void)
{
- void __iomem *scu_base = scu_base_addr();
- unsigned int i, ncores;
-
- ncores = scu_base ? scu_get_core_count(scu_base) : 1;
-
- /* sanity check */
- if (ncores == 0) {
- printk(KERN_ERR
- "vexpress: strange CM count of 0? Default to 1\n");
-
- ncores = 1;
- }
+ scu_init_cpus(scu_base_addr());
+}

- if (ncores > NR_CPUS) {
- printk(KERN_WARNING
- "vexpress: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, NR_CPUS);
- ncores = NR_CPUS;
- }
+/* If there are more than one CPU let them know where to start. */
+static void __init smp_point_cpus(void)
+{
+ if (num_present_cpus() <= 1)
+ return;

- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
+ writel(~0, MMIO_P2V(V2M_SYS_FLAGSCLR));
+ writel(BSYM(virt_to_phys(scu_secondary_startup)),
+ MMIO_P2V(V2M_SYS_FLAGSSET));
}

void __init smp_prepare_cpus(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_addr());
-
- /*
- * Write the address of secondary startup into the
- * system-wide flags register. The boot monitor waits
- * until it receives a soft interrupt, and then the
- * secondary CPU branches to this address.
- */
- writel(~0, MMIO_P2V(V2M_SYS_FLAGSCLR));
- writel(BSYM(virt_to_phys(vexpress_secondary_startup)),
- MMIO_P2V(V2M_SYS_FLAGSSET));
- }
+ scu_prepare_cpus(scu_base_addr(), max_cpus);
+ smp_point_cpus();
}
--
1.7.0.5

2010-11-30 17:38:37

by Anton Vorontsov

[permalink] [raw]
Subject: [PATCH 4/8] ARM: RealView: Switch to generic SCU routines

This shrinks platform-specific code quite a bit.

Signed-off-by: Anton Vorontsov <[email protected]>
---
arch/arm/mach-realview/Makefile | 2 +-
arch/arm/mach-realview/headsmp.S | 39 ---------
arch/arm/mach-realview/hotplug.c | 5 +-
arch/arm/mach-realview/platsmp.c | 161 +++-----------------------------------
4 files changed, 14 insertions(+), 193 deletions(-)
delete mode 100644 arch/arm/mach-realview/headsmp.S

diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile
index a01b76b..d456163 100644
--- a/arch/arm/mach-realview/Makefile
+++ b/arch/arm/mach-realview/Makefile
@@ -8,6 +8,6 @@ obj-$(CONFIG_MACH_REALVIEW_PB11MP) += realview_pb11mp.o
obj-$(CONFIG_MACH_REALVIEW_PB1176) += realview_pb1176.o
obj-$(CONFIG_MACH_REALVIEW_PBA8) += realview_pba8.o
obj-$(CONFIG_MACH_REALVIEW_PBX) += realview_pbx.o
-obj-$(CONFIG_SMP) += platsmp.o headsmp.o
+obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
diff --git a/arch/arm/mach-realview/headsmp.S b/arch/arm/mach-realview/headsmp.S
deleted file mode 100644
index 4075473..0000000
--- a/arch/arm/mach-realview/headsmp.S
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * linux/arch/arm/mach-realview/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>
-
- __INIT
-
-/*
- * Realview 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(realview_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
-
-1: .long .
- .long pen_release
diff --git a/arch/arm/mach-realview/hotplug.c b/arch/arm/mach-realview/hotplug.c
index e06572e..0261785 100644
--- a/arch/arm/mach-realview/hotplug.c
+++ b/arch/arm/mach-realview/hotplug.c
@@ -12,10 +12,9 @@
#include <linux/errno.h>
#include <linux/smp.h>

+#include <asm/smp_scu.h>
#include <asm/cacheflush.h>

-extern volatile int pen_release;
-
static inline void cpu_enter_lowpower(void)
{
unsigned int v;
@@ -69,7 +68,7 @@ static inline void platform_do_lowpower(unsigned int cpu)
:
: "memory", "cc");

- if (pen_release == cpu) {
+ if (scu_pen_release == cpu) {
/*
* OK, proper wakeup, we're done
*/
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index af3d909..3c1000b 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -9,17 +9,11 @@
* published by the Free Software Foundation.
*/
#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/jiffies.h>
#include <linux/smp.h>
#include <linux/io.h>

-#include <asm/cacheflush.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
-#include <asm/localtimer.h>
#include <asm/unified.h>

#include <mach/board-eb.h>
@@ -29,14 +23,6 @@

#include "core.h"

-extern void realview_secondary_startup(void);
-
-/*
- * control for which core is the next to come out of the secondary
- * boot "holding pen"
- */
-volatile int __cpuinitdata pen_release = -1;
-
static void __iomem *scu_base_addr(void)
{
if (machine_is_realview_eb_mp())
@@ -50,16 +36,6 @@ static void __iomem *scu_base_addr(void)
return (void __iomem *)0;
}

-static inline unsigned int get_core_count(void)
-{
- void __iomem *scu_base = scu_base_addr();
- if (scu_base)
- return scu_get_core_count(scu_base);
- return 1;
-}
-
-static DEFINE_SPINLOCK(boot_lock);
-
void __cpuinit platform_secondary_init(unsigned int cpu)
{
trace_hardirqs_off();
@@ -71,151 +47,36 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
*/
gic_cpu_init(0, gic_cpu_base_addr);

- /*
- * let the primary processor know we're out of the
- * pen, then head off into the C entry point
- */
- pen_release = -1;
- smp_wmb();
-
- /*
- * Synchronise with the boot thread.
- */
- spin_lock(&boot_lock);
- spin_unlock(&boot_lock);
+ scu_secondary_init(cpu);
}

int __cpuinit 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);
-
- /*
- * The secondary processor is waiting to be released from
- * the holding pen - release it, then wait for it to flag
- * that it has been released by resetting pen_release.
- *
- * Note that "pen_release" is the hardware CPU ID, whereas
- * "cpu" is Linux's internal ID.
- */
- pen_release = cpu;
- flush_cache_all();
-
- /*
- * XXX
- *
- * This is a later addition to the booting protocol: the
- * bootMonitor now puts secondary cores into WFI, so
- * poke_milo() no longer gets the cores moving; we need
- * to send a soft interrupt to wake the secondary core.
- * Use smp_cross_call() for this, since there's little
- * point duplicating the code here
- */
- smp_cross_call(cpumask_of(cpu), 1);
-
- 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 scu_boot_secondary(cpu, idle);
+}

- return pen_release != -1 ? -ENOSYS : 0;
+void __init smp_init_cpus(void)
+{
+ scu_init_cpus(scu_base_addr());
}

static void __init poke_milo(void)
{
- /* nobody is to be released from the pen yet */
- pen_release = -1;
-
+ if (num_present_cpus() <= 1)
+ return;
/*
* Write the address of secondary startup into the system-wide flags
* register. The BootMonitor waits for this register to become
* non-zero.
*/
- __raw_writel(BSYM(virt_to_phys(realview_secondary_startup)),
+ __raw_writel(BSYM(virt_to_phys(scu_secondary_startup)),
__io_address(REALVIEW_SYS_FLAGSSET));

mb();
}

-/*
- * Initialise the CPU possible map early - this describes the CPUs
- * which may be present or become present in the system.
- */
-void __init smp_init_cpus(void)
-{
- unsigned int i, ncores = get_core_count();
-
- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
-}
-
void __init smp_prepare_cpus(unsigned int max_cpus)
{
- unsigned int ncores = get_core_count();
- unsigned int cpu = smp_processor_id();
- int i;
-
- /* sanity check */
- if (ncores == 0) {
- printk(KERN_ERR
- "Realview: strange CM count of 0? Default to 1\n");
-
- ncores = 1;
- }
-
- if (ncores > NR_CPUS) {
- printk(KERN_WARNING
- "Realview: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, NR_CPUS);
- ncores = NR_CPUS;
- }
-
- 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. Note that, on modern versions of
- * MILO, the "poke" doesn't actually do anything until each
- * individual core is sent a soft interrupt to get it out of
- * WFI
- */
- 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_addr());
- poke_milo();
- }
+ scu_prepare_cpus(scu_base_addr(), max_cpus);
+ poke_milo();
}
--
1.7.0.5

2010-11-30 17:38:33

by Anton Vorontsov

[permalink] [raw]
Subject: [PATCH 5/8] ARM: S5PV310: Switch to generic SCU routines

This shrinks platform-specific code quite a bit.

Signed-off-by: Anton Vorontsov <[email protected]>
---
arch/arm/mach-s5pv310/Makefile | 2 +-
arch/arm/mach-s5pv310/headsmp.S | 41 -------------
arch/arm/mach-s5pv310/hotplug.c | 5 +-
arch/arm/mach-s5pv310/platsmp.c | 125 ++-------------------------------------
4 files changed, 9 insertions(+), 164 deletions(-)
delete mode 100644 arch/arm/mach-s5pv310/headsmp.S

diff --git a/arch/arm/mach-s5pv310/Makefile b/arch/arm/mach-s5pv310/Makefile
index 84afc64..b72abd2 100644
--- a/arch/arm/mach-s5pv310/Makefile
+++ b/arch/arm/mach-s5pv310/Makefile
@@ -15,7 +15,7 @@ obj- :=
obj-$(CONFIG_CPU_S5PV310) += cpu.o init.o clock.o irq-combiner.o
obj-$(CONFIG_CPU_S5PV310) += setup-i2c0.o time.o gpiolib.o irq-eint.o

-obj-$(CONFIG_SMP) += platsmp.o headsmp.o
+obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o

diff --git a/arch/arm/mach-s5pv310/headsmp.S b/arch/arm/mach-s5pv310/headsmp.S
deleted file mode 100644
index 164b7b0..0000000
--- a/arch/arm/mach-s5pv310/headsmp.S
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * linux/arch/arm/mach-s5pv310/headsmp.S
- *
- * Cloned from linux/arch/arm/mach-realview/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>
-
- __INIT
-
-/*
- * s5pv310 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(s5pv310_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
-
-1: .long .
- .long pen_release
diff --git a/arch/arm/mach-s5pv310/hotplug.c b/arch/arm/mach-s5pv310/hotplug.c
index ea951ef..ff1bc05 100644
--- a/arch/arm/mach-s5pv310/hotplug.c
+++ b/arch/arm/mach-s5pv310/hotplug.c
@@ -14,10 +14,9 @@
#include <linux/errno.h>
#include <linux/smp.h>

+#include <asm/smp_scu.h>
#include <asm/cacheflush.h>

-extern volatile int pen_release;
-
static inline void cpu_enter_lowpower(void)
{
unsigned int v;
@@ -72,7 +71,7 @@ static inline void platform_do_lowpower(unsigned int cpu)
:
: "memory", "cc");

- if (pen_release == cpu) {
+ if (scu_pen_release == cpu) {
/*
* OK, proper wakeup, we're done
*/
diff --git a/arch/arm/mach-s5pv310/platsmp.c b/arch/arm/mach-s5pv310/platsmp.c
index d474426..1a3f681 100644
--- a/arch/arm/mach-s5pv310/platsmp.c
+++ b/arch/arm/mach-s5pv310/platsmp.c
@@ -14,37 +14,25 @@
*/

#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/jiffies.h>
#include <linux/smp.h>
#include <linux/io.h>

-#include <asm/cacheflush.h>
-#include <asm/localtimer.h>
#include <asm/smp_scu.h>
#include <asm/unified.h>

#include <mach/hardware.h>
#include <mach/regs-clock.h>

-extern void s5pv310_secondary_startup(void);
-
/*
* control for which core is the next to come out of the secondary
* boot "holding pen"
*/

-volatile int __cpuinitdata pen_release = -1;
-
static void __iomem *scu_base_addr(void)
{
return (void __iomem *)(S5P_VA_SCU);
}

-static DEFINE_SPINLOCK(boot_lock);
-
void __cpuinit platform_secondary_init(unsigned int cpu)
{
trace_hardirqs_off();
@@ -56,65 +44,12 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
*/
gic_cpu_init(0, gic_cpu_base_addr);

- /*
- * let the primary processor know we're out of the
- * pen, then head off into the C entry point
- */
- pen_release = -1;
- smp_wmb();
-
- /*
- * Synchronise with the boot thread.
- */
- spin_lock(&boot_lock);
- spin_unlock(&boot_lock);
+ scu_secondary_init(cpu);
}

int __cpuinit 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);
-
- /*
- * The secondary processor is waiting to be released from
- * the holding pen - release it, then wait for it to flag
- * that it has been released by resetting pen_release.
- *
- * Note that "pen_release" is the hardware CPU ID, whereas
- * "cpu" is Linux's internal ID.
- */
- pen_release = cpu;
- __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
- outer_clean_range(__pa(&pen_release), __pa(&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 (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 scu_boot_secondary(cpu, idle);
}

/*
@@ -124,69 +59,21 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)

void __init smp_init_cpus(void)
{
- void __iomem *scu_base = scu_base_addr();
- unsigned int i, ncores;
-
- ncores = scu_base ? scu_get_core_count(scu_base) : 1;
-
- /* sanity check */
- if (ncores == 0) {
- printk(KERN_ERR
- "S5PV310: strange CM count of 0? Default to 1\n");
-
- ncores = 1;
- }
-
- if (ncores > NR_CPUS) {
- printk(KERN_WARNING
- "S5PV310: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, NR_CPUS);
- ncores = NR_CPUS;
- }
-
- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
+ scu_init_cpus(scu_base_addr());
}

void __init smp_prepare_cpus(unsigned int max_cpus)
{
- unsigned int ncores = num_possible_cpus();
- unsigned int cpu = smp_processor_id();
- int i;
-
- smp_store_cpu_info(cpu);
+ scu_prepare_cpus(scu_base_addr(), max_cpus);

- /* 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_addr());
-
- /*
* Write the address of secondary startup into the
* system-wide flags register. The boot monitor waits
* until it receives a soft interrupt, and then the
* secondary CPU branches to this address.
*/
- __raw_writel(BSYM(virt_to_phys(s5pv310_secondary_startup)), S5P_VA_SYSRAM);
+ __raw_writel(BSYM(virt_to_phys(scu_secondary_startup)),
+ S5P_VA_SYSRAM);
}
}
--
1.7.0.5

2010-11-30 17:38:32

by Anton Vorontsov

[permalink] [raw]
Subject: [PATCH 7/8] ARM: tegra: Switch to generic SCU routines

This shrinks platform-specific code a little bit.

Signed-off-by: Anton Vorontsov <[email protected]>
---
arch/arm/mach-tegra/platsmp.c | 36 ++----------------------------------
1 files changed, 2 insertions(+), 34 deletions(-)

diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index 1c0fd92..bf5433a 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -115,42 +115,10 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
*/
void __init smp_init_cpus(void)
{
- unsigned int i, ncores = scu_get_core_count(scu_base);
-
- for (i = 0; i < ncores; i++)
- cpu_set(i, cpu_possible_map);
+ scu_init_cpus(scu_base);
}

void __init smp_prepare_cpus(unsigned int max_cpus)
{
- unsigned int ncores = scu_get_core_count(scu_base);
- 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. Note that, on modern versions of
- * MILO, the "poke" doesn't actually do anything until each
- * individual core is sent a soft interrupt to get it out of
- * WFI
- */
- if (max_cpus > 1) {
- percpu_timer_setup();
- scu_enable(scu_base);
- }
+ scu_prepare_cpus(scu_base, max_cpus);
}
--
1.7.0.5

2010-11-30 17:39:27

by Anton Vorontsov

[permalink] [raw]
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 <[email protected]>
---
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

2010-11-30 17:39:41

by Anton Vorontsov

[permalink] [raw]
Subject: [PATCH 2/8] ARM: cns3xxx: Add support for SMP

Nothing fancy needs to be done, just use generic SCU routines.

Signed-off-by: Anton Vorontsov <[email protected]>
---
arch/arm/Kconfig | 2 +-
arch/arm/mach-cns3xxx/Kconfig | 1 +
arch/arm/mach-cns3xxx/Makefile | 1 +
arch/arm/mach-cns3xxx/include/mach/smp.h | 28 ++++++++++++
arch/arm/mach-cns3xxx/platsmp.c | 69 ++++++++++++++++++++++++++++++
5 files changed, 100 insertions(+), 1 deletions(-)
create mode 100644 arch/arm/mach-cns3xxx/include/mach/smp.h
create mode 100644 arch/arm/mach-cns3xxx/platsmp.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9aff0e8..38c1697 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1208,7 +1208,7 @@ config SMP
depends on REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP || \
MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || \
ARCH_S5PV310 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || \
- ARCH_MSM_SCORPIONMP
+ ARCH_MSM_SCORPIONMP || ARCH_CNS3XXX
select USE_GENERIC_SMP_HELPERS
select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP
help
diff --git a/arch/arm/mach-cns3xxx/Kconfig b/arch/arm/mach-cns3xxx/Kconfig
index 9ebfcc4..0ba82aa 100644
--- a/arch/arm/mach-cns3xxx/Kconfig
+++ b/arch/arm/mach-cns3xxx/Kconfig
@@ -3,6 +3,7 @@ menu "CNS3XXX platform type"

config MACH_CNS3420VB
bool "Support for CNS3420 Validation Board"
+ select HAVE_ARM_SCU if SMP
help
Include support for the Cavium Networks CNS3420 MPCore Platform
Baseboard.
diff --git a/arch/arm/mach-cns3xxx/Makefile b/arch/arm/mach-cns3xxx/Makefile
index 11033f1..ba4ee7b 100644
--- a/arch/arm/mach-cns3xxx/Makefile
+++ b/arch/arm/mach-cns3xxx/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_ARCH_CNS3XXX) += core.o pm.o devices.o
+obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_PCI) += pcie.o
obj-$(CONFIG_MACH_CNS3420VB) += cns3420vb.o
diff --git a/arch/arm/mach-cns3xxx/include/mach/smp.h b/arch/arm/mach-cns3xxx/include/mach/smp.h
new file mode 100644
index 0000000..44aa7ea
--- /dev/null
+++ b/arch/arm/mach-cns3xxx/include/mach/smp.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2002 ARM Ltd.
+ * Copyright 2008 Cavium Networks
+ *
+ * This file 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.
+ */
+
+#ifndef __MACH_SMP_H
+#define __MACH_SMP_H
+
+#include <asm/hardware/gic.h>
+
+#define hard_smp_processor_id() \
+ ({ \
+ unsigned int cpunum; \
+ __asm__("mrc p15, 0, %0, c0, c0, 5" \
+ : "=r" (cpunum)); \
+ cpunum &= 0x0F; \
+ })
+
+static inline void smp_cross_call(const struct cpumask *mask, int ipi)
+{
+ gic_raise_softirq(mask, ipi);
+}
+
+#endif /* __MACH_SMP_H */
diff --git a/arch/arm/mach-cns3xxx/platsmp.c b/arch/arm/mach-cns3xxx/platsmp.c
new file mode 100644
index 0000000..fc1595c
--- /dev/null
+++ b/arch/arm/mach-cns3xxx/platsmp.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2002 ARM Ltd
+ * Copyright 2008 Cavium Networks
+ * Copyright 2010 MontaVista Software, LLC.
+ *
+ * This file 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/smp.h>
+#include <linux/io.h>
+#include <asm/unified.h>
+#include <asm/smp_scu.h>
+#include <mach/cns3xxx.h>
+#include "core.h"
+
+static void __iomem *scu_base_addr(void)
+{
+ return (void __iomem *)CNS3XXX_TC11MP_SCU_BASE_VIRT;
+}
+
+void __cpuinit platform_secondary_init(unsigned int cpu)
+{
+ trace_hardirqs_off();
+
+ /*
+ * 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_cpu_init(0, gic_cpu_base_addr);
+
+ scu_secondary_init(cpu);
+}
+
+int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ return scu_boot_secondary(cpu, idle);
+}
+
+void __init smp_init_cpus(void)
+{
+ scu_init_cpus(scu_base_addr());
+}
+
+static void __init poke_milo(void)
+{
+ if (num_present_cpus() <= 1)
+ return;
+ /*
+ * Write the address of secondary startup into the system-wide flags
+ * register. The BootMonitor waits for this register to become
+ * non-zero.
+ */
+ __raw_writel(BSYM(virt_to_phys(scu_secondary_startup)),
+ (void __iomem *)(0xFFF07000 + 0x0600));
+
+ mb();
+}
+
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+ scu_prepare_cpus(scu_base_addr(), max_cpus);
+ poke_milo();
+}
--
1.7.0.5

2010-11-30 17:39:56

by Anton Vorontsov

[permalink] [raw]
Subject: [PATCH 6/8] ARM: ux500: Switch to generic SCU routines

This shrinks platform-specific code quite a bit.

Signed-off-by: Anton Vorontsov <[email protected]>
---
arch/arm/mach-ux500/Makefile | 2 +-
arch/arm/mach-ux500/headsmp.S | 38 -----------
arch/arm/mach-ux500/hotplug.c | 5 +-
arch/arm/mach-ux500/include/mach/smp.h | 3 -
arch/arm/mach-ux500/platsmp.c | 115 ++------------------------------
5 files changed, 10 insertions(+), 153 deletions(-)
delete mode 100644 arch/arm/mach-ux500/headsmp.S

diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile
index 9e27a84..90fa03c 100644
--- a/arch/arm/mach-ux500/Makefile
+++ b/arch/arm/mach-ux500/Makefile
@@ -7,7 +7,7 @@ obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o devices-db5500.o
obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o prcmu.o
obj-$(CONFIG_MACH_U8500_MOP) += board-mop500.o board-mop500-sdi.o
obj-$(CONFIG_MACH_U5500) += board-u5500.o
-obj-$(CONFIG_SMP) += platsmp.o headsmp.o
+obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
obj-$(CONFIG_REGULATOR_AB8500) += board-mop500-regulators.o
diff --git a/arch/arm/mach-ux500/headsmp.S b/arch/arm/mach-ux500/headsmp.S
deleted file mode 100644
index a6be2cd..0000000
--- a/arch/arm/mach-ux500/headsmp.S
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2009 ST-Ericsson
- * This file is based ARM Realview platform
- * 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
-
-/*
- * U8500 specific entry point for secondary CPUs.
- */
-ENTRY(u8500_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
- dsb
-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 pen_release
diff --git a/arch/arm/mach-ux500/hotplug.c b/arch/arm/mach-ux500/hotplug.c
index dd8037e..38f4e1b 100644
--- a/arch/arm/mach-ux500/hotplug.c
+++ b/arch/arm/mach-ux500/hotplug.c
@@ -12,10 +12,9 @@
#include <linux/errno.h>
#include <linux/smp.h>

+#include <asm/smp_scu.h>
#include <asm/cacheflush.h>

-extern volatile int pen_release;
-
static inline void platform_do_lowpower(unsigned int cpu)
{
flush_cache_all();
@@ -24,7 +23,7 @@ static inline void platform_do_lowpower(unsigned int cpu)
for (;;) {
__asm__ __volatile__("dsb\n\t" "wfi\n\t"
: : : "memory");
- if (pen_release == cpu) {
+ if (scu_pen_release == cpu) {
/*
* OK, proper wakeup, we're done
*/
diff --git a/arch/arm/mach-ux500/include/mach/smp.h b/arch/arm/mach-ux500/include/mach/smp.h
index bd57c50..646cea7 100644
--- a/arch/arm/mach-ux500/include/mach/smp.h
+++ b/arch/arm/mach-ux500/include/mach/smp.h
@@ -12,9 +12,6 @@
#include <asm/hardware/gic.h>
#include <asm/smp_mpidr.h>

-/* This is required to wakeup the secondary core */
-extern void u8500_secondary_startup(void);
-
/*
* We use IRQ1 as the IPI
*/
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c
index b8987bd..0e195a2 100644
--- a/arch/arm/mach-ux500/platsmp.c
+++ b/arch/arm/mach-ux500/platsmp.c
@@ -11,30 +11,12 @@
* published by the Free Software Foundation.
*/
#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/device.h>
#include <linux/smp.h>
#include <linux/io.h>

-#include <asm/cacheflush.h>
-#include <asm/localtimer.h>
#include <asm/smp_scu.h>
#include <mach/hardware.h>

-/*
- * control for which core is the next to come out of the secondary
- * boot "holding pen"
- */
-volatile int __cpuinitdata pen_release = -1;
-
-static unsigned int __init get_core_count(void)
-{
- return scu_get_core_count(__io_address(UX500_SCU_BASE));
-}
-
-static DEFINE_SPINLOCK(boot_lock);
-
void __cpuinit platform_secondary_init(unsigned int cpu)
{
trace_hardirqs_off();
@@ -46,59 +28,18 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
*/
gic_cpu_init(0, __io_address(UX500_GIC_CPU_BASE));

- /*
- * let the primary processor know we're out of the
- * pen, then head off into the C entry point
- */
- pen_release = -1;
-
- /*
- * Synchronise with the boot thread.
- */
- spin_lock(&boot_lock);
- spin_unlock(&boot_lock);
+ scu_secondary_init(cpu);
}

int __cpuinit 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);
-
- /*
- * The secondary processor is waiting to be released from
- * the holding pen - release it, then wait for it to flag
- * that it has been released by resetting pen_release.
- */
- pen_release = cpu;
- __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
- outer_clean_range(__pa(&pen_release), __pa(&pen_release) + 1);
-
- smp_cross_call(cpumask_of(cpu), 1);
-
- timeout = jiffies + (1 * HZ);
- while (time_before(jiffies, timeout)) {
- if (pen_release == -1)
- break;
- }
-
- /*
- * 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 scu_boot_secondary(cpu, idle);
}

static void __init wakeup_secondary(void)
{
/* nobody is to be released from the pen yet */
- pen_release = -1;
+ scu_pen_release = -1;

/*
* write the address of secondary startup into the backup ram register
@@ -107,7 +48,7 @@ static void __init wakeup_secondary(void)
* is waiting for. This would wake up the secondary core from WFE
*/
#define U8500_CPU1_JUMPADDR_OFFSET 0x1FF4
- __raw_writel(virt_to_phys(u8500_secondary_startup),
+ __raw_writel(virt_to_phys(scu_secondary_startup),
__io_address(UX500_BACKUPRAM0_BASE) +
U8500_CPU1_JUMPADDR_OFFSET);

@@ -126,55 +67,13 @@ static void __init wakeup_secondary(void)
*/
void __init smp_init_cpus(void)
{
- unsigned int i, ncores = get_core_count();
-
- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
+ scu_init_cpus(__io_address(UX500_SCU_BASE));
}

void __init smp_prepare_cpus(unsigned int max_cpus)
{
- unsigned int ncores = get_core_count();
- unsigned int cpu = smp_processor_id();
- int i;
-
- /* sanity check */
- if (ncores == 0) {
- printk(KERN_ERR
- "U8500: strange CM count of 0? Default to 1\n");
- ncores = 1;
- }
-
- if (ncores > num_possible_cpus()) {
- printk(KERN_WARNING
- "U8500: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, num_possible_cpus());
- ncores = num_possible_cpus();
- }
-
- 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);
+ scu_prepare_cpus(__io_address(UX500_SCU_BASE), max_cpus);

- 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(__io_address(UX500_SCU_BASE));
+ if (max_cpus > 1)
wakeup_secondary();
- }
}
--
1.7.0.5

2010-11-30 17:39:57

by Anton Vorontsov

[permalink] [raw]
Subject: [PATCH 8/8] ARM: OMAP2: Switch to generic SCU routines

This shrinks platform-specific code a little bit.

Signed-off-by: Anton Vorontsov <[email protected]>
---
arch/arm/mach-omap2/omap-smp.c | 64 ++--------------------------------------
1 files changed, 3 insertions(+), 61 deletions(-)

diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
index 56a8bce..52379c7 100644
--- a/arch/arm/mach-omap2/omap-smp.c
+++ b/arch/arm/mach-omap2/omap-smp.c
@@ -29,16 +29,6 @@
/* SCU base address */
static void __iomem *scu_base;

-/*
- * Use SCU config register to count number of cores
- */
-static inline unsigned int get_core_count(void)
-{
- if (scu_base)
- return scu_get_core_count(scu_base);
- return 1;
-}
-
static DEFINE_SPINLOCK(boot_lock);

void __cpuinit platform_secondary_init(unsigned int cpu)
@@ -112,65 +102,17 @@ static void __init wakeup_secondary(void)
*/
void __init smp_init_cpus(void)
{
- unsigned int i, ncores;
-
/* Never released */
scu_base = ioremap(OMAP44XX_SCU_BASE, SZ_256);
BUG_ON(!scu_base);

- ncores = get_core_count();
-
- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
+ scu_init_cpus(scu_base);
}

void __init smp_prepare_cpus(unsigned int max_cpus)
{
- unsigned int ncores = get_core_count();
- unsigned int cpu = smp_processor_id();
- int i;
-
- /* sanity check */
- if (ncores == 0) {
- printk(KERN_ERR
- "OMAP4: strange core count of 0? Default to 1\n");
- ncores = 1;
- }
-
- if (ncores > NR_CPUS) {
- printk(KERN_WARNING
- "OMAP4: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, NR_CPUS);
- ncores = NR_CPUS;
- }
- smp_store_cpu_info(cpu);
-
- /*
- * are we trying to boot more cores than exist?
- */
- if (max_cpus > ncores)
- max_cpus = ncores;
+ scu_prepare_cpus(scu_base, max_cpus);

- /*
- * 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);
-
- 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();
-
- /*
- * Initialise the SCU and wake up the secondary core using
- * wakeup_secondary().
- */
- scu_enable(scu_base);
+ if (max_cpus > 1)
wakeup_secondary();
- }
}
--
1.7.0.5

2010-11-30 18:16:08

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH 2/8] ARM: cns3xxx: Add support for SMP

On Tue, Nov 30, 2010 at 08:17:00PM +0300, Anton Vorontsov wrote:
> Nothing fancy needs to be done, just use generic SCU routines.
>
> Signed-off-by: Anton Vorontsov <[email protected]>

This I assume is an age old patch.

> diff --git a/arch/arm/mach-cns3xxx/include/mach/smp.h b/arch/arm/mach-cns3xxx/include/mach/smp.h
> new file mode 100644
> index 0000000..44aa7ea
> --- /dev/null
> +++ b/arch/arm/mach-cns3xxx/include/mach/smp.h
> @@ -0,0 +1,28 @@
> +/*
> + * Copyright 2002 ARM Ltd.
> + * Copyright 2008 Cavium Networks
> + *
> + * This file 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.
> + */
> +
> +#ifndef __MACH_SMP_H
> +#define __MACH_SMP_H
> +
> +#include <asm/hardware/gic.h>
> +
> +#define hard_smp_processor_id() \
> + ({ \
> + unsigned int cpunum; \
> + __asm__("mrc p15, 0, %0, c0, c0, 5" \
> + : "=r" (cpunum)); \
> + cpunum &= 0x0F; \
> + })

#include <asm/smp_mpidr.h>

replaces this, but it's not actually necessary - it's only used by some
bug checking code in the CPU hotplug code. I'm shortly going to be
deleting all hard_smp_processor_id() implementations.

2010-11-30 22:26:05

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH 1/8] ARM: SCU: Add common routines for secondary CPU bootup

On Tue, Nov 30, 2010 at 08:16:58PM +0300, Anton Vorontsov wrote:
> 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.

I still think that we can do better with this - especially once the
crappy situation with the hotplug CPU code gets resolved.

The SCU does not require the pen_release code. What currently requires
that is the hotplug CPU code to allow offlined CPUs to be re-woken. If
these CPUs can be properly shutdown, and brought back online via their
reset vector, they can be brought back online via the same method used
for their initial boot.

What that means is, as we send each individual CPU an IPI, we don't
need the pen_release mess nor the holding pen, and all this code can go.

If all that code is tied into a generic "SCU" support option, then we
have to ensure that _all_ SCU using platforms can use this method before
we switch to it, rather than doing it on a per-platform basis as we can
now.

2010-11-30 23:27:51

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH 3/8] ARM: VExpress: Switch to generic SCU routines

On Tue, Nov 30, 2010 at 08:17:01PM +0300, Anton Vorontsov wrote:
> +/* If there are more than one CPU let them know where to start. */
> +static void __init smp_point_cpus(void)
> +{
> + if (num_present_cpus() <= 1)
> + return;
>
> - for (i = 0; i < ncores; i++)
> - set_cpu_possible(i, true);
> + writel(~0, MMIO_P2V(V2M_SYS_FLAGSCLR));
> + writel(BSYM(virt_to_phys(scu_secondary_startup)),
> + MMIO_P2V(V2M_SYS_FLAGSSET));
> }

I don't see the point of separating this code from the code below. It
doesn't seem to bring any benefit. Could you explain why it's necessary
to separate this?

> void __init smp_prepare_cpus(unsigned int max_cpus)
> {
...

2010-11-30 23:32:59

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH 1/8] ARM: SCU: Add common routines for secondary CPU bootup

On Tue, Nov 30, 2010 at 08:16:58PM +0300, Anton Vorontsov wrote:
> +/*
> + * 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);
> + }
> +}

Note that I'll go with factoring this out into arch/arm/kernel/smp_scu.c
for the time being, but I'm not convinced about the other parts yet.

> + sub r4, r4, r5
> + add r6, r6, r4
> +#if __LINUX_ARM_ARCH__ >= 7
> + dsb
> +#endif

Another question though - probably for Linus though - why is the u8500
code needing this dsb whereas other ARMv7 implementations don't appear
to require it?

2010-12-01 00:26:03

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH 1/8] ARM: SCU: Add common routines for secondary CPU bootup

On Tue, Nov 30, 2010 at 11:32:04PM +0000, Russell King - ARM Linux wrote:
> Note that I'll go with factoring this out into arch/arm/kernel/smp_scu.c
> for the time being, but I'm not convinced about the other parts yet.

IOW, something like the attached. I've gone a little further and removed
the now unnecessary scu_enable() and scu_get_core_count() global functions,
making scu_enable() static, and eliminating scu_get_core_count() entirely.

arch/arm/include/asm/smp_scu.h | 4 +-
arch/arm/kernel/smp_scu.c | 65 +++++++++++++++++++++++++++++++------
arch/arm/mach-omap2/omap-smp.c | 61 ++--------------------------------
arch/arm/mach-realview/platsmp.c | 66 ++------------------------------------
arch/arm/mach-s5pv310/platsmp.c | 58 ++-------------------------------
arch/arm/mach-tegra/platsmp.c | 37 +--------------------
arch/arm/mach-ux500/platsmp.c | 48 ++--------------------------
arch/arm/mach-vexpress/platsmp.c | 58 ++-------------------------------
8 files changed, 76 insertions(+), 321 deletions(-)

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

-unsigned int scu_get_core_count(void __iomem *);
-void scu_enable(void __iomem *);
+void scu_init_cpus(void __iomem *);
+void scu_prepare_cpus(void __iomem *, unsigned int);

#endif
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
index 9ab4149..6c949b4 100644
--- a/arch/arm/kernel/smp_scu.c
+++ b/arch/arm/kernel/smp_scu.c
@@ -11,6 +11,7 @@
#include <linux/init.h>
#include <linux/io.h>

+#include <asm/localtimer.h>
#include <asm/smp_scu.h>
#include <asm/cacheflush.h>

@@ -21,18 +22,9 @@
#define SCU_FPGA_REVISION 0x10

/*
- * Get the number of CPU cores from the SCU configuration
- */
-unsigned int __init scu_get_core_count(void __iomem *scu_base)
-{
- unsigned int ncores = __raw_readl(scu_base + SCU_CONFIG);
- return (ncores & 0x03) + 1;
-}
-
-/*
* Enable the SCU
*/
-void __init scu_enable(void __iomem *scu_base)
+static void __init scu_enable(void __iomem *scu_base)
{
u32 scu_ctrl;

@@ -50,3 +42,56 @@ void __init scu_enable(void __iomem *scu_base)
*/
flush_cache_all();
}
+
+void scu_init_cpus(void __iomem *scu_base)
+{
+ unsigned int i, ncores = 1;
+
+ if (scu_base)
+ ncores += __raw_readl(scu_base + SCU_CONFIG) & 0x03;
+
+ if (ncores > NR_CPUS) {
+ pr_warning("SMP: no. of cores (%d) greater than configured maximum of %d - clipping\n",
+ ncores, NR_CPUS);
+ ncores = NR_CPUS;
+ }
+
+ for (i = 0; i < ncores; i++)
+ set_cpu_possible(i, true);
+}
+
+void 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/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
index 56a8bce..05cc85e 100644
--- a/arch/arm/mach-omap2/omap-smp.c
+++ b/arch/arm/mach-omap2/omap-smp.c
@@ -21,7 +21,6 @@
#include <linux/io.h>

#include <asm/cacheflush.h>
-#include <asm/localtimer.h>
#include <asm/smp_scu.h>
#include <mach/hardware.h>
#include <mach/omap4-common.h>
@@ -29,16 +28,6 @@
/* SCU base address */
static void __iomem *scu_base;

-/*
- * Use SCU config register to count number of cores
- */
-static inline unsigned int get_core_count(void)
-{
- if (scu_base)
- return scu_get_core_count(scu_base);
- return 1;
-}
-
static DEFINE_SPINLOCK(boot_lock);

void __cpuinit platform_secondary_init(unsigned int cpu)
@@ -118,59 +107,17 @@ void __init smp_init_cpus(void)
scu_base = ioremap(OMAP44XX_SCU_BASE, SZ_256);
BUG_ON(!scu_base);

- ncores = get_core_count();
-
- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
+ scu_init_cpus(scu_base);
}

void __init smp_prepare_cpus(unsigned int max_cpus)
{
- unsigned int ncores = get_core_count();
- unsigned int cpu = smp_processor_id();
- int i;
-
- /* sanity check */
- if (ncores == 0) {
- printk(KERN_ERR
- "OMAP4: strange core count of 0? Default to 1\n");
- ncores = 1;
- }
-
- if (ncores > NR_CPUS) {
- printk(KERN_WARNING
- "OMAP4: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, NR_CPUS);
- ncores = NR_CPUS;
- }
- 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);
-
- 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_prepare_cpus(scu_base, max_cpus);

+ if (num_present_cpus() > 1) {
/*
- * Initialise the SCU and wake up the secondary core using
- * wakeup_secondary().
+ * Wake up the secondary core using wakeup_secondary().
*/
- scu_enable(scu_base);
wakeup_secondary();
}
}
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index af3d909..43614f2 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -19,7 +19,6 @@
#include <asm/cacheflush.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
-#include <asm/localtimer.h>
#include <asm/unified.h>

#include <mach/board-eb.h>
@@ -50,14 +49,6 @@ static void __iomem *scu_base_addr(void)
return (void __iomem *)0;
}

-static inline unsigned int get_core_count(void)
-{
- void __iomem *scu_base = scu_base_addr();
- if (scu_base)
- return scu_get_core_count(scu_base);
- return 1;
-}
-
static DEFINE_SPINLOCK(boot_lock);

void __cpuinit platform_secondary_init(unsigned int cpu)
@@ -158,64 +149,13 @@ static void __init poke_milo(void)
*/
void __init smp_init_cpus(void)
{
- unsigned int i, ncores = get_core_count();
-
- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
+ scu_init_cpus(scu_base_addr());
}

void __init smp_prepare_cpus(unsigned int max_cpus)
{
- unsigned int ncores = get_core_count();
- unsigned int cpu = smp_processor_id();
- int i;
-
- /* sanity check */
- if (ncores == 0) {
- printk(KERN_ERR
- "Realview: strange CM count of 0? Default to 1\n");
-
- ncores = 1;
- }
-
- if (ncores > NR_CPUS) {
- printk(KERN_WARNING
- "Realview: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, NR_CPUS);
- ncores = NR_CPUS;
- }
-
- smp_store_cpu_info(cpu);
+ scu_prepare_cpus(scu_base_addr(), max_cpus);

- /*
- * 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. Note that, on modern versions of
- * MILO, the "poke" doesn't actually do anything until each
- * individual core is sent a soft interrupt to get it out of
- * WFI
- */
- 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_addr());
+ if (num_present_cpus() > 1)
poke_milo();
- }
}
diff --git a/arch/arm/mach-s5pv310/platsmp.c b/arch/arm/mach-s5pv310/platsmp.c
index d474426..4da410a 100644
--- a/arch/arm/mach-s5pv310/platsmp.c
+++ b/arch/arm/mach-s5pv310/platsmp.c
@@ -22,7 +22,6 @@
#include <linux/io.h>

#include <asm/cacheflush.h>
-#include <asm/localtimer.h>
#include <asm/smp_scu.h>
#include <asm/unified.h>

@@ -124,69 +123,20 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)

void __init smp_init_cpus(void)
{
- void __iomem *scu_base = scu_base_addr();
- unsigned int i, ncores;
-
- ncores = scu_base ? scu_get_core_count(scu_base) : 1;
-
- /* sanity check */
- if (ncores == 0) {
- printk(KERN_ERR
- "S5PV310: strange CM count of 0? Default to 1\n");
-
- ncores = 1;
- }
-
- if (ncores > NR_CPUS) {
- printk(KERN_WARNING
- "S5PV310: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, NR_CPUS);
- ncores = NR_CPUS;
- }
-
- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
+ scu_init_cpus(scu_base_addr());
}

void __init smp_prepare_cpus(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_addr());
+ scu_prepare_cpus(scu_base_addr(), max_cpus);

+ if (num_present_cpus() > 1) {
/*
* Write the address of secondary startup into the
* system-wide flags register. The boot monitor waits
* until it receives a soft interrupt, and then the
* secondary CPU branches to this address.
*/
- __raw_writel(BSYM(virt_to_phys(s5pv310_secondary_startup)), S5P_VA_SYSRAM);
+ __raw_writel(BSYM(virt_to_phys(s5pv310_secondary_startup)), S5P_VA_SYSRAM);
}
}
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index 1c0fd92..3b6bcca 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -22,7 +22,6 @@
#include <asm/cacheflush.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
-#include <asm/localtimer.h>
#include <asm/smp_scu.h>

#include <mach/iomap.h>
@@ -115,42 +114,10 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
*/
void __init smp_init_cpus(void)
{
- unsigned int i, ncores = scu_get_core_count(scu_base);
-
- for (i = 0; i < ncores; i++)
- cpu_set(i, cpu_possible_map);
+ scu_init_cpus(scu_base);
}

void __init smp_prepare_cpus(unsigned int max_cpus)
{
- unsigned int ncores = scu_get_core_count(scu_base);
- 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. Note that, on modern versions of
- * MILO, the "poke" doesn't actually do anything until each
- * individual core is sent a soft interrupt to get it out of
- * WFI
- */
- if (max_cpus > 1) {
- percpu_timer_setup();
- scu_enable(scu_base);
- }
+ scu_prepare_cpus(scu_base, max_cpus);
}
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c
index b8987bd..8910c08 100644
--- a/arch/arm/mach-ux500/platsmp.c
+++ b/arch/arm/mach-ux500/platsmp.c
@@ -28,11 +28,6 @@
*/
volatile int __cpuinitdata pen_release = -1;

-static unsigned int __init get_core_count(void)
-{
- return scu_get_core_count(__io_address(UX500_SCU_BASE));
-}
-
static DEFINE_SPINLOCK(boot_lock);

void __cpuinit platform_secondary_init(unsigned int cpu)
@@ -126,55 +121,18 @@ static void __init wakeup_secondary(void)
*/
void __init smp_init_cpus(void)
{
- unsigned int i, ncores = get_core_count();
-
- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
+ scu_init_cpus(__io_address(UX500_SCU_BASE));
}

void __init smp_prepare_cpus(unsigned int max_cpus)
{
- unsigned int ncores = get_core_count();
- unsigned int cpu = smp_processor_id();
- int i;
-
- /* sanity check */
- if (ncores == 0) {
- printk(KERN_ERR
- "U8500: strange CM count of 0? Default to 1\n");
- ncores = 1;
- }
-
- if (ncores > num_possible_cpus()) {
- printk(KERN_WARNING
- "U8500: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, num_possible_cpus());
- ncores = num_possible_cpus();
- }
-
- 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);
+ scu_prepare_cpus(__io_address(UX500_SCU_BASE), max_cpus);

- if (max_cpus > 1) {
+ if (num_present_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(__io_address(UX500_SCU_BASE));
wakeup_secondary();
}
}
diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c
index 276f916..ecedd5a 100644
--- a/arch/arm/mach-vexpress/platsmp.c
+++ b/arch/arm/mach-vexpress/platsmp.c
@@ -17,7 +17,6 @@
#include <linux/io.h>

#include <asm/cacheflush.h>
-#include <asm/localtimer.h>
#include <asm/smp_scu.h>
#include <asm/unified.h>

@@ -118,65 +117,14 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
*/
void __init smp_init_cpus(void)
{
- void __iomem *scu_base = scu_base_addr();
- unsigned int i, ncores;
-
- ncores = scu_base ? scu_get_core_count(scu_base) : 1;
-
- /* sanity check */
- if (ncores == 0) {
- printk(KERN_ERR
- "vexpress: strange CM count of 0? Default to 1\n");
-
- ncores = 1;
- }
-
- if (ncores > NR_CPUS) {
- printk(KERN_WARNING
- "vexpress: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, NR_CPUS);
- ncores = NR_CPUS;
- }
-
- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
+ scu_init_cpus(scu_base_addr());
}

void __init smp_prepare_cpus(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_addr());
+ scu_prepare_cpus(scu_base_addr(), max_cpus);

+ if (num_present_cpus() > 1) {
/*
* Write the address of secondary startup into the
* system-wide flags register. The boot monitor waits

2010-12-01 06:21:45

by Srinidhi Kasagar

[permalink] [raw]
Subject: Re: [PATCH 1/8] ARM: SCU: Add common routines for secondary CPU bootup

On Wed, Dec 1, 2010 at 5:02 AM, Russell King - ARM Linux
<[email protected]> wrote:
> On Tue, Nov 30, 2010 at 08:16:58PM +0300, Anton Vorontsov wrote:

[...]

>> + ? ? sub ? ? r4, r4, r5
>> + ? ? add ? ? r6, r6, r4
>> +#if __LINUX_ARM_ARCH__ >= 7
>> + ? ? dsb
>> +#endif
>
> Another question though - probably for Linus though - why is the u8500
> code needing this dsb whereas other ARMv7 implementations don't appear
> to require it?

No strong reason, we can safely ignore this now.

srinidhi

2010-12-02 15:19:10

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH 1/8] ARM: SCU: Add common routines for secondary CPU bootup

On 1 December 2010 00:25, Russell King - ARM Linux
<[email protected]> wrote:
> On Tue, Nov 30, 2010 at 11:32:04PM +0000, Russell King - ARM Linux wrote:
>> Note that I'll go with factoring this out into arch/arm/kernel/smp_scu.c
>> for the time being, but I'm not convinced about the other parts yet.
>
> IOW, something like the attached.  I've gone a little further and removed
> the now unnecessary scu_enable() and scu_get_core_count() global functions,
> making scu_enable() static, and eliminating scu_get_core_count() entirely.

There is some benefit in leaving get_core_count() in the platform
code. For example, the SCU on Cortex-A15 doesn't expose the core count
register and we have to get it from somewhere else (for now from some
L2 cache controller register but in the future it may be hardcoded,
passed via FDT or simply trying to boot maxcpus).

--
Catalin

2010-12-02 15:25:09

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH 1/8] ARM: SCU: Add common routines for secondary CPU bootup

On Thu, Dec 02, 2010 at 03:19:05PM +0000, Catalin Marinas wrote:
> On 1 December 2010 00:25, Russell King - ARM Linux
> <[email protected]> wrote:
> > On Tue, Nov 30, 2010 at 11:32:04PM +0000, Russell King - ARM Linux wrote:
> >> Note that I'll go with factoring this out into arch/arm/kernel/smp_scu.c
> >> for the time being, but I'm not convinced about the other parts yet.
> >
> > IOW, something like the attached. ?I've gone a little further and removed
> > the now unnecessary scu_enable() and scu_get_core_count() global functions,
> > making scu_enable() static, and eliminating scu_get_core_count() entirely.
>
> There is some benefit in leaving get_core_count() in the platform
> code. For example, the SCU on Cortex-A15 doesn't expose the core count
> register and we have to get it from somewhere else (for now from some
> L2 cache controller register but in the future it may be hardcoded,
> passed via FDT or simply trying to boot maxcpus).

I notice that there's no way to tell what revision of SCU is implemented
on _any_ mpcore platform.

In light of that, I think there's no point what so ever trying to
consolidate this code - even the control register bits vary in
unpredictable ways between different MPcore implementations.

So we can't say "this is a SCU X and this is its register layout."

And really, having it undetectable except via DT (which from what I
can see, isn't happening any time soon) or via a command line argument
isn't acceptable.

So I think the idea of consolidating the SCU code is a lost cause.

2010-12-02 16:28:55

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH 1/8] ARM: SCU: Add common routines for secondary CPU bootup

On Thu, 2010-12-02 at 15:24 +0000, Russell King - ARM Linux wrote:
> On Thu, Dec 02, 2010 at 03:19:05PM +0000, Catalin Marinas wrote:
> > On 1 December 2010 00:25, Russell King - ARM Linux
> > <[email protected]> wrote:
> > > On Tue, Nov 30, 2010 at 11:32:04PM +0000, Russell King - ARM Linux wrote:
> > >> Note that I'll go with factoring this out into arch/arm/kernel/smp_scu.c
> > >> for the time being, but I'm not convinced about the other parts yet.
> > >
> > > IOW, something like the attached. I've gone a little further and removed
> > > the now unnecessary scu_enable() and scu_get_core_count() global functions,
> > > making scu_enable() static, and eliminating scu_get_core_count() entirely.
> >
> > There is some benefit in leaving get_core_count() in the platform
> > code. For example, the SCU on Cortex-A15 doesn't expose the core count
> > register and we have to get it from somewhere else (for now from some
> > L2 cache controller register but in the future it may be hardcoded,
> > passed via FDT or simply trying to boot maxcpus).
>
> I notice that there's no way to tell what revision of SCU is implemented
> on _any_ mpcore platform.

C-A15 doesn't have any SCU registers exposed (and it's enabled by
default).

> In light of that, I think there's no point what so ever trying to
> consolidate this code - even the control register bits vary in
> unpredictable ways between different MPcore implementations.

The SCU is part of the core TRM, so I don't expect it to be the same
across various MP cores (and A15 is an example).

You may want to consolidate functions like scu_prepare_cpus (maybe call
it smp_prepare_cpus) and something that calls set_cpu_possible() but
with platform callbacks for getting the number of calls and initialising
the SMP (SCU for most platforms).

Whether this is worth, I don't know.

--
Catalin

2010-12-02 17:39:04

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH 1/8] ARM: SCU: Add common routines for secondary CPU bootup

On Thu, Dec 02, 2010 at 04:28:40PM +0000, Catalin Marinas wrote:
> The SCU is part of the core TRM, so I don't expect it to be the same
> across various MP cores (and A15 is an example).
>
> You may want to consolidate functions like scu_prepare_cpus (maybe call
> it smp_prepare_cpus)

You do realise the function called from architecture independent code is
called 'smp_prepare_cpus' ?

> and something that calls set_cpu_possible() but
> with platform callbacks for getting the number of calls and initialising
> the SMP (SCU for most platforms).

What if a platform, for what ever reason, wants to have 3 CPUs,
numbered 0, 2, 3 ? That's the reason why the code which sets the
possible and present maps isn't in the ARM core code - Eg, we don't
know if a platform wants to keep CPU 1 in AMP mode to run some
special software on it.

> Whether this is worth, I don't know.

I don't think it's worth it because I think trying to considate this
is going to cripple the code structure in the future.

What we currently have is a nice sane separation of the core SMP
support from the platform specific parts of the SMP support.

BTW, is it worth making sure that the IC and SCU standby mode bits
are set for A9 MPCore ?

2010-12-02 17:55:29

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH 1/8] ARM: SCU: Add common routines for secondary CPU bootup

On Thu, 2010-12-02 at 17:38 +0000, Russell King - ARM Linux wrote:
> On Thu, Dec 02, 2010 at 04:28:40PM +0000, Catalin Marinas wrote:
> > The SCU is part of the core TRM, so I don't expect it to be the same
> > across various MP cores (and A15 is an example).
> >
> > You may want to consolidate functions like scu_prepare_cpus (maybe call
> > it smp_prepare_cpus)
>
> You do realise the function called from architecture independent code is
> called 'smp_prepare_cpus' ?

It indeed looked familiar when I wrote it down :)

> BTW, is it worth making sure that the IC and SCU standby mode bits
> are set for A9 MPCore ?

IMHO I would leave such default settings to the boot monitor as it knows
better whether such feature works or has any benefits. If you want to
always set the bits, it may need trying on a few A9 platforms to make
sure they still work.

--
Catalin

2010-12-02 18:02:26

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH 1/8] ARM: SCU: Add common routines for secondary CPU bootup

On Thu, Dec 02, 2010 at 05:38:24PM +0000, Russell King - ARM Linux wrote:
> What if a platform, for what ever reason, wants to have 3 CPUs,
> numbered 0, 2, 3 ? That's the reason why the code which sets the
> possible and present maps isn't in the ARM core code - Eg, we don't
> know if a platform wants to keep CPU 1 in AMP mode to run some
> special software on it.
>
> I don't think it's worth it because I think trying to considate this
> is going to cripple the code structure in the future.

I don't think this is particularly worth it either:

8e511800fe64114d00b6a22c6e37a510b208785e
arch/arm/include/asm/smp.h | 14 ++++++-
arch/arm/kernel/smp.c | 71 ++++++++++++++++++++++++++++++++------
arch/arm/kernel/smp_scu.c | 2 +-
arch/arm/mach-omap2/omap-smp.c | 67 +++---------------------------------
arch/arm/mach-realview/platsmp.c | 71 ++++---------------------------------
arch/arm/mach-s5pv310/platsmp.c | 63 ++++-----------------------------
arch/arm/mach-tegra/platsmp.c | 39 ++-------------------
arch/arm/mach-ux500/platsmp.c | 55 +++--------------------------
arch/arm/mach-vexpress/platsmp.c | 69 +++++-------------------------------
9 files changed, 113 insertions(+), 338 deletions(-)

diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index f93d0a6..99dd48b 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -46,9 +46,14 @@ asmlinkage void do_IPI(int ipinr, struct pt_regs *regs);
extern void smp_init_cpus(void);

/*
- * Move global data into per-processor storage.
+ * Initialize cpu_possible map for 0 .. CPUs.
*/
-extern void smp_store_cpu_info(unsigned int cpuid);
+void smp_init_cpu_possible(unsigned int);
+
+/*
+ * Initialize cpu_present map for 0 .. CPUs.
+ */
+void smp_init_cpu_present(unsigned int);

/*
* Raise an IPI cross call on CPUs in callmap.
@@ -73,6 +78,11 @@ asmlinkage void secondary_start_kernel(void);
extern void platform_secondary_init(unsigned int cpu);

/*
+ * Initialize cpu_possible map, and enable coherency
+ */
+extern void platform_smp_prepare_cpus(unsigned int);
+
+/*
* Initial data for bringing up a secondary CPU.
*/
struct secondary_data {
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 4c3ed4f..46af08f 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -296,6 +296,17 @@ void __ref cpu_die(void)
#endif /* CONFIG_HOTPLUG_CPU */

/*
+ * Called by both boot and secondaries to move global data into
+ * per-processor storage.
+ */
+static void __cpuinit smp_store_cpu_info(unsigned int cpuid)
+{
+ struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid);
+
+ cpu_info->loops_per_jiffy = loops_per_jiffy;
+}
+
+/*
* This is the secondary CPU boot entry. We're using this CPUs
* idle thread stack, but a set of temporary page tables.
*/
@@ -353,17 +364,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
cpu_idle();
}

-/*
- * Called by both boot and secondaries to move global data into
- * per-processor storage.
- */
-void __cpuinit smp_store_cpu_info(unsigned int cpuid)
-{
- struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid);
-
- cpu_info->loops_per_jiffy = loops_per_jiffy;
-}
-
void __init smp_cpus_done(unsigned int max_cpus)
{
int cpu;
@@ -386,6 +386,55 @@ void __init smp_prepare_boot_cpu(void)
per_cpu(cpu_data, cpu).idle = current;
}

+void __init smp_init_cpu_possible(unsigned int ncores)
+{
+ unsigned int i;
+
+ if (ncores > NR_CPUS) {
+ pr_warning("SMP: no. of cores (%u) greater than configured maximum of %u - clipping\n",
+ ncores, NR_CPUS);
+ ncores = NR_CPUS;
+ }
+
+ for (i = 0; i < ncores; i++)
+ set_cpu_possible(i, true);
+}
+
+void __init smp_init_cpu_present(unsigned int ncores)
+{
+ unsigned int i;
+
+ for (i = 0; i < ncores; i++)
+ set_cpu_present(i, true);
+}
+
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+ unsigned int ncores = num_possible_cpus();
+
+ smp_store_cpu_info(smp_processor_id());
+
+ /*
+ * are we trying to boot more cores than exist?
+ */
+ if (max_cpus > ncores)
+ max_cpus = ncores;
+
+ 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();
+
+ /*
+ * Initialise the SCU if there are more than one CPU
+ * and let them know where to start.
+ */
+ platform_smp_prepare_cpus(max_cpus);
+ }
+}
+
static void send_ipi_message(const struct cpumask *mask, enum ipi_msg_type msg)
{
unsigned long flags;
diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
index 9ab4149..904b77b 100644
--- a/arch/arm/kernel/smp_scu.c
+++ b/arch/arm/kernel/smp_scu.c
@@ -11,8 +11,8 @@
#include <linux/init.h>
#include <linux/io.h>

-#include <asm/smp_scu.h>
#include <asm/cacheflush.h>
+#include <asm/smp_scu.h>

#define SCU_CTRL 0x00
#define SCU_CONFIG 0x04
diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
index 56a8bce..a123edf 100644
--- a/arch/arm/mach-omap2/omap-smp.c
+++ b/arch/arm/mach-omap2/omap-smp.c
@@ -21,7 +21,6 @@
#include <linux/io.h>

#include <asm/cacheflush.h>
-#include <asm/localtimer.h>
#include <asm/smp_scu.h>
#include <mach/hardware.h>
#include <mach/omap4-common.h>
@@ -29,16 +28,6 @@
/* SCU base address */
static void __iomem *scu_base;

-/*
- * Use SCU config register to count number of cores
- */
-static inline unsigned int get_core_count(void)
-{
- if (scu_base)
- return scu_get_core_count(scu_base);
- return 1;
-}
-
static DEFINE_SPINLOCK(boot_lock);

void __cpuinit platform_secondary_init(unsigned int cpu)
@@ -112,65 +101,19 @@ static void __init wakeup_secondary(void)
*/
void __init smp_init_cpus(void)
{
- unsigned int i, ncores;
-
/* Never released */
scu_base = ioremap(OMAP44XX_SCU_BASE, SZ_256);
BUG_ON(!scu_base);

- ncores = get_core_count();
-
- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
+ smp_init_cpu_possible(scu_get_core_count(scu_base));
}

-void __init smp_prepare_cpus(unsigned int max_cpus)
+void __init platform_smp_prepare_cpus(unsigned int max_cpus)
{
- unsigned int ncores = get_core_count();
- unsigned int cpu = smp_processor_id();
- int i;
-
- /* sanity check */
- if (ncores == 0) {
- printk(KERN_ERR
- "OMAP4: strange core count of 0? Default to 1\n");
- ncores = 1;
- }
-
- if (ncores > NR_CPUS) {
- printk(KERN_WARNING
- "OMAP4: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, NR_CPUS);
- ncores = NR_CPUS;
- }
- smp_store_cpu_info(cpu);
-
- /*
- * are we trying to boot more cores than exist?
- */
- if (max_cpus > ncores)
- max_cpus = ncores;
+ smp_init_cpu_present(max_cpus);

/*
- * Initialise the present map, which describes the set of CPUs
- * actually populated at the present time.
+ * Wake up the secondary core using wakeup_secondary().
*/
- for (i = 0; i < max_cpus; i++)
- set_cpu_present(i, true);
-
- 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();
-
- /*
- * Initialise the SCU and wake up the secondary core using
- * wakeup_secondary().
- */
- scu_enable(scu_base);
- wakeup_secondary();
- }
+ wakeup_secondary();
}
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index af3d909..b9908e4 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -19,7 +19,6 @@
#include <asm/cacheflush.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
-#include <asm/localtimer.h>
#include <asm/unified.h>

#include <mach/board-eb.h>
@@ -50,14 +49,6 @@ static void __iomem *scu_base_addr(void)
return (void __iomem *)0;
}

-static inline unsigned int get_core_count(void)
-{
- void __iomem *scu_base = scu_base_addr();
- if (scu_base)
- return scu_get_core_count(scu_base);
- return 1;
-}
-
static DEFINE_SPINLOCK(boot_lock);

void __cpuinit platform_secondary_init(unsigned int cpu)
@@ -158,64 +149,18 @@ static void __init poke_milo(void)
*/
void __init smp_init_cpus(void)
{
- unsigned int i, ncores = get_core_count();
+ void __iomem *scu_base = scu_base_addr();
+ unsigned int ncores;
+
+ ncores = scu_base ? scu_get_core_count(scu_base) : 1;

- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
+ smp_init_cpu_possible(ncores);
}

-void __init smp_prepare_cpus(unsigned int max_cpus)
+void __init platform_smp_prepare_cpus(unsigned int max_cpus)
{
- unsigned int ncores = get_core_count();
- unsigned int cpu = smp_processor_id();
- int i;
-
- /* sanity check */
- if (ncores == 0) {
- printk(KERN_ERR
- "Realview: strange CM count of 0? Default to 1\n");
-
- ncores = 1;
- }
-
- if (ncores > NR_CPUS) {
- printk(KERN_WARNING
- "Realview: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, NR_CPUS);
- ncores = NR_CPUS;
- }
+ smp_init_cpu_present(max_cpus);

- 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. Note that, on modern versions of
- * MILO, the "poke" doesn't actually do anything until each
- * individual core is sent a soft interrupt to get it out of
- * WFI
- */
- 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_addr());
+ if (num_present_cpus() > 1)
poke_milo();
- }
}
diff --git a/arch/arm/mach-s5pv310/platsmp.c b/arch/arm/mach-s5pv310/platsmp.c
index d474426..407c825 100644
--- a/arch/arm/mach-s5pv310/platsmp.c
+++ b/arch/arm/mach-s5pv310/platsmp.c
@@ -22,7 +22,6 @@
#include <linux/io.h>

#include <asm/cacheflush.h>
-#include <asm/localtimer.h>
#include <asm/smp_scu.h>
#include <asm/unified.h>

@@ -125,68 +124,22 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
void __init smp_init_cpus(void)
{
void __iomem *scu_base = scu_base_addr();
- unsigned int i, ncores;
+ unsigned int ncores;

ncores = scu_base ? scu_get_core_count(scu_base) : 1;

- /* sanity check */
- if (ncores == 0) {
- printk(KERN_ERR
- "S5PV310: strange CM count of 0? Default to 1\n");
-
- ncores = 1;
- }
-
- if (ncores > NR_CPUS) {
- printk(KERN_WARNING
- "S5PV310: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, NR_CPUS);
- ncores = NR_CPUS;
- }
-
- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
+ smp_init_cpu_possible(ncores);
}

-void __init smp_prepare_cpus(unsigned int max_cpus)
+void __init platform_smp_prepare_cpus(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;
+ smp_init_cpu_present(max_cpus);

/*
- * Initialise the present map, which describes the set of CPUs
- * actually populated at the present time.
+ * Write the address of secondary startup into the
+ * system-wide flags register. The boot monitor waits
+ * until it receives a soft interrupt, and then the
+ * secondary CPU branches to this address.
*/
- 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_addr());
-
- /*
- * Write the address of secondary startup into the
- * system-wide flags register. The boot monitor waits
- * until it receives a soft interrupt, and then the
- * secondary CPU branches to this address.
- */
__raw_writel(BSYM(virt_to_phys(s5pv310_secondary_startup)), S5P_VA_SYSRAM);
- }
}
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index 1c0fd92..abbb97b 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -22,7 +22,6 @@
#include <asm/cacheflush.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
-#include <asm/localtimer.h>
#include <asm/smp_scu.h>

#include <mach/iomap.h>
@@ -115,42 +114,10 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
*/
void __init smp_init_cpus(void)
{
- unsigned int i, ncores = scu_get_core_count(scu_base);
-
- for (i = 0; i < ncores; i++)
- cpu_set(i, cpu_possible_map);
+ smp_init_cpu_possible(scu_get_core_count(scu_base));
}

-void __init smp_prepare_cpus(unsigned int max_cpus)
+void __init platform_smp_prepare_cpus(unsigned int max_cpus)
{
- unsigned int ncores = scu_get_core_count(scu_base);
- 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. Note that, on modern versions of
- * MILO, the "poke" doesn't actually do anything until each
- * individual core is sent a soft interrupt to get it out of
- * WFI
- */
- if (max_cpus > 1) {
- percpu_timer_setup();
- scu_enable(scu_base);
- }
+ smp_init_cpu_present(max_cpus);
}
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c
index b8987bd..e03a5d0 100644
--- a/arch/arm/mach-ux500/platsmp.c
+++ b/arch/arm/mach-ux500/platsmp.c
@@ -18,7 +18,6 @@
#include <linux/io.h>

#include <asm/cacheflush.h>
-#include <asm/localtimer.h>
#include <asm/smp_scu.h>
#include <mach/hardware.h>

@@ -28,11 +27,6 @@
*/
volatile int __cpuinitdata pen_release = -1;

-static unsigned int __init get_core_count(void)
-{
- return scu_get_core_count(__io_address(UX500_SCU_BASE));
-}
-
static DEFINE_SPINLOCK(boot_lock);

void __cpuinit platform_secondary_init(unsigned int cpu)
@@ -126,55 +120,18 @@ static void __init wakeup_secondary(void)
*/
void __init smp_init_cpus(void)
{
- unsigned int i, ncores = get_core_count();
+ unsigned int ncores = scu_get_core_count(__io_address(UX500_SCU_BASE));

- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
+ smp_init_cpu_possible(ncores);
}

void __init smp_prepare_cpus(unsigned int max_cpus)
{
- unsigned int ncores = get_core_count();
- unsigned int cpu = smp_processor_id();
- int i;
-
- /* sanity check */
- if (ncores == 0) {
- printk(KERN_ERR
- "U8500: strange CM count of 0? Default to 1\n");
- ncores = 1;
- }
-
- if (ncores > num_possible_cpus()) {
- printk(KERN_WARNING
- "U8500: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, num_possible_cpus());
- ncores = num_possible_cpus();
- }
-
- smp_store_cpu_info(cpu);
+ smp_init_cpu_present(max_cpus);

/*
- * are we trying to boot more cores than exist?
+ * Enable the local timer or broadcast device for the
+ * boot CPU, but only if we have more than one CPU.
*/
- 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);
-
- 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(__io_address(UX500_SCU_BASE));
- wakeup_secondary();
- }
+ wakeup_secondary();
}
diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c
index 276f916..92ef7cb 100644
--- a/arch/arm/mach-vexpress/platsmp.c
+++ b/arch/arm/mach-vexpress/platsmp.c
@@ -17,7 +17,6 @@
#include <linux/io.h>

#include <asm/cacheflush.h>
-#include <asm/localtimer.h>
#include <asm/smp_scu.h>
#include <asm/unified.h>

@@ -119,72 +118,24 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
void __init smp_init_cpus(void)
{
void __iomem *scu_base = scu_base_addr();
- unsigned int i, ncores;
+ unsigned int ncores;

ncores = scu_base ? scu_get_core_count(scu_base) : 1;

- /* sanity check */
- if (ncores == 0) {
- printk(KERN_ERR
- "vexpress: strange CM count of 0? Default to 1\n");
-
- ncores = 1;
- }
-
- if (ncores > NR_CPUS) {
- printk(KERN_WARNING
- "vexpress: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, NR_CPUS);
- ncores = NR_CPUS;
- }
-
- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
+ smp_init_cpu_possible(ncores);
}

void __init smp_prepare_cpus(unsigned int max_cpus)
{
- unsigned int ncores = num_possible_cpus();
- unsigned int cpu = smp_processor_id();
- int i;
-
- smp_store_cpu_info(cpu);
+ smp_init_cpu_present(max_cpus);

/*
- * are we trying to boot more cores than exist?
+ * Write the address of secondary startup into the
+ * system-wide flags register. The boot monitor waits
+ * until it receives a soft interrupt, and then the
+ * secondary CPU branches to this address.
*/
- 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_addr());
-
- /*
- * Write the address of secondary startup into the
- * system-wide flags register. The boot monitor waits
- * until it receives a soft interrupt, and then the
- * secondary CPU branches to this address.
- */
- writel(~0, MMIO_P2V(V2M_SYS_FLAGSCLR));
- writel(BSYM(virt_to_phys(vexpress_secondary_startup)),
- MMIO_P2V(V2M_SYS_FLAGSSET));
- }
+ writel(~0, MMIO_P2V(V2M_SYS_FLAGSCLR));
+ writel(BSYM(virt_to_phys(vexpress_secondary_startup)),
+ MMIO_P2V(V2M_SYS_FLAGSSET));
}

2010-12-04 08:48:45

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH 1/8] ARM: SCU: Add common routines for secondary CPU bootup

On Thu, Dec 02, 2010 at 06:01:50PM +0000, Russell King - ARM Linux wrote:
> On Thu, Dec 02, 2010 at 05:38:24PM +0000, Russell King - ARM Linux wrote:
> > What if a platform, for what ever reason, wants to have 3 CPUs,
> > numbered 0, 2, 3 ? That's the reason why the code which sets the
> > possible and present maps isn't in the ARM core code - Eg, we don't
> > know if a platform wants to keep CPU 1 in AMP mode to run some
> > special software on it.
> >
> > I don't think it's worth it because I think trying to considate this
> > is going to cripple the code structure in the future.
>
> I don't think this is particularly worth it either:

As Catalin has pointed out:

http://lists.arm.linux.org.uk/lurker/message/20101202.162840.5465758c.en.html

The SCU is part of the core, and if you consult the TRMs for the MPCore
devices, it is actually different in ARM11 MPCore vs Cortex-A9 MPCore.
Cortex-A15 doesn't have a MMIO addressable SCU at all.

So, this is about as far as I want to go with stripping out the common
code from the various platforms (this includes my previous SMP series):

http://lists.arm.linux.org.uk/lurker/message/20101203.200746.31424430.en.html

This results in a net reduction of 242 LOC, as shown in the following
diffstat:

arch/arm/include/asm/hardirq.h | 18 ++
arch/arm/include/asm/mach/irq.h | 2 +-
arch/arm/include/asm/smp.h | 17 +-
arch/arm/include/asm/smp_mpidr.h | 17 --
arch/arm/kernel/entry-armv.S | 2 +-
arch/arm/kernel/fiq.c | 5 +-
arch/arm/kernel/head.S | 39 +++--
arch/arm/kernel/irq.c | 23 ++-
arch/arm/kernel/smp.c | 243 ++++++++++++++++-------------
arch/arm/mach-msm/include/mach/smp.h | 4 +-
arch/arm/mach-omap2/omap-hotplug.c | 14 +--
arch/arm/mach-omap2/omap-smp.c | 66 ++------
arch/arm/mach-realview/hotplug.c | 18 +--
arch/arm/mach-realview/include/mach/smp.h | 5 +-
arch/arm/mach-realview/platsmp.c | 95 +++---------
arch/arm/mach-s5pv310/hotplug.c | 18 +--
arch/arm/mach-s5pv310/include/mach/smp.h | 5 +-
arch/arm/mach-s5pv310/platsmp.c | 46 +-----
arch/arm/mach-tegra/hotplug.c | 18 +--
arch/arm/mach-tegra/include/mach/smp.h | 12 +--
arch/arm/mach-tegra/platsmp.c | 33 +---
arch/arm/mach-ux500/hotplug.c | 18 +--
arch/arm/mach-ux500/include/mach/smp.h | 5 +-
arch/arm/mach-ux500/platsmp.c | 57 ++-----
arch/arm/mach-vexpress/include/mach/smp.h | 5 +-
arch/arm/mach-vexpress/platsmp.c | 54 ++-----
arch/arm/plat-omap/include/plat/smp.h | 5 +-
27 files changed, 301 insertions(+), 543 deletions(-)

Can someone also explain why OMAP uses different file naming from everyone
else? It's annoying as (eg) arch/arm/*/platsmp.c for editing the platform
SMP support files gets everyone except OMAP.

2010-12-06 07:35:24

by Santosh Shilimkar

[permalink] [raw]
Subject: RE: [PATCH 1/8] ARM: SCU: Add common routines for secondary CPUbootup

> -----Original Message-----
> From: [email protected] [mailto:linux-omap-
> [email protected]] On Behalf Of Russell King - ARM Linux
> Sent: Saturday, December 04, 2010 2:18 PM
> To: Tony Lindgren; Kukjin Kim; Srinidhi Kasagar; Jamie Iles; Anton
> Vorontsov; [email protected]; linux-samsung-
> [email protected]; Colin Cross; [email protected]; Uwe
Kleine-
> K?nig; [email protected]; [email protected]
> Subject: Re: [PATCH 1/8] ARM: SCU: Add common routines for secondary
> CPUbootup
>
> On Thu, Dec 02, 2010 at 06:01:50PM +0000, Russell King - ARM Linux
wrote:
> > On Thu, Dec 02, 2010 at 05:38:24PM +0000, Russell King - ARM Linux
> wrote:
> > > What if a platform, for what ever reason, wants to have 3 CPUs,
> > > numbered 0, 2, 3 ? That's the reason why the code which sets the
> > > possible and present maps isn't in the ARM core code - Eg, we don't
> > > know if a platform wants to keep CPU 1 in AMP mode to run some
> > > special software on it.
> > >
> > > I don't think it's worth it because I think trying to considate this
> > > is going to cripple the code structure in the future.
> >
> > I don't think this is particularly worth it either:
>
> As Catalin has pointed out:
>
>
http://lists.arm.linux.org.uk/lurker/message/20101202.162840.5465758c.en.h
> tml
>
> The SCU is part of the core, and if you consult the TRMs for the MPCore
> devices, it is actually different in ARM11 MPCore vs Cortex-A9 MPCore.
> Cortex-A15 doesn't have a MMIO addressable SCU at all.
>
> So, this is about as far as I want to go with stripping out the common
> code from the various platforms (this includes my previous SMP series):
>
>
http://lists.arm.linux.org.uk/lurker/message/20101203.200746.31424430.en.h
> tml
>
> This results in a net reduction of 242 LOC, as shown in the following
> diffstat:
>
> arch/arm/include/asm/hardirq.h | 18 ++
> arch/arm/include/asm/mach/irq.h | 2 +-
> arch/arm/include/asm/smp.h | 17 +-
> arch/arm/include/asm/smp_mpidr.h | 17 --
> arch/arm/kernel/entry-armv.S | 2 +-
> arch/arm/kernel/fiq.c | 5 +-
> arch/arm/kernel/head.S | 39 +++--
> arch/arm/kernel/irq.c | 23 ++-
> arch/arm/kernel/smp.c | 243
++++++++++++++++--------
> -----
> arch/arm/mach-msm/include/mach/smp.h | 4 +-
> arch/arm/mach-omap2/omap-hotplug.c | 14 +--
> arch/arm/mach-omap2/omap-smp.c | 66 ++------
> arch/arm/mach-realview/hotplug.c | 18 +--
> arch/arm/mach-realview/include/mach/smp.h | 5 +-
> arch/arm/mach-realview/platsmp.c | 95 +++---------
> arch/arm/mach-s5pv310/hotplug.c | 18 +--
> arch/arm/mach-s5pv310/include/mach/smp.h | 5 +-
> arch/arm/mach-s5pv310/platsmp.c | 46 +-----
> arch/arm/mach-tegra/hotplug.c | 18 +--
> arch/arm/mach-tegra/include/mach/smp.h | 12 +--
> arch/arm/mach-tegra/platsmp.c | 33 +---
> arch/arm/mach-ux500/hotplug.c | 18 +--
> arch/arm/mach-ux500/include/mach/smp.h | 5 +-
> arch/arm/mach-ux500/platsmp.c | 57 ++-----
> arch/arm/mach-vexpress/include/mach/smp.h | 5 +-
> arch/arm/mach-vexpress/platsmp.c | 54 ++-----
> arch/arm/plat-omap/include/plat/smp.h | 5 +-
> 27 files changed, 301 insertions(+), 543 deletions(-)
>
> Can someone also explain why OMAP uses different file naming from
everyone
> else? It's annoying as (eg) arch/arm/*/platsmp.c for editing the
platform
> SMP support files gets everyone except OMAP.

Nothing specific Russell?.
Its just to keep in sync with the way other files are named
under omap directories. We could rename this if it helps.

Regards,
Ssantosh