summaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2012-09-22 09:06:21 +0200
committerOlof Johansson <olof@lixom.net>2012-09-22 09:16:04 +0200
commit25468fe89f88c4ceeef94526e94ae0db176f6999 (patch)
treed70a713525281276b5063c814413bb3141e6056c /arch/arm/kernel
parentARM: highbank: call highbank_pm_init from .init_machine (diff)
parentARM: consolidate pen_release instead of having per platform definitions (diff)
downloadlinux-25468fe89f88c4ceeef94526e94ae0db176f6999.tar.xz
linux-25468fe89f88c4ceeef94526e94ae0db176f6999.zip
Merge branch 'multiplatform/smp_ops' into next/multiplatform
* multiplatform/smp_ops: ARM: consolidate pen_release instead of having per platform definitions ARM: smp: Make SMP operations mandatory ARM: SoC: convert spear13xx to SMP operations ARM: SoC: convert imx6q to SMP operations ARM: SoC: convert highbank to SMP operations ARM: SoC: convert shmobile SMP to SMP operations ARM: SoC: convert ux500 to SMP operations ARM: SoC: convert MSM to SMP operations ARM: SoC: convert Exynos4 to SMP operations ARM: SoC: convert Tegra to SMP operations ARM: SoC: convert OMAP4 to SMP operations ARM: SoC: convert VExpress/RealView to SMP operations ARM: SoC: add per-platform SMP operations Conflicts due to file moves or removals in: arch/arm/mach-msm/board-msm8960.c arch/arm/mach-msm/board-msm8x60.c arch/arm/mach-tegra/board-harmony.c arch/arm/mach-tegra/board-trimslice.c Conflicts due to board file cleanup: arch/arm/mach-tegra/board-paz00.c Conflicts due to cpu hotplug addition: arch/arm/mach-tegra/hotplug.c Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/setup.c4
-rw-r--r--arch/arm/kernel/smp.c72
2 files changed, 72 insertions, 4 deletions
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index a81dcecc7343..725f9f2a9541 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -977,8 +977,10 @@ void __init setup_arch(char **cmdline_p)
unflatten_device_tree();
#ifdef CONFIG_SMP
- if (is_smp())
+ if (is_smp()) {
+ smp_set_ops(mdesc->smp);
smp_init_cpus();
+ }
#endif
reserve_crashkernel();
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index ebd8ad274d76..aa4ffe6e5ecf 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -19,7 +19,6 @@
#include <linux/mm.h>
#include <linux/err.h>
#include <linux/cpu.h>
-#include <linux/smp.h>
#include <linux/seq_file.h>
#include <linux/irq.h>
#include <linux/percpu.h>
@@ -27,6 +26,7 @@
#include <linux/completion.h>
#include <linux/atomic.h>
+#include <asm/smp.h>
#include <asm/cacheflush.h>
#include <asm/cpu.h>
#include <asm/cputype.h>
@@ -42,6 +42,7 @@
#include <asm/ptrace.h>
#include <asm/localtimer.h>
#include <asm/smp_plat.h>
+#include <asm/mach/arch.h>
/*
* as from 2.5, kernels no longer have an init_tasks structure
@@ -50,6 +51,12 @@
*/
struct secondary_data secondary_data;
+/*
+ * control for which core is the next to come out of the secondary
+ * boot "holding pen"
+ */
+volatile int __cpuinitdata pen_release = -1;
+
enum ipi_msg_type {
IPI_TIMER = 2,
IPI_RESCHEDULE,
@@ -60,6 +67,14 @@ enum ipi_msg_type {
static DECLARE_COMPLETION(cpu_running);
+static struct smp_operations smp_ops;
+
+void __init smp_set_ops(struct smp_operations *ops)
+{
+ if (ops)
+ smp_ops = *ops;
+};
+
int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
{
int ret;
@@ -100,13 +115,64 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
return ret;
}
+/* platform specific SMP operations */
+void __init smp_init_cpus(void)
+{
+ if (smp_ops.smp_init_cpus)
+ smp_ops.smp_init_cpus();
+}
+
+static void __init platform_smp_prepare_cpus(unsigned int max_cpus)
+{
+ if (smp_ops.smp_prepare_cpus)
+ smp_ops.smp_prepare_cpus(max_cpus);
+}
+
+static void __cpuinit platform_secondary_init(unsigned int cpu)
+{
+ if (smp_ops.smp_secondary_init)
+ smp_ops.smp_secondary_init(cpu);
+}
+
+int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ if (smp_ops.smp_boot_secondary)
+ return smp_ops.smp_boot_secondary(cpu, idle);
+ return -ENOSYS;
+}
+
#ifdef CONFIG_HOTPLUG_CPU
static void percpu_timer_stop(void);
+static int platform_cpu_kill(unsigned int cpu)
+{
+ if (smp_ops.cpu_kill)
+ return smp_ops.cpu_kill(cpu);
+ return 1;
+}
+
+static void platform_cpu_die(unsigned int cpu)
+{
+ if (smp_ops.cpu_die)
+ smp_ops.cpu_die(cpu);
+}
+
+static int platform_cpu_disable(unsigned int cpu)
+{
+ if (smp_ops.cpu_disable)
+ return smp_ops.cpu_disable(cpu);
+
+ /*
+ * By default, allow disabling all CPUs except the first one,
+ * since this is special on a lot of platforms, e.g. because
+ * of clock tick interrupts.
+ */
+ return cpu == 0 ? -EPERM : 0;
+}
/*
* __cpu_disable runs on the processor to be shutdown.
*/
-int __cpu_disable(void)
+int __cpuinit __cpu_disable(void)
{
unsigned int cpu = smp_processor_id();
int ret;
@@ -149,7 +215,7 @@ static DECLARE_COMPLETION(cpu_died);
* called on the thread which is asking for a CPU to be shutdown -
* waits until shutdown has completed, or it is timed out.
*/
-void __cpu_die(unsigned int cpu)
+void __cpuinit __cpu_die(unsigned int cpu)
{
if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) {
pr_err("CPU%u: cpu didn't die\n", cpu);