linux-bk/arch/um/kernel/smp.c
<<
>>
Prefs
   1/* 
   2 * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
   3 * Licensed under the GPL
   4 */
   5
   6#include "linux/config.h"
   7#include "linux/percpu.h"
   8#include "asm/pgalloc.h"
   9#include "asm/tlb.h"
  10
  11/* For some reason, mmu_gathers are referenced when CONFIG_SMP is off. */
  12DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
  13
  14#ifdef CONFIG_SMP
  15
  16#include "linux/sched.h"
  17#include "linux/module.h"
  18#include "linux/threads.h"
  19#include "linux/interrupt.h"
  20#include "linux/err.h"
  21#include "linux/hardirq.h"
  22#include "asm/smp.h"
  23#include "asm/processor.h"
  24#include "asm/spinlock.h"
  25#include "user_util.h"
  26#include "kern_util.h"
  27#include "kern.h"
  28#include "irq_user.h"
  29#include "os.h"
  30
  31/* CPU online map, set by smp_boot_cpus */
  32cpumask_t cpu_online_map = CPU_MASK_NONE;
  33cpumask_t cpu_possible_map = CPU_MASK_NONE;
  34
  35EXPORT_SYMBOL(cpu_online_map);
  36EXPORT_SYMBOL(cpu_possible_map);
  37
  38/* Per CPU bogomips and other parameters
  39 * The only piece used here is the ipi pipe, which is set before SMP is
  40 * started and never changed.
  41 */
  42struct cpuinfo_um cpu_data[NR_CPUS];
  43
  44/* Set when the idlers are all forked */
  45int smp_threads_ready = 0;
  46
  47/* A statistic, can be a little off */
  48int num_reschedules_sent = 0;
  49
  50/* Small, random number, never changed */
  51unsigned long cache_decay_ticks = 5;
  52
  53/* Not changed after boot */
  54struct task_struct *idle_threads[NR_CPUS];
  55
  56void smp_send_reschedule(int cpu)
  57{
  58        os_write_file(cpu_data[cpu].ipi_pipe[1], "R", 1);
  59        num_reschedules_sent++;
  60}
  61
  62void smp_send_stop(void)
  63{
  64        int i;
  65
  66        printk(KERN_INFO "Stopping all CPUs...");
  67        for(i = 0; i < num_online_cpus(); i++){
  68                if(i == current_thread->cpu)
  69                        continue;
  70                os_write_file(cpu_data[i].ipi_pipe[1], "S", 1);
  71        }
  72        printk("done\n");
  73}
  74
  75static cpumask_t smp_commenced_mask = CPU_MASK_NONE;
  76static cpumask_t cpu_callin_map = CPU_MASK_NONE;
  77
  78static int idle_proc(void *cpup)
  79{
  80        int cpu = (int) cpup, err;
  81
  82        err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1);
  83        if(err < 0)
  84                panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err);
  85
  86        activate_ipi(cpu_data[cpu].ipi_pipe[0], 
  87                     current->thread.mode.tt.extern_pid);
  88 
  89        wmb();
  90        if (cpu_test_and_set(cpu, cpu_callin_map)) {
  91                printk("huh, CPU#%d already present??\n", cpu);
  92                BUG();
  93        }
  94
  95        while (!cpu_isset(cpu, smp_commenced_mask))
  96                cpu_relax();
  97
  98        cpu_set(cpu, cpu_online_map);
  99        default_idle();
 100        return(0);
 101}
 102
 103static struct task_struct *idle_thread(int cpu)
 104{
 105        struct task_struct *new_task;
 106        unsigned char c;
 107
 108        current->thread.request.u.thread.proc = idle_proc;
 109        current->thread.request.u.thread.arg = (void *) cpu;
 110        new_task = fork_idle(cpu);
 111        if(IS_ERR(new_task))
 112                panic("copy_process failed in idle_thread, error = %ld",
 113                      PTR_ERR(new_task));
 114
 115        cpu_tasks[cpu] = ((struct cpu_task) 
 116                          { .pid =      new_task->thread.mode.tt.extern_pid,
 117                            .task =     new_task } );
 118        idle_threads[cpu] = new_task;
 119        CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c,
 120                          sizeof(c)),
 121                    ({ panic("skas mode doesn't support SMP"); }));
 122        return(new_task);
 123}
 124
 125void smp_prepare_cpus(unsigned int maxcpus)
 126{
 127        struct task_struct *idle;
 128        unsigned long waittime;
 129        int err, cpu, me = smp_processor_id();
 130        int i;
 131
 132        for (i = 0; i < ncpus; ++i)
 133                cpu_set(i, cpu_possible_map);
 134
 135        cpu_clear(me, cpu_online_map);
 136        cpu_set(me, cpu_online_map);
 137        cpu_set(me, cpu_callin_map);
 138
 139        err = os_pipe(cpu_data[me].ipi_pipe, 1, 1);
 140        if(err < 0)
 141                panic("CPU#0 failed to create IPI pipe, errno = %d", -err);
 142
 143        activate_ipi(cpu_data[me].ipi_pipe[0],
 144                     current->thread.mode.tt.extern_pid);
 145
 146        for(cpu = 1; cpu < ncpus; cpu++){
 147                printk("Booting processor %d...\n", cpu);
 148                
 149                idle = idle_thread(cpu);
 150
 151                init_idle(idle, cpu);
 152                unhash_process(idle);
 153
 154                waittime = 200000000;
 155                while (waittime-- && !cpu_isset(cpu, cpu_callin_map))
 156                        cpu_relax();
 157
 158                if (cpu_isset(cpu, cpu_callin_map))
 159                        printk("done\n");
 160                else printk("failed\n");
 161        }
 162}
 163
 164void smp_prepare_boot_cpu(void)
 165{
 166        cpu_set(smp_processor_id(), cpu_online_map);
 167}
 168
 169int __cpu_up(unsigned int cpu)
 170{
 171        cpu_set(cpu, smp_commenced_mask);
 172        while (!cpu_isset(cpu, cpu_online_map))
 173                mb();
 174        return(0);
 175}
 176
 177int setup_profiling_timer(unsigned int multiplier)
 178{
 179        printk(KERN_INFO "setup_profiling_timer\n");
 180        return(0);
 181}
 182
 183void smp_call_function_slave(int cpu);
 184
 185void IPI_handler(int cpu)
 186{
 187        unsigned char c;
 188        int fd;
 189
 190        fd = cpu_data[cpu].ipi_pipe[0];
 191        while (os_read_file(fd, &c, 1) == 1) {
 192                switch (c) {
 193                case 'C':
 194                        smp_call_function_slave(cpu);
 195                        break;
 196
 197                case 'R':
 198                        set_tsk_need_resched(current);
 199                        break;
 200
 201                case 'S':
 202                        printk("CPU#%d stopping\n", cpu);
 203                        while(1)
 204                                pause();
 205                        break;
 206
 207                default:
 208                        printk("CPU#%d received unknown IPI [%c]!\n", cpu, c);
 209                        break;
 210                }
 211        }
 212}
 213
 214int hard_smp_processor_id(void)
 215{
 216        return(pid_to_processor_id(os_getpid()));
 217}
 218
 219static DEFINE_SPINLOCK(call_lock);
 220static atomic_t scf_started;
 221static atomic_t scf_finished;
 222static void (*func)(void *info);
 223static void *info;
 224
 225void smp_call_function_slave(int cpu)
 226{
 227        atomic_inc(&scf_started);
 228        (*func)(info);
 229        atomic_inc(&scf_finished);
 230}
 231
 232int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, 
 233                      int wait)
 234{
 235        int cpus = num_online_cpus() - 1;
 236        int i;
 237
 238        if (!cpus)
 239                return 0;
 240
 241        /* Can deadlock when called with interrupts disabled */
 242        WARN_ON(irqs_disabled());
 243
 244        spin_lock_bh(&call_lock);
 245        atomic_set(&scf_started, 0);
 246        atomic_set(&scf_finished, 0);
 247        func = _func;
 248        info = _info;
 249
 250        for_each_online_cpu(i)
 251                os_write_file(cpu_data[i].ipi_pipe[1], "C", 1);
 252
 253        while (atomic_read(&scf_started) != cpus)
 254                barrier();
 255
 256        if (wait)
 257                while (atomic_read(&scf_finished) != cpus)
 258                        barrier();
 259
 260        spin_unlock_bh(&call_lock);
 261        return 0;
 262}
 263
 264#endif
 265
 266/*
 267 * Overrides for Emacs so that we follow Linus's tabbing style.
 268 * Emacs will notice this stuff at the end of the file and automatically
 269 * adjust the settings for this buffer only.  This must remain at the end
 270 * of the file.
 271 * ---------------------------------------------------------------------------
 272 * Local variables:
 273 * c-file-style: "linux"
 274 * End:
 275 */
 276
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.