• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010, 2011, 2012, Lemote, Inc.
3  * Author: Chen Huacai, chenhc@lemote.com
4  *
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.
9  *
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.
14  *
15  */
16 
17 #include <linux/init.h>
18 #include <linux/cpu.h>
19 #include <linux/sched.h>
20 #include <linux/smp.h>
21 #include <linux/cpufreq.h>
22 #include <asm/processor.h>
23 #include <asm/time.h>
24 #include <asm/clock.h>
25 #include <asm/tlbflush.h>
26 #include <asm/cacheflush.h>
27 #include <loongson.h>
28 
29 #include "smp.h"
30 
31 DEFINE_PER_CPU(int, cpu_state);
32 DEFINE_PER_CPU(uint32_t, core0_c0count);
33 
34 static void *ipi_set0_regs[16];
35 static void *ipi_clear0_regs[16];
36 static void *ipi_status0_regs[16];
37 static void *ipi_en0_regs[16];
38 static void *ipi_mailbox_buf[16];
39 
40 /* read a 32bit value from ipi register */
41 #define loongson3_ipi_read32(addr) readl(addr)
42 /* read a 64bit value from ipi register */
43 #define loongson3_ipi_read64(addr) readq(addr)
44 /* write a 32bit value to ipi register */
45 #define loongson3_ipi_write32(action, addr)	\
46 	do {					\
47 		writel(action, addr);		\
48 		__wbflush();			\
49 	} while (0)
50 /* write a 64bit value to ipi register */
51 #define loongson3_ipi_write64(action, addr)	\
52 	do {					\
53 		writeq(action, addr);		\
54 		__wbflush();			\
55 	} while (0)
56 
ipi_set0_regs_init(void)57 static void ipi_set0_regs_init(void)
58 {
59 	ipi_set0_regs[0] = (void *)
60 		(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + SET0);
61 	ipi_set0_regs[1] = (void *)
62 		(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + SET0);
63 	ipi_set0_regs[2] = (void *)
64 		(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + SET0);
65 	ipi_set0_regs[3] = (void *)
66 		(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + SET0);
67 	ipi_set0_regs[4] = (void *)
68 		(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + SET0);
69 	ipi_set0_regs[5] = (void *)
70 		(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + SET0);
71 	ipi_set0_regs[6] = (void *)
72 		(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + SET0);
73 	ipi_set0_regs[7] = (void *)
74 		(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + SET0);
75 	ipi_set0_regs[8] = (void *)
76 		(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + SET0);
77 	ipi_set0_regs[9] = (void *)
78 		(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + SET0);
79 	ipi_set0_regs[10] = (void *)
80 		(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + SET0);
81 	ipi_set0_regs[11] = (void *)
82 		(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + SET0);
83 	ipi_set0_regs[12] = (void *)
84 		(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + SET0);
85 	ipi_set0_regs[13] = (void *)
86 		(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + SET0);
87 	ipi_set0_regs[14] = (void *)
88 		(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + SET0);
89 	ipi_set0_regs[15] = (void *)
90 		(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + SET0);
91 }
92 
ipi_clear0_regs_init(void)93 static void ipi_clear0_regs_init(void)
94 {
95 	ipi_clear0_regs[0] = (void *)
96 		(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + CLEAR0);
97 	ipi_clear0_regs[1] = (void *)
98 		(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + CLEAR0);
99 	ipi_clear0_regs[2] = (void *)
100 		(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + CLEAR0);
101 	ipi_clear0_regs[3] = (void *)
102 		(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + CLEAR0);
103 	ipi_clear0_regs[4] = (void *)
104 		(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + CLEAR0);
105 	ipi_clear0_regs[5] = (void *)
106 		(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + CLEAR0);
107 	ipi_clear0_regs[6] = (void *)
108 		(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + CLEAR0);
109 	ipi_clear0_regs[7] = (void *)
110 		(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + CLEAR0);
111 	ipi_clear0_regs[8] = (void *)
112 		(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + CLEAR0);
113 	ipi_clear0_regs[9] = (void *)
114 		(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + CLEAR0);
115 	ipi_clear0_regs[10] = (void *)
116 		(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + CLEAR0);
117 	ipi_clear0_regs[11] = (void *)
118 		(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + CLEAR0);
119 	ipi_clear0_regs[12] = (void *)
120 		(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + CLEAR0);
121 	ipi_clear0_regs[13] = (void *)
122 		(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + CLEAR0);
123 	ipi_clear0_regs[14] = (void *)
124 		(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + CLEAR0);
125 	ipi_clear0_regs[15] = (void *)
126 		(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + CLEAR0);
127 }
128 
ipi_status0_regs_init(void)129 static void ipi_status0_regs_init(void)
130 {
131 	ipi_status0_regs[0] = (void *)
132 		(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + STATUS0);
133 	ipi_status0_regs[1] = (void *)
134 		(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + STATUS0);
135 	ipi_status0_regs[2] = (void *)
136 		(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + STATUS0);
137 	ipi_status0_regs[3] = (void *)
138 		(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + STATUS0);
139 	ipi_status0_regs[4] = (void *)
140 		(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + STATUS0);
141 	ipi_status0_regs[5] = (void *)
142 		(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + STATUS0);
143 	ipi_status0_regs[6] = (void *)
144 		(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + STATUS0);
145 	ipi_status0_regs[7] = (void *)
146 		(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + STATUS0);
147 	ipi_status0_regs[8] = (void *)
148 		(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + STATUS0);
149 	ipi_status0_regs[9] = (void *)
150 		(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + STATUS0);
151 	ipi_status0_regs[10] = (void *)
152 		(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + STATUS0);
153 	ipi_status0_regs[11] = (void *)
154 		(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + STATUS0);
155 	ipi_status0_regs[12] = (void *)
156 		(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + STATUS0);
157 	ipi_status0_regs[13] = (void *)
158 		(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + STATUS0);
159 	ipi_status0_regs[14] = (void *)
160 		(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + STATUS0);
161 	ipi_status0_regs[15] = (void *)
162 		(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + STATUS0);
163 }
164 
ipi_en0_regs_init(void)165 static void ipi_en0_regs_init(void)
166 {
167 	ipi_en0_regs[0] = (void *)
168 		(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + EN0);
169 	ipi_en0_regs[1] = (void *)
170 		(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + EN0);
171 	ipi_en0_regs[2] = (void *)
172 		(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + EN0);
173 	ipi_en0_regs[3] = (void *)
174 		(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + EN0);
175 	ipi_en0_regs[4] = (void *)
176 		(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + EN0);
177 	ipi_en0_regs[5] = (void *)
178 		(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + EN0);
179 	ipi_en0_regs[6] = (void *)
180 		(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + EN0);
181 	ipi_en0_regs[7] = (void *)
182 		(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + EN0);
183 	ipi_en0_regs[8] = (void *)
184 		(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + EN0);
185 	ipi_en0_regs[9] = (void *)
186 		(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + EN0);
187 	ipi_en0_regs[10] = (void *)
188 		(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + EN0);
189 	ipi_en0_regs[11] = (void *)
190 		(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + EN0);
191 	ipi_en0_regs[12] = (void *)
192 		(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + EN0);
193 	ipi_en0_regs[13] = (void *)
194 		(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + EN0);
195 	ipi_en0_regs[14] = (void *)
196 		(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + EN0);
197 	ipi_en0_regs[15] = (void *)
198 		(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + EN0);
199 }
200 
ipi_mailbox_buf_init(void)201 static void ipi_mailbox_buf_init(void)
202 {
203 	ipi_mailbox_buf[0] = (void *)
204 		(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + BUF);
205 	ipi_mailbox_buf[1] = (void *)
206 		(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + BUF);
207 	ipi_mailbox_buf[2] = (void *)
208 		(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + BUF);
209 	ipi_mailbox_buf[3] = (void *)
210 		(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + BUF);
211 	ipi_mailbox_buf[4] = (void *)
212 		(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + BUF);
213 	ipi_mailbox_buf[5] = (void *)
214 		(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + BUF);
215 	ipi_mailbox_buf[6] = (void *)
216 		(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + BUF);
217 	ipi_mailbox_buf[7] = (void *)
218 		(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + BUF);
219 	ipi_mailbox_buf[8] = (void *)
220 		(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + BUF);
221 	ipi_mailbox_buf[9] = (void *)
222 		(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + BUF);
223 	ipi_mailbox_buf[10] = (void *)
224 		(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + BUF);
225 	ipi_mailbox_buf[11] = (void *)
226 		(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + BUF);
227 	ipi_mailbox_buf[12] = (void *)
228 		(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + BUF);
229 	ipi_mailbox_buf[13] = (void *)
230 		(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + BUF);
231 	ipi_mailbox_buf[14] = (void *)
232 		(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + BUF);
233 	ipi_mailbox_buf[15] = (void *)
234 		(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + BUF);
235 }
236 
237 /*
238  * Simple enough, just poke the appropriate ipi register
239  */
loongson3_send_ipi_single(int cpu,unsigned int action)240 static void loongson3_send_ipi_single(int cpu, unsigned int action)
241 {
242 	loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu]);
243 }
244 
245 static void
loongson3_send_ipi_mask(const struct cpumask * mask,unsigned int action)246 loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action)
247 {
248 	unsigned int i;
249 
250 	for_each_cpu(i, mask)
251 		loongson3_ipi_write32((u32)action, ipi_set0_regs[i]);
252 }
253 
loongson3_ipi_interrupt(struct pt_regs * regs)254 void loongson3_ipi_interrupt(struct pt_regs *regs)
255 {
256 	int i, cpu = smp_processor_id();
257 	unsigned int action, c0count;
258 
259 	/* Load the ipi register to figure out what we're supposed to do */
260 	action = loongson3_ipi_read32(ipi_status0_regs[cpu]);
261 
262 	/* Clear the ipi register to clear the interrupt */
263 	loongson3_ipi_write32((u32)action, ipi_clear0_regs[cpu]);
264 
265 	if (action & SMP_RESCHEDULE_YOURSELF)
266 		scheduler_ipi();
267 
268 	if (action & SMP_CALL_FUNCTION)
269 		smp_call_function_interrupt();
270 
271 	if (action & SMP_ASK_C0COUNT) {
272 		BUG_ON(cpu != 0);
273 		c0count = read_c0_count();
274 		for (i = 1; i < loongson_sysconf.nr_cpus; i++)
275 			per_cpu(core0_c0count, i) = c0count;
276 	}
277 }
278 
279 #define MAX_LOOPS 1111
280 /*
281  * SMP init and finish on secondary CPUs
282  */
loongson3_init_secondary(void)283 static void loongson3_init_secondary(void)
284 {
285 	int i;
286 	uint32_t initcount;
287 	unsigned int cpu = smp_processor_id();
288 	unsigned int imask = STATUSF_IP7 | STATUSF_IP6 |
289 			     STATUSF_IP3 | STATUSF_IP2;
290 
291 	/* Set interrupt mask, but don't enable */
292 	change_c0_status(ST0_IM, imask);
293 
294 	for (i = 0; i < loongson_sysconf.nr_cpus; i++)
295 		loongson3_ipi_write32(0xffffffff, ipi_en0_regs[i]);
296 
297 	cpu_data[cpu].package = cpu / loongson_sysconf.cores_per_package;
298 	cpu_data[cpu].core = cpu % loongson_sysconf.cores_per_package;
299 	per_cpu(cpu_state, cpu) = CPU_ONLINE;
300 
301 	i = 0;
302 	__this_cpu_write(core0_c0count, 0);
303 	loongson3_send_ipi_single(0, SMP_ASK_C0COUNT);
304 	while (!__this_cpu_read(core0_c0count)) {
305 		i++;
306 		cpu_relax();
307 	}
308 
309 	if (i > MAX_LOOPS)
310 		i = MAX_LOOPS;
311 	initcount = __this_cpu_read(core0_c0count) + i;
312 	write_c0_count(initcount);
313 }
314 
loongson3_smp_finish(void)315 static void loongson3_smp_finish(void)
316 {
317 	write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ);
318 	local_irq_enable();
319 	loongson3_ipi_write64(0,
320 			(void *)(ipi_mailbox_buf[smp_processor_id()]+0x0));
321 	pr_info("CPU#%d finished, CP0_ST=%x\n",
322 			smp_processor_id(), read_c0_status());
323 }
324 
loongson3_smp_setup(void)325 static void __init loongson3_smp_setup(void)
326 {
327 	int i, num;
328 
329 	init_cpu_possible(cpu_none_mask);
330 	set_cpu_possible(0, true);
331 
332 	__cpu_number_map[0] = 0;
333 	__cpu_logical_map[0] = 0;
334 
335 	/* For unified kernel, NR_CPUS is the maximum possible value,
336 	 * loongson_sysconf.nr_cpus is the really present value */
337 	for (i = 1, num = 0; i < loongson_sysconf.nr_cpus; i++) {
338 		set_cpu_possible(i, true);
339 		__cpu_number_map[i] = ++num;
340 		__cpu_logical_map[num] = i;
341 	}
342 	ipi_set0_regs_init();
343 	ipi_clear0_regs_init();
344 	ipi_status0_regs_init();
345 	ipi_en0_regs_init();
346 	ipi_mailbox_buf_init();
347 	pr_info("Detected %i available secondary CPU(s)\n", num);
348 }
349 
loongson3_prepare_cpus(unsigned int max_cpus)350 static void __init loongson3_prepare_cpus(unsigned int max_cpus)
351 {
352 	init_cpu_present(cpu_possible_mask);
353 	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
354 }
355 
356 /*
357  * Setup the PC, SP, and GP of a secondary processor and start it runing!
358  */
loongson3_boot_secondary(int cpu,struct task_struct * idle)359 static void loongson3_boot_secondary(int cpu, struct task_struct *idle)
360 {
361 	unsigned long startargs[4];
362 
363 	pr_info("Booting CPU#%d...\n", cpu);
364 
365 	/* startargs[] are initial PC, SP and GP for secondary CPU */
366 	startargs[0] = (unsigned long)&smp_bootstrap;
367 	startargs[1] = (unsigned long)__KSTK_TOS(idle);
368 	startargs[2] = (unsigned long)task_thread_info(idle);
369 	startargs[3] = 0;
370 
371 	pr_debug("CPU#%d, func_pc=%lx, sp=%lx, gp=%lx\n",
372 			cpu, startargs[0], startargs[1], startargs[2]);
373 
374 	loongson3_ipi_write64(startargs[3], (void *)(ipi_mailbox_buf[cpu]+0x18));
375 	loongson3_ipi_write64(startargs[2], (void *)(ipi_mailbox_buf[cpu]+0x10));
376 	loongson3_ipi_write64(startargs[1], (void *)(ipi_mailbox_buf[cpu]+0x8));
377 	loongson3_ipi_write64(startargs[0], (void *)(ipi_mailbox_buf[cpu]+0x0));
378 }
379 
380 #ifdef CONFIG_HOTPLUG_CPU
381 
loongson3_cpu_disable(void)382 static int loongson3_cpu_disable(void)
383 {
384 	unsigned long flags;
385 	unsigned int cpu = smp_processor_id();
386 
387 	if (cpu == 0)
388 		return -EBUSY;
389 
390 	set_cpu_online(cpu, false);
391 	cpu_clear(cpu, cpu_callin_map);
392 	local_irq_save(flags);
393 	fixup_irqs();
394 	local_irq_restore(flags);
395 	flush_cache_all();
396 	local_flush_tlb_all();
397 
398 	return 0;
399 }
400 
401 
loongson3_cpu_die(unsigned int cpu)402 static void loongson3_cpu_die(unsigned int cpu)
403 {
404 	while (per_cpu(cpu_state, cpu) != CPU_DEAD)
405 		cpu_relax();
406 
407 	mb();
408 }
409 
410 /* To shutdown a core in Loongson 3, the target core should go to CKSEG1 and
411  * flush all L1 entries at first. Then, another core (usually Core 0) can
412  * safely disable the clock of the target core. loongson3_play_dead() is
413  * called via CKSEG1 (uncached and unmmaped) */
loongson3a_play_dead(int * state_addr)414 static void loongson3a_play_dead(int *state_addr)
415 {
416 	register int val;
417 	register long cpuid, core, node, count;
418 	register void *addr, *base, *initfunc;
419 
420 	__asm__ __volatile__(
421 		"   .set push                     \n"
422 		"   .set noreorder                \n"
423 		"   li %[addr], 0x80000000        \n" /* KSEG0 */
424 		"1: cache 0, 0(%[addr])           \n" /* flush L1 ICache */
425 		"   cache 0, 1(%[addr])           \n"
426 		"   cache 0, 2(%[addr])           \n"
427 		"   cache 0, 3(%[addr])           \n"
428 		"   cache 1, 0(%[addr])           \n" /* flush L1 DCache */
429 		"   cache 1, 1(%[addr])           \n"
430 		"   cache 1, 2(%[addr])           \n"
431 		"   cache 1, 3(%[addr])           \n"
432 		"   addiu %[sets], %[sets], -1    \n"
433 		"   bnez  %[sets], 1b             \n"
434 		"   addiu %[addr], %[addr], 0x20  \n"
435 		"   li    %[val], 0x7             \n" /* *state_addr = CPU_DEAD; */
436 		"   sw    %[val], (%[state_addr]) \n"
437 		"   sync                          \n"
438 		"   cache 21, (%[state_addr])     \n" /* flush entry of *state_addr */
439 		"   .set pop                      \n"
440 		: [addr] "=&r" (addr), [val] "=&r" (val)
441 		: [state_addr] "r" (state_addr),
442 		  [sets] "r" (cpu_data[smp_processor_id()].dcache.sets));
443 
444 	__asm__ __volatile__(
445 		"   .set push                         \n"
446 		"   .set noreorder                    \n"
447 		"   .set mips64                       \n"
448 		"   mfc0  %[cpuid], $15, 1            \n"
449 		"   andi  %[cpuid], 0x3ff             \n"
450 		"   dli   %[base], 0x900000003ff01000 \n"
451 		"   andi  %[core], %[cpuid], 0x3      \n"
452 		"   sll   %[core], 8                  \n" /* get core id */
453 		"   or    %[base], %[base], %[core]   \n"
454 		"   andi  %[node], %[cpuid], 0xc      \n"
455 		"   dsll  %[node], 42                 \n" /* get node id */
456 		"   or    %[base], %[base], %[node]   \n"
457 		"1: li    %[count], 0x100             \n" /* wait for init loop */
458 		"2: bnez  %[count], 2b                \n" /* limit mailbox access */
459 		"   addiu %[count], -1                \n"
460 		"   ld    %[initfunc], 0x20(%[base])  \n" /* get PC via mailbox */
461 		"   beqz  %[initfunc], 1b             \n"
462 		"   nop                               \n"
463 		"   ld    $sp, 0x28(%[base])          \n" /* get SP via mailbox */
464 		"   ld    $gp, 0x30(%[base])          \n" /* get GP via mailbox */
465 		"   ld    $a1, 0x38(%[base])          \n"
466 		"   jr    %[initfunc]                 \n" /* jump to initial PC */
467 		"   nop                               \n"
468 		"   .set pop                          \n"
469 		: [core] "=&r" (core), [node] "=&r" (node),
470 		  [base] "=&r" (base), [cpuid] "=&r" (cpuid),
471 		  [count] "=&r" (count), [initfunc] "=&r" (initfunc)
472 		: /* No Input */
473 		: "a1");
474 }
475 
loongson3b_play_dead(int * state_addr)476 static void loongson3b_play_dead(int *state_addr)
477 {
478 	register int val;
479 	register long cpuid, core, node, count;
480 	register void *addr, *base, *initfunc;
481 
482 	__asm__ __volatile__(
483 		"   .set push                     \n"
484 		"   .set noreorder                \n"
485 		"   li %[addr], 0x80000000        \n" /* KSEG0 */
486 		"1: cache 0, 0(%[addr])           \n" /* flush L1 ICache */
487 		"   cache 0, 1(%[addr])           \n"
488 		"   cache 0, 2(%[addr])           \n"
489 		"   cache 0, 3(%[addr])           \n"
490 		"   cache 1, 0(%[addr])           \n" /* flush L1 DCache */
491 		"   cache 1, 1(%[addr])           \n"
492 		"   cache 1, 2(%[addr])           \n"
493 		"   cache 1, 3(%[addr])           \n"
494 		"   addiu %[sets], %[sets], -1    \n"
495 		"   bnez  %[sets], 1b             \n"
496 		"   addiu %[addr], %[addr], 0x20  \n"
497 		"   li    %[val], 0x7             \n" /* *state_addr = CPU_DEAD; */
498 		"   sw    %[val], (%[state_addr]) \n"
499 		"   sync                          \n"
500 		"   cache 21, (%[state_addr])     \n" /* flush entry of *state_addr */
501 		"   .set pop                      \n"
502 		: [addr] "=&r" (addr), [val] "=&r" (val)
503 		: [state_addr] "r" (state_addr),
504 		  [sets] "r" (cpu_data[smp_processor_id()].dcache.sets));
505 
506 	__asm__ __volatile__(
507 		"   .set push                         \n"
508 		"   .set noreorder                    \n"
509 		"   .set mips64                       \n"
510 		"   mfc0  %[cpuid], $15, 1            \n"
511 		"   andi  %[cpuid], 0x3ff             \n"
512 		"   dli   %[base], 0x900000003ff01000 \n"
513 		"   andi  %[core], %[cpuid], 0x3      \n"
514 		"   sll   %[core], 8                  \n" /* get core id */
515 		"   or    %[base], %[base], %[core]   \n"
516 		"   andi  %[node], %[cpuid], 0xc      \n"
517 		"   dsll  %[node], 42                 \n" /* get node id */
518 		"   or    %[base], %[base], %[node]   \n"
519 		"   dsrl  %[node], 30                 \n" /* 15:14 */
520 		"   or    %[base], %[base], %[node]   \n"
521 		"1: li    %[count], 0x100             \n" /* wait for init loop */
522 		"2: bnez  %[count], 2b                \n" /* limit mailbox access */
523 		"   addiu %[count], -1                \n"
524 		"   ld    %[initfunc], 0x20(%[base])  \n" /* get PC via mailbox */
525 		"   beqz  %[initfunc], 1b             \n"
526 		"   nop                               \n"
527 		"   ld    $sp, 0x28(%[base])          \n" /* get SP via mailbox */
528 		"   ld    $gp, 0x30(%[base])          \n" /* get GP via mailbox */
529 		"   ld    $a1, 0x38(%[base])          \n"
530 		"   jr    %[initfunc]                 \n" /* jump to initial PC */
531 		"   nop                               \n"
532 		"   .set pop                          \n"
533 		: [core] "=&r" (core), [node] "=&r" (node),
534 		  [base] "=&r" (base), [cpuid] "=&r" (cpuid),
535 		  [count] "=&r" (count), [initfunc] "=&r" (initfunc)
536 		: /* No Input */
537 		: "a1");
538 }
539 
play_dead(void)540 void play_dead(void)
541 {
542 	int *state_addr;
543 	unsigned int cpu = smp_processor_id();
544 	void (*play_dead_at_ckseg1)(int *);
545 
546 	idle_task_exit();
547 	switch (loongson_sysconf.cputype) {
548 	case Loongson_3A:
549 	default:
550 		play_dead_at_ckseg1 =
551 			(void *)CKSEG1ADDR((unsigned long)loongson3a_play_dead);
552 		break;
553 	case Loongson_3B:
554 		play_dead_at_ckseg1 =
555 			(void *)CKSEG1ADDR((unsigned long)loongson3b_play_dead);
556 		break;
557 	}
558 	state_addr = &per_cpu(cpu_state, cpu);
559 	mb();
560 	play_dead_at_ckseg1(state_addr);
561 }
562 
loongson3_disable_clock(int cpu)563 void loongson3_disable_clock(int cpu)
564 {
565 	uint64_t core_id = cpu_data[cpu].core;
566 	uint64_t package_id = cpu_data[cpu].package;
567 
568 	if (loongson_sysconf.cputype == Loongson_3A) {
569 		LOONGSON_CHIPCFG(package_id) &= ~(1 << (12 + core_id));
570 	} else if (loongson_sysconf.cputype == Loongson_3B) {
571 		if (!cpuhotplug_workaround)
572 			LOONGSON_FREQCTRL(package_id) &= ~(1 << (core_id * 4 + 3));
573 	}
574 }
575 
loongson3_enable_clock(int cpu)576 void loongson3_enable_clock(int cpu)
577 {
578 	uint64_t core_id = cpu_data[cpu].core;
579 	uint64_t package_id = cpu_data[cpu].package;
580 
581 	if (loongson_sysconf.cputype == Loongson_3A) {
582 		LOONGSON_CHIPCFG(package_id) |= 1 << (12 + core_id);
583 	} else if (loongson_sysconf.cputype == Loongson_3B) {
584 		if (!cpuhotplug_workaround)
585 			LOONGSON_FREQCTRL(package_id) |= 1 << (core_id * 4 + 3);
586 	}
587 }
588 
589 #define CPU_POST_DEAD_FROZEN	(CPU_POST_DEAD | CPU_TASKS_FROZEN)
loongson3_cpu_callback(struct notifier_block * nfb,unsigned long action,void * hcpu)590 static int loongson3_cpu_callback(struct notifier_block *nfb,
591 	unsigned long action, void *hcpu)
592 {
593 	unsigned int cpu = (unsigned long)hcpu;
594 
595 	switch (action) {
596 	case CPU_POST_DEAD:
597 	case CPU_POST_DEAD_FROZEN:
598 		pr_info("Disable clock for CPU#%d\n", cpu);
599 		loongson3_disable_clock(cpu);
600 		break;
601 	case CPU_UP_PREPARE:
602 	case CPU_UP_PREPARE_FROZEN:
603 		pr_info("Enable clock for CPU#%d\n", cpu);
604 		loongson3_enable_clock(cpu);
605 		break;
606 	}
607 
608 	return NOTIFY_OK;
609 }
610 
register_loongson3_notifier(void)611 static int register_loongson3_notifier(void)
612 {
613 	hotcpu_notifier(loongson3_cpu_callback, 0);
614 	return 0;
615 }
616 early_initcall(register_loongson3_notifier);
617 
618 #endif
619 
620 struct plat_smp_ops loongson3_smp_ops = {
621 	.send_ipi_single = loongson3_send_ipi_single,
622 	.send_ipi_mask = loongson3_send_ipi_mask,
623 	.init_secondary = loongson3_init_secondary,
624 	.smp_finish = loongson3_smp_finish,
625 	.boot_secondary = loongson3_boot_secondary,
626 	.smp_setup = loongson3_smp_setup,
627 	.prepare_cpus = loongson3_prepare_cpus,
628 #ifdef CONFIG_HOTPLUG_CPU
629 	.cpu_disable = loongson3_cpu_disable,
630 	.cpu_die = loongson3_cpu_die,
631 #endif
632 };
633