aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-04-11 15:23:43 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-04-11 15:23:43 -0700
commit9ec7dfaf2cc0e5000dec931bde41f17c7eb203db (patch)
treececab9759d0298ec1af3a24f8a1ef14a6e383473
parent9e528fe13c95cee1b4ee23690aebf8b02eebac1f (diff)
downloadltsi-kernel-9ec7dfaf2cc0e5000dec931bde41f17c7eb203db.tar.gz
two arm smp ops patches
-rw-r--r--patches.misc/arm-soc-add-per-platform-smp-operations.patch223
-rw-r--r--patches.misc/arm-soc-convert-shmobile-smp-to-smp-operations.patch611
-rw-r--r--series7
3 files changed, 841 insertions, 0 deletions
diff --git a/patches.misc/arm-soc-add-per-platform-smp-operations.patch b/patches.misc/arm-soc-add-per-platform-smp-operations.patch
new file mode 100644
index 00000000000000..15a4615d449edb
--- /dev/null
+++ b/patches.misc/arm-soc-add-per-platform-smp-operations.patch
@@ -0,0 +1,223 @@
+From horms@vergenet.net Tue Mar 26 21:37:55 2013
+From: Simon Horman <horms+renesas@verge.net.au>
+Date: Wed, 27 Mar 2013 13:37:49 +0900
+Subject: [PATCH 1/2] ARM: SoC: add per-platform SMP operations
+To: ltsi-dev@lists.linuxfoundation.org
+Cc: Greg KH <gregkh@linuxfoundation.org>
+Message-ID: <1364359070-7002-2-git-send-email-horms+renesas@verge.net.au>
+
+
+From: Marc Zyngier <marc.zyngier@arm.com>
+
+This adds a 'struct smp_operations' to abstract the CPU initialization
+and hot plugging functions on SMP systems, which otherwise conflict
+in a multiplatform kernel. This also helps shmobile and potentially
+others that have more than one method to do these.
+
+To allow the kernel to continue building, the platform hooks are
+defined as weak symbols which are overrided by the platform code.
+Once all platforms are converted, the "weak" attribute will be
+removed and the function made static.
+
+Unlike the original version from Marc, this new version from Arnd
+does not use a generalized abstraction for per-soc data structures
+but only tries to solve the problem for the SMP operations. This
+way, we can collapse the previous four data structures into a
+single struct, which is less systematic but also easier to follow
+as a causal reader.
+
+Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+Acked-by: Nicolas Pitre <nico@fluxnic.net>
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+(cherry picked from commit abcee5fb0dfbb248d883a2f6bdb4820abe3ac524)
+
+Conflicts:
+ arch/arm/kernel/smp.c
+
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ arch/arm/include/asm/mach/arch.h | 7 ++++
+ arch/arm/include/asm/smp.h | 33 ++++++++++++++++++++
+ arch/arm/kernel/setup.c | 4 +-
+ arch/arm/kernel/smp.c | 62 ++++++++++++++++++++++++++++++++++++++-
+ 4 files changed, 104 insertions(+), 2 deletions(-)
+
+--- 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 */
+--- a/arch/arm/include/asm/smp.h
++++ b/arch/arm/include/asm/smp.h
+@@ -93,4 +93,37 @@ extern void platform_cpu_enable(unsigned
+ 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 */
+--- 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();
+
+--- 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
+@@ -60,6 +61,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 cpuinfo_arm *ci = &per_cpu(cpu_data, cpu);
+@@ -121,9 +130,60 @@ int __cpuinit __cpu_up(unsigned int cpu)
+ return ret;
+ }
+
++/* platform specific SMP operations */
++void __attribute__((weak)) __init smp_init_cpus(void)
++{
++ if (smp_ops.smp_init_cpus)
++ smp_ops.smp_init_cpus();
++}
++
++void __attribute__((weak)) __init platform_smp_prepare_cpus(unsigned int max_cpus)
++{
++ if (smp_ops.smp_prepare_cpus)
++ smp_ops.smp_prepare_cpus(max_cpus);
++}
++
++void __attribute__((weak)) __cpuinit platform_secondary_init(unsigned int cpu)
++{
++ if (smp_ops.smp_secondary_init)
++ smp_ops.smp_secondary_init(cpu);
++}
++
++int __attribute__((weak)) __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);
+
++int __attribute__((weak)) platform_cpu_kill(unsigned int cpu)
++{
++ if (smp_ops.cpu_kill)
++ return smp_ops.cpu_kill(cpu);
++ return 1;
++}
++
++void __attribute__((weak)) platform_cpu_die(unsigned int cpu)
++{
++ if (smp_ops.cpu_die)
++ smp_ops.cpu_die(cpu);
++}
++
++int __attribute__((weak)) 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.
+ */
diff --git a/patches.misc/arm-soc-convert-shmobile-smp-to-smp-operations.patch b/patches.misc/arm-soc-convert-shmobile-smp-to-smp-operations.patch
new file mode 100644
index 00000000000000..c5a35dcae70a98
--- /dev/null
+++ b/patches.misc/arm-soc-convert-shmobile-smp-to-smp-operations.patch
@@ -0,0 +1,611 @@
+From horms@vergenet.net Tue Mar 26 21:37:56 2013
+From: Simon Horman <horms+renesas@verge.net.au>
+Date: Wed, 27 Mar 2013 13:37:50 +0900
+Subject: [PATCH 2/2] ARM: SoC: convert shmobile SMP to SMP operations
+To: ltsi-dev@lists.linuxfoundation.org
+Cc: Greg KH <gregkh@linuxfoundation.org>
+Message-ID: <1364359070-7002-3-git-send-email-horms+renesas@verge.net.au>
+
+
+From: Marc Zyngier <marc.zyngier@arm.com>
+
+Convert shmobile SMP platforms to use struct smp_operations to provide
+their SMP and CPU hotplug operations.
+
+Cc: Paul Mundt <lethal@linux-sh.org>
+Cc: Magnus Damm <magnus.damm@gmail.com>
+Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+Acked-by: Nicolas Pitre <nico@linaro.org>
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+---
+ arch/arm/mach-shmobile/board-ag5evm.c | 1
+ arch/arm/mach-shmobile/board-kota2.c | 1
+ arch/arm/mach-shmobile/board-kzm9d.c | 1
+ arch/arm/mach-shmobile/board-kzm9g.c | 1
+ arch/arm/mach-shmobile/board-marzen.c | 1
+ arch/arm/mach-shmobile/hotplug.c | 31 ++------
+ arch/arm/mach-shmobile/include/mach/common.h | 24 +++---
+ arch/arm/mach-shmobile/include/mach/emev2.h | 7 -
+ arch/arm/mach-shmobile/include/mach/r8a7779.h | 2
+ arch/arm/mach-shmobile/include/mach/sh73a0.h | 2
+ arch/arm/mach-shmobile/platsmp.c | 96 --------------------------
+ arch/arm/mach-shmobile/setup-emev2.c | 1
+ arch/arm/mach-shmobile/smp-emev2.c | 47 +++++++++++-
+ arch/arm/mach-shmobile/smp-r8a7779.c | 48 +++++++++++--
+ arch/arm/mach-shmobile/smp-sh73a0.c | 48 +++++++++++--
+ 15 files changed, 165 insertions(+), 146 deletions(-)
+
+--- a/arch/arm/mach-shmobile/board-ag5evm.c
++++ b/arch/arm/mach-shmobile/board-ag5evm.c
+@@ -574,6 +574,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,
+--- a/arch/arm/mach-shmobile/board-kota2.c
++++ b/arch/arm/mach-shmobile/board-kota2.c
+@@ -515,6 +515,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,
+--- a/arch/arm/mach-shmobile/board-kzm9d.c
++++ b/arch/arm/mach-shmobile/board-kzm9d.c
+@@ -74,6 +74,7 @@ static const char *kzm9d_boards_compat_d
+ };
+
+ 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,
+--- a/arch/arm/mach-shmobile/board-kzm9g.c
++++ b/arch/arm/mach-shmobile/board-kzm9g.c
+@@ -744,6 +744,7 @@ static const char *kzm9g_boards_compat_d
+ };
+
+ 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,
+--- 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,
+--- a/arch/arm/mach-shmobile/hotplug.c
++++ b/arch/arm/mach-shmobile/hotplug.c
+@@ -14,30 +14,16 @@
+ #include <linux/smp.h>
+ #include <linux/cpumask.h>
+ #include <linux/delay.h>
++#include <linux/of.h>
+ #include <mach/common.h>
++#include <mach/r8a7779.h>
++#include <mach/emev2.h>
+ #include <asm/cacheflush.h>
++#include <asm/mach-types.h>
+
+ 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 cp
+ */
+ return cpu == 0 ? -EPERM : 0;
+ }
++
++int shmobile_cpu_is_dead(unsigned int cpu)
++{
++ return cpumask_test_cpu(cpu, &dead_cpus);
++}
+--- 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);
+@@ -80,11 +74,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);
+@@ -101,4 +90,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 */
+--- 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__ */
+--- 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
+ #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__ */
+--- 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__ */
+--- 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 <linux/init.h>
+-#include <linux/errno.h>
+-#include <linux/delay.h>
+-#include <linux/device.h>
+ #include <linux/smp.h>
+-#include <linux/io.h>
+-#include <linux/of.h>
+ #include <asm/hardware/gic.h>
+-#include <asm/mach-types.h>
+-#include <mach/common.h>
+-#include <mach/emev2.h>
+
+-#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)
+-{
+- 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)
++void __init shmobile_smp_init_cpus(unsigned int ncores)
+ {
+- 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();
+-}
+--- a/arch/arm/mach-shmobile/setup-emev2.c
++++ b/arch/arm/mach-shmobile/setup-emev2.c
+@@ -440,6 +440,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,
+--- 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
+
+ }
+
+-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
+ 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(unsig
+ 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
++};
+--- 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
+ __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 i
+ 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(uns
+ 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(voi
+ 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
++};
+--- a/arch/arm/mach-shmobile/smp-sh73a0.c
++++ b/arch/arm/mach-shmobile/smp-sh73a0.c
+@@ -22,8 +22,10 @@
+ #include <linux/smp.h>
+ #include <linux/spinlock.h>
+ #include <linux/io.h>
++#include <linux/delay.h>
+ #include <mach/common.h>
+ #include <asm/smp_plat.h>
++#include <mach/sh73a0.h>
+ #include <asm/smp_scu.h>
+ #include <asm/smp_twd.h>
+ #include <asm/hardware/gic.h>
+@@ -64,19 +66,19 @@ static void modify_scu_cpu_psr(unsigned
+ __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(unsi
+ 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/series b/series
index 20122f39c9af2f..3eba6fb2b2b30c 100644
--- a/series
+++ b/series
@@ -782,6 +782,13 @@ patches.codel/codel-refine-one-condition-to-avoid-a-nul-rec_inv_sq.patch
#############################################################################
+# Misc patches that don't fit into the above categories.
+#
+patches.misc/arm-soc-add-per-platform-smp-operations.patch
+patches.misc/arm-soc-convert-shmobile-smp-to-smp-operations.patch
+
+
+#############################################################################
# fixes that go after all of the above
#
patches.fixes/0001-ASoC-fsi-fixup-channels_min-max.patch