2 * Copyright (C) 2010, 2011, 2012, Lemote, Inc.
3 * Author: Chen Huacai, chenhc@lemote.com
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
17 #include <linux/init.h>
18 #include <linux/cpu.h>
19 #include <linux/sched.h>
20 #include <linux/sched/hotplug.h>
21 #include <linux/sched/task_stack.h>
22 #include <linux/smp.h>
23 #include <linux/cpufreq.h>
24 #include <linux/kexec.h>
25 #include <asm/processor.h>
27 #include <asm/clock.h>
28 #include <asm/tlbflush.h>
29 #include <asm/cacheflush.h>
31 #include <workarounds.h>
35 DEFINE_PER_CPU(int, cpu_state
);
37 static void *ipi_set0_regs
[16];
38 static void *ipi_clear0_regs
[16];
39 static void *ipi_status0_regs
[16];
40 static void *ipi_en0_regs
[16];
41 static void *ipi_mailbox_buf
[16];
42 static uint32_t core0_c0count
[NR_CPUS
];
44 /* read a 32bit value from ipi register */
45 #define loongson3_ipi_read32(addr) readl(addr)
46 /* read a 64bit value from ipi register */
47 #define loongson3_ipi_read64(addr) readq(addr)
48 /* write a 32bit value to ipi register */
49 #define loongson3_ipi_write32(action, addr) \
51 writel(action, addr); \
54 /* write a 64bit value to ipi register */
55 #define loongson3_ipi_write64(action, addr) \
57 writeq(action, addr); \
61 static void ipi_set0_regs_init(void)
63 ipi_set0_regs
[0] = (void *)
64 (SMP_CORE_GROUP0_BASE
+ SMP_CORE0_OFFSET
+ SET0
);
65 ipi_set0_regs
[1] = (void *)
66 (SMP_CORE_GROUP0_BASE
+ SMP_CORE1_OFFSET
+ SET0
);
67 ipi_set0_regs
[2] = (void *)
68 (SMP_CORE_GROUP0_BASE
+ SMP_CORE2_OFFSET
+ SET0
);
69 ipi_set0_regs
[3] = (void *)
70 (SMP_CORE_GROUP0_BASE
+ SMP_CORE3_OFFSET
+ SET0
);
71 ipi_set0_regs
[4] = (void *)
72 (SMP_CORE_GROUP1_BASE
+ SMP_CORE0_OFFSET
+ SET0
);
73 ipi_set0_regs
[5] = (void *)
74 (SMP_CORE_GROUP1_BASE
+ SMP_CORE1_OFFSET
+ SET0
);
75 ipi_set0_regs
[6] = (void *)
76 (SMP_CORE_GROUP1_BASE
+ SMP_CORE2_OFFSET
+ SET0
);
77 ipi_set0_regs
[7] = (void *)
78 (SMP_CORE_GROUP1_BASE
+ SMP_CORE3_OFFSET
+ SET0
);
79 ipi_set0_regs
[8] = (void *)
80 (SMP_CORE_GROUP2_BASE
+ SMP_CORE0_OFFSET
+ SET0
);
81 ipi_set0_regs
[9] = (void *)
82 (SMP_CORE_GROUP2_BASE
+ SMP_CORE1_OFFSET
+ SET0
);
83 ipi_set0_regs
[10] = (void *)
84 (SMP_CORE_GROUP2_BASE
+ SMP_CORE2_OFFSET
+ SET0
);
85 ipi_set0_regs
[11] = (void *)
86 (SMP_CORE_GROUP2_BASE
+ SMP_CORE3_OFFSET
+ SET0
);
87 ipi_set0_regs
[12] = (void *)
88 (SMP_CORE_GROUP3_BASE
+ SMP_CORE0_OFFSET
+ SET0
);
89 ipi_set0_regs
[13] = (void *)
90 (SMP_CORE_GROUP3_BASE
+ SMP_CORE1_OFFSET
+ SET0
);
91 ipi_set0_regs
[14] = (void *)
92 (SMP_CORE_GROUP3_BASE
+ SMP_CORE2_OFFSET
+ SET0
);
93 ipi_set0_regs
[15] = (void *)
94 (SMP_CORE_GROUP3_BASE
+ SMP_CORE3_OFFSET
+ SET0
);
97 static void ipi_clear0_regs_init(void)
99 ipi_clear0_regs
[0] = (void *)
100 (SMP_CORE_GROUP0_BASE
+ SMP_CORE0_OFFSET
+ CLEAR0
);
101 ipi_clear0_regs
[1] = (void *)
102 (SMP_CORE_GROUP0_BASE
+ SMP_CORE1_OFFSET
+ CLEAR0
);
103 ipi_clear0_regs
[2] = (void *)
104 (SMP_CORE_GROUP0_BASE
+ SMP_CORE2_OFFSET
+ CLEAR0
);
105 ipi_clear0_regs
[3] = (void *)
106 (SMP_CORE_GROUP0_BASE
+ SMP_CORE3_OFFSET
+ CLEAR0
);
107 ipi_clear0_regs
[4] = (void *)
108 (SMP_CORE_GROUP1_BASE
+ SMP_CORE0_OFFSET
+ CLEAR0
);
109 ipi_clear0_regs
[5] = (void *)
110 (SMP_CORE_GROUP1_BASE
+ SMP_CORE1_OFFSET
+ CLEAR0
);
111 ipi_clear0_regs
[6] = (void *)
112 (SMP_CORE_GROUP1_BASE
+ SMP_CORE2_OFFSET
+ CLEAR0
);
113 ipi_clear0_regs
[7] = (void *)
114 (SMP_CORE_GROUP1_BASE
+ SMP_CORE3_OFFSET
+ CLEAR0
);
115 ipi_clear0_regs
[8] = (void *)
116 (SMP_CORE_GROUP2_BASE
+ SMP_CORE0_OFFSET
+ CLEAR0
);
117 ipi_clear0_regs
[9] = (void *)
118 (SMP_CORE_GROUP2_BASE
+ SMP_CORE1_OFFSET
+ CLEAR0
);
119 ipi_clear0_regs
[10] = (void *)
120 (SMP_CORE_GROUP2_BASE
+ SMP_CORE2_OFFSET
+ CLEAR0
);
121 ipi_clear0_regs
[11] = (void *)
122 (SMP_CORE_GROUP2_BASE
+ SMP_CORE3_OFFSET
+ CLEAR0
);
123 ipi_clear0_regs
[12] = (void *)
124 (SMP_CORE_GROUP3_BASE
+ SMP_CORE0_OFFSET
+ CLEAR0
);
125 ipi_clear0_regs
[13] = (void *)
126 (SMP_CORE_GROUP3_BASE
+ SMP_CORE1_OFFSET
+ CLEAR0
);
127 ipi_clear0_regs
[14] = (void *)
128 (SMP_CORE_GROUP3_BASE
+ SMP_CORE2_OFFSET
+ CLEAR0
);
129 ipi_clear0_regs
[15] = (void *)
130 (SMP_CORE_GROUP3_BASE
+ SMP_CORE3_OFFSET
+ CLEAR0
);
133 static void ipi_status0_regs_init(void)
135 ipi_status0_regs
[0] = (void *)
136 (SMP_CORE_GROUP0_BASE
+ SMP_CORE0_OFFSET
+ STATUS0
);
137 ipi_status0_regs
[1] = (void *)
138 (SMP_CORE_GROUP0_BASE
+ SMP_CORE1_OFFSET
+ STATUS0
);
139 ipi_status0_regs
[2] = (void *)
140 (SMP_CORE_GROUP0_BASE
+ SMP_CORE2_OFFSET
+ STATUS0
);
141 ipi_status0_regs
[3] = (void *)
142 (SMP_CORE_GROUP0_BASE
+ SMP_CORE3_OFFSET
+ STATUS0
);
143 ipi_status0_regs
[4] = (void *)
144 (SMP_CORE_GROUP1_BASE
+ SMP_CORE0_OFFSET
+ STATUS0
);
145 ipi_status0_regs
[5] = (void *)
146 (SMP_CORE_GROUP1_BASE
+ SMP_CORE1_OFFSET
+ STATUS0
);
147 ipi_status0_regs
[6] = (void *)
148 (SMP_CORE_GROUP1_BASE
+ SMP_CORE2_OFFSET
+ STATUS0
);
149 ipi_status0_regs
[7] = (void *)
150 (SMP_CORE_GROUP1_BASE
+ SMP_CORE3_OFFSET
+ STATUS0
);
151 ipi_status0_regs
[8] = (void *)
152 (SMP_CORE_GROUP2_BASE
+ SMP_CORE0_OFFSET
+ STATUS0
);
153 ipi_status0_regs
[9] = (void *)
154 (SMP_CORE_GROUP2_BASE
+ SMP_CORE1_OFFSET
+ STATUS0
);
155 ipi_status0_regs
[10] = (void *)
156 (SMP_CORE_GROUP2_BASE
+ SMP_CORE2_OFFSET
+ STATUS0
);
157 ipi_status0_regs
[11] = (void *)
158 (SMP_CORE_GROUP2_BASE
+ SMP_CORE3_OFFSET
+ STATUS0
);
159 ipi_status0_regs
[12] = (void *)
160 (SMP_CORE_GROUP3_BASE
+ SMP_CORE0_OFFSET
+ STATUS0
);
161 ipi_status0_regs
[13] = (void *)
162 (SMP_CORE_GROUP3_BASE
+ SMP_CORE1_OFFSET
+ STATUS0
);
163 ipi_status0_regs
[14] = (void *)
164 (SMP_CORE_GROUP3_BASE
+ SMP_CORE2_OFFSET
+ STATUS0
);
165 ipi_status0_regs
[15] = (void *)
166 (SMP_CORE_GROUP3_BASE
+ SMP_CORE3_OFFSET
+ STATUS0
);
169 static void ipi_en0_regs_init(void)
171 ipi_en0_regs
[0] = (void *)
172 (SMP_CORE_GROUP0_BASE
+ SMP_CORE0_OFFSET
+ EN0
);
173 ipi_en0_regs
[1] = (void *)
174 (SMP_CORE_GROUP0_BASE
+ SMP_CORE1_OFFSET
+ EN0
);
175 ipi_en0_regs
[2] = (void *)
176 (SMP_CORE_GROUP0_BASE
+ SMP_CORE2_OFFSET
+ EN0
);
177 ipi_en0_regs
[3] = (void *)
178 (SMP_CORE_GROUP0_BASE
+ SMP_CORE3_OFFSET
+ EN0
);
179 ipi_en0_regs
[4] = (void *)
180 (SMP_CORE_GROUP1_BASE
+ SMP_CORE0_OFFSET
+ EN0
);
181 ipi_en0_regs
[5] = (void *)
182 (SMP_CORE_GROUP1_BASE
+ SMP_CORE1_OFFSET
+ EN0
);
183 ipi_en0_regs
[6] = (void *)
184 (SMP_CORE_GROUP1_BASE
+ SMP_CORE2_OFFSET
+ EN0
);
185 ipi_en0_regs
[7] = (void *)
186 (SMP_CORE_GROUP1_BASE
+ SMP_CORE3_OFFSET
+ EN0
);
187 ipi_en0_regs
[8] = (void *)
188 (SMP_CORE_GROUP2_BASE
+ SMP_CORE0_OFFSET
+ EN0
);
189 ipi_en0_regs
[9] = (void *)
190 (SMP_CORE_GROUP2_BASE
+ SMP_CORE1_OFFSET
+ EN0
);
191 ipi_en0_regs
[10] = (void *)
192 (SMP_CORE_GROUP2_BASE
+ SMP_CORE2_OFFSET
+ EN0
);
193 ipi_en0_regs
[11] = (void *)
194 (SMP_CORE_GROUP2_BASE
+ SMP_CORE3_OFFSET
+ EN0
);
195 ipi_en0_regs
[12] = (void *)
196 (SMP_CORE_GROUP3_BASE
+ SMP_CORE0_OFFSET
+ EN0
);
197 ipi_en0_regs
[13] = (void *)
198 (SMP_CORE_GROUP3_BASE
+ SMP_CORE1_OFFSET
+ EN0
);
199 ipi_en0_regs
[14] = (void *)
200 (SMP_CORE_GROUP3_BASE
+ SMP_CORE2_OFFSET
+ EN0
);
201 ipi_en0_regs
[15] = (void *)
202 (SMP_CORE_GROUP3_BASE
+ SMP_CORE3_OFFSET
+ EN0
);
205 static void ipi_mailbox_buf_init(void)
207 ipi_mailbox_buf
[0] = (void *)
208 (SMP_CORE_GROUP0_BASE
+ SMP_CORE0_OFFSET
+ BUF
);
209 ipi_mailbox_buf
[1] = (void *)
210 (SMP_CORE_GROUP0_BASE
+ SMP_CORE1_OFFSET
+ BUF
);
211 ipi_mailbox_buf
[2] = (void *)
212 (SMP_CORE_GROUP0_BASE
+ SMP_CORE2_OFFSET
+ BUF
);
213 ipi_mailbox_buf
[3] = (void *)
214 (SMP_CORE_GROUP0_BASE
+ SMP_CORE3_OFFSET
+ BUF
);
215 ipi_mailbox_buf
[4] = (void *)
216 (SMP_CORE_GROUP1_BASE
+ SMP_CORE0_OFFSET
+ BUF
);
217 ipi_mailbox_buf
[5] = (void *)
218 (SMP_CORE_GROUP1_BASE
+ SMP_CORE1_OFFSET
+ BUF
);
219 ipi_mailbox_buf
[6] = (void *)
220 (SMP_CORE_GROUP1_BASE
+ SMP_CORE2_OFFSET
+ BUF
);
221 ipi_mailbox_buf
[7] = (void *)
222 (SMP_CORE_GROUP1_BASE
+ SMP_CORE3_OFFSET
+ BUF
);
223 ipi_mailbox_buf
[8] = (void *)
224 (SMP_CORE_GROUP2_BASE
+ SMP_CORE0_OFFSET
+ BUF
);
225 ipi_mailbox_buf
[9] = (void *)
226 (SMP_CORE_GROUP2_BASE
+ SMP_CORE1_OFFSET
+ BUF
);
227 ipi_mailbox_buf
[10] = (void *)
228 (SMP_CORE_GROUP2_BASE
+ SMP_CORE2_OFFSET
+ BUF
);
229 ipi_mailbox_buf
[11] = (void *)
230 (SMP_CORE_GROUP2_BASE
+ SMP_CORE3_OFFSET
+ BUF
);
231 ipi_mailbox_buf
[12] = (void *)
232 (SMP_CORE_GROUP3_BASE
+ SMP_CORE0_OFFSET
+ BUF
);
233 ipi_mailbox_buf
[13] = (void *)
234 (SMP_CORE_GROUP3_BASE
+ SMP_CORE1_OFFSET
+ BUF
);
235 ipi_mailbox_buf
[14] = (void *)
236 (SMP_CORE_GROUP3_BASE
+ SMP_CORE2_OFFSET
+ BUF
);
237 ipi_mailbox_buf
[15] = (void *)
238 (SMP_CORE_GROUP3_BASE
+ SMP_CORE3_OFFSET
+ BUF
);
242 * Simple enough, just poke the appropriate ipi register
244 static void loongson3_send_ipi_single(int cpu
, unsigned int action
)
246 loongson3_ipi_write32((u32
)action
, ipi_set0_regs
[cpu_logical_map(cpu
)]);
250 loongson3_send_ipi_mask(const struct cpumask
*mask
, unsigned int action
)
254 for_each_cpu(i
, mask
)
255 loongson3_ipi_write32((u32
)action
, ipi_set0_regs
[cpu_logical_map(i
)]);
258 #define IPI_IRQ_OFFSET 6
260 void loongson3_send_irq_by_ipi(int cpu
, int irqs
)
262 loongson3_ipi_write32(irqs
<< IPI_IRQ_OFFSET
, ipi_set0_regs
[cpu_logical_map(cpu
)]);
265 void loongson3_ipi_interrupt(struct pt_regs
*regs
)
267 int i
, cpu
= smp_processor_id();
268 unsigned int action
, c0count
, irqs
;
270 /* Load the ipi register to figure out what we're supposed to do */
271 action
= loongson3_ipi_read32(ipi_status0_regs
[cpu_logical_map(cpu
)]);
272 irqs
= action
>> IPI_IRQ_OFFSET
;
274 /* Clear the ipi register to clear the interrupt */
275 loongson3_ipi_write32((u32
)action
, ipi_clear0_regs
[cpu_logical_map(cpu
)]);
277 if (action
& SMP_RESCHEDULE_YOURSELF
)
280 if (action
& SMP_CALL_FUNCTION
) {
282 generic_smp_call_function_interrupt();
286 if (action
& SMP_ASK_C0COUNT
) {
288 c0count
= read_c0_count();
289 c0count
= c0count
? c0count
: 1;
290 for (i
= 1; i
< nr_cpu_ids
; i
++)
291 core0_c0count
[i
] = c0count
;
292 __wbflush(); /* Let others see the result ASAP */
297 while ((irq
= ffs(irqs
))) {
299 irqs
&= ~(1<<(irq
-1));
304 #define MAX_LOOPS 800
306 * SMP init and finish on secondary CPUs
308 static void loongson3_init_secondary(void)
312 unsigned int cpu
= smp_processor_id();
313 unsigned int imask
= STATUSF_IP7
| STATUSF_IP6
|
314 STATUSF_IP3
| STATUSF_IP2
;
316 /* Set interrupt mask, but don't enable */
317 change_c0_status(ST0_IM
, imask
);
319 for (i
= 0; i
< num_possible_cpus(); i
++)
320 loongson3_ipi_write32(0xffffffff, ipi_en0_regs
[cpu_logical_map(i
)]);
322 per_cpu(cpu_state
, cpu
) = CPU_ONLINE
;
323 cpu_set_core(&cpu_data
[cpu
],
324 cpu_logical_map(cpu
) % loongson_sysconf
.cores_per_package
);
325 cpu_data
[cpu
].package
=
326 cpu_logical_map(cpu
) / loongson_sysconf
.cores_per_package
;
329 core0_c0count
[cpu
] = 0;
330 loongson3_send_ipi_single(0, SMP_ASK_C0COUNT
);
331 while (!core0_c0count
[cpu
]) {
338 if (cpu_data
[cpu
].package
)
339 initcount
= core0_c0count
[cpu
] + i
;
340 else /* Local access is faster for loops */
341 initcount
= core0_c0count
[cpu
] + i
/2;
343 write_c0_count(initcount
);
346 static void loongson3_smp_finish(void)
348 int cpu
= smp_processor_id();
350 write_c0_compare(read_c0_count() + mips_hpt_frequency
/HZ
);
352 loongson3_ipi_write64(0,
353 ipi_mailbox_buf
[cpu_logical_map(cpu
)] + 0x0);
354 pr_info("CPU#%d finished, CP0_ST=%x\n",
355 smp_processor_id(), read_c0_status());
358 static void __init
loongson3_smp_setup(void)
360 int i
= 0, num
= 0; /* i: physical id, num: logical id */
362 init_cpu_possible(cpu_none_mask
);
364 /* For unified kernel, NR_CPUS is the maximum possible value,
365 * loongson_sysconf.nr_cpus is the really present value */
366 while (i
< loongson_sysconf
.nr_cpus
) {
367 if (loongson_sysconf
.reserved_cpus_mask
& (1<<i
)) {
368 /* Reserved physical CPU cores */
369 __cpu_number_map
[i
] = -1;
371 __cpu_number_map
[i
] = num
;
372 __cpu_logical_map
[num
] = i
;
373 set_cpu_possible(num
, true);
378 pr_info("Detected %i available CPU(s)\n", num
);
380 while (num
< loongson_sysconf
.nr_cpus
) {
381 __cpu_logical_map
[num
] = -1;
385 ipi_set0_regs_init();
386 ipi_clear0_regs_init();
387 ipi_status0_regs_init();
389 ipi_mailbox_buf_init();
390 cpu_set_core(&cpu_data
[0],
391 cpu_logical_map(0) % loongson_sysconf
.cores_per_package
);
392 cpu_data
[0].package
= cpu_logical_map(0) / loongson_sysconf
.cores_per_package
;
395 static void __init
loongson3_prepare_cpus(unsigned int max_cpus
)
397 init_cpu_present(cpu_possible_mask
);
398 per_cpu(cpu_state
, smp_processor_id()) = CPU_ONLINE
;
402 * Setup the PC, SP, and GP of a secondary processor and start it runing!
404 static int loongson3_boot_secondary(int cpu
, struct task_struct
*idle
)
406 unsigned long startargs
[4];
408 pr_info("Booting CPU#%d...\n", cpu
);
410 /* startargs[] are initial PC, SP and GP for secondary CPU */
411 startargs
[0] = (unsigned long)&smp_bootstrap
;
412 startargs
[1] = (unsigned long)__KSTK_TOS(idle
);
413 startargs
[2] = (unsigned long)task_thread_info(idle
);
416 pr_debug("CPU#%d, func_pc=%lx, sp=%lx, gp=%lx\n",
417 cpu
, startargs
[0], startargs
[1], startargs
[2]);
419 loongson3_ipi_write64(startargs
[3],
420 ipi_mailbox_buf
[cpu_logical_map(cpu
)] + 0x18);
421 loongson3_ipi_write64(startargs
[2],
422 ipi_mailbox_buf
[cpu_logical_map(cpu
)] + 0x10);
423 loongson3_ipi_write64(startargs
[1],
424 ipi_mailbox_buf
[cpu_logical_map(cpu
)] + 0x8);
425 loongson3_ipi_write64(startargs
[0],
426 ipi_mailbox_buf
[cpu_logical_map(cpu
)] + 0x0);
430 #ifdef CONFIG_HOTPLUG_CPU
432 static int loongson3_cpu_disable(void)
435 unsigned int cpu
= smp_processor_id();
440 set_cpu_online(cpu
, false);
441 calculate_cpu_foreign_map();
442 local_irq_save(flags
);
444 local_irq_restore(flags
);
445 local_flush_tlb_all();
451 static void loongson3_cpu_die(unsigned int cpu
)
453 while (per_cpu(cpu_state
, cpu
) != CPU_DEAD
)
459 /* To shutdown a core in Loongson 3, the target core should go to CKSEG1 and
460 * flush all L1 entries at first. Then, another core (usually Core 0) can
461 * safely disable the clock of the target core. loongson3_play_dead() is
462 * called via CKSEG1 (uncached and unmmaped) */
463 static void loongson3a_r1_play_dead(int *state_addr
)
466 register long cpuid
, core
, node
, count
;
467 register void *addr
, *base
, *initfunc
;
469 __asm__
__volatile__(
472 " li %[addr], 0x80000000 \n" /* KSEG0 */
473 "1: cache 0, 0(%[addr]) \n" /* flush L1 ICache */
474 " cache 0, 1(%[addr]) \n"
475 " cache 0, 2(%[addr]) \n"
476 " cache 0, 3(%[addr]) \n"
477 " cache 1, 0(%[addr]) \n" /* flush L1 DCache */
478 " cache 1, 1(%[addr]) \n"
479 " cache 1, 2(%[addr]) \n"
480 " cache 1, 3(%[addr]) \n"
481 " addiu %[sets], %[sets], -1 \n"
482 " bnez %[sets], 1b \n"
483 " addiu %[addr], %[addr], 0x20 \n"
484 " li %[val], 0x7 \n" /* *state_addr = CPU_DEAD; */
485 " sw %[val], (%[state_addr]) \n"
487 " cache 21, (%[state_addr]) \n" /* flush entry of *state_addr */
489 : [addr
] "=&r" (addr
), [val
] "=&r" (val
)
490 : [state_addr
] "r" (state_addr
),
491 [sets
] "r" (cpu_data
[smp_processor_id()].dcache
.sets
));
493 __asm__
__volatile__(
497 " mfc0 %[cpuid], $15, 1 \n"
498 " andi %[cpuid], 0x3ff \n"
499 " dli %[base], 0x900000003ff01000 \n"
500 " andi %[core], %[cpuid], 0x3 \n"
501 " sll %[core], 8 \n" /* get core id */
502 " or %[base], %[base], %[core] \n"
503 " andi %[node], %[cpuid], 0xc \n"
504 " dsll %[node], 42 \n" /* get node id */
505 " or %[base], %[base], %[node] \n"
506 "1: li %[count], 0x100 \n" /* wait for init loop */
507 "2: bnez %[count], 2b \n" /* limit mailbox access */
508 " addiu %[count], -1 \n"
509 " ld %[initfunc], 0x20(%[base]) \n" /* get PC via mailbox */
510 " beqz %[initfunc], 1b \n"
512 " ld $sp, 0x28(%[base]) \n" /* get SP via mailbox */
513 " ld $gp, 0x30(%[base]) \n" /* get GP via mailbox */
514 " ld $a1, 0x38(%[base]) \n"
515 " jr %[initfunc] \n" /* jump to initial PC */
518 : [core
] "=&r" (core
), [node
] "=&r" (node
),
519 [base
] "=&r" (base
), [cpuid
] "=&r" (cpuid
),
520 [count
] "=&r" (count
), [initfunc
] "=&r" (initfunc
)
525 static void loongson3a_r2r3_play_dead(int *state_addr
)
528 register long cpuid
, core
, node
, count
;
529 register void *addr
, *base
, *initfunc
;
531 __asm__
__volatile__(
534 " li %[addr], 0x80000000 \n" /* KSEG0 */
535 "1: cache 0, 0(%[addr]) \n" /* flush L1 ICache */
536 " cache 0, 1(%[addr]) \n"
537 " cache 0, 2(%[addr]) \n"
538 " cache 0, 3(%[addr]) \n"
539 " cache 1, 0(%[addr]) \n" /* flush L1 DCache */
540 " cache 1, 1(%[addr]) \n"
541 " cache 1, 2(%[addr]) \n"
542 " cache 1, 3(%[addr]) \n"
543 " addiu %[sets], %[sets], -1 \n"
544 " bnez %[sets], 1b \n"
545 " addiu %[addr], %[addr], 0x40 \n"
546 " li %[addr], 0x80000000 \n" /* KSEG0 */
547 "2: cache 2, 0(%[addr]) \n" /* flush L1 VCache */
548 " cache 2, 1(%[addr]) \n"
549 " cache 2, 2(%[addr]) \n"
550 " cache 2, 3(%[addr]) \n"
551 " cache 2, 4(%[addr]) \n"
552 " cache 2, 5(%[addr]) \n"
553 " cache 2, 6(%[addr]) \n"
554 " cache 2, 7(%[addr]) \n"
555 " cache 2, 8(%[addr]) \n"
556 " cache 2, 9(%[addr]) \n"
557 " cache 2, 10(%[addr]) \n"
558 " cache 2, 11(%[addr]) \n"
559 " cache 2, 12(%[addr]) \n"
560 " cache 2, 13(%[addr]) \n"
561 " cache 2, 14(%[addr]) \n"
562 " cache 2, 15(%[addr]) \n"
563 " addiu %[vsets], %[vsets], -1 \n"
564 " bnez %[vsets], 2b \n"
565 " addiu %[addr], %[addr], 0x40 \n"
566 " li %[val], 0x7 \n" /* *state_addr = CPU_DEAD; */
567 " sw %[val], (%[state_addr]) \n"
569 " cache 21, (%[state_addr]) \n" /* flush entry of *state_addr */
571 : [addr
] "=&r" (addr
), [val
] "=&r" (val
)
572 : [state_addr
] "r" (state_addr
),
573 [sets
] "r" (cpu_data
[smp_processor_id()].dcache
.sets
),
574 [vsets
] "r" (cpu_data
[smp_processor_id()].vcache
.sets
));
576 __asm__
__volatile__(
580 " mfc0 %[cpuid], $15, 1 \n"
581 " andi %[cpuid], 0x3ff \n"
582 " dli %[base], 0x900000003ff01000 \n"
583 " andi %[core], %[cpuid], 0x3 \n"
584 " sll %[core], 8 \n" /* get core id */
585 " or %[base], %[base], %[core] \n"
586 " andi %[node], %[cpuid], 0xc \n"
587 " dsll %[node], 42 \n" /* get node id */
588 " or %[base], %[base], %[node] \n"
589 "1: li %[count], 0x100 \n" /* wait for init loop */
590 "2: bnez %[count], 2b \n" /* limit mailbox access */
591 " addiu %[count], -1 \n"
592 " ld %[initfunc], 0x20(%[base]) \n" /* get PC via mailbox */
593 " beqz %[initfunc], 1b \n"
595 " ld $sp, 0x28(%[base]) \n" /* get SP via mailbox */
596 " ld $gp, 0x30(%[base]) \n" /* get GP via mailbox */
597 " ld $a1, 0x38(%[base]) \n"
598 " jr %[initfunc] \n" /* jump to initial PC */
601 : [core
] "=&r" (core
), [node
] "=&r" (node
),
602 [base
] "=&r" (base
), [cpuid
] "=&r" (cpuid
),
603 [count
] "=&r" (count
), [initfunc
] "=&r" (initfunc
)
608 static void loongson3b_play_dead(int *state_addr
)
611 register long cpuid
, core
, node
, count
;
612 register void *addr
, *base
, *initfunc
;
614 __asm__
__volatile__(
617 " li %[addr], 0x80000000 \n" /* KSEG0 */
618 "1: cache 0, 0(%[addr]) \n" /* flush L1 ICache */
619 " cache 0, 1(%[addr]) \n"
620 " cache 0, 2(%[addr]) \n"
621 " cache 0, 3(%[addr]) \n"
622 " cache 1, 0(%[addr]) \n" /* flush L1 DCache */
623 " cache 1, 1(%[addr]) \n"
624 " cache 1, 2(%[addr]) \n"
625 " cache 1, 3(%[addr]) \n"
626 " addiu %[sets], %[sets], -1 \n"
627 " bnez %[sets], 1b \n"
628 " addiu %[addr], %[addr], 0x20 \n"
629 " li %[val], 0x7 \n" /* *state_addr = CPU_DEAD; */
630 " sw %[val], (%[state_addr]) \n"
632 " cache 21, (%[state_addr]) \n" /* flush entry of *state_addr */
634 : [addr
] "=&r" (addr
), [val
] "=&r" (val
)
635 : [state_addr
] "r" (state_addr
),
636 [sets
] "r" (cpu_data
[smp_processor_id()].dcache
.sets
));
638 __asm__
__volatile__(
642 " mfc0 %[cpuid], $15, 1 \n"
643 " andi %[cpuid], 0x3ff \n"
644 " dli %[base], 0x900000003ff01000 \n"
645 " andi %[core], %[cpuid], 0x3 \n"
646 " sll %[core], 8 \n" /* get core id */
647 " or %[base], %[base], %[core] \n"
648 " andi %[node], %[cpuid], 0xc \n"
649 " dsll %[node], 42 \n" /* get node id */
650 " or %[base], %[base], %[node] \n"
651 " dsrl %[node], 30 \n" /* 15:14 */
652 " or %[base], %[base], %[node] \n"
653 "1: li %[count], 0x100 \n" /* wait for init loop */
654 "2: bnez %[count], 2b \n" /* limit mailbox access */
655 " addiu %[count], -1 \n"
656 " ld %[initfunc], 0x20(%[base]) \n" /* get PC via mailbox */
657 " beqz %[initfunc], 1b \n"
659 " ld $sp, 0x28(%[base]) \n" /* get SP via mailbox */
660 " ld $gp, 0x30(%[base]) \n" /* get GP via mailbox */
661 " ld $a1, 0x38(%[base]) \n"
662 " jr %[initfunc] \n" /* jump to initial PC */
665 : [core
] "=&r" (core
), [node
] "=&r" (node
),
666 [base
] "=&r" (base
), [cpuid
] "=&r" (cpuid
),
667 [count
] "=&r" (count
), [initfunc
] "=&r" (initfunc
)
675 unsigned int cpu
= smp_processor_id();
676 void (*play_dead_at_ckseg1
)(int *);
679 switch (read_c0_prid() & PRID_REV_MASK
) {
680 case PRID_REV_LOONGSON3A_R1
:
682 play_dead_at_ckseg1
=
683 (void *)CKSEG1ADDR((unsigned long)loongson3a_r1_play_dead
);
685 case PRID_REV_LOONGSON3A_R2_0
:
686 case PRID_REV_LOONGSON3A_R2_1
:
687 case PRID_REV_LOONGSON3A_R3_0
:
688 case PRID_REV_LOONGSON3A_R3_1
:
689 play_dead_at_ckseg1
=
690 (void *)CKSEG1ADDR((unsigned long)loongson3a_r2r3_play_dead
);
692 case PRID_REV_LOONGSON3B_R1
:
693 case PRID_REV_LOONGSON3B_R2
:
694 play_dead_at_ckseg1
=
695 (void *)CKSEG1ADDR((unsigned long)loongson3b_play_dead
);
698 state_addr
= &per_cpu(cpu_state
, cpu
);
700 play_dead_at_ckseg1(state_addr
);
703 static int loongson3_disable_clock(unsigned int cpu
)
705 uint64_t core_id
= cpu_core(&cpu_data
[cpu
]);
706 uint64_t package_id
= cpu_data
[cpu
].package
;
708 if ((read_c0_prid() & PRID_REV_MASK
) == PRID_REV_LOONGSON3A_R1
) {
709 LOONGSON_CHIPCFG(package_id
) &= ~(1 << (12 + core_id
));
711 if (!(loongson_sysconf
.workarounds
& WORKAROUND_CPUHOTPLUG
))
712 LOONGSON_FREQCTRL(package_id
) &= ~(1 << (core_id
* 4 + 3));
717 static int loongson3_enable_clock(unsigned int cpu
)
719 uint64_t core_id
= cpu_core(&cpu_data
[cpu
]);
720 uint64_t package_id
= cpu_data
[cpu
].package
;
722 if ((read_c0_prid() & PRID_REV_MASK
) == PRID_REV_LOONGSON3A_R1
) {
723 LOONGSON_CHIPCFG(package_id
) |= 1 << (12 + core_id
);
725 if (!(loongson_sysconf
.workarounds
& WORKAROUND_CPUHOTPLUG
))
726 LOONGSON_FREQCTRL(package_id
) |= 1 << (core_id
* 4 + 3);
731 static int register_loongson3_notifier(void)
733 return cpuhp_setup_state_nocalls(CPUHP_MIPS_SOC_PREPARE
,
734 "mips/loongson:prepare",
735 loongson3_enable_clock
,
736 loongson3_disable_clock
);
738 early_initcall(register_loongson3_notifier
);
742 const struct plat_smp_ops loongson3_smp_ops
= {
743 .send_ipi_single
= loongson3_send_ipi_single
,
744 .send_ipi_mask
= loongson3_send_ipi_mask
,
745 .init_secondary
= loongson3_init_secondary
,
746 .smp_finish
= loongson3_smp_finish
,
747 .boot_secondary
= loongson3_boot_secondary
,
748 .smp_setup
= loongson3_smp_setup
,
749 .prepare_cpus
= loongson3_prepare_cpus
,
750 #ifdef CONFIG_HOTPLUG_CPU
751 .cpu_disable
= loongson3_cpu_disable
,
752 .cpu_die
= loongson3_cpu_die
,
755 .kexec_nonboot_cpu
= kexec_nonboot_cpu_jump
,