1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* smp.c: Sparc SMP support. |
3 | * |
4 | * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) |
5 | * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) |
6 | * Copyright (C) 2004 Keith M Wesolowski (wesolows@foobazco.org) |
7 | */ |
8 | |
9 | #include <asm/head.h> |
10 | |
11 | #include <linux/kernel.h> |
12 | #include <linux/sched.h> |
13 | #include <linux/threads.h> |
14 | #include <linux/smp.h> |
15 | #include <linux/interrupt.h> |
16 | #include <linux/kernel_stat.h> |
17 | #include <linux/init.h> |
18 | #include <linux/spinlock.h> |
19 | #include <linux/mm.h> |
20 | #include <linux/fs.h> |
21 | #include <linux/seq_file.h> |
22 | #include <linux/cache.h> |
23 | #include <linux/delay.h> |
24 | #include <linux/profile.h> |
25 | #include <linux/cpu.h> |
26 | |
27 | #include <asm/ptrace.h> |
28 | #include <linux/atomic.h> |
29 | |
30 | #include <asm/irq.h> |
31 | #include <asm/page.h> |
32 | #include <asm/oplib.h> |
33 | #include <asm/cacheflush.h> |
34 | #include <asm/tlbflush.h> |
35 | #include <asm/cpudata.h> |
36 | #include <asm/timer.h> |
37 | #include <asm/leon.h> |
38 | |
39 | #include "kernel.h" |
40 | #include "irq.h" |
41 | |
42 | volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; |
43 | |
44 | cpumask_t smp_commenced_mask = CPU_MASK_NONE; |
45 | |
46 | const struct sparc32_ipi_ops *sparc32_ipi_ops; |
47 | |
48 | /* The only guaranteed locking primitive available on all Sparc |
49 | * processors is 'ldstub [%reg + immediate], %dest_reg' which atomically |
50 | * places the current byte at the effective address into dest_reg and |
51 | * places 0xff there afterwards. Pretty lame locking primitive |
52 | * compared to the Alpha and the Intel no? Most Sparcs have 'swap' |
53 | * instruction which is much better... |
54 | */ |
55 | |
56 | void smp_store_cpu_info(int id) |
57 | { |
58 | int cpu_node; |
59 | int mid; |
60 | |
61 | cpu_data(id).udelay_val = loops_per_jiffy; |
62 | |
63 | cpu_find_by_mid(id, &cpu_node); |
64 | cpu_data(id).clock_tick = prom_getintdefault(cpu_node, |
65 | "clock-frequency" , 0); |
66 | cpu_data(id).prom_node = cpu_node; |
67 | mid = cpu_get_hwmid(cpu_node); |
68 | |
69 | if (mid < 0) { |
70 | printk(KERN_NOTICE "No MID found for CPU%d at node 0x%08x" , id, cpu_node); |
71 | mid = 0; |
72 | } |
73 | cpu_data(id).mid = mid; |
74 | } |
75 | |
76 | void __init smp_cpus_done(unsigned int max_cpus) |
77 | { |
78 | unsigned long bogosum = 0; |
79 | int cpu, num = 0; |
80 | |
81 | for_each_online_cpu(cpu) { |
82 | num++; |
83 | bogosum += cpu_data(cpu).udelay_val; |
84 | } |
85 | |
86 | printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n" , |
87 | num, bogosum/(500000/HZ), |
88 | (bogosum/(5000/HZ))%100); |
89 | |
90 | switch(sparc_cpu_model) { |
91 | case sun4m: |
92 | smp4m_smp_done(); |
93 | break; |
94 | case sun4d: |
95 | smp4d_smp_done(); |
96 | break; |
97 | case sparc_leon: |
98 | leon_smp_done(); |
99 | break; |
100 | case sun4e: |
101 | printk("SUN4E\n" ); |
102 | BUG(); |
103 | break; |
104 | case sun4u: |
105 | printk("SUN4U\n" ); |
106 | BUG(); |
107 | break; |
108 | default: |
109 | printk("UNKNOWN!\n" ); |
110 | BUG(); |
111 | break; |
112 | } |
113 | } |
114 | |
115 | void cpu_panic(void) |
116 | { |
117 | printk("CPU[%d]: Returns from cpu_idle!\n" , smp_processor_id()); |
118 | panic(fmt: "SMP bolixed\n" ); |
119 | } |
120 | |
121 | struct linux_prom_registers smp_penguin_ctable = { 0 }; |
122 | |
123 | void arch_smp_send_reschedule(int cpu) |
124 | { |
125 | /* |
126 | * CPU model dependent way of implementing IPI generation targeting |
127 | * a single CPU. The trap handler needs only to do trap entry/return |
128 | * to call schedule. |
129 | */ |
130 | sparc32_ipi_ops->resched(cpu); |
131 | } |
132 | |
133 | void smp_send_stop(void) |
134 | { |
135 | } |
136 | |
137 | void arch_send_call_function_single_ipi(int cpu) |
138 | { |
139 | /* trigger one IPI single call on one CPU */ |
140 | sparc32_ipi_ops->single(cpu); |
141 | } |
142 | |
143 | void arch_send_call_function_ipi_mask(const struct cpumask *mask) |
144 | { |
145 | int cpu; |
146 | |
147 | /* trigger IPI mask call on each CPU */ |
148 | for_each_cpu(cpu, mask) |
149 | sparc32_ipi_ops->mask_one(cpu); |
150 | } |
151 | |
152 | void smp_resched_interrupt(void) |
153 | { |
154 | irq_enter(); |
155 | scheduler_ipi(); |
156 | local_cpu_data().irq_resched_count++; |
157 | irq_exit(); |
158 | /* re-schedule routine called by interrupt return code. */ |
159 | } |
160 | |
161 | void smp_call_function_single_interrupt(void) |
162 | { |
163 | irq_enter(); |
164 | generic_smp_call_function_single_interrupt(); |
165 | local_cpu_data().irq_call_count++; |
166 | irq_exit(); |
167 | } |
168 | |
169 | void smp_call_function_interrupt(void) |
170 | { |
171 | irq_enter(); |
172 | generic_smp_call_function_interrupt(); |
173 | local_cpu_data().irq_call_count++; |
174 | irq_exit(); |
175 | } |
176 | |
177 | void __init smp_prepare_cpus(unsigned int max_cpus) |
178 | { |
179 | int i, cpuid, ; |
180 | |
181 | printk("Entering SMP Mode...\n" ); |
182 | |
183 | extra = 0; |
184 | for (i = 0; !cpu_find_by_instance(i, NULL, &cpuid); i++) { |
185 | if (cpuid >= NR_CPUS) |
186 | extra++; |
187 | } |
188 | /* i = number of cpus */ |
189 | if (extra && max_cpus > i - extra) |
190 | printk("Warning: NR_CPUS is too low to start all cpus\n" ); |
191 | |
192 | smp_store_cpu_info(id: boot_cpu_id); |
193 | |
194 | switch(sparc_cpu_model) { |
195 | case sun4m: |
196 | smp4m_boot_cpus(); |
197 | break; |
198 | case sun4d: |
199 | smp4d_boot_cpus(); |
200 | break; |
201 | case sparc_leon: |
202 | leon_boot_cpus(); |
203 | break; |
204 | case sun4e: |
205 | printk("SUN4E\n" ); |
206 | BUG(); |
207 | break; |
208 | case sun4u: |
209 | printk("SUN4U\n" ); |
210 | BUG(); |
211 | break; |
212 | default: |
213 | printk("UNKNOWN!\n" ); |
214 | BUG(); |
215 | break; |
216 | } |
217 | } |
218 | |
219 | /* Set this up early so that things like the scheduler can init |
220 | * properly. We use the same cpu mask for both the present and |
221 | * possible cpu map. |
222 | */ |
223 | void __init smp_setup_cpu_possible_map(void) |
224 | { |
225 | int instance, mid; |
226 | |
227 | instance = 0; |
228 | while (!cpu_find_by_instance(instance, NULL, &mid)) { |
229 | if (mid < NR_CPUS) { |
230 | set_cpu_possible(cpu: mid, possible: true); |
231 | set_cpu_present(cpu: mid, present: true); |
232 | } |
233 | instance++; |
234 | } |
235 | } |
236 | |
237 | void __init smp_prepare_boot_cpu(void) |
238 | { |
239 | int cpuid = hard_smp_processor_id(); |
240 | |
241 | if (cpuid >= NR_CPUS) { |
242 | prom_printf("Serious problem, boot cpu id >= NR_CPUS\n" ); |
243 | prom_halt(); |
244 | } |
245 | if (cpuid != 0) |
246 | printk("boot cpu id != 0, this could work but is untested\n" ); |
247 | |
248 | current_thread_info()->cpu = cpuid; |
249 | set_cpu_online(cpu: cpuid, online: true); |
250 | set_cpu_possible(cpu: cpuid, possible: true); |
251 | } |
252 | |
253 | int __cpu_up(unsigned int cpu, struct task_struct *tidle) |
254 | { |
255 | int ret=0; |
256 | |
257 | switch(sparc_cpu_model) { |
258 | case sun4m: |
259 | ret = smp4m_boot_one_cpu(cpu, tidle); |
260 | break; |
261 | case sun4d: |
262 | ret = smp4d_boot_one_cpu(cpu, tidle); |
263 | break; |
264 | case sparc_leon: |
265 | ret = leon_boot_one_cpu(cpu, tidle); |
266 | break; |
267 | case sun4e: |
268 | printk("SUN4E\n" ); |
269 | BUG(); |
270 | break; |
271 | case sun4u: |
272 | printk("SUN4U\n" ); |
273 | BUG(); |
274 | break; |
275 | default: |
276 | printk("UNKNOWN!\n" ); |
277 | BUG(); |
278 | break; |
279 | } |
280 | |
281 | if (!ret) { |
282 | cpumask_set_cpu(cpu, dstp: &smp_commenced_mask); |
283 | while (!cpu_online(cpu)) |
284 | mb(); |
285 | } |
286 | return ret; |
287 | } |
288 | |
289 | static void arch_cpu_pre_starting(void *arg) |
290 | { |
291 | local_ops->cache_all(); |
292 | local_ops->tlb_all(); |
293 | |
294 | switch(sparc_cpu_model) { |
295 | case sun4m: |
296 | sun4m_cpu_pre_starting(arg); |
297 | break; |
298 | case sun4d: |
299 | sun4d_cpu_pre_starting(arg); |
300 | break; |
301 | case sparc_leon: |
302 | leon_cpu_pre_starting(arg); |
303 | break; |
304 | default: |
305 | BUG(); |
306 | } |
307 | } |
308 | |
309 | static void arch_cpu_pre_online(void *arg) |
310 | { |
311 | unsigned int cpuid = hard_smp_processor_id(); |
312 | |
313 | register_percpu_ce(cpuid); |
314 | |
315 | calibrate_delay(); |
316 | smp_store_cpu_info(id: cpuid); |
317 | |
318 | local_ops->cache_all(); |
319 | local_ops->tlb_all(); |
320 | |
321 | switch(sparc_cpu_model) { |
322 | case sun4m: |
323 | sun4m_cpu_pre_online(arg); |
324 | break; |
325 | case sun4d: |
326 | sun4d_cpu_pre_online(arg); |
327 | break; |
328 | case sparc_leon: |
329 | leon_cpu_pre_online(arg); |
330 | break; |
331 | default: |
332 | BUG(); |
333 | } |
334 | } |
335 | |
336 | static void sparc_start_secondary(void *arg) |
337 | { |
338 | unsigned int cpu; |
339 | |
340 | /* |
341 | * SMP booting is extremely fragile in some architectures. So run |
342 | * the cpu initialization code first before anything else. |
343 | */ |
344 | arch_cpu_pre_starting(arg); |
345 | |
346 | cpu = smp_processor_id(); |
347 | |
348 | notify_cpu_starting(cpu); |
349 | arch_cpu_pre_online(arg); |
350 | |
351 | /* Set the CPU in the cpu_online_mask */ |
352 | set_cpu_online(cpu, online: true); |
353 | |
354 | /* Enable local interrupts now */ |
355 | local_irq_enable(); |
356 | |
357 | wmb(); |
358 | cpu_startup_entry(state: CPUHP_AP_ONLINE_IDLE); |
359 | |
360 | /* We should never reach here! */ |
361 | BUG(); |
362 | } |
363 | |
364 | void smp_callin(void) |
365 | { |
366 | sparc_start_secondary(NULL); |
367 | } |
368 | |
369 | void smp_bogo(struct seq_file *m) |
370 | { |
371 | int i; |
372 | |
373 | for_each_online_cpu(i) { |
374 | seq_printf(m, |
375 | fmt: "Cpu%dBogo\t: %lu.%02lu\n" , |
376 | i, |
377 | cpu_data(i).udelay_val/(500000/HZ), |
378 | (cpu_data(i).udelay_val/(5000/HZ))%100); |
379 | } |
380 | } |
381 | |
382 | void smp_info(struct seq_file *m) |
383 | { |
384 | int i; |
385 | |
386 | seq_printf(m, fmt: "State:\n" ); |
387 | for_each_online_cpu(i) |
388 | seq_printf(m, fmt: "CPU%d\t\t: online\n" , i); |
389 | } |
390 | |