1300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen/*
2300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen * Copyright (C) 2010, 2011, 2012, Lemote, Inc.
3300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen * Author: Chen Huacai, chenhc@lemote.com
4300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen *
5300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen * This program is free software; you can redistribute it and/or
6300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen * modify it under the terms of the GNU General Public License
7300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen * as published by the Free Software Foundation; either version 2
8300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen * of the License, or (at your option) any later version.
9300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen *
10300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen * This program is distributed in the hope that it will be useful,
11300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen * but WITHOUT ANY WARRANTY; without even the implied warranty of
12300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen * GNU General Public License for more details.
14300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen *
15300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen */
16300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
17300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen#include <linux/init.h>
18300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen#include <linux/cpu.h>
19300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen#include <linux/sched.h>
20300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen#include <linux/smp.h>
21300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen#include <linux/cpufreq.h>
22300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen#include <asm/processor.h>
23300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen#include <asm/time.h>
24300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen#include <asm/clock.h>
25300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen#include <asm/tlbflush.h>
26c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen#include <asm/cacheflush.h>
27300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen#include <loongson.h>
28300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
29300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen#include "smp.h"
30300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
31c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai ChenDEFINE_PER_CPU(int, cpu_state);
32c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai ChenDEFINE_PER_CPU(uint32_t, core0_c0count);
33c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
34e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chenstatic void *ipi_set0_regs[16];
35e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chenstatic void *ipi_clear0_regs[16];
36e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chenstatic void *ipi_status0_regs[16];
37e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chenstatic void *ipi_en0_regs[16];
38e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chenstatic void *ipi_mailbox_buf[16];
39e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen
40300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen/* read a 32bit value from ipi register */
41300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen#define loongson3_ipi_read32(addr) readl(addr)
42300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen/* read a 64bit value from ipi register */
43300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen#define loongson3_ipi_read64(addr) readq(addr)
44300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen/* write a 32bit value to ipi register */
45300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen#define loongson3_ipi_write32(action, addr)	\
46300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	do {					\
47300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen		writel(action, addr);		\
48300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen		__wbflush();			\
49300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	} while (0)
50300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen/* write a 64bit value to ipi register */
51300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen#define loongson3_ipi_write64(action, addr)	\
52300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	do {					\
53300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen		writeq(action, addr);		\
54300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen		__wbflush();			\
55300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	} while (0)
56300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
57e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chenstatic void ipi_set0_regs_init(void)
58e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen{
59e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_set0_regs[0] = (void *)
60e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + SET0);
61e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_set0_regs[1] = (void *)
62e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + SET0);
63e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_set0_regs[2] = (void *)
64e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + SET0);
65e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_set0_regs[3] = (void *)
66e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + SET0);
67e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_set0_regs[4] = (void *)
68e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + SET0);
69e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_set0_regs[5] = (void *)
70e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + SET0);
71e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_set0_regs[6] = (void *)
72e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + SET0);
73e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_set0_regs[7] = (void *)
74e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + SET0);
75e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_set0_regs[8] = (void *)
76e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + SET0);
77e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_set0_regs[9] = (void *)
78e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + SET0);
79e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_set0_regs[10] = (void *)
80e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + SET0);
81e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_set0_regs[11] = (void *)
82e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + SET0);
83e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_set0_regs[12] = (void *)
84e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + SET0);
85e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_set0_regs[13] = (void *)
86e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + SET0);
87e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_set0_regs[14] = (void *)
88e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + SET0);
89e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_set0_regs[15] = (void *)
90e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + SET0);
91e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen}
92300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
93e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chenstatic void ipi_clear0_regs_init(void)
94e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen{
95e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_clear0_regs[0] = (void *)
96e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + CLEAR0);
97e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_clear0_regs[1] = (void *)
98e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + CLEAR0);
99e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_clear0_regs[2] = (void *)
100e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + CLEAR0);
101e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_clear0_regs[3] = (void *)
102e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + CLEAR0);
103e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_clear0_regs[4] = (void *)
104e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + CLEAR0);
105e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_clear0_regs[5] = (void *)
106e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + CLEAR0);
107e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_clear0_regs[6] = (void *)
108e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + CLEAR0);
109e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_clear0_regs[7] = (void *)
110e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + CLEAR0);
111e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_clear0_regs[8] = (void *)
112e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + CLEAR0);
113e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_clear0_regs[9] = (void *)
114e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + CLEAR0);
115e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_clear0_regs[10] = (void *)
116e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + CLEAR0);
117e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_clear0_regs[11] = (void *)
118e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + CLEAR0);
119e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_clear0_regs[12] = (void *)
120e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + CLEAR0);
121e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_clear0_regs[13] = (void *)
122e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + CLEAR0);
123e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_clear0_regs[14] = (void *)
124e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + CLEAR0);
125e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_clear0_regs[15] = (void *)
126e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + CLEAR0);
127e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen}
128300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
129e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chenstatic void ipi_status0_regs_init(void)
130e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen{
131e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_status0_regs[0] = (void *)
132e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + STATUS0);
133e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_status0_regs[1] = (void *)
134e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + STATUS0);
135e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_status0_regs[2] = (void *)
136e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + STATUS0);
137e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_status0_regs[3] = (void *)
138e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + STATUS0);
139e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_status0_regs[4] = (void *)
140e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + STATUS0);
141e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_status0_regs[5] = (void *)
142e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + STATUS0);
143e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_status0_regs[6] = (void *)
144e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + STATUS0);
145e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_status0_regs[7] = (void *)
146e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + STATUS0);
147e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_status0_regs[8] = (void *)
148e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + STATUS0);
149e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_status0_regs[9] = (void *)
150e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + STATUS0);
151e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_status0_regs[10] = (void *)
152e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + STATUS0);
153e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_status0_regs[11] = (void *)
154e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + STATUS0);
155e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_status0_regs[12] = (void *)
156e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + STATUS0);
157e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_status0_regs[13] = (void *)
158e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + STATUS0);
159e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_status0_regs[14] = (void *)
160e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + STATUS0);
161e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_status0_regs[15] = (void *)
162e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + STATUS0);
163e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen}
164300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
165e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chenstatic void ipi_en0_regs_init(void)
166e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen{
167e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_en0_regs[0] = (void *)
168e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + EN0);
169e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_en0_regs[1] = (void *)
170e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + EN0);
171e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_en0_regs[2] = (void *)
172e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + EN0);
173e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_en0_regs[3] = (void *)
174e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + EN0);
175e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_en0_regs[4] = (void *)
176e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + EN0);
177e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_en0_regs[5] = (void *)
178e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + EN0);
179e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_en0_regs[6] = (void *)
180e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + EN0);
181e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_en0_regs[7] = (void *)
182e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + EN0);
183e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_en0_regs[8] = (void *)
184e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + EN0);
185e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_en0_regs[9] = (void *)
186e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + EN0);
187e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_en0_regs[10] = (void *)
188e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + EN0);
189e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_en0_regs[11] = (void *)
190e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + EN0);
191e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_en0_regs[12] = (void *)
192e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + EN0);
193e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_en0_regs[13] = (void *)
194e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + EN0);
195e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_en0_regs[14] = (void *)
196e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + EN0);
197e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_en0_regs[15] = (void *)
198e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + EN0);
199e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen}
200300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
201e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chenstatic void ipi_mailbox_buf_init(void)
202e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen{
203e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_mailbox_buf[0] = (void *)
204e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + BUF);
205e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_mailbox_buf[1] = (void *)
206e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + BUF);
207e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_mailbox_buf[2] = (void *)
208e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + BUF);
209e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_mailbox_buf[3] = (void *)
210e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + BUF);
211e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_mailbox_buf[4] = (void *)
212e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + BUF);
213e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_mailbox_buf[5] = (void *)
214e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + BUF);
215e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_mailbox_buf[6] = (void *)
216e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + BUF);
217e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_mailbox_buf[7] = (void *)
218e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + BUF);
219e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_mailbox_buf[8] = (void *)
220e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + BUF);
221e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_mailbox_buf[9] = (void *)
222e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + BUF);
223e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_mailbox_buf[10] = (void *)
224e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + BUF);
225e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_mailbox_buf[11] = (void *)
226e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + BUF);
227e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_mailbox_buf[12] = (void *)
228e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + BUF);
229e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_mailbox_buf[13] = (void *)
230e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + BUF);
231e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_mailbox_buf[14] = (void *)
232e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + BUF);
233e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_mailbox_buf[15] = (void *)
234e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + BUF);
235e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen}
236300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
237300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen/*
238300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen * Simple enough, just poke the appropriate ipi register
239300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen */
240300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chenstatic void loongson3_send_ipi_single(int cpu, unsigned int action)
241300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen{
242300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu]);
243300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen}
244300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
245300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chenstatic void
246300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chenloongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action)
247300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen{
248300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	unsigned int i;
249300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
250300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	for_each_cpu(i, mask)
251300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen		loongson3_ipi_write32((u32)action, ipi_set0_regs[i]);
252300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen}
253300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
254300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chenvoid loongson3_ipi_interrupt(struct pt_regs *regs)
255300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen{
256c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	int i, cpu = smp_processor_id();
257c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	unsigned int action, c0count;
258300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
259300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	/* Load the ipi register to figure out what we're supposed to do */
260300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	action = loongson3_ipi_read32(ipi_status0_regs[cpu]);
261300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
262300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	/* Clear the ipi register to clear the interrupt */
263300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	loongson3_ipi_write32((u32)action, ipi_clear0_regs[cpu]);
264300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
265300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	if (action & SMP_RESCHEDULE_YOURSELF)
266300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen		scheduler_ipi();
267300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
268300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	if (action & SMP_CALL_FUNCTION)
269300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen		smp_call_function_interrupt();
270c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
271c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	if (action & SMP_ASK_C0COUNT) {
272c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		BUG_ON(cpu != 0);
273c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		c0count = read_c0_count();
274c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		for (i = 1; i < loongson_sysconf.nr_cpus; i++)
275c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen			per_cpu(core0_c0count, i) = c0count;
276c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	}
277300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen}
278300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
279c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen#define MAX_LOOPS 1111
280300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen/*
281300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen * SMP init and finish on secondary CPUs
282300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen */
283300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chenstatic void loongson3_init_secondary(void)
284300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen{
285300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	int i;
286c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	uint32_t initcount;
287c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	unsigned int cpu = smp_processor_id();
288300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	unsigned int imask = STATUSF_IP7 | STATUSF_IP6 |
289300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen			     STATUSF_IP3 | STATUSF_IP2;
290300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
291300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	/* Set interrupt mask, but don't enable */
292300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	change_c0_status(ST0_IM, imask);
293300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
294300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	for (i = 0; i < loongson_sysconf.nr_cpus; i++)
295300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen		loongson3_ipi_write32(0xffffffff, ipi_en0_regs[i]);
296c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
297c46173183657bbdbe0d54a981c28807581648422Huacai Chen	cpu_data[cpu].package = cpu / loongson_sysconf.cores_per_package;
298c46173183657bbdbe0d54a981c28807581648422Huacai Chen	cpu_data[cpu].core = cpu % loongson_sysconf.cores_per_package;
299c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	per_cpu(cpu_state, cpu) = CPU_ONLINE;
300c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
301c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	i = 0;
30235898716b4d3382791d219be317faace580b6a41Christoph Lameter	__this_cpu_write(core0_c0count, 0);
303c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	loongson3_send_ipi_single(0, SMP_ASK_C0COUNT);
30435898716b4d3382791d219be317faace580b6a41Christoph Lameter	while (!__this_cpu_read(core0_c0count)) {
305c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		i++;
306c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		cpu_relax();
307c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	}
308c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
309c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	if (i > MAX_LOOPS)
310c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		i = MAX_LOOPS;
31135898716b4d3382791d219be317faace580b6a41Christoph Lameter	initcount = __this_cpu_read(core0_c0count) + i;
312c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	write_c0_count(initcount);
313300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen}
314300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
315300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chenstatic void loongson3_smp_finish(void)
316300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen{
317300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ);
318300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	local_irq_enable();
319300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	loongson3_ipi_write64(0,
320300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen			(void *)(ipi_mailbox_buf[smp_processor_id()]+0x0));
321300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	pr_info("CPU#%d finished, CP0_ST=%x\n",
322300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen			smp_processor_id(), read_c0_status());
323300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen}
324300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
325300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chenstatic void __init loongson3_smp_setup(void)
326300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen{
327300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	int i, num;
328300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
329300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	init_cpu_possible(cpu_none_mask);
330300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	set_cpu_possible(0, true);
331300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
332300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	__cpu_number_map[0] = 0;
333300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	__cpu_logical_map[0] = 0;
334300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
335300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	/* For unified kernel, NR_CPUS is the maximum possible value,
336300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	 * loongson_sysconf.nr_cpus is the really present value */
337300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	for (i = 1, num = 0; i < loongson_sysconf.nr_cpus; i++) {
338300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen		set_cpu_possible(i, true);
339300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen		__cpu_number_map[i] = ++num;
340300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen		__cpu_logical_map[num] = i;
341300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	}
342e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_set0_regs_init();
343e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_clear0_regs_init();
344e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_status0_regs_init();
345e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_en0_regs_init();
346e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	ipi_mailbox_buf_init();
347300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	pr_info("Detected %i available secondary CPU(s)\n", num);
348300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen}
349300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
350300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chenstatic void __init loongson3_prepare_cpus(unsigned int max_cpus)
351300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen{
352c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	init_cpu_present(cpu_possible_mask);
353c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
354300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen}
355300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
356300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen/*
357300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen * Setup the PC, SP, and GP of a secondary processor and start it runing!
358300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen */
359300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chenstatic void loongson3_boot_secondary(int cpu, struct task_struct *idle)
360300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen{
361300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	unsigned long startargs[4];
362300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
363300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	pr_info("Booting CPU#%d...\n", cpu);
364300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
365300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	/* startargs[] are initial PC, SP and GP for secondary CPU */
366300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	startargs[0] = (unsigned long)&smp_bootstrap;
367300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	startargs[1] = (unsigned long)__KSTK_TOS(idle);
368300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	startargs[2] = (unsigned long)task_thread_info(idle);
369300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	startargs[3] = 0;
370300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
371300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	pr_debug("CPU#%d, func_pc=%lx, sp=%lx, gp=%lx\n",
372300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen			cpu, startargs[0], startargs[1], startargs[2]);
373300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
374300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	loongson3_ipi_write64(startargs[3], (void *)(ipi_mailbox_buf[cpu]+0x18));
375300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	loongson3_ipi_write64(startargs[2], (void *)(ipi_mailbox_buf[cpu]+0x10));
376300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	loongson3_ipi_write64(startargs[1], (void *)(ipi_mailbox_buf[cpu]+0x8));
377300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	loongson3_ipi_write64(startargs[0], (void *)(ipi_mailbox_buf[cpu]+0x0));
378300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen}
379300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen
380c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen#ifdef CONFIG_HOTPLUG_CPU
381c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
382c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chenstatic int loongson3_cpu_disable(void)
383c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen{
384c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	unsigned long flags;
385c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	unsigned int cpu = smp_processor_id();
386c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
387c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	if (cpu == 0)
388c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		return -EBUSY;
389c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
390c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	set_cpu_online(cpu, false);
391c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	cpu_clear(cpu, cpu_callin_map);
392c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	local_irq_save(flags);
393c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	fixup_irqs();
394c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	local_irq_restore(flags);
395c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	flush_cache_all();
396c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	local_flush_tlb_all();
397c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
398c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	return 0;
399c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen}
400c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
401c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
402c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chenstatic void loongson3_cpu_die(unsigned int cpu)
403c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen{
404c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	while (per_cpu(cpu_state, cpu) != CPU_DEAD)
405c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		cpu_relax();
406c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
407c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	mb();
408c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen}
409c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
410c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen/* To shutdown a core in Loongson 3, the target core should go to CKSEG1 and
411c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen * flush all L1 entries at first. Then, another core (usually Core 0) can
412c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen * safely disable the clock of the target core. loongson3_play_dead() is
413c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen * called via CKSEG1 (uncached and unmmaped) */
414e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chenstatic void loongson3a_play_dead(int *state_addr)
415c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen{
416c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	register int val;
417c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	register long cpuid, core, node, count;
418c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	register void *addr, *base, *initfunc;
419c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
420c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	__asm__ __volatile__(
421c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   .set push                     \n"
422c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   .set noreorder                \n"
423c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   li %[addr], 0x80000000        \n" /* KSEG0 */
424c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"1: cache 0, 0(%[addr])           \n" /* flush L1 ICache */
425c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   cache 0, 1(%[addr])           \n"
426c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   cache 0, 2(%[addr])           \n"
427c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   cache 0, 3(%[addr])           \n"
428c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   cache 1, 0(%[addr])           \n" /* flush L1 DCache */
429c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   cache 1, 1(%[addr])           \n"
430c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   cache 1, 2(%[addr])           \n"
431c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   cache 1, 3(%[addr])           \n"
432c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   addiu %[sets], %[sets], -1    \n"
433c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   bnez  %[sets], 1b             \n"
434c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   addiu %[addr], %[addr], 0x20  \n"
435c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   li    %[val], 0x7             \n" /* *state_addr = CPU_DEAD; */
436c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   sw    %[val], (%[state_addr]) \n"
437c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   sync                          \n"
438c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   cache 21, (%[state_addr])     \n" /* flush entry of *state_addr */
439c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   .set pop                      \n"
440c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		: [addr] "=&r" (addr), [val] "=&r" (val)
441c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		: [state_addr] "r" (state_addr),
442c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		  [sets] "r" (cpu_data[smp_processor_id()].dcache.sets));
443c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
444c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	__asm__ __volatile__(
445c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   .set push                         \n"
446c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   .set noreorder                    \n"
447c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   .set mips64                       \n"
448c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   mfc0  %[cpuid], $15, 1            \n"
449c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   andi  %[cpuid], 0x3ff             \n"
450c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   dli   %[base], 0x900000003ff01000 \n"
451c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   andi  %[core], %[cpuid], 0x3      \n"
452c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   sll   %[core], 8                  \n" /* get core id */
453c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   or    %[base], %[base], %[core]   \n"
454c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   andi  %[node], %[cpuid], 0xc      \n"
455c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   dsll  %[node], 42                 \n" /* get node id */
456c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   or    %[base], %[base], %[node]   \n"
457c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"1: li    %[count], 0x100             \n" /* wait for init loop */
458c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"2: bnez  %[count], 2b                \n" /* limit mailbox access */
459c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   addiu %[count], -1                \n"
460c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   ld    %[initfunc], 0x20(%[base])  \n" /* get PC via mailbox */
461c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   beqz  %[initfunc], 1b             \n"
462c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   nop                               \n"
463c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   ld    $sp, 0x28(%[base])          \n" /* get SP via mailbox */
464c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   ld    $gp, 0x30(%[base])          \n" /* get GP via mailbox */
465c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   ld    $a1, 0x38(%[base])          \n"
466c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   jr    %[initfunc]                 \n" /* jump to initial PC */
467c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   nop                               \n"
468c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		"   .set pop                          \n"
469c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		: [core] "=&r" (core), [node] "=&r" (node),
470c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		  [base] "=&r" (base), [cpuid] "=&r" (cpuid),
471c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		  [count] "=&r" (count), [initfunc] "=&r" (initfunc)
472c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		: /* No Input */
473c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		: "a1");
474c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen}
475c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
476e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chenstatic void loongson3b_play_dead(int *state_addr)
477e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen{
478e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	register int val;
479e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	register long cpuid, core, node, count;
480e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	register void *addr, *base, *initfunc;
481e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen
482e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	__asm__ __volatile__(
483e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   .set push                     \n"
484e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   .set noreorder                \n"
485e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   li %[addr], 0x80000000        \n" /* KSEG0 */
486e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"1: cache 0, 0(%[addr])           \n" /* flush L1 ICache */
487e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   cache 0, 1(%[addr])           \n"
488e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   cache 0, 2(%[addr])           \n"
489e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   cache 0, 3(%[addr])           \n"
490e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   cache 1, 0(%[addr])           \n" /* flush L1 DCache */
491e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   cache 1, 1(%[addr])           \n"
492e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   cache 1, 2(%[addr])           \n"
493e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   cache 1, 3(%[addr])           \n"
494e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   addiu %[sets], %[sets], -1    \n"
495e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   bnez  %[sets], 1b             \n"
496e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   addiu %[addr], %[addr], 0x20  \n"
497e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   li    %[val], 0x7             \n" /* *state_addr = CPU_DEAD; */
498e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   sw    %[val], (%[state_addr]) \n"
499e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   sync                          \n"
500e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   cache 21, (%[state_addr])     \n" /* flush entry of *state_addr */
501e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   .set pop                      \n"
502e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		: [addr] "=&r" (addr), [val] "=&r" (val)
503e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		: [state_addr] "r" (state_addr),
504e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		  [sets] "r" (cpu_data[smp_processor_id()].dcache.sets));
505e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen
506e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	__asm__ __volatile__(
507e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   .set push                         \n"
508e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   .set noreorder                    \n"
509e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   .set mips64                       \n"
510e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   mfc0  %[cpuid], $15, 1            \n"
511e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   andi  %[cpuid], 0x3ff             \n"
512e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   dli   %[base], 0x900000003ff01000 \n"
513e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   andi  %[core], %[cpuid], 0x3      \n"
514e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   sll   %[core], 8                  \n" /* get core id */
515e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   or    %[base], %[base], %[core]   \n"
516e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   andi  %[node], %[cpuid], 0xc      \n"
517e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   dsll  %[node], 42                 \n" /* get node id */
518e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   or    %[base], %[base], %[node]   \n"
519e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   dsrl  %[node], 30                 \n" /* 15:14 */
520e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   or    %[base], %[base], %[node]   \n"
521e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"1: li    %[count], 0x100             \n" /* wait for init loop */
522e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"2: bnez  %[count], 2b                \n" /* limit mailbox access */
523e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   addiu %[count], -1                \n"
524e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   ld    %[initfunc], 0x20(%[base])  \n" /* get PC via mailbox */
525e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   beqz  %[initfunc], 1b             \n"
526e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   nop                               \n"
527e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   ld    $sp, 0x28(%[base])          \n" /* get SP via mailbox */
528e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   ld    $gp, 0x30(%[base])          \n" /* get GP via mailbox */
529e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   ld    $a1, 0x38(%[base])          \n"
530e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   jr    %[initfunc]                 \n" /* jump to initial PC */
531e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   nop                               \n"
532e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		"   .set pop                          \n"
533e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		: [core] "=&r" (core), [node] "=&r" (node),
534e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		  [base] "=&r" (base), [cpuid] "=&r" (cpuid),
535e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		  [count] "=&r" (count), [initfunc] "=&r" (initfunc)
536e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		: /* No Input */
537e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		: "a1");
538e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen}
539e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen
540c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chenvoid play_dead(void)
541c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen{
542c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	int *state_addr;
543c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	unsigned int cpu = smp_processor_id();
544c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	void (*play_dead_at_ckseg1)(int *);
545c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
546c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	idle_task_exit();
547e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	switch (loongson_sysconf.cputype) {
548e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	case Loongson_3A:
549e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	default:
550e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		play_dead_at_ckseg1 =
551e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen			(void *)CKSEG1ADDR((unsigned long)loongson3a_play_dead);
552e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		break;
553e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	case Loongson_3B:
554e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		play_dead_at_ckseg1 =
555e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen			(void *)CKSEG1ADDR((unsigned long)loongson3b_play_dead);
556e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		break;
557e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	}
558c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	state_addr = &per_cpu(cpu_state, cpu);
559c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	mb();
560c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	play_dead_at_ckseg1(state_addr);
561c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen}
562c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
563e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chenvoid loongson3_disable_clock(int cpu)
564e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen{
565e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	uint64_t core_id = cpu_data[cpu].core;
566e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	uint64_t package_id = cpu_data[cpu].package;
567e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen
568e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	if (loongson_sysconf.cputype == Loongson_3A) {
569e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		LOONGSON_CHIPCFG(package_id) &= ~(1 << (12 + core_id));
570e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	} else if (loongson_sysconf.cputype == Loongson_3B) {
571e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		if (!cpuhotplug_workaround)
572e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen			LOONGSON_FREQCTRL(package_id) &= ~(1 << (core_id * 4 + 3));
573e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	}
574e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen}
575e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen
576e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chenvoid loongson3_enable_clock(int cpu)
577e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen{
578e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	uint64_t core_id = cpu_data[cpu].core;
579e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	uint64_t package_id = cpu_data[cpu].package;
580e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen
581e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	if (loongson_sysconf.cputype == Loongson_3A) {
582e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		LOONGSON_CHIPCFG(package_id) |= 1 << (12 + core_id);
583e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	} else if (loongson_sysconf.cputype == Loongson_3B) {
584e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		if (!cpuhotplug_workaround)
585e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen			LOONGSON_FREQCTRL(package_id) |= 1 << (core_id * 4 + 3);
586e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen	}
587e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen}
588e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen
589c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen#define CPU_POST_DEAD_FROZEN	(CPU_POST_DEAD | CPU_TASKS_FROZEN)
590c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chenstatic int loongson3_cpu_callback(struct notifier_block *nfb,
591c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	unsigned long action, void *hcpu)
592c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen{
593c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	unsigned int cpu = (unsigned long)hcpu;
594c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
595c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	switch (action) {
596c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	case CPU_POST_DEAD:
597c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	case CPU_POST_DEAD_FROZEN:
598c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		pr_info("Disable clock for CPU#%d\n", cpu);
599e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		loongson3_disable_clock(cpu);
600c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		break;
601c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	case CPU_UP_PREPARE:
602c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	case CPU_UP_PREPARE_FROZEN:
603c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		pr_info("Enable clock for CPU#%d\n", cpu);
604e7841be50fe2b8751a51a068b8cdcdcb6611e354Huacai Chen		loongson3_enable_clock(cpu);
605c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen		break;
606c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	}
607c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
608c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	return NOTIFY_OK;
609c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen}
610c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
611c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chenstatic int register_loongson3_notifier(void)
612c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen{
613c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	hotcpu_notifier(loongson3_cpu_callback, 0);
614c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	return 0;
615c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen}
616c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chenearly_initcall(register_loongson3_notifier);
617c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
618c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen#endif
619c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen
620300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chenstruct plat_smp_ops loongson3_smp_ops = {
621300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	.send_ipi_single = loongson3_send_ipi_single,
622300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	.send_ipi_mask = loongson3_send_ipi_mask,
623300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	.init_secondary = loongson3_init_secondary,
624300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	.smp_finish = loongson3_smp_finish,
625300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	.boot_secondary = loongson3_boot_secondary,
626300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	.smp_setup = loongson3_smp_setup,
627300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen	.prepare_cpus = loongson3_prepare_cpus,
628c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen#ifdef CONFIG_HOTPLUG_CPU
629c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	.cpu_disable = loongson3_cpu_disable,
630c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen	.cpu_die = loongson3_cpu_die,
631c4a987db1b3cd89207cece4b8121c09cbfbc978aHuacai Chen#endif
632300459d558725cdada5ddebbe52c24ef6e1853d3Huacai Chen};
633