diff options
Diffstat (limited to 'arch/sh/kernel/smp.c')
-rw-r--r-- | arch/sh/kernel/smp.c | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c new file mode 100644 index 000000000000..56a39d69e080 --- /dev/null +++ b/arch/sh/kernel/smp.c @@ -0,0 +1,199 @@ +/* + * arch/sh/kernel/smp.c + * + * SMP support for the SuperH processors. + * + * Copyright (C) 2002, 2003 Paul Mundt + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include <linux/config.h> +#include <linux/cache.h> +#include <linux/cpumask.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/threads.h> +#include <linux/module.h> +#include <linux/time.h> +#include <linux/timex.h> +#include <linux/sched.h> + +#include <asm/atomic.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/mmu_context.h> +#include <asm/smp.h> + +/* + * This was written with the Sega Saturn (SMP SH-2 7604) in mind, + * but is designed to be usable regardless if there's an MMU + * present or not. + */ +struct sh_cpuinfo cpu_data[NR_CPUS]; + +extern void per_cpu_trap_init(void); + +cpumask_t cpu_possible_map; +cpumask_t cpu_online_map; +static atomic_t cpus_booted = ATOMIC_INIT(0); + +/* These are defined by the board-specific code. */ + +/* + * Cause the function described by call_data to be executed on the passed + * cpu. When the function has finished, increment the finished field of + * call_data. + */ +void __smp_send_ipi(unsigned int cpu, unsigned int action); + +/* + * Find the number of available processors + */ +unsigned int __smp_probe_cpus(void); + +/* + * Start a particular processor + */ +void __smp_slave_init(unsigned int cpu); + +/* + * Run specified function on a particular processor. + */ +void __smp_call_function(unsigned int cpu); + +static inline void __init smp_store_cpu_info(unsigned int cpu) +{ + cpu_data[cpu].loops_per_jiffy = loops_per_jiffy; +} + +void __init smp_prepare_cpus(unsigned int max_cpus) +{ + unsigned int cpu = smp_processor_id(); + int i; + + atomic_set(&cpus_booted, 1); + smp_store_cpu_info(cpu); + + for (i = 0; i < __smp_probe_cpus(); i++) + cpu_set(i, cpu_possible_map); +} + +void __devinit smp_prepare_boot_cpu(void) +{ + unsigned int cpu = smp_processor_id(); + + cpu_set(cpu, cpu_online_map); + cpu_set(cpu, cpu_possible_map); +} + +int __cpu_up(unsigned int cpu) +{ + struct task_struct *tsk; + + tsk = fork_idle(cpu); + + if (IS_ERR(tsk)) + panic("Failed forking idle task for cpu %d\n", cpu); + + tsk->thread_info->cpu = cpu; + + cpu_set(cpu, cpu_online_map); + + return 0; +} + +int start_secondary(void *unused) +{ + unsigned int cpu = smp_processor_id(); + + atomic_inc(&init_mm.mm_count); + current->active_mm = &init_mm; + + smp_store_cpu_info(cpu); + + __smp_slave_init(cpu); + per_cpu_trap_init(); + + atomic_inc(&cpus_booted); + + cpu_idle(); + return 0; +} + +void __init smp_cpus_done(unsigned int max_cpus) +{ + smp_mb(); +} + +void smp_send_reschedule(int cpu) +{ + __smp_send_ipi(cpu, SMP_MSG_RESCHEDULE); +} + +static void stop_this_cpu(void *unused) +{ + cpu_clear(smp_processor_id(), cpu_online_map); + local_irq_disable(); + + for (;;) + cpu_relax(); +} + +void smp_send_stop(void) +{ + smp_call_function(stop_this_cpu, 0, 1, 0); +} + + +struct smp_fn_call_struct smp_fn_call = { + .lock = SPIN_LOCK_UNLOCKED, + .finished = ATOMIC_INIT(0), +}; + +/* + * The caller of this wants the passed function to run on every cpu. If wait + * is set, wait until all cpus have finished the function before returning. + * The lock is here to protect the call structure. + * You must not call this function with disabled interrupts or from a + * hardware interrupt handler or from a bottom half handler. + */ +int smp_call_function(void (*func)(void *info), void *info, int retry, int wait) +{ + unsigned int nr_cpus = atomic_read(&cpus_booted); + int i; + + if (nr_cpus < 2) + return 0; + + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + + spin_lock(&smp_fn_call.lock); + + atomic_set(&smp_fn_call.finished, 0); + smp_fn_call.fn = func; + smp_fn_call.data = info; + + for (i = 0; i < nr_cpus; i++) + if (i != smp_processor_id()) + __smp_call_function(i); + + if (wait) + while (atomic_read(&smp_fn_call.finished) != (nr_cpus - 1)); + + spin_unlock(&smp_fn_call.lock); + + return 0; +} + +/* Not really SMP stuff ... */ +int setup_profiling_timer(unsigned int multiplier) +{ + return 0; +} + |