linux/arch/um/kernel/smp.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
   3 * Licensed under the GPL
   4 */
   5
   6#include "linux/percpu.h"
   7#include "asm/pgalloc.h"
   8#include "asm/tlb.h"
   9
  10#ifdef CONFIG_SMP
  11
  12#include "linux/sched.h"
  13#include "linux/module.h"
  14#include "linux/threads.h"
  15#include "linux/interrupt.h"
  16#include "linux/err.h"
  17#include "linux/hardirq.h"
  18#include "asm/smp.h"
  19#include "asm/processor.h"
  20#include "asm/spinlock.h"
  21#include "kern.h"
  22#include "irq_user.h"
  23#include "os.h"
  24
  25/* Per CPU bogomips and other parameters
  26 * The only piece used here is the ipi pipe, which is set before SMP is
  27 * started and never changed.
  28 */
  29struct cpuinfo_um cpu_data[NR_CPUS];
  30
  31/* A statistic, can be a little off */
  32int num_reschedules_sent = 0;
  33
  34/* Not changed after boot */
  35struct task_struct *idle_threads[NR_CPUS];
  36
  37void smp_send_reschedule(int cpu)
  38{
  39        os_write_file(cpu_data[cpu].ipi_pipe[1], "R", 1);
  40        num_reschedules_sent++;
  41}
  42
  43void smp_send_stop(void)
  44{
  45        int i;
  46
  47        printk(KERN_INFO "Stopping all CPUs...");
  48        for (i = 0; i < num_online_cpus(); i++) {
  49                if (i == current_thread->cpu)
  50                        continue;
  51                os_write_file(cpu_data[i].ipi_pipe[1], "S", 1);
  52        }
  53        printk(KERN_CONT "done\n");
  54}
  55
  56static cpumask_t smp_commenced_mask = CPU_MASK_NONE;
  57static cpumask_t cpu_callin_map = CPU_MASK_NONE;
  58
  59static int idle_proc(void *cpup)
  60{
  61        int cpu = (int) cpup, err;
  62
  63        err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1);
  64        if (err < 0)
  65                panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err);
  66
  67        os_set_fd_async(cpu_data[cpu].ipi_pipe[0]);
  68
  69        wmb();
  70        if (cpu_test_and_set(cpu, cpu_callin_map)) {
  71                printk(KERN_ERR "huh, CPU#%d already present??\n", cpu);
  72                BUG();
  73        }
  74
  75        while (!cpu_isset(cpu, smp_commenced_mask))
  76                cpu_relax();
  77
  78        notify_cpu_starting(cpu);
  79        cpu_set(cpu, cpu_online_map);
  80        default_idle();
  81        return 0;
  82}
  83
  84static struct task_struct *idle_thread(int cpu)
  85{
  86        struct task_struct *new_task;
  87
  88        current->thread.request.u.thread.proc = idle_proc;
  89        current->thread.request.u.thread.arg = (void *) cpu;
  90        new_task = fork_idle(cpu);
  91        if (IS_ERR(new_task))
  92                panic("copy_process failed in idle_thread, error = %ld",
  93                      PTR_ERR(new_task));
  94
  95        cpu_tasks[cpu] = ((struct cpu_task)
  96                          { .pid =      new_task->thread.mode.tt.extern_pid,
  97                            .task =     new_task } );
  98        idle_threads[cpu] = new_task;
  99        panic("skas mode doesn't support SMP");
 100        return new_task;
 101}
 102
 103void smp_prepare_cpus(unsigned int maxcpus)
 104{
 105        struct task_struct *idle;
 106        unsigned long waittime;
 107        int err, cpu, me = smp_processor_id();
 108        int i;
 109
 110        for (i = 0; i < ncpus; ++i)
 111                set_cpu_possible(i, true);
 112
 113        cpu_clear(me, cpu_online_map);
 114        cpu_set(me, cpu_online_map);
 115        cpu_set(me, cpu_callin_map);
 116
 117        err = os_pipe(cpu_data[me].ipi_pipe, 1, 1);
 118        if (err < 0)
 119                panic("CPU#0 failed to create IPI pipe, errno = %d", -err);
 120
 121        os_set_fd_async(cpu_data[me].ipi_pipe[0]);
 122
 123        for (cpu = 1; cpu < ncpus; cpu++) {
 124                printk(KERN_INFO "Booting processor %d...\n", cpu);
 125
 126                idle = idle_thread(cpu);
 127
 128                init_idle(idle, cpu);
 129
 130                waittime = 200000000;
 131                while (waittime-- && !cpu_isset(cpu, cpu_callin_map))
 132                        cpu_relax();
 133
 134                printk(KERN_INFO "%s\n",
 135                       cpu_isset(cpu, cpu_calling_map) ? "done" : "failed");
 136        }
 137}
 138
 139void smp_prepare_boot_cpu(void)
 140{
 141        cpu_set(smp_processor_id(), cpu_online_map);
 142}
 143
 144int __cpu_up(unsigned int cpu)
 145{
 146        cpu_set(cpu, smp_commenced_mask);
 147        while (!cpu_isset(cpu, cpu_online_map))
 148                mb();
 149        return 0;
 150}
 151
 152int setup_profiling_timer(unsigned int multiplier)
 153{
 154        printk(KERN_INFO "setup_profiling_timer\n");
 155        return 0;
 156}
 157
 158void smp_call_function_slave(int cpu);
 159
 160void IPI_handler(int cpu)
 161{
 162        unsigned char c;
 163        int fd;
 164
 165        fd = cpu_data[cpu].ipi_pipe[0];
 166        while (os_read_file(fd, &c, 1) == 1) {
 167                switch (c) {
 168                case 'C':
 169                        smp_call_function_slave(cpu);
 170                        break;
 171
 172                case 'R':
 173                        scheduler_ipi();
 174                        break;
 175
 176                case 'S':
 177                        printk(KERN_INFO "CPU#%d stopping\n", cpu);
 178                        while (1)
 179                                pause();
 180                        break;
 181
 182                default:
 183                        printk(KERN_ERR "CPU#%d received unknown IPI [%c]!\n",
 184                               cpu, c);
 185                        break;
 186                }
 187        }
 188}
 189
 190int hard_smp_processor_id(void)
 191{
 192        return pid_to_processor_id(os_getpid());
 193}
 194
 195static DEFINE_SPINLOCK(call_lock);
 196static atomic_t scf_started;
 197static atomic_t scf_finished;
 198static void (*func)(void *info);
 199static void *info;
 200
 201void smp_call_function_slave(int cpu)
 202{
 203        atomic_inc(&scf_started);
 204        (*func)(info);
 205        atomic_inc(&scf_finished);
 206}
 207
 208int smp_call_function(void (*_func)(void *info), void *_info, int wait)
 209{
 210        int cpus = num_online_cpus() - 1;
 211        int i;
 212
 213        if (!cpus)
 214                return 0;
 215
 216        /* Can deadlock when called with interrupts disabled */
 217        WARN_ON(irqs_disabled());
 218
 219        spin_lock_bh(&call_lock);
 220        atomic_set(&scf_started, 0);
 221        atomic_set(&scf_finished, 0);
 222        func = _func;
 223        info = _info;
 224
 225        for_each_online_cpu(i)
 226                os_write_file(cpu_data[i].ipi_pipe[1], "C", 1);
 227
 228        while (atomic_read(&scf_started) != cpus)
 229                barrier();
 230
 231        if (wait)
 232                while (atomic_read(&scf_finished) != cpus)
 233                        barrier();
 234
 235        spin_unlock_bh(&call_lock);
 236        return 0;
 237}
 238
 239#endif
 240