Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/um/kernel/smp.c
10817 views
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
*/
29
struct cpuinfo_um cpu_data[NR_CPUS];
30
31
/* A statistic, can be a little off */
32
int num_reschedules_sent = 0;
33
34
/* Not changed after boot */
35
struct task_struct *idle_threads[NR_CPUS];
36
37
void smp_send_reschedule(int cpu)
38
{
39
os_write_file(cpu_data[cpu].ipi_pipe[1], "R", 1);
40
num_reschedules_sent++;
41
}
42
43
void 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
56
static cpumask_t smp_commenced_mask = CPU_MASK_NONE;
57
static cpumask_t cpu_callin_map = CPU_MASK_NONE;
58
59
static 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
84
static 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
103
void 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
139
void smp_prepare_boot_cpu(void)
140
{
141
cpu_set(smp_processor_id(), cpu_online_map);
142
}
143
144
int __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
152
int setup_profiling_timer(unsigned int multiplier)
153
{
154
printk(KERN_INFO "setup_profiling_timer\n");
155
return 0;
156
}
157
158
void smp_call_function_slave(int cpu);
159
160
void 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
190
int hard_smp_processor_id(void)
191
{
192
return pid_to_processor_id(os_getpid());
193
}
194
195
static DEFINE_SPINLOCK(call_lock);
196
static atomic_t scf_started;
197
static atomic_t scf_finished;
198
static void (*func)(void *info);
199
static void *info;
200
201
void smp_call_function_slave(int cpu)
202
{
203
atomic_inc(&scf_started);
204
(*func)(info);
205
atomic_inc(&scf_finished);
206
}
207
208
int 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
241