File: /usr/src/linux/arch/mips64/kernel/smp.c
1 #include <linux/config.h>
2 #include <linux/init.h>
3 #include <linux/spinlock.h>
4 #include <linux/threads.h>
5 #include <linux/time.h>
6 #include <linux/timex.h>
7 #include <linux/sched.h>
8
9 #include <asm/atomic.h>
10 #include <asm/processor.h>
11 #include <asm/system.h>
12 #include <asm/hardirq.h>
13 #include <asm/softirq.h>
14 #include <asm/mmu_context.h>
15 #include <asm/irq.h>
16
17 #ifdef CONFIG_SGI_IP27
18
19 #include <asm/sn/arch.h>
20 #include <asm/sn/intr.h>
21 #include <asm/sn/addrs.h>
22 #include <asm/sn/agent.h>
23 #include <asm/sn/sn0/ip27.h>
24
25 #define DORESCHED 0xab
26 #define DOCALL 0xbc
27
28 static void sendintr(int destid, unsigned char status)
29 {
30 int irq;
31
32 #if (CPUS_PER_NODE == 2)
33 switch (status) {
34 case DORESCHED: irq = CPU_RESCHED_A_IRQ; break;
35 case DOCALL: irq = CPU_CALL_A_IRQ; break;
36 default: panic("sendintr");
37 }
38 irq += cputoslice(destid);
39
40 /*
41 * Convert the compact hub number to the NASID to get the correct
42 * part of the address space. Then set the interrupt bit associated
43 * with the CPU we want to send the interrupt to.
44 */
45 REMOTE_HUB_SEND_INTR(COMPACT_TO_NASID_NODEID(cputocnode(destid)),
46 FAST_IRQ_TO_LEVEL(irq));
47 #else
48 << Bomb! Must redefine this for more than 2 CPUS. >>
49 #endif
50 }
51
52 #endif /* CONFIG_SGI_IP27 */
53
54 /* The 'big kernel lock' */
55 spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
56 int smp_threads_ready; /* Not used */
57 atomic_t smp_commenced = ATOMIC_INIT(0);
58 struct cpuinfo_mips cpu_data[NR_CPUS];
59 int smp_num_cpus = 1; /* Number that came online. */
60 int __cpu_number_map[NR_CPUS];
61 int __cpu_logical_map[NR_CPUS];
62 cycles_t cacheflush_time;
63
64 static void smp_tune_scheduling (void)
65 {
66 }
67
68 void __init smp_boot_cpus(void)
69 {
70 extern void allowboot(void);
71
72 init_new_context(current, &init_mm);
73 current->processor = 0;
74 init_idle();
75 smp_tune_scheduling();
76 allowboot();
77 }
78
79 void __init smp_commence(void)
80 {
81 wmb();
82 atomic_set(&smp_commenced,1);
83 }
84
85 static void stop_this_cpu(void *dummy)
86 {
87 /*
88 * Remove this CPU
89 */
90 for (;;);
91 }
92
93 void smp_send_stop(void)
94 {
95 smp_call_function(stop_this_cpu, NULL, 1, 0);
96 smp_num_cpus = 1;
97 }
98
99 /*
100 * this function sends a 'reschedule' IPI to another CPU.
101 * it goes straight through and wastes no time serializing
102 * anything. Worst case is that we lose a reschedule ...
103 */
104 void smp_send_reschedule(int cpu)
105 {
106 sendintr(cpu, DORESCHED);
107 }
108
109 /* Not really SMP stuff ... */
110 int setup_profiling_timer(unsigned int multiplier)
111 {
112 return 0;
113 }
114
115 /*
116 * Run a function on all other CPUs.
117 * <func> The function to run. This must be fast and non-blocking.
118 * <info> An arbitrary pointer to pass to the function.
119 * <retry> If true, keep retrying until ready.
120 * <wait> If true, wait until function has completed on other CPUs.
121 * [RETURNS] 0 on success, else a negative status code.
122 *
123 * Does not return until remote CPUs are nearly ready to execute <func>
124 * or are or have executed.
125 */
126 static volatile struct call_data_struct {
127 void (*func) (void *info);
128 void *info;
129 atomic_t started;
130 atomic_t finished;
131 int wait;
132 } *call_data;
133
134 int smp_call_function (void (*func) (void *info), void *info, int retry,
135 int wait)
136 {
137 struct call_data_struct data;
138 int i, cpus = smp_num_cpus-1;
139 static spinlock_t lock = SPIN_LOCK_UNLOCKED;
140
141 if (cpus == 0)
142 return 0;
143
144 data.func = func;
145 data.info = info;
146 atomic_set(&data.started, 0);
147 data.wait = wait;
148 if (wait)
149 atomic_set(&data.finished, 0);
150
151 spin_lock_bh(&lock);
152 call_data = &data;
153 /* Send a message to all other CPUs and wait for them to respond */
154 for (i = 0; i < smp_num_cpus; i++)
155 if (smp_processor_id() != i)
156 sendintr(i, DOCALL);
157
158 /* Wait for response */
159 /* FIXME: lock-up detection, backtrace on lock-up */
160 while (atomic_read(&data.started) != cpus)
161 barrier();
162
163 if (wait)
164 while (atomic_read(&data.finished) != cpus)
165 barrier();
166 spin_unlock_bh(&lock);
167 return 0;
168 }
169
170 extern void smp_call_function_interrupt(int irq, void *d, struct pt_regs *r)
171 {
172 void (*func) (void *info) = call_data->func;
173 void *info = call_data->info;
174 int wait = call_data->wait;
175
176 /*
177 * Notify initiating CPU that I've grabbed the data and am
178 * about to execute the function.
179 */
180 atomic_inc(&call_data->started);
181
182 /*
183 * At this point the info structure may be out of scope unless wait==1.
184 */
185 (*func)(info);
186 if (wait)
187 atomic_inc(&call_data->finished);
188 }
189
190
191 static void flush_tlb_all_ipi(void *info)
192 {
193 _flush_tlb_all();
194 }
195
196 void flush_tlb_all(void)
197 {
198 smp_call_function(flush_tlb_all_ipi, 0, 1, 1);
199 _flush_tlb_all();
200 }
201
202 static void flush_tlb_mm_ipi(void *mm)
203 {
204 _flush_tlb_mm((struct mm_struct *)mm);
205 }
206
207 /*
208 * The following tlb flush calls are invoked when old translations are
209 * being torn down, or pte attributes are changing. For single threaded
210 * address spaces, a new context is obtained on the current cpu, and tlb
211 * context on other cpus are invalidated to force a new context allocation
212 * at switch_mm time, should the mm ever be used on other cpus. For
213 * multithreaded address spaces, intercpu interrupts have to be sent.
214 * Another case where intercpu interrupts are required is when the target
215 * mm might be active on another cpu (eg debuggers doing the flushes on
216 * behalf of debugees, kswapd stealing pages from another process etc).
217 * Kanoj 07/00.
218 */
219
220 void flush_tlb_mm(struct mm_struct *mm)
221 {
222 if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
223 smp_call_function(flush_tlb_mm_ipi, (void *)mm, 1, 1);
224 } else {
225 int i;
226 for (i = 0; i < smp_num_cpus; i++)
227 if (smp_processor_id() != i)
228 CPU_CONTEXT(i, mm) = 0;
229 }
230 _flush_tlb_mm(mm);
231 }
232
233 struct flush_tlb_data {
234 struct mm_struct *mm;
235 struct vm_area_struct *vma;
236 unsigned long addr1;
237 unsigned long addr2;
238 };
239
240 static void flush_tlb_range_ipi(void *info)
241 {
242 struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
243
244 _flush_tlb_range(fd->mm, fd->addr1, fd->addr2);
245 }
246
247 void flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
248 {
249 if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
250 struct flush_tlb_data fd;
251
252 fd.mm = mm;
253 fd.addr1 = start;
254 fd.addr2 = end;
255 smp_call_function(flush_tlb_range_ipi, (void *)&fd, 1, 1);
256 } else {
257 int i;
258 for (i = 0; i < smp_num_cpus; i++)
259 if (smp_processor_id() != i)
260 CPU_CONTEXT(i, mm) = 0;
261 }
262 _flush_tlb_range(mm, start, end);
263 }
264
265 static void flush_tlb_page_ipi(void *info)
266 {
267 struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
268
269 _flush_tlb_page(fd->vma, fd->addr1);
270 }
271
272 void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
273 {
274 if ((atomic_read(&vma->vm_mm->mm_users) != 1) || (current->mm != vma->vm_mm)) {
275 struct flush_tlb_data fd;
276
277 fd.vma = vma;
278 fd.addr1 = page;
279 smp_call_function(flush_tlb_page_ipi, (void *)&fd, 1, 1);
280 } else {
281 int i;
282 for (i = 0; i < smp_num_cpus; i++)
283 if (smp_processor_id() != i)
284 CPU_CONTEXT(i, vma->vm_mm) = 0;
285 }
286 _flush_tlb_page(vma, page);
287 }
288
289