Skip to content

Commit

Permalink
ARM: SoC: add per-platform SMP operations
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Marc Zyngier authored and Arnd Bergmann committed Sep 13, 2012
1 parent 4cbe5a5 commit abcee5f
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 2 deletions.
7 changes: 7 additions & 0 deletions arch/arm/include/asm/mach/arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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 */
Expand Down
33 changes: 33 additions & 0 deletions arch/arm/include/asm/smp.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,37 @@ 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 */
4 changes: 3 additions & 1 deletion arch/arm/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
62 changes: 61 additions & 1 deletion arch/arm/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
#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>
#include <linux/clockchips.h>
#include <linux/completion.h>

#include <linux/atomic.h>
#include <asm/smp.h>
#include <asm/cacheflush.h>
#include <asm/cpu.h>
#include <asm/cputype.h>
Expand All @@ -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
Expand All @@ -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 task_struct *idle)
{
int ret;
Expand Down Expand Up @@ -100,9 +109,60 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
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.
*/
Expand Down

0 comments on commit abcee5f

Please sign in to comment.