Blame view

arch/um/kernel/smp.c 4.79 KB
63ae2a94d   Jeff Dike   [PATCH] uml: move...
1
  /*
4c9e13851   Jeff Dike   uml: style fixes ...
2
   * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
   * Licensed under the GPL
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
  #include "linux/percpu.h"
  #include "asm/pgalloc.h"
  #include "asm/tlb.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
12
13
14
15
16
17
18
  #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"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
  #include "kern.h"
  #include "irq_user.h"
  #include "os.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  /* 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)
  {
a6ea4ccee   Jeff Dike   uml: rename os_{r...
36
  	os_write_file(cpu_data[cpu].ipi_pipe[1], "R", 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
40
41
42
43
44
  	num_reschedules_sent++;
  }
  
  void smp_send_stop(void)
  {
  	int i;
  
  	printk(KERN_INFO "Stopping all CPUs...");
4c9e13851   Jeff Dike   uml: style fixes ...
45
46
  	for (i = 0; i < num_online_cpus(); i++) {
  		if (i == current_thread->cpu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  			continue;
a6ea4ccee   Jeff Dike   uml: rename os_{r...
48
  		os_write_file(cpu_data[i].ipi_pipe[1], "S", 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  	}
c5d4bb171   Jeff Dike   uml: style fixes ...
50
51
  	printk(KERN_CONT "done
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
56
57
58
59
60
61
  }
  
  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);
4c9e13851   Jeff Dike   uml: style fixes ...
62
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
  		panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err);
bf8fde785   Jeff Dike   uml: miscellaneou...
64
  	os_set_fd_async(cpu_data[cpu].ipi_pipe[0]);
63ae2a94d   Jeff Dike   [PATCH] uml: move...
65

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
  	wmb();
  	if (cpu_test_and_set(cpu, cpu_callin_map)) {
4c9e13851   Jeff Dike   uml: style fixes ...
68
69
  		printk(KERN_ERR "huh, CPU#%d already present??
  ", cpu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
73
74
  		BUG();
  	}
  
  	while (!cpu_isset(cpu, smp_commenced_mask))
  		cpu_relax();
e545a6140   Manfred Spraul   kernel/cpu.c: cre...
75
  	notify_cpu_starting(cpu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
  	cpu_set(cpu, cpu_online_map);
  	default_idle();
dc764e508   Jeff Dike   uml: formatting f...
78
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
81
82
83
  }
  
  static struct task_struct *idle_thread(int cpu)
  {
  	struct task_struct *new_task;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84

dc764e508   Jeff Dike   uml: formatting f...
85
86
  	current->thread.request.u.thread.proc = idle_proc;
  	current->thread.request.u.thread.arg = (void *) cpu;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
  	new_task = fork_idle(cpu);
4c9e13851   Jeff Dike   uml: style fixes ...
88
  	if (IS_ERR(new_task))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
  		panic("copy_process failed in idle_thread, error = %ld",
  		      PTR_ERR(new_task));
63ae2a94d   Jeff Dike   [PATCH] uml: move...
91
  	cpu_tasks[cpu] = ((struct cpu_task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
  		          { .pid = 	new_task->thread.mode.tt.extern_pid,
  			    .task = 	new_task } );
  	idle_threads[cpu] = new_task;
42fda6638   Jeff Dike   uml: throw out CO...
95
  	panic("skas mode doesn't support SMP");
dc764e508   Jeff Dike   uml: formatting f...
96
  	return new_task;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
100
101
102
103
104
105
106
  }
  
  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)
a6a01063d   Rusty Russell   cpumask: Use acce...
107
  		set_cpu_possible(i, true);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
111
112
113
  
  	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);
4c9e13851   Jeff Dike   uml: style fixes ...
114
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
  		panic("CPU#0 failed to create IPI pipe, errno = %d", -err);
bf8fde785   Jeff Dike   uml: miscellaneou...
116
  	os_set_fd_async(cpu_data[me].ipi_pipe[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117

4c9e13851   Jeff Dike   uml: style fixes ...
118
119
120
  	for (cpu = 1; cpu < ncpus; cpu++) {
  		printk(KERN_INFO "Booting processor %d...
  ", cpu);
63ae2a94d   Jeff Dike   [PATCH] uml: move...
121

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
  		idle = idle_thread(cpu);
  
  		init_idle(idle, cpu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
127
128
  
  		waittime = 200000000;
  		while (waittime-- && !cpu_isset(cpu, cpu_callin_map))
  			cpu_relax();
c5d4bb171   Jeff Dike   uml: style fixes ...
129
130
131
  		printk(KERN_INFO "%s
  ",
  		       cpu_isset(cpu, cpu_calling_map) ? "done" : "failed");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
135
136
137
138
139
140
141
142
143
144
  	}
  }
  
  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();
dc764e508   Jeff Dike   uml: formatting f...
145
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
148
149
150
151
  }
  
  int setup_profiling_timer(unsigned int multiplier)
  {
  	printk(KERN_INFO "setup_profiling_timer
  ");
dc764e508   Jeff Dike   uml: formatting f...
152
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
157
158
159
160
161
162
  }
  
  void smp_call_function_slave(int cpu);
  
  void IPI_handler(int cpu)
  {
  	unsigned char c;
  	int fd;
  
  	fd = cpu_data[cpu].ipi_pipe[0];
a6ea4ccee   Jeff Dike   uml: rename os_{r...
163
  	while (os_read_file(fd, &c, 1) == 1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
166
167
168
169
  		switch (c) {
  		case 'C':
  			smp_call_function_slave(cpu);
  			break;
  
  		case 'R':
184748cc5   Peter Zijlstra   sched: Provide sc...
170
  			scheduler_ipi();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
173
  			break;
  
  		case 'S':
4c9e13851   Jeff Dike   uml: style fixes ...
174
175
176
  			printk(KERN_INFO "CPU#%d stopping
  ", cpu);
  			while (1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
178
179
180
  				pause();
  			break;
  
  		default:
4c9e13851   Jeff Dike   uml: style fixes ...
181
182
183
  			printk(KERN_ERR "CPU#%d received unknown IPI [%c]!
  ",
  			       cpu, c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
188
189
190
  			break;
  		}
  	}
  }
  
  int hard_smp_processor_id(void)
  {
dc764e508   Jeff Dike   uml: formatting f...
191
  	return pid_to_processor_id(os_getpid());
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
195
196
197
198
199
200
201
202
203
204
205
  }
  
  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);
  }
8691e5a8f   Jens Axboe   smp_call_function...
206
  int smp_call_function(void (*_func)(void *info), void *_info, int wait)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  {
  	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)
a6ea4ccee   Jeff Dike   uml: rename os_{r...
224
  		os_write_file(cpu_data[i].ipi_pipe[1], "C", 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
226
227
228
229
230
231
232
233
234
235
236
237
  
  	while (atomic_read(&scf_started) != cpus)
  		barrier();
  
  	if (wait)
  		while (atomic_read(&scf_finished) != cpus)
  			barrier();
  
  	spin_unlock_bh(&call_lock);
  	return 0;
  }
  
  #endif