1
linux/arch/um/kernel/smp.c
Jeff Dike edea138584 uml: tidy kern_util.h
Tidy kern_util.h.  It turns out that most of the function declarations
aren't used, so they can go away.  os.h no longer includes
kern_util.h, so files which got it through os.h now need to include it
directly.  A number of other files never needed it, so these includes
are deleted.

The structure which was used to pass signal handlers from the kernel
side to the userspace side is gone.  Instead, the handlers are
declared here, and used directly from libc code.  This allows
arch/um/os-Linux/trap.c to be deleted, with its remnants being moved
to arch/um/os-Linux/skas/trap.c.

arch/um/os-Linux/tty.c had its inclusions changed, and it needed some
style attention, so it got tidied.

Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-02-05 09:44:26 -08:00

253 lines
5.2 KiB
C

/*
* Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
#include "linux/percpu.h"
#include "asm/pgalloc.h"
#include "asm/tlb.h"
/* For some reason, mmu_gathers are referenced when CONFIG_SMP is off. */
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
#ifdef CONFIG_SMP
#include "linux/sched.h"
#include "linux/module.h"
#include "linux/threads.h"
#include "linux/interrupt.h"
#include "linux/err.h"
#include "linux/hardirq.h"
#include "asm/smp.h"
#include "asm/processor.h"
#include "asm/spinlock.h"
#include "kern.h"
#include "irq_user.h"
#include "os.h"
/* CPU online map, set by smp_boot_cpus */
cpumask_t cpu_online_map = CPU_MASK_NONE;
cpumask_t cpu_possible_map = CPU_MASK_NONE;
EXPORT_SYMBOL(cpu_online_map);
EXPORT_SYMBOL(cpu_possible_map);
/* Per CPU bogomips and other parameters
* The only piece used here is the ipi pipe, which is set before SMP is
* started and never changed.
*/
struct cpuinfo_um cpu_data[NR_CPUS];
/* A statistic, can be a little off */
int num_reschedules_sent = 0;
/* Not changed after boot */
struct task_struct *idle_threads[NR_CPUS];
void smp_send_reschedule(int cpu)
{
os_write_file(cpu_data[cpu].ipi_pipe[1], "R", 1);
num_reschedules_sent++;
}
void smp_send_stop(void)
{
int i;
printk(KERN_INFO "Stopping all CPUs...");
for (i = 0; i < num_online_cpus(); i++) {
if (i == current_thread->cpu)
continue;
os_write_file(cpu_data[i].ipi_pipe[1], "S", 1);
}
printk(KERN_INFO "done\n");
}
static cpumask_t smp_commenced_mask = CPU_MASK_NONE;
static cpumask_t cpu_callin_map = CPU_MASK_NONE;
static int idle_proc(void *cpup)
{
int cpu = (int) cpup, err;
err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1);
if (err < 0)
panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err);
os_set_fd_async(cpu_data[cpu].ipi_pipe[0],
current->thread.mode.tt.extern_pid);
wmb();
if (cpu_test_and_set(cpu, cpu_callin_map)) {
printk(KERN_ERR "huh, CPU#%d already present??\n", cpu);
BUG();
}
while (!cpu_isset(cpu, smp_commenced_mask))
cpu_relax();
cpu_set(cpu, cpu_online_map);
default_idle();
return 0;
}
static struct task_struct *idle_thread(int cpu)
{
struct task_struct *new_task;
current->thread.request.u.thread.proc = idle_proc;
current->thread.request.u.thread.arg = (void *) cpu;
new_task = fork_idle(cpu);
if (IS_ERR(new_task))
panic("copy_process failed in idle_thread, error = %ld",
PTR_ERR(new_task));
cpu_tasks[cpu] = ((struct cpu_task)
{ .pid = new_task->thread.mode.tt.extern_pid,
.task = new_task } );
idle_threads[cpu] = new_task;
panic("skas mode doesn't support SMP");
return new_task;
}
void smp_prepare_cpus(unsigned int maxcpus)
{
struct task_struct *idle;
unsigned long waittime;
int err, cpu, me = smp_processor_id();
int i;
for (i = 0; i < ncpus; ++i)
cpu_set(i, cpu_possible_map);
cpu_clear(me, cpu_online_map);
cpu_set(me, cpu_online_map);
cpu_set(me, cpu_callin_map);
err = os_pipe(cpu_data[me].ipi_pipe, 1, 1);
if (err < 0)
panic("CPU#0 failed to create IPI pipe, errno = %d", -err);
os_set_fd_async(cpu_data[me].ipi_pipe[0],
current->thread.mode.tt.extern_pid);
for (cpu = 1; cpu < ncpus; cpu++) {
printk(KERN_INFO "Booting processor %d...\n", cpu);
idle = idle_thread(cpu);
init_idle(idle, cpu);
waittime = 200000000;
while (waittime-- && !cpu_isset(cpu, cpu_callin_map))
cpu_relax();
if (cpu_isset(cpu, cpu_callin_map))
printk(KERN_INFO "done\n");
else printk(KERN_INFO "failed\n");
}
}
void smp_prepare_boot_cpu(void)
{
cpu_set(smp_processor_id(), cpu_online_map);
}
int __cpu_up(unsigned int cpu)
{
cpu_set(cpu, smp_commenced_mask);
while (!cpu_isset(cpu, cpu_online_map))
mb();
return 0;
}
int setup_profiling_timer(unsigned int multiplier)
{
printk(KERN_INFO "setup_profiling_timer\n");
return 0;
}
void smp_call_function_slave(int cpu);
void IPI_handler(int cpu)
{
unsigned char c;
int fd;
fd = cpu_data[cpu].ipi_pipe[0];
while (os_read_file(fd, &c, 1) == 1) {
switch (c) {
case 'C':
smp_call_function_slave(cpu);
break;
case 'R':
set_tsk_need_resched(current);
break;
case 'S':
printk(KERN_INFO "CPU#%d stopping\n", cpu);
while (1)
pause();
break;
default:
printk(KERN_ERR "CPU#%d received unknown IPI [%c]!\n",
cpu, c);
break;
}
}
}
int hard_smp_processor_id(void)
{
return pid_to_processor_id(os_getpid());
}
static DEFINE_SPINLOCK(call_lock);
static atomic_t scf_started;
static atomic_t scf_finished;
static void (*func)(void *info);
static void *info;
void smp_call_function_slave(int cpu)
{
atomic_inc(&scf_started);
(*func)(info);
atomic_inc(&scf_finished);
}
int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic,
int wait)
{
int cpus = num_online_cpus() - 1;
int i;
if (!cpus)
return 0;
/* Can deadlock when called with interrupts disabled */
WARN_ON(irqs_disabled());
spin_lock_bh(&call_lock);
atomic_set(&scf_started, 0);
atomic_set(&scf_finished, 0);
func = _func;
info = _info;
for_each_online_cpu(i)
os_write_file(cpu_data[i].ipi_pipe[1], "C", 1);
while (atomic_read(&scf_started) != cpus)
barrier();
if (wait)
while (atomic_read(&scf_finished) != cpus)
barrier();
spin_unlock_bh(&call_lock);
return 0;
}
#endif