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