diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h index 0b1c94b8c652..917d4fcfd9b4 100644 --- a/arch/arm/include/asm/mach/arch.h +++ b/arch/arm/include/asm/mach/arch.h @@ -14,6 +14,12 @@ struct tag; struct meminfo; struct sys_timer; struct pt_regs; +struct smp_operations; +#ifdef CONFIG_SMP +#define smp_ops(ops) (&(ops)) +#else +#define smp_ops(ops) (struct smp_operations *)NULL +#endif struct machine_desc { unsigned int nr; /* architecture number */ @@ -35,6 +41,7 @@ struct machine_desc { unsigned char reserve_lp1 :1; /* never has lp1 */ unsigned char reserve_lp2 :1; /* never has lp2 */ char restart_mode; /* default restart mode */ + struct smp_operations *smp; /* SMP operations */ void (*fixup)(struct tag *, char **, struct meminfo *); void (*reserve)(void);/* reserve mem blocks */ diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index ae29293270a3..2e3be16c6766 100644 --- a/arch/arm/include/asm/smp.h +++ b/arch/arm/include/asm/smp.h @@ -60,15 +60,6 @@ extern int boot_secondary(unsigned int cpu, struct task_struct *); */ asmlinkage void secondary_start_kernel(void); -/* - * Perform platform specific initialisation of the specified CPU. - */ -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. @@ -79,18 +70,47 @@ struct secondary_data { void *stack; }; extern struct secondary_data secondary_data; +extern volatile int pen_release; extern int __cpu_disable(void); -extern int platform_cpu_disable(unsigned int cpu); extern void __cpu_die(unsigned int cpu); extern void cpu_die(void); -extern void platform_cpu_die(unsigned int cpu); -extern int platform_cpu_kill(unsigned int cpu); -extern void platform_cpu_enable(unsigned int cpu); - extern void arch_send_call_function_single_ipi(int cpu); extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); +struct smp_operations { +#ifdef CONFIG_SMP + /* + * Setup the set of possible CPUs (via set_cpu_possible) + */ + void (*smp_init_cpus)(void); + /* + * Initialize cpu_possible map, and enable coherency + */ + void (*smp_prepare_cpus)(unsigned int max_cpus); + + /* + * Perform platform specific initialisation of the specified CPU. + */ + void (*smp_secondary_init)(unsigned int cpu); + /* + * Boot a secondary CPU, and assign it the specified idle task. + * This also gives us the initial stack to use for this CPU. + */ + int (*smp_boot_secondary)(unsigned int cpu, struct task_struct *idle); +#ifdef CONFIG_HOTPLUG_CPU + int (*cpu_kill)(unsigned int cpu); + void (*cpu_die)(unsigned int cpu); + int (*cpu_disable)(unsigned int cpu); +#endif +#endif +}; + +/* + * set platform specific SMP operations + */ +extern void smp_set_ops(struct smp_operations *); + #endif /* ifndef __ASM_ARM_SMP_H */ 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 #include #include -#include #include #include #include @@ -27,6 +26,7 @@ #include #include +#include #include #include #include @@ -42,6 +42,7 @@ #include #include #include +#include /* * 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); diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index aed2eeb06517..dac146df79ac 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -14,6 +14,7 @@ extern struct sys_timer exynos4_timer; +struct map_desc; void exynos_init_io(struct map_desc *mach_desc, int size); void exynos4_init_irq(void); void exynos5_init_irq(void); @@ -59,4 +60,8 @@ void exynos4212_register_clocks(void); #define exynos4212_register_clocks() #endif +extern struct smp_operations exynos_smp_ops; + +extern void exynos_cpu_die(unsigned int cpu); + #endif /* __ARCH_ARM_MACH_EXYNOS_COMMON_H */ diff --git a/arch/arm/mach-exynos/hotplug.c b/arch/arm/mach-exynos/hotplug.c index 9c17a0a43858..f4d7dd20cdac 100644 --- a/arch/arm/mach-exynos/hotplug.c +++ b/arch/arm/mach-exynos/hotplug.c @@ -21,7 +21,7 @@ #include -extern volatile int pen_release; +#include "common.h" static inline void cpu_enter_lowpower(void) { @@ -95,17 +95,12 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious) } } -int platform_cpu_kill(unsigned int cpu) -{ - return 1; -} - /* * platform-specific code to shutdown a CPU * * Called with IRQs disabled */ -void platform_cpu_die(unsigned int cpu) +void __ref exynos_cpu_die(unsigned int cpu) { int spurious = 0; @@ -124,12 +119,3 @@ void platform_cpu_die(unsigned int cpu) if (spurious) pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); } - -int platform_cpu_disable(unsigned int cpu) -{ - /* - * we don't allow CPU 0 to be shutdown (it is still too special - * e.g. clock tick interrupts) - */ - return cpu == 0 ? -EPERM : 0; -} diff --git a/arch/arm/mach-exynos/mach-armlex4210.c b/arch/arm/mach-exynos/mach-armlex4210.c index 5a3daa0168d8..3f37a5e8a1f4 100644 --- a/arch/arm/mach-exynos/mach-armlex4210.c +++ b/arch/arm/mach-exynos/mach-armlex4210.c @@ -199,6 +199,7 @@ static void __init armlex4210_machine_init(void) MACHINE_START(ARMLEX4210, "ARMLEX4210") /* Maintainer: Alim Akhtar */ .atag_offset = 0x100, + .smp = smp_ops(exynos_smp_ops), .init_irq = exynos4_init_irq, .map_io = armlex4210_map_io, .handle_irq = gic_handle_irq, diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c index ef770bc2318f..8833060f77e9 100644 --- a/arch/arm/mach-exynos/mach-exynos5-dt.c +++ b/arch/arm/mach-exynos/mach-exynos5-dt.c @@ -79,6 +79,7 @@ static char const *exynos5250_dt_compat[] __initdata = { DT_MACHINE_START(EXYNOS5_DT, "SAMSUNG EXYNOS5 (Flattened Device Tree)") /* Maintainer: Kukjin Kim */ .init_irq = exynos5_init_irq, + .smp = smp_ops(exynos_smp_ops), .map_io = exynos5250_dt_map_io, .handle_irq = gic_handle_irq, .init_machine = exynos5250_dt_machine_init, diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index ea785fcaf6c3..ffaa355c1bde 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c @@ -1383,6 +1383,7 @@ static void __init nuri_machine_init(void) MACHINE_START(NURI, "NURI") /* Maintainer: Kyungmin Park */ .atag_offset = 0x100, + .smp = smp_ops(exynos_smp_ops), .init_irq = exynos4_init_irq, .map_io = nuri_map_io, .handle_irq = gic_handle_irq, diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c index 4e574c24581c..abd0e6059ab3 100644 --- a/arch/arm/mach-exynos/mach-origen.c +++ b/arch/arm/mach-exynos/mach-origen.c @@ -806,6 +806,7 @@ static void __init origen_machine_init(void) MACHINE_START(ORIGEN, "ORIGEN") /* Maintainer: JeongHyeon Kim */ .atag_offset = 0x100, + .smp = smp_ops(exynos_smp_ops), .init_irq = exynos4_init_irq, .map_io = origen_map_io, .handle_irq = gic_handle_irq, diff --git a/arch/arm/mach-exynos/mach-smdk4x12.c b/arch/arm/mach-exynos/mach-smdk4x12.c index b26beb13ebef..964693bdc242 100644 --- a/arch/arm/mach-exynos/mach-smdk4x12.c +++ b/arch/arm/mach-exynos/mach-smdk4x12.c @@ -370,6 +370,7 @@ static void __init smdk4x12_machine_init(void) MACHINE_START(SMDK4212, "SMDK4212") /* Maintainer: Kukjin Kim */ .atag_offset = 0x100, + .smp = smp_ops(exynos_smp_ops), .init_irq = exynos4_init_irq, .map_io = smdk4x12_map_io, .handle_irq = gic_handle_irq, @@ -383,6 +384,7 @@ MACHINE_START(SMDK4412, "SMDK4412") /* Maintainer: Kukjin Kim */ /* Maintainer: Changhwan Youn */ .atag_offset = 0x100, + .smp = smp_ops(exynos_smp_ops), .init_irq = exynos4_init_irq, .map_io = smdk4x12_map_io, .handle_irq = gic_handle_irq, diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c index 73f2bce097e1..69b858ceefc5 100644 --- a/arch/arm/mach-exynos/mach-smdkv310.c +++ b/arch/arm/mach-exynos/mach-smdkv310.c @@ -417,6 +417,7 @@ MACHINE_START(SMDKV310, "SMDKV310") /* Maintainer: Kukjin Kim */ /* Maintainer: Changhwan Youn */ .atag_offset = 0x100, + .smp = smp_ops(exynos_smp_ops), .init_irq = exynos4_init_irq, .map_io = smdkv310_map_io, .handle_irq = gic_handle_irq, @@ -429,6 +430,7 @@ MACHINE_END MACHINE_START(SMDKC210, "SMDKC210") /* Maintainer: Kukjin Kim */ .atag_offset = 0x100, + .smp = smp_ops(exynos_smp_ops), .init_irq = exynos4_init_irq, .map_io = smdkv310_map_io, .handle_irq = gic_handle_irq, diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c index 4d1f40d44ed1..922ca0f11795 100644 --- a/arch/arm/mach-exynos/mach-universal_c210.c +++ b/arch/arm/mach-exynos/mach-universal_c210.c @@ -1155,6 +1155,7 @@ static void __init universal_machine_init(void) MACHINE_START(UNIVERSAL_C210, "UNIVERSAL_C210") /* Maintainer: Kyungmin Park */ .atag_offset = 0x100, + .smp = smp_ops(exynos_smp_ops), .init_irq = exynos4_init_irq, .map_io = universal_map_io, .handle_irq = gic_handle_irq, diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index 36c3984aaa47..8d57e4223bdb 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c @@ -32,18 +32,13 @@ #include +#include "common.h" + extern void exynos4_secondary_startup(void); #define CPU1_BOOT_REG (samsung_rev() == EXYNOS4210_REV_1_1 ? \ S5P_INFORM5 : S5P_VA_SYSRAM) -/* - * control for which core is the next to come out of the secondary - * boot "holding pen" - */ - -volatile int __cpuinitdata pen_release = -1; - /* * Write pen_release in a way that is guaranteed to be visible to all * observers, irrespective of whether they're taking part in coherency @@ -64,7 +59,7 @@ static void __iomem *scu_base_addr(void) static DEFINE_SPINLOCK(boot_lock); -void __cpuinit platform_secondary_init(unsigned int cpu) +static void __cpuinit exynos_secondary_init(unsigned int cpu) { /* * if any interrupts are already enabled for the primary @@ -86,7 +81,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) spin_unlock(&boot_lock); } -int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +static int __cpuinit exynos_boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout; @@ -161,7 +156,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) * which may be present or become present in the system. */ -void __init smp_init_cpus(void) +static void __init exynos_smp_init_cpus(void) { void __iomem *scu_base = scu_base_addr(); unsigned int i, ncores; @@ -184,7 +179,7 @@ void __init smp_init_cpus(void) set_smp_cross_call(gic_raise_softirq); } -void __init platform_smp_prepare_cpus(unsigned int max_cpus) +static void __init exynos_smp_prepare_cpus(unsigned int max_cpus) { if (!soc_is_exynos5250()) scu_enable(scu_base_addr()); @@ -198,3 +193,13 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus) __raw_writel(virt_to_phys(exynos4_secondary_startup), CPU1_BOOT_REG); } + +struct smp_operations exynos_smp_ops __initdata = { + .smp_init_cpus = exynos_smp_init_cpus, + .smp_prepare_cpus = exynos_smp_prepare_cpus, + .smp_secondary_init = exynos_secondary_init, + .smp_boot_secondary = exynos_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = exynos_cpu_die, +#endif +}; diff --git a/arch/arm/mach-highbank/core.h b/arch/arm/mach-highbank/core.h index 8b9fb1a46a91..286ec82a4f63 100644 --- a/arch/arm/mach-highbank/core.h +++ b/arch/arm/mach-highbank/core.h @@ -15,3 +15,6 @@ static inline void highbank_pm_init(void) {} #endif extern void highbank_smc1(int fn, int arg); +extern void highbank_cpu_die(unsigned int cpu); + +extern struct smp_operations highbank_smp_ops; diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c index f376c26cb0e1..af1da34ccf9d 100644 --- a/arch/arm/mach-highbank/highbank.c +++ b/arch/arm/mach-highbank/highbank.c @@ -163,6 +163,7 @@ static const char *highbank_match[] __initconst = { }; DT_MACHINE_START(HIGHBANK, "Highbank") + .smp = smp_ops(highbank_smp_ops), .map_io = highbank_map_io, .init_irq = highbank_init_irq, .timer = &highbank_timer, diff --git a/arch/arm/mach-highbank/hotplug.c b/arch/arm/mach-highbank/hotplug.c index 977cebbea580..2c1b8c3c8e45 100644 --- a/arch/arm/mach-highbank/hotplug.c +++ b/arch/arm/mach-highbank/hotplug.c @@ -24,16 +24,11 @@ extern void secondary_startup(void); -int platform_cpu_kill(unsigned int cpu) -{ - return 1; -} - /* * platform-specific code to shutdown a CPU * */ -void platform_cpu_die(unsigned int cpu) +void __ref highbank_cpu_die(unsigned int cpu) { flush_cache_all(); @@ -45,12 +40,3 @@ void platform_cpu_die(unsigned int cpu) /* We should never return from idle */ panic("highbank: cpu %d unexpectedly exit from shutdown\n", cpu); } - -int platform_cpu_disable(unsigned int cpu) -{ - /* - * CPU0 should not be shut down via hotplug. cpu_idle can WFI - * or a proper shutdown or hibernate should be used. - */ - return cpu == 0 ? -EPERM : 0; -} diff --git a/arch/arm/mach-highbank/platsmp.c b/arch/arm/mach-highbank/platsmp.c index d01364c72b45..fa9560ec6e70 100644 --- a/arch/arm/mach-highbank/platsmp.c +++ b/arch/arm/mach-highbank/platsmp.c @@ -25,12 +25,12 @@ extern void secondary_startup(void); -void __cpuinit platform_secondary_init(unsigned int cpu) +static void __cpuinit highbank_secondary_init(unsigned int cpu) { gic_secondary_init(0); } -int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +static int __cpuinit highbank_boot_secondary(unsigned int cpu, struct task_struct *idle) { gic_raise_softirq(cpumask_of(cpu), 0); return 0; @@ -40,7 +40,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *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) +static void __init highbank_smp_init_cpus(void) { unsigned int i, ncores; @@ -61,7 +61,7 @@ void __init smp_init_cpus(void) set_smp_cross_call(gic_raise_softirq); } -void __init platform_smp_prepare_cpus(unsigned int max_cpus) +static void __init highbank_smp_prepare_cpus(unsigned int max_cpus) { int i; @@ -76,3 +76,13 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus) for (i = 1; i < max_cpus; i++) highbank_set_cpu_jump(i, secondary_startup); } + +struct smp_operations highbank_smp_ops __initdata = { + .smp_init_cpus = highbank_smp_init_cpus, + .smp_prepare_cpus = highbank_smp_prepare_cpus, + .smp_secondary_init = highbank_secondary_init, + .smp_boot_secondary = highbank_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = highbank_cpu_die, +#endif +}; diff --git a/arch/arm/mach-imx/hotplug.c b/arch/arm/mach-imx/hotplug.c index f8f7437c83b8..b07b778dc9a8 100644 --- a/arch/arm/mach-imx/hotplug.c +++ b/arch/arm/mach-imx/hotplug.c @@ -15,11 +15,6 @@ #include #include -int platform_cpu_kill(unsigned int cpu) -{ - return 1; -} - static inline void cpu_enter_lowpower(void) { unsigned int v; @@ -47,7 +42,7 @@ static inline void cpu_enter_lowpower(void) * * Called with IRQs disabled */ -void platform_cpu_die(unsigned int cpu) +void imx_cpu_die(unsigned int cpu) { cpu_enter_lowpower(); imx_enable_cpu(cpu, false); @@ -56,12 +51,3 @@ void platform_cpu_die(unsigned int cpu) while (1) ; } - -int platform_cpu_disable(unsigned int cpu) -{ - /* - * we don't allow CPU 0 to be shutdown (it is still too special - * e.g. clock tick interrupts) - */ - return cpu == 0 ? -EPERM : 0; -} diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 692b4b143bb1..36979d3dfe34 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -215,6 +215,7 @@ static const char *imx6q_dt_compat[] __initdata = { }; DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad (Device Tree)") + .smp = smp_ops(imx_smp_ops), .map_io = imx6q_map_io, .init_irq = imx6q_init_irq, .handle_irq = imx6q_handle_irq, diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c index ab98c6fec9eb..2ac43e1a2dfd 100644 --- a/arch/arm/mach-imx/platsmp.c +++ b/arch/arm/mach-imx/platsmp.c @@ -41,7 +41,7 @@ void __init imx_scu_map_io(void) scu_base = IMX_IO_ADDRESS(base); } -void __cpuinit platform_secondary_init(unsigned int cpu) +static void __cpuinit imx_secondary_init(unsigned int cpu) { /* * if any interrupts are already enabled for the primary @@ -51,7 +51,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) gic_secondary_init(0); } -int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +static int __cpuinit imx_boot_secondary(unsigned int cpu, struct task_struct *idle) { imx_set_cpu_jump(cpu, v7_secondary_startup); imx_enable_cpu(cpu, true); @@ -62,7 +62,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *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) +static void __init imx_smp_init_cpus(void) { int i, ncores; @@ -79,7 +79,17 @@ void imx_smp_prepare(void) scu_enable(scu_base); } -void __init platform_smp_prepare_cpus(unsigned int max_cpus) +static void __init imx_smp_prepare_cpus(unsigned int max_cpus) { imx_smp_prepare(); } + +struct smp_operations imx_smp_ops __initdata = { + .smp_init_cpus = imx_smp_init_cpus, + .smp_prepare_cpus = imx_smp_prepare_cpus, + .smp_secondary_init = imx_secondary_init, + .smp_boot_secondary = imx_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = imx_cpu_die, +#endif +}; diff --git a/arch/arm/mach-msm/board-dt-8660.c b/arch/arm/mach-msm/board-dt-8660.c index f77f57f39104..e5643f629dcd 100644 --- a/arch/arm/mach-msm/board-dt-8660.c +++ b/arch/arm/mach-msm/board-dt-8660.c @@ -20,6 +20,7 @@ #include #include "common.h" +#include "core.h" static const struct of_device_id msm_dt_gic_match[] __initconst = { { .compatible = "qcom,msm-8660-qgic", .data = gic_of_init }, @@ -53,6 +54,7 @@ static const char *msm8x60_fluid_match[] __initdata = { }; DT_MACHINE_START(MSM_DT, "Qualcomm MSM (Flattened Device Tree)") + .smp = smp_ops(msm_smp_ops), .map_io = msm_map_msm8x60_io, .init_irq = msm8x60_init_irq, .handle_irq = gic_handle_irq, diff --git a/arch/arm/mach-msm/board-dt-8960.c b/arch/arm/mach-msm/board-dt-8960.c index 8df99b8f3c92..139d61bbc8e7 100644 --- a/arch/arm/mach-msm/board-dt-8960.c +++ b/arch/arm/mach-msm/board-dt-8960.c @@ -18,6 +18,7 @@ #include #include "common.h" +#include "core.h" static const struct of_device_id msm_dt_gic_match[] __initconst = { { .compatible = "qcom,msm-qgic2", .data = gic_of_init }, @@ -40,6 +41,7 @@ static const char * const msm8960_dt_match[] __initconst = { }; DT_MACHINE_START(MSM8960_DT, "Qualcomm MSM (Flattened Device Tree)") + .smp = smp_ops(msm_smp_ops), .map_io = msm_map_msm8960_io, .init_irq = msm_dt_init_irq, .timer = &msm_dt_timer, diff --git a/arch/arm/mach-msm/core.h b/arch/arm/mach-msm/core.h new file mode 100644 index 000000000000..a9bab53dddf4 --- /dev/null +++ b/arch/arm/mach-msm/core.h @@ -0,0 +1,2 @@ +extern struct smp_operations msm_smp_ops; +extern void msm_cpu_die(unsigned int cpu); diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c index a446fc14221f..002ac1e47235 100644 --- a/arch/arm/mach-msm/hotplug.c +++ b/arch/arm/mach-msm/hotplug.c @@ -13,7 +13,7 @@ #include #include -extern volatile int pen_release; +#include "core.h" static inline void cpu_enter_lowpower(void) { @@ -57,17 +57,12 @@ static inline void platform_do_lowpower(unsigned int cpu) } } -int platform_cpu_kill(unsigned int cpu) -{ - return 1; -} - /* * platform-specific code to shutdown a CPU * * Called with IRQs disabled */ -void platform_cpu_die(unsigned int cpu) +void __ref msm_cpu_die(unsigned int cpu) { /* * we're ready for shutdown now, so do it @@ -81,12 +76,3 @@ void platform_cpu_die(unsigned int cpu) */ cpu_leave_lowpower(); } - -int platform_cpu_disable(unsigned int cpu) -{ - /* - * we don't allow CPU 0 to be shutdown (it is still too special - * e.g. clock tick interrupts) - */ - return cpu == 0 ? -EPERM : 0; -} diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c index 2d791e6b4ad1..637021c0d8af 100644 --- a/arch/arm/mach-msm/platsmp.c +++ b/arch/arm/mach-msm/platsmp.c @@ -23,17 +23,13 @@ #include #include "scm-boot.h" +#include "core.h" #define VDD_SC1_ARRAY_CLAMP_GFS_CTL 0x15A0 #define SCSS_CPU1CORE_RESET 0xD80 #define SCSS_DBG_STATUS_CORE_PWRDUP 0xE64 extern void msm_secondary_startup(void); -/* - * control for which core is the next to come out of the secondary - * boot "holding pen". - */ -volatile int pen_release = -1; static DEFINE_SPINLOCK(boot_lock); @@ -43,7 +39,7 @@ static inline int get_core_count(void) return ((read_cpuid_id() >> 4) & 3) + 1; } -void __cpuinit platform_secondary_init(unsigned int cpu) +static void __cpuinit msm_secondary_init(unsigned int cpu) { /* * if any interrupts are already enabled for the primary @@ -85,7 +81,7 @@ static __cpuinit void prepare_cold_cpu(unsigned int cpu) "address\n"); } -int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +static int __cpuinit msm_boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout; static int cold_boot_done; @@ -145,7 +141,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) * does not support the ARM SCU, so just set the possible cpu mask to * NR_CPUS. */ -void __init smp_init_cpus(void) +static void __init msm_smp_init_cpus(void) { unsigned int i, ncores = get_core_count(); @@ -161,6 +157,16 @@ void __init smp_init_cpus(void) set_smp_cross_call(gic_raise_softirq); } -void __init platform_smp_prepare_cpus(unsigned int max_cpus) +static void __init msm_smp_prepare_cpus(unsigned int max_cpus) { } + +struct smp_operations msm_smp_ops __initdata = { + .smp_init_cpus = msm_smp_init_cpus, + .smp_prepare_cpus = msm_smp_prepare_cpus, + .smp_secondary_init = msm_secondary_init, + .smp_boot_secondary = msm_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = msm_cpu_die, +#endif +}; diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index e82098fbedd6..6fe90796d462 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -907,6 +907,7 @@ static void __init omap_4430sdp_init(void) MACHINE_START(OMAP_4430SDP, "OMAP4430 4430SDP board") /* Maintainer: Santosh Shilimkar - Texas Instruments Inc */ .atag_offset = 0x100, + .smp = smp_ops(omap4_smp_ops), .reserve = omap_reserve, .map_io = omap4_map_io, .init_early = omap4430_init_early, diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index 2ea7c577b295..601ecdfb1cf9 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -125,6 +125,7 @@ static const char *omap4_boards_compat[] __initdata = { DT_MACHINE_START(OMAP4_DT, "Generic OMAP4 (Flattened Device Tree)") .reserve = omap_reserve, + .smp = smp_ops(omap4_smp_ops), .map_io = omap4_map_io, .init_early = omap4430_init_early, .init_irq = omap_gic_of_init, @@ -145,6 +146,7 @@ static const char *omap5_boards_compat[] __initdata = { DT_MACHINE_START(OMAP5_DT, "Generic OMAP5 (Flattened Device Tree)") .reserve = omap_reserve, + .smp = smp_ops(omap4_smp_ops), .map_io = omap5_map_io, .init_early = omap5_init_early, .init_irq = omap_gic_of_init, diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index 45fe2d3f59b1..8ebb16c5182e 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -516,6 +516,7 @@ static void __init omap4_panda_init(void) MACHINE_START(OMAP4_PANDA, "OMAP4 Panda board") /* Maintainer: David Anders - Texas Instruments Inc */ .atag_offset = 0x100, + .smp = smp_ops(omap4_smp_ops), .reserve = omap_reserve, .map_io = omap4_map_io, .init_early = omap4430_init_early, diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index da0f5c187353..7045e4d61ac3 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -285,6 +285,11 @@ extern void omap_secondary_startup(void); extern u32 omap_modify_auxcoreboot0(u32 set_mask, u32 clear_mask); extern void omap_auxcoreboot_addr(u32 cpu_addr); extern u32 omap_read_auxcoreboot0(void); + +extern void omap4_cpu_die(unsigned int cpu); + +extern struct smp_operations omap4_smp_ops; + extern void omap5_secondary_startup(void); #endif diff --git a/arch/arm/mach-omap2/omap-hotplug.c b/arch/arm/mach-omap2/omap-hotplug.c index 765a2aceb665..e712d1725a8b 100644 --- a/arch/arm/mach-omap2/omap-hotplug.c +++ b/arch/arm/mach-omap2/omap-hotplug.c @@ -26,16 +26,11 @@ #include "powerdomain.h" -int platform_cpu_kill(unsigned int cpu) -{ - return 1; -} - /* * platform-specific code to shutdown a CPU * Called with IRQs disabled */ -void __ref platform_cpu_die(unsigned int cpu) +void __ref omap4_cpu_die(unsigned int cpu) { unsigned int boot_cpu = 0; void __iomem *base = omap_get_wakeupgen_base(); @@ -75,12 +70,3 @@ void __ref platform_cpu_die(unsigned int cpu) pr_debug("CPU%u: spurious wakeup call\n", cpu); } } - -int platform_cpu_disable(unsigned int cpu) -{ - /* - * we don't allow CPU 0 to be shutdown (it is still too special - * e.g. clock tick interrupts) - */ - return cpu == 0 ? -EPERM : 0; -} diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 06d8bc3a8886..4d05fa8a4e48 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -49,7 +49,7 @@ void __iomem *omap4_get_scu_base(void) return scu_base; } -void __cpuinit platform_secondary_init(unsigned int cpu) +static void __cpuinit omap4_secondary_init(unsigned int cpu) { /* * Configure ACTRL and enable NS SMP bit access on CPU1 on HS device. @@ -77,7 +77,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) spin_unlock(&boot_lock); } -int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +static int __cpuinit omap4_boot_secondary(unsigned int cpu, struct task_struct *idle) { static struct clockdomain *cpu1_clkdm; static bool booted; @@ -165,7 +165,7 @@ static void __init wakeup_secondary(void) * 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) +static void __init omap4_smp_init_cpus(void) { unsigned int i = 0, ncores = 1, cpu_id; @@ -196,7 +196,7 @@ void __init smp_init_cpus(void) set_smp_cross_call(gic_raise_softirq); } -void __init platform_smp_prepare_cpus(unsigned int max_cpus) +static void __init omap4_smp_prepare_cpus(unsigned int max_cpus) { /* @@ -207,3 +207,13 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus) scu_enable(scu_base); wakeup_secondary(); } + +struct smp_operations omap4_smp_ops __initdata = { + .smp_init_cpus = omap4_smp_init_cpus, + .smp_prepare_cpus = omap4_smp_prepare_cpus, + .smp_secondary_init = omap4_secondary_init, + .smp_boot_secondary = omap4_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = omap4_cpu_die, +#endif +}; diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h index f8f2c0ac4c01..78cd970c80f2 100644 --- a/arch/arm/mach-realview/core.h +++ b/arch/arm/mach-realview/core.h @@ -56,4 +56,7 @@ extern void realview_init_early(void); extern void realview_fixup(struct tag *tags, char **from, struct meminfo *meminfo); +extern struct smp_operations realview_smp_ops; +extern void realview_cpu_die(unsigned int cpu); + #endif diff --git a/arch/arm/mach-realview/hotplug.c b/arch/arm/mach-realview/hotplug.c index 57d9efba2956..53818e5cd3ad 100644 --- a/arch/arm/mach-realview/hotplug.c +++ b/arch/arm/mach-realview/hotplug.c @@ -16,8 +16,6 @@ #include #include -extern volatile int pen_release; - static inline void cpu_enter_lowpower(void) { unsigned int v; @@ -89,17 +87,12 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious) } } -int platform_cpu_kill(unsigned int cpu) -{ - return 1; -} - /* * platform-specific code to shutdown a CPU * * Called with IRQs disabled */ -void platform_cpu_die(unsigned int cpu) +void __ref realview_cpu_die(unsigned int cpu) { int spurious = 0; @@ -118,12 +111,3 @@ void platform_cpu_die(unsigned int cpu) if (spurious) pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); } - -int platform_cpu_disable(unsigned int cpu) -{ - /* - * we don't allow CPU 0 to be shutdown (it is still too special - * e.g. clock tick interrupts) - */ - return cpu == 0 ? -EPERM : 0; -} diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index 17c878ddbc70..300f7064465d 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -22,9 +22,9 @@ #include #include -#include "core.h" +#include -extern void versatile_secondary_startup(void); +#include "core.h" static void __iomem *scu_base_addr(void) { @@ -43,7 +43,7 @@ static void __iomem *scu_base_addr(void) * 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) +static void __init realview_smp_init_cpus(void) { void __iomem *scu_base = scu_base_addr(); unsigned int i, ncores; @@ -63,7 +63,7 @@ void __init smp_init_cpus(void) set_smp_cross_call(gic_raise_softirq); } -void __init platform_smp_prepare_cpus(unsigned int max_cpus) +static void __init realview_smp_prepare_cpus(unsigned int max_cpus) { scu_enable(scu_base_addr()); @@ -77,3 +77,13 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus) __raw_writel(virt_to_phys(versatile_secondary_startup), __io_address(REALVIEW_SYS_FLAGSSET)); } + +struct smp_operations realview_smp_ops __initdata = { + .smp_init_cpus = realview_smp_init_cpus, + .smp_prepare_cpus = realview_smp_prepare_cpus, + .smp_secondary_init = versatile_secondary_init, + .smp_boot_secondary = versatile_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = realview_cpu_die, +#endif +}; diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c index b442fb276d57..a80269981dd4 100644 --- a/arch/arm/mach-realview/realview_pb11mp.c +++ b/arch/arm/mach-realview/realview_pb11mp.c @@ -367,6 +367,7 @@ static void __init realview_pb11mp_init(void) MACHINE_START(REALVIEW_PB11MP, "ARM-RealView PB11MPCore") /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */ .atag_offset = 0x100, + .smp = smp_ops(realview_smp_ops), .fixup = realview_fixup, .map_io = realview_pb11mp_map_io, .init_early = realview_init_early, diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c index 5d2c8bebb069..a4b1aa93bb5a 100644 --- a/arch/arm/mach-realview/realview_pbx.c +++ b/arch/arm/mach-realview/realview_pbx.c @@ -404,6 +404,7 @@ static void __init realview_pbx_init(void) MACHINE_START(REALVIEW_PBX, "ARM-RealView PBX") /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */ .atag_offset = 0x100, + .smp = smp_ops(realview_smp_ops), .fixup = realview_pbx_fixup, .map_io = realview_pbx_map_io, .init_early = realview_init_early, diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c index cfc3b5c43ba8..25eb88a923e6 100644 --- a/arch/arm/mach-shmobile/board-ag5evm.c +++ b/arch/arm/mach-shmobile/board-ag5evm.c @@ -649,6 +649,7 @@ static void __init ag5evm_init(void) } MACHINE_START(AG5EVM, "ag5evm") + .smp = smp_ops(sh73a0_smp_ops), .map_io = sh73a0_map_io, .init_early = sh73a0_add_early_devices, .nr_irqs = NR_IRQS_LEGACY, diff --git a/arch/arm/mach-shmobile/board-kota2.c b/arch/arm/mach-shmobile/board-kota2.c index 21dbe54304d5..bf88f9a8b7ac 100644 --- a/arch/arm/mach-shmobile/board-kota2.c +++ b/arch/arm/mach-shmobile/board-kota2.c @@ -545,6 +545,7 @@ static void __init kota2_init(void) } MACHINE_START(KOTA2, "kota2") + .smp = smp_ops(sh73a0_smp_ops), .map_io = sh73a0_map_io, .init_early = sh73a0_add_early_devices, .nr_irqs = NR_IRQS_LEGACY, diff --git a/arch/arm/mach-shmobile/board-kzm9d.c b/arch/arm/mach-shmobile/board-kzm9d.c index 2c986eaae7b4..b52bc0d1273f 100644 --- a/arch/arm/mach-shmobile/board-kzm9d.c +++ b/arch/arm/mach-shmobile/board-kzm9d.c @@ -84,6 +84,7 @@ static const char *kzm9d_boards_compat_dt[] __initdata = { }; DT_MACHINE_START(KZM9D_DT, "kzm9d") + .smp = smp_ops(emev2_smp_ops), .map_io = emev2_map_io, .init_early = emev2_add_early_devices, .nr_irqs = NR_IRQS_LEGACY, diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c index fd21fb6f9953..0a3d1f19077e 100644 --- a/arch/arm/mach-shmobile/board-kzm9g.c +++ b/arch/arm/mach-shmobile/board-kzm9g.c @@ -776,6 +776,7 @@ static const char *kzm9g_boards_compat_dt[] __initdata = { }; DT_MACHINE_START(KZM9G_DT, "kzm9g") + .smp = smp_ops(sh73a0_smp_ops), .map_io = sh73a0_map_io, .init_early = sh73a0_add_early_devices, .nr_irqs = NR_IRQS_LEGACY, diff --git a/arch/arm/mach-shmobile/board-marzen.c b/arch/arm/mach-shmobile/board-marzen.c index fcf5a47f4772..01ce3f15c6a3 100644 --- a/arch/arm/mach-shmobile/board-marzen.c +++ b/arch/arm/mach-shmobile/board-marzen.c @@ -102,6 +102,7 @@ static void __init marzen_init(void) } MACHINE_START(MARZEN, "marzen") + .smp = smp_ops(r8a7779_smp_ops), .map_io = r8a7779_map_io, .init_early = r8a7779_add_early_devices, .nr_irqs = NR_IRQS_LEGACY, diff --git a/arch/arm/mach-shmobile/hotplug.c b/arch/arm/mach-shmobile/hotplug.c index 828d22f3af57..b09a0bdbf813 100644 --- a/arch/arm/mach-shmobile/hotplug.c +++ b/arch/arm/mach-shmobile/hotplug.c @@ -14,30 +14,16 @@ #include #include #include +#include #include +#include +#include #include +#include static cpumask_t dead_cpus; -int platform_cpu_kill(unsigned int cpu) -{ - int k; - - /* this function is running on another CPU than the offline target, - * here we need wait for shutdown code in platform_cpu_die() to - * finish before asking SoC-specific code to power off the CPU core. - */ - for (k = 0; k < 1000; k++) { - if (cpumask_test_cpu(cpu, &dead_cpus)) - return shmobile_platform_cpu_kill(cpu); - - mdelay(1); - } - - return 0; -} - -void platform_cpu_die(unsigned int cpu) +void shmobile_cpu_die(unsigned int cpu) { /* hardware shutdown code running on the CPU that is being offlined */ flush_cache_all(); @@ -60,7 +46,7 @@ void platform_cpu_die(unsigned int cpu) } } -int platform_cpu_disable(unsigned int cpu) +int shmobile_cpu_disable(unsigned int cpu) { cpumask_clear_cpu(cpu, &dead_cpus); /* @@ -69,3 +55,8 @@ int platform_cpu_disable(unsigned int cpu) */ return cpu == 0 ? -EPERM : 0; } + +int shmobile_cpu_is_dead(unsigned int cpu) +{ + return cpumask_test_cpu(cpu, &dead_cpus); +} diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index 45e61dada030..f80f9c549393 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -4,11 +4,10 @@ extern void shmobile_earlytimer_init(void); extern struct sys_timer shmobile_timer; extern void shmobile_setup_delay(unsigned int max_cpu_core_mhz, - unsigned int mult, unsigned int div); + unsigned int mult, unsigned int div); struct twd_local_timer; extern void shmobile_setup_console(void); extern void shmobile_secondary_vector(void); -extern int shmobile_platform_cpu_kill(unsigned int cpu); struct clk; extern int shmobile_clk_init(void); extern void shmobile_handle_irq_intc(struct pt_regs *); @@ -58,11 +57,6 @@ extern struct clk sh73a0_extal2_clk; extern struct clk sh73a0_extcki_clk; extern struct clk sh73a0_extalr_clk; -extern unsigned int sh73a0_get_core_count(void); -extern void sh73a0_secondary_init(unsigned int cpu); -extern int sh73a0_boot_secondary(unsigned int cpu); -extern void sh73a0_smp_prepare_cpus(void); - extern void r8a7740_init_irq(void); extern void r8a7740_map_io(void); extern void r8a7740_add_early_devices(void); @@ -79,11 +73,6 @@ extern void r8a7779_pinmux_init(void); extern void r8a7779_pm_init(void); extern void r8a7740_meram_workaround(void); -extern unsigned int r8a7779_get_core_count(void); -extern int r8a7779_platform_cpu_kill(unsigned int cpu); -extern void r8a7779_secondary_init(unsigned int cpu); -extern int r8a7779_boot_secondary(unsigned int cpu); -extern void r8a7779_smp_prepare_cpus(void); extern void r8a7779_register_twd(void); extern void shmobile_init_late(void); @@ -100,4 +89,15 @@ int shmobile_cpuidle_init(void); static inline int shmobile_cpuidle_init(void) { return 0; } #endif +extern void shmobile_cpu_die(unsigned int cpu); +extern int shmobile_cpu_disable(unsigned int cpu); + +#ifdef CONFIG_HOTPLUG_CPU +extern int shmobile_cpu_is_dead(unsigned int cpu); +#else +static inline int shmobile_cpu_is_dead(unsigned int cpu) { return 1; } +#endif + +extern void shmobile_smp_init_cpus(unsigned int ncores); + #endif /* __ARCH_MACH_COMMON_H */ diff --git a/arch/arm/mach-shmobile/include/mach/emev2.h b/arch/arm/mach-shmobile/include/mach/emev2.h index e6b0c1bf4b7e..ac3751705cab 100644 --- a/arch/arm/mach-shmobile/include/mach/emev2.h +++ b/arch/arm/mach-shmobile/include/mach/emev2.h @@ -7,13 +7,10 @@ extern void emev2_add_early_devices(void); extern void emev2_add_standard_devices(void); extern void emev2_clock_init(void); extern void emev2_set_boot_vector(unsigned long value); -extern unsigned int emev2_get_core_count(void); -extern int emev2_platform_cpu_kill(unsigned int cpu); -extern void emev2_secondary_init(unsigned int cpu); -extern int emev2_boot_secondary(unsigned int cpu); -extern void emev2_smp_prepare_cpus(void); #define EMEV2_GPIO_BASE 200 #define EMEV2_GPIO_IRQ(n) (EMEV2_GPIO_BASE + (n)) +extern struct smp_operations emev2_smp_ops; + #endif /* __ASM_EMEV2_H__ */ diff --git a/arch/arm/mach-shmobile/include/mach/r8a7779.h b/arch/arm/mach-shmobile/include/mach/r8a7779.h index b07ad318eb2e..f504c5e81b47 100644 --- a/arch/arm/mach-shmobile/include/mach/r8a7779.h +++ b/arch/arm/mach-shmobile/include/mach/r8a7779.h @@ -360,4 +360,6 @@ extern void r8a7779_add_device_to_domain(struct r8a7779_pm_domain *r8a7779_pd, #define r8a7779_add_device_to_domain(pd, pdev) do { } while (0) #endif /* CONFIG_PM */ +extern struct smp_operations r8a7779_smp_ops; + #endif /* __ASM_R8A7779_H__ */ diff --git a/arch/arm/mach-shmobile/include/mach/sh73a0.h b/arch/arm/mach-shmobile/include/mach/sh73a0.h index fe950f25d793..606d31d02a4e 100644 --- a/arch/arm/mach-shmobile/include/mach/sh73a0.h +++ b/arch/arm/mach-shmobile/include/mach/sh73a0.h @@ -557,4 +557,6 @@ enum { #define SH73A0_PINT0_IRQ(irq) ((irq) + 700) #define SH73A0_PINT1_IRQ(irq) ((irq) + 732) +extern struct smp_operations sh73a0_smp_ops; + #endif /* __ASM_SH73A0_H__ */ diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c index fde0d23121dc..ed8d2351915e 100644 --- a/arch/arm/mach-shmobile/platsmp.c +++ b/arch/arm/mach-shmobile/platsmp.c @@ -11,100 +11,11 @@ * published by the Free Software Foundation. */ #include -#include -#include -#include #include -#include -#include #include -#include -#include -#include -#ifdef CONFIG_ARCH_SH73A0 -#define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2() || \ - of_machine_is_compatible("renesas,sh73a0")) -#else -#define is_sh73a0() (0) -#endif - -#define is_r8a7779() machine_is_marzen() - -#ifdef CONFIG_ARCH_EMEV2 -#define is_emev2() of_machine_is_compatible("renesas,emev2") -#else -#define is_emev2() (0) -#endif - -static unsigned int __init shmobile_smp_get_core_count(void) +void __init shmobile_smp_init_cpus(unsigned int ncores) { - if (is_sh73a0()) - return sh73a0_get_core_count(); - - if (is_r8a7779()) - return r8a7779_get_core_count(); - - if (is_emev2()) - return emev2_get_core_count(); - - return 1; -} - -static void __init shmobile_smp_prepare_cpus(void) -{ - if (is_sh73a0()) - sh73a0_smp_prepare_cpus(); - - if (is_r8a7779()) - r8a7779_smp_prepare_cpus(); - - if (is_emev2()) - emev2_smp_prepare_cpus(); -} - -int shmobile_platform_cpu_kill(unsigned int cpu) -{ - if (is_r8a7779()) - return r8a7779_platform_cpu_kill(cpu); - - if (is_emev2()) - return emev2_platform_cpu_kill(cpu); - - return 1; -} - -void __cpuinit platform_secondary_init(unsigned int cpu) -{ - trace_hardirqs_off(); - - if (is_sh73a0()) - sh73a0_secondary_init(cpu); - - if (is_r8a7779()) - r8a7779_secondary_init(cpu); - - if (is_emev2()) - emev2_secondary_init(cpu); -} - -int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) -{ - if (is_sh73a0()) - return sh73a0_boot_secondary(cpu); - - if (is_r8a7779()) - return r8a7779_boot_secondary(cpu); - - if (is_emev2()) - return emev2_boot_secondary(cpu); - - return -ENOSYS; -} - -void __init smp_init_cpus(void) -{ - unsigned int ncores = shmobile_smp_get_core_count(); unsigned int i; if (ncores > nr_cpu_ids) { @@ -118,8 +29,3 @@ void __init smp_init_cpus(void) set_smp_cross_call(gic_raise_softirq); } - -void __init platform_smp_prepare_cpus(unsigned int max_cpus) -{ - shmobile_smp_prepare_cpus(); -} diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c index 61446f30e397..a47beeb18283 100644 --- a/arch/arm/mach-shmobile/setup-emev2.c +++ b/arch/arm/mach-shmobile/setup-emev2.c @@ -461,6 +461,7 @@ void __init emev2_init_irq_dt(void) } DT_MACHINE_START(EMEV2_DT, "Generic Emma Mobile EV2 (Flattened Device Tree)") + .smp = smp_ops(emev2_smp_ops), .init_early = emev2_init_delay, .nr_irqs = NR_IRQS_LEGACY, .init_irq = emev2_init_irq_dt, diff --git a/arch/arm/mach-shmobile/smp-emev2.c b/arch/arm/mach-shmobile/smp-emev2.c index 6a35c4a31e6c..f978c5d0e1ae 100644 --- a/arch/arm/mach-shmobile/smp-emev2.c +++ b/arch/arm/mach-shmobile/smp-emev2.c @@ -50,7 +50,7 @@ static void modify_scu_cpu_psr(unsigned long set, unsigned long clr) } -unsigned int __init emev2_get_core_count(void) +static unsigned int __init emev2_get_core_count(void) { if (!scu_base) { scu_base = ioremap(EMEV2_SCU_BASE, PAGE_SIZE); @@ -62,17 +62,35 @@ unsigned int __init emev2_get_core_count(void) return scu_base ? scu_get_core_count(scu_base) : 1; } -int emev2_platform_cpu_kill(unsigned int cpu) +static int emev2_platform_cpu_kill(unsigned int cpu) { return 0; /* not supported yet */ } -void __cpuinit emev2_secondary_init(unsigned int cpu) +static int __maybe_unused emev2_cpu_kill(unsigned int cpu) +{ + int k; + + /* this function is running on another CPU than the offline target, + * here we need wait for shutdown code in platform_cpu_die() to + * finish before asking SoC-specific code to power off the CPU core. + */ + for (k = 0; k < 1000; k++) { + if (shmobile_cpu_is_dead(cpu)) + return emev2_platform_cpu_kill(cpu); + mdelay(1); + } + + return 0; +} + + +static void __cpuinit emev2_secondary_init(unsigned int cpu) { gic_secondary_init(0); } -int __cpuinit emev2_boot_secondary(unsigned int cpu) +static int __cpuinit emev2_boot_secondary(unsigned int cpu, struct task_struct *idle) { cpu = cpu_logical_map(cpu); @@ -86,7 +104,7 @@ int __cpuinit emev2_boot_secondary(unsigned int cpu) return 0; } -void __init emev2_smp_prepare_cpus(void) +static void __init emev2_smp_prepare_cpus(unsigned int max_cpus) { int cpu = cpu_logical_map(0); @@ -95,3 +113,22 @@ void __init emev2_smp_prepare_cpus(void) /* enable cache coherency on CPU0 */ modify_scu_cpu_psr(0, 3 << (cpu * 8)); } + +static void __init emev2_smp_init_cpus(void) +{ + unsigned int ncores = emev2_get_core_count(); + + shmobile_smp_init_cpus(ncores); +} + +struct smp_operations emev2_smp_ops __initdata = { + .smp_init_cpus = emev2_smp_init_cpus, + .smp_prepare_cpus = emev2_smp_prepare_cpus, + .smp_secondary_init = emev2_secondary_init, + .smp_boot_secondary = emev2_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_kill = emev2_cpu_kill, + .cpu_die = shmobile_cpu_die, + .cpu_disable = shmobile_cpu_disable, +#endif +}; diff --git a/arch/arm/mach-shmobile/smp-r8a7779.c b/arch/arm/mach-shmobile/smp-r8a7779.c index 6d1d0238cbf7..2ce6af9a6a37 100644 --- a/arch/arm/mach-shmobile/smp-r8a7779.c +++ b/arch/arm/mach-shmobile/smp-r8a7779.c @@ -87,14 +87,14 @@ static void modify_scu_cpu_psr(unsigned long set, unsigned long clr) __raw_writel(tmp, scu_base + 8); } -unsigned int __init r8a7779_get_core_count(void) +static unsigned int __init r8a7779_get_core_count(void) { void __iomem *scu_base = scu_base_addr(); return scu_get_core_count(scu_base); } -int r8a7779_platform_cpu_kill(unsigned int cpu) +static int r8a7779_platform_cpu_kill(unsigned int cpu) { struct r8a7779_pm_ch *ch = NULL; int ret = -EIO; @@ -113,12 +113,31 @@ int r8a7779_platform_cpu_kill(unsigned int cpu) return ret ? ret : 1; } -void __cpuinit r8a7779_secondary_init(unsigned int cpu) +static int __maybe_unused r8a7779_cpu_kill(unsigned int cpu) +{ + int k; + + /* this function is running on another CPU than the offline target, + * here we need wait for shutdown code in platform_cpu_die() to + * finish before asking SoC-specific code to power off the CPU core. + */ + for (k = 0; k < 1000; k++) { + if (shmobile_cpu_is_dead(cpu)) + return r8a7779_platform_cpu_kill(cpu); + + mdelay(1); + } + + return 0; +} + + +static void __cpuinit r8a7779_secondary_init(unsigned int cpu) { gic_secondary_init(0); } -int __cpuinit r8a7779_boot_secondary(unsigned int cpu) +static int __cpuinit r8a7779_boot_secondary(unsigned int cpu, struct task_struct *idle) { struct r8a7779_pm_ch *ch = NULL; int ret = -EIO; @@ -137,7 +156,7 @@ int __cpuinit r8a7779_boot_secondary(unsigned int cpu) return ret; } -void __init r8a7779_smp_prepare_cpus(void) +static void __init r8a7779_smp_prepare_cpus(unsigned int max_cpus) { int cpu = cpu_logical_map(0); @@ -156,3 +175,22 @@ void __init r8a7779_smp_prepare_cpus(void) r8a7779_platform_cpu_kill(2); r8a7779_platform_cpu_kill(3); } + +static void __init r8a7779_smp_init_cpus(void) +{ + unsigned int ncores = r8a7779_get_core_count(); + + shmobile_smp_init_cpus(ncores); +} + +struct smp_operations r8a7779_smp_ops __initdata = { + .smp_init_cpus = r8a7779_smp_init_cpus, + .smp_prepare_cpus = r8a7779_smp_prepare_cpus, + .smp_secondary_init = r8a7779_secondary_init, + .smp_boot_secondary = r8a7779_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_kill = r8a7779_cpu_kill, + .cpu_die = shmobile_cpu_die, + .cpu_disable = shmobile_cpu_disable, +#endif +}; diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c index e36c41c4ab40..624f00f70abf 100644 --- a/arch/arm/mach-shmobile/smp-sh73a0.c +++ b/arch/arm/mach-shmobile/smp-sh73a0.c @@ -22,8 +22,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -64,19 +66,19 @@ static void modify_scu_cpu_psr(unsigned long set, unsigned long clr) __raw_writel(tmp, scu_base + 8); } -unsigned int __init sh73a0_get_core_count(void) +static unsigned int __init sh73a0_get_core_count(void) { void __iomem *scu_base = scu_base_addr(); return scu_get_core_count(scu_base); } -void __cpuinit sh73a0_secondary_init(unsigned int cpu) +static void __cpuinit sh73a0_secondary_init(unsigned int cpu) { gic_secondary_init(0); } -int __cpuinit sh73a0_boot_secondary(unsigned int cpu) +static int __cpuinit sh73a0_boot_secondary(unsigned int cpu, struct task_struct *idle) { cpu = cpu_logical_map(cpu); @@ -91,7 +93,7 @@ int __cpuinit sh73a0_boot_secondary(unsigned int cpu) return 0; } -void __init sh73a0_smp_prepare_cpus(void) +static void __init sh73a0_smp_prepare_cpus(unsigned int max_cpus) { int cpu = cpu_logical_map(0); @@ -104,3 +106,41 @@ void __init sh73a0_smp_prepare_cpus(void) /* enable cache coherency on CPU0 */ modify_scu_cpu_psr(0, 3 << (cpu * 8)); } + +static void __init sh73a0_smp_init_cpus(void) +{ + unsigned int ncores = sh73a0_get_core_count(); + + shmobile_smp_init_cpus(ncores); +} + +static int __maybe_unused sh73a0_cpu_kill(unsigned int cpu) +{ + int k; + + /* this function is running on another CPU than the offline target, + * here we need wait for shutdown code in platform_cpu_die() to + * finish before asking SoC-specific code to power off the CPU core. + */ + for (k = 0; k < 1000; k++) { + if (shmobile_cpu_is_dead(cpu)) + return 1; + + mdelay(1); + } + + return 0; +} + + +struct smp_operations sh73a0_smp_ops __initdata = { + .smp_init_cpus = sh73a0_smp_init_cpus, + .smp_prepare_cpus = sh73a0_smp_prepare_cpus, + .smp_secondary_init = sh73a0_secondary_init, + .smp_boot_secondary = sh73a0_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_kill = sh73a0_cpu_kill, + .cpu_die = shmobile_cpu_die, + .cpu_disable = shmobile_cpu_disable, +#endif +}; diff --git a/arch/arm/mach-spear13xx/hotplug.c b/arch/arm/mach-spear13xx/hotplug.c index 5c6867b46d09..a7d2dd11a4f2 100644 --- a/arch/arm/mach-spear13xx/hotplug.c +++ b/arch/arm/mach-spear13xx/hotplug.c @@ -17,8 +17,6 @@ #include #include -extern volatile int pen_release; - static inline void cpu_enter_lowpower(void) { unsigned int v; @@ -56,7 +54,7 @@ static inline void cpu_leave_lowpower(void) : "cc"); } -static inline void platform_do_lowpower(unsigned int cpu, int *spurious) +static inline void spear13xx_do_lowpower(unsigned int cpu, int *spurious) { for (;;) { wfi(); @@ -79,17 +77,12 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious) } } -int platform_cpu_kill(unsigned int cpu) -{ - return 1; -} - /* * platform-specific code to shutdown a CPU * * Called with IRQs disabled */ -void __cpuinit platform_cpu_die(unsigned int cpu) +void __ref spear13xx_cpu_die(unsigned int cpu) { int spurious = 0; @@ -97,7 +90,7 @@ void __cpuinit platform_cpu_die(unsigned int cpu) * we're ready for shutdown now, so do it */ cpu_enter_lowpower(); - platform_do_lowpower(cpu, &spurious); + spear13xx_do_lowpower(cpu, &spurious); /* * bring this CPU back into the world of cache @@ -108,12 +101,3 @@ void __cpuinit platform_cpu_die(unsigned int cpu) if (spurious) pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); } - -int platform_cpu_disable(unsigned int cpu) -{ - /* - * we don't allow CPU 0 to be shutdown (it is still too special - * e.g. clock tick interrupts) - */ - return cpu == 0 ? -EPERM : 0; -} diff --git a/arch/arm/mach-spear13xx/include/mach/generic.h b/arch/arm/mach-spear13xx/include/mach/generic.h index dac57fd0cdfd..c33f4d9361bd 100644 --- a/arch/arm/mach-spear13xx/include/mach/generic.h +++ b/arch/arm/mach-spear13xx/include/mach/generic.h @@ -33,6 +33,9 @@ void __init spear13xx_l2x0_init(void); bool dw_dma_filter(struct dma_chan *chan, void *slave); void spear_restart(char, const char *); void spear13xx_secondary_startup(void); +void __cpuinit spear13xx_cpu_die(unsigned int cpu); + +extern struct smp_operations spear13xx_smp_ops; #ifdef CONFIG_MACH_SPEAR1310 void __init spear1310_clk_init(void); diff --git a/arch/arm/mach-spear13xx/platsmp.c b/arch/arm/mach-spear13xx/platsmp.c index f5d07f2663d7..2eaa3fa7b432 100644 --- a/arch/arm/mach-spear13xx/platsmp.c +++ b/arch/arm/mach-spear13xx/platsmp.c @@ -19,18 +19,13 @@ #include #include #include +#include -/* - * control for which core is the next to come out of the secondary - * boot "holding pen" - */ -volatile int __cpuinitdata pen_release = -1; static DEFINE_SPINLOCK(boot_lock); static void __iomem *scu_base = IOMEM(VA_SCU_BASE); -extern void spear13xx_secondary_startup(void); -void __cpuinit platform_secondary_init(unsigned int cpu) +static void __cpuinit spear13xx_secondary_init(unsigned int cpu) { /* * if any interrupts are already enabled for the primary @@ -53,7 +48,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) spin_unlock(&boot_lock); } -int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +static int __cpuinit spear13xx_boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout; @@ -97,7 +92,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *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) +static void __init spear13xx_smp_init_cpus(void) { unsigned int i, ncores = scu_get_core_count(scu_base); @@ -113,7 +108,7 @@ void __init smp_init_cpus(void) set_smp_cross_call(gic_raise_softirq); } -void __init platform_smp_prepare_cpus(unsigned int max_cpus) +static void __init spear13xx_smp_prepare_cpus(unsigned int max_cpus) { scu_enable(scu_base); @@ -125,3 +120,13 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus) */ __raw_writel(virt_to_phys(spear13xx_secondary_startup), SYS_LOCATION); } + +struct smp_operations spear13xx_smp_ops __initdata = { + .smp_init_cpus = spear13xx_smp_init_cpus, + .smp_prepare_cpus = spear13xx_smp_prepare_cpus, + .smp_secondary_init = spear13xx_secondary_init, + .smp_boot_secondary = spear13xx_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = spear13xx_cpu_die, +#endif +}; diff --git a/arch/arm/mach-spear13xx/spear1310.c b/arch/arm/mach-spear13xx/spear1310.c index 732d29bc7330..9fbbfc5650aa 100644 --- a/arch/arm/mach-spear13xx/spear1310.c +++ b/arch/arm/mach-spear13xx/spear1310.c @@ -78,6 +78,7 @@ static void __init spear1310_map_io(void) } DT_MACHINE_START(SPEAR1310_DT, "ST SPEAr1310 SoC with Flattened Device Tree") + .smp = smp_ops(spear13xx_smp_ops), .map_io = spear1310_map_io, .init_irq = spear13xx_dt_init_irq, .handle_irq = gic_handle_irq, diff --git a/arch/arm/mach-spear13xx/spear1340.c b/arch/arm/mach-spear13xx/spear1340.c index 81e4ed76ad06..081014fb314a 100644 --- a/arch/arm/mach-spear13xx/spear1340.c +++ b/arch/arm/mach-spear13xx/spear1340.c @@ -182,6 +182,7 @@ static const char * const spear1340_dt_board_compat[] = { }; DT_MACHINE_START(SPEAR1340_DT, "ST SPEAr1340 SoC with Flattened Device Tree") + .smp = smp_ops(spear13xx_smp_ops), .map_io = spear13xx_map_io, .init_irq = spear13xx_dt_init_irq, .handle_irq = gic_handle_irq, diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c index 5957ffbd4af6..5d8c8fb060b0 100644 --- a/arch/arm/mach-tegra/board-dt-tegra20.c +++ b/arch/arm/mach-tegra/board-dt-tegra20.c @@ -44,6 +44,7 @@ #include "board.h" #include "clock.h" #include "devices.h" +#include "common.h" struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC1_BASE, "sdhci-tegra.0", NULL), @@ -152,6 +153,7 @@ static const char *tegra20_dt_board_compat[] = { DT_MACHINE_START(TEGRA_DT, "nVidia Tegra20 (Flattened Device Tree)") .map_io = tegra_map_common_io, + .smp = smp_ops(tegra_smp_ops), .init_early = tegra20_init_early, .init_irq = tegra_dt_init_irq, .handle_irq = gic_handle_irq, diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c index 53bf60f11580..e4a676d4ddf7 100644 --- a/arch/arm/mach-tegra/board-dt-tegra30.c +++ b/arch/arm/mach-tegra/board-dt-tegra30.c @@ -37,6 +37,7 @@ #include "board.h" #include "clock.h" +#include "common.h" struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = { OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000000, "sdhci-tegra.0", NULL), @@ -83,6 +84,7 @@ static const char *tegra30_dt_board_compat[] = { }; DT_MACHINE_START(TEGRA30_DT, "NVIDIA Tegra30 (Flattened Device Tree)") + .smp = smp_ops(tegra_smp_ops), .map_io = tegra_map_common_io, .init_early = tegra30_init_early, .init_irq = tegra_dt_init_irq, diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 0560538bf598..0b0a5f556d34 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -31,6 +31,7 @@ #include "board.h" #include "clock.h" +#include "common.h" #include "fuse.h" #include "pmc.h" #include "apbio.h" diff --git a/arch/arm/mach-tegra/common.h b/arch/arm/mach-tegra/common.h new file mode 100644 index 000000000000..02f71b4f1e51 --- /dev/null +++ b/arch/arm/mach-tegra/common.h @@ -0,0 +1,4 @@ +extern struct smp_operations tegra_smp_ops; + +extern void tegra_cpu_die(unsigned int cpu); +extern int tegra_cpu_disable(unsigned int cpu); diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c index d02a35476135..dca5141a2c31 100644 --- a/arch/arm/mach-tegra/hotplug.c +++ b/arch/arm/mach-tegra/hotplug.c @@ -19,17 +19,12 @@ static void (*tegra_hotplug_shutdown)(void); -int platform_cpu_kill(unsigned int cpu) -{ - return 1; -} - /* * platform-specific code to shutdown a CPU * * Called with IRQs disabled */ -void platform_cpu_die(unsigned int cpu) +void __ref tegra_cpu_die(unsigned int cpu) { cpu = cpu_logical_map(cpu); @@ -47,7 +42,7 @@ void platform_cpu_die(unsigned int cpu) BUG(); } -int platform_cpu_disable(unsigned int cpu) +int tegra_cpu_disable(unsigned int cpu) { /* * we don't allow CPU 0 to be shutdown (it is still too special diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 96ed1718eef0..81cb26591acf 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -33,6 +33,8 @@ #include "reset.h" #include "tegra_cpu_car.h" +#include "common.h" + extern void tegra_secondary_startup(void); static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE); @@ -40,7 +42,7 @@ static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE); #define EVP_CPU_RESET_VECTOR \ (IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100) -void __cpuinit platform_secondary_init(unsigned int cpu) +static void __cpuinit tegra_secondary_init(unsigned int cpu) { /* * if any interrupts are already enabled for the primary @@ -100,7 +102,7 @@ static int tegra30_power_up_cpu(unsigned int cpu) return 0; } -int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +static int __cpuinit tegra_boot_secondary(unsigned int cpu, struct task_struct *idle) { int status; @@ -146,7 +148,7 @@ done: * 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) +static void __init tegra_smp_init_cpus(void) { unsigned int i, ncores = scu_get_core_count(scu_base); @@ -162,8 +164,19 @@ void __init smp_init_cpus(void) set_smp_cross_call(gic_raise_softirq); } -void __init platform_smp_prepare_cpus(unsigned int max_cpus) +static void __init tegra_smp_prepare_cpus(unsigned int max_cpus) { tegra_cpu_reset_handler_init(); scu_enable(scu_base); } + +struct smp_operations tegra_smp_ops __initdata = { + .smp_init_cpus = tegra_smp_init_cpus, + .smp_prepare_cpus = tegra_smp_prepare_cpus, + .smp_secondary_init = tegra_secondary_init, + .smp_boot_secondary = tegra_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = tegra_cpu_die, + .cpu_disable = tegra_cpu_disable, +#endif +}; diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index 1d2e3c6f8b59..e783790c79cd 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -673,6 +673,7 @@ static void __init hrefv60_init_machine(void) MACHINE_START(U8500, "ST-Ericsson MOP500 platform") /* Maintainer: Srinidhi Kasagar */ .atag_offset = 0x100, + .smp = smp_ops(ux500_smp_ops), .map_io = u8500_map_io, .init_irq = ux500_init_irq, /* we re-use nomadik timer here */ @@ -684,6 +685,7 @@ MACHINE_END MACHINE_START(HREFV60, "ST-Ericsson U8500 Platform HREFv60+") .atag_offset = 0x100, + .smp = smp_ops(ux500_smp_ops), .map_io = u8500_map_io, .init_irq = ux500_init_irq, .timer = &ux500_timer, @@ -694,6 +696,7 @@ MACHINE_END MACHINE_START(SNOWBALL, "Calao Systems Snowball platform") .atag_offset = 0x100, + .smp = smp_ops(ux500_smp_ops), .map_io = u8500_map_io, .init_irq = ux500_init_irq, /* we re-use nomadik timer here */ @@ -823,6 +826,7 @@ static const char * u8500_dt_board_compat[] = { DT_MACHINE_START(U8500_DT, "ST-Ericsson U8500 platform (Device Tree Support)") + .smp = smp_ops(ux500_smp_ops), .map_io = u8500_map_io, .init_irq = ux500_init_irq, /* we re-use nomadik timer here */ diff --git a/arch/arm/mach-ux500/hotplug.c b/arch/arm/mach-ux500/hotplug.c index c76f0f456f04..2f6af259015d 100644 --- a/arch/arm/mach-ux500/hotplug.c +++ b/arch/arm/mach-ux500/hotplug.c @@ -15,13 +15,18 @@ #include #include -extern volatile int pen_release; +#include -static inline void platform_do_lowpower(unsigned int cpu) +/* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +void __ref ux500_cpu_die(unsigned int cpu) { flush_cache_all(); - /* we put the platform to just WFI */ + /* directly enter low power state, skipping secure registers */ for (;;) { __asm__ __volatile__("dsb\n\t" "wfi\n\t" : : : "memory"); @@ -33,28 +38,3 @@ static inline void platform_do_lowpower(unsigned int cpu) } } } - -int platform_cpu_kill(unsigned int cpu) -{ - return 1; -} - -/* - * platform-specific code to shutdown a CPU - * - * Called with IRQs disabled - */ -void platform_cpu_die(unsigned int cpu) -{ - /* directly enter low power state, skipping secure registers */ - platform_do_lowpower(cpu); -} - -int platform_cpu_disable(unsigned int cpu) -{ - /* - * we don't allow CPU 0 to be shutdown (it is still too special - * e.g. clock tick interrupts) - */ - return cpu == 0 ? -EPERM : 0; -} diff --git a/arch/arm/mach-ux500/include/mach/setup.h b/arch/arm/mach-ux500/include/mach/setup.h index 7914e5eaa9c7..6be4c4d2ab88 100644 --- a/arch/arm/mach-ux500/include/mach/setup.h +++ b/arch/arm/mach-ux500/include/mach/setup.h @@ -45,4 +45,7 @@ extern struct sys_timer ux500_timer; .type = MT_MEMORY, \ } +extern struct smp_operations ux500_smp_ops; +extern void ux500_cpu_die(unsigned int cpu); + #endif /* __ASM_ARCH_SETUP_H */ diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index a5dda68444db..3db7782f3afb 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c @@ -27,12 +27,6 @@ /* This is called from headsmp.S to wakeup the secondary core */ extern void u8500_secondary_startup(void); -/* - * control for which core is the next to come out of the secondary - * boot "holding pen" - */ -volatile int pen_release = -1; - /* * Write pen_release in a way that is guaranteed to be visible to all * observers, irrespective of whether they're taking part in coherency @@ -58,7 +52,7 @@ static void __iomem *scu_base_addr(void) static DEFINE_SPINLOCK(boot_lock); -void __cpuinit platform_secondary_init(unsigned int cpu) +static void __cpuinit ux500_secondary_init(unsigned int cpu) { /* * if any interrupts are already enabled for the primary @@ -80,7 +74,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) spin_unlock(&boot_lock); } -int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +static int __cpuinit ux500_boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout; @@ -145,7 +139,7 @@ static void __init wakeup_secondary(void) * 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) +static void __init ux500_smp_init_cpus(void) { void __iomem *scu_base = scu_base_addr(); unsigned int i, ncores; @@ -165,9 +159,19 @@ void __init smp_init_cpus(void) set_smp_cross_call(gic_raise_softirq); } -void __init platform_smp_prepare_cpus(unsigned int max_cpus) +static void __init ux500_smp_prepare_cpus(unsigned int max_cpus) { scu_enable(scu_base_addr()); wakeup_secondary(); } + +struct smp_operations ux500_smp_ops __initdata = { + .smp_init_cpus = ux500_smp_init_cpus, + .smp_prepare_cpus = ux500_smp_prepare_cpus, + .smp_secondary_init = ux500_secondary_init, + .smp_boot_secondary = ux500_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = ux500_cpu_die, +#endif +}; diff --git a/arch/arm/mach-vexpress/core.h b/arch/arm/mach-vexpress/core.h index a3a4980770bd..f134cd4a85f1 100644 --- a/arch/arm/mach-vexpress/core.h +++ b/arch/arm/mach-vexpress/core.h @@ -5,3 +5,7 @@ #define V2T_PERIPH 0xf8200000 void vexpress_dt_smp_map_io(void); + +extern struct smp_operations vexpress_smp_ops; + +extern void vexpress_cpu_die(unsigned int cpu); diff --git a/arch/arm/mach-vexpress/hotplug.c b/arch/arm/mach-vexpress/hotplug.c index c504a72b94d6..a141b98d84fe 100644 --- a/arch/arm/mach-vexpress/hotplug.c +++ b/arch/arm/mach-vexpress/hotplug.c @@ -16,8 +16,6 @@ #include #include -extern volatile int pen_release; - static inline void cpu_enter_lowpower(void) { unsigned int v; @@ -84,17 +82,12 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious) } } -int platform_cpu_kill(unsigned int cpu) -{ - return 1; -} - /* * platform-specific code to shutdown a CPU * * Called with IRQs disabled */ -void platform_cpu_die(unsigned int cpu) +void __ref vexpress_cpu_die(unsigned int cpu) { int spurious = 0; @@ -113,12 +106,3 @@ void platform_cpu_die(unsigned int cpu) if (spurious) pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); } - -int platform_cpu_disable(unsigned int cpu) -{ - /* - * we don't allow CPU 0 to be shutdown (it is still too special - * e.g. clock tick interrupts) - */ - return cpu == 0 ? -EPERM : 0; -} diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c index 14ba1128ae8d..7db27c8c05cc 100644 --- a/arch/arm/mach-vexpress/platsmp.c +++ b/arch/arm/mach-vexpress/platsmp.c @@ -20,9 +20,9 @@ #include -#include "core.h" +#include -extern void versatile_secondary_startup(void); +#include "core.h" #if defined(CONFIG_OF) @@ -167,7 +167,7 @@ void __init vexpress_dt_smp_prepare_cpus(unsigned int max_cpus) * 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) +static void __init vexpress_smp_init_cpus(void) { if (ct_desc) ct_desc->init_cpu_map(); @@ -176,7 +176,7 @@ void __init smp_init_cpus(void) } -void __init platform_smp_prepare_cpus(unsigned int max_cpus) +static void __init vexpress_smp_prepare_cpus(unsigned int max_cpus) { /* * Initialise the present map, which describes the set of CPUs @@ -195,3 +195,13 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus) */ v2m_flags_set(virt_to_phys(versatile_secondary_startup)); } + +struct smp_operations __initdata vexpress_smp_ops = { + .smp_init_cpus = vexpress_smp_init_cpus, + .smp_prepare_cpus = vexpress_smp_prepare_cpus, + .smp_secondary_init = versatile_secondary_init, + .smp_boot_secondary = versatile_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = vexpress_cpu_die, +#endif +}; diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index 2ca86c50174d..5f6b7d543e55 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ #include #include +#include #include "core.h" @@ -530,6 +532,7 @@ static void __init v2m_init(void) MACHINE_START(VEXPRESS, "ARM-Versatile Express") .atag_offset = 0x100, + .smp = smp_ops(vexpress_smp_ops), .map_io = v2m_map_io, .init_early = v2m_init_early, .init_irq = v2m_init_irq, @@ -661,6 +664,7 @@ const static char *v2m_dt_match[] __initconst = { DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express") .dt_compat = v2m_dt_match, + .smp = smp_ops(vexpress_smp_ops), .map_io = v2m_dt_map_io, .init_early = v2m_dt_init_early, .init_irq = v2m_dt_init_irq, diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h index 28ba09f4ebb9..ead901814c0d 100644 --- a/arch/arm/plat-mxc/include/mach/common.h +++ b/arch/arm/plat-mxc/include/mach/common.h @@ -139,6 +139,8 @@ extern void imx_gpc_post_resume(void); extern int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode); extern void imx6q_clock_map_io(void); +extern void imx_cpu_die(unsigned int cpu); + #ifdef CONFIG_PM extern void imx6q_pm_init(void); extern void imx51_pm_init(void); @@ -155,4 +157,6 @@ extern int mx51_neon_fixup(void); static inline int mx51_neon_fixup(void) { return 0; } #endif +extern struct smp_operations imx_smp_ops; + #endif diff --git a/arch/arm/plat-versatile/include/plat/platsmp.h b/arch/arm/plat-versatile/include/plat/platsmp.h new file mode 100644 index 000000000000..50fb830192e0 --- /dev/null +++ b/arch/arm/plat-versatile/include/plat/platsmp.h @@ -0,0 +1,14 @@ +/* + * linux/arch/arm/plat-versatile/include/plat/platsmp.h + * + * Copyright (C) 2011 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. + */ + +extern void versatile_secondary_startup(void); +extern void versatile_secondary_init(unsigned int cpu); +extern int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle); diff --git a/arch/arm/plat-versatile/platsmp.c b/arch/arm/plat-versatile/platsmp.c index d7c5c171f5aa..04ca4937d8ca 100644 --- a/arch/arm/plat-versatile/platsmp.c +++ b/arch/arm/plat-versatile/platsmp.c @@ -19,12 +19,6 @@ #include #include -/* - * control for which core is the next to come out of the secondary - * boot "holding pen" - */ -volatile int __cpuinitdata pen_release = -1; - /* * Write pen_release in a way that is guaranteed to be visible to all * observers, irrespective of whether they're taking part in coherency @@ -40,7 +34,7 @@ static void __cpuinit write_pen_release(int val) static DEFINE_SPINLOCK(boot_lock); -void __cpuinit platform_secondary_init(unsigned int cpu) +void __cpuinit versatile_secondary_init(unsigned int cpu) { /* * if any interrupts are already enabled for the primary @@ -62,7 +56,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) spin_unlock(&boot_lock); } -int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +int __cpuinit versatile_boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout;