diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2006-10-31 13:25:10 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2006-10-31 15:13:21 -0500 |
commit | 781b0f8d4f9c90137ea32771346ab49f0e5319b3 (patch) | |
tree | 3bd3ec1edfce6680c5d6f8184df967fb66577a18 /arch/mips/kernel/smp-mt.c | |
parent | 3ab0f40f333007eb31dc1e08f578ec224c7d71c2 (diff) |
[MIPS] VSMP: Fix initialization ordering bug.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/smp-mt.c')
-rw-r--r-- | arch/mips/kernel/smp-mt.c | 152 |
1 files changed, 83 insertions, 69 deletions
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c index 3b5f3b632622..06b29fa73f56 100644 --- a/arch/mips/kernel/smp-mt.c +++ b/arch/mips/kernel/smp-mt.c | |||
@@ -140,15 +140,88 @@ static struct irqaction irq_call = { | |||
140 | .name = "IPI_call" | 140 | .name = "IPI_call" |
141 | }; | 141 | }; |
142 | 142 | ||
143 | static void __init smp_copy_vpe_config(void) | ||
144 | { | ||
145 | write_vpe_c0_status( | ||
146 | (read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0); | ||
147 | |||
148 | /* set config to be the same as vpe0, particularly kseg0 coherency alg */ | ||
149 | write_vpe_c0_config( read_c0_config()); | ||
150 | |||
151 | /* make sure there are no software interrupts pending */ | ||
152 | write_vpe_c0_cause(0); | ||
153 | |||
154 | /* Propagate Config7 */ | ||
155 | write_vpe_c0_config7(read_c0_config7()); | ||
156 | } | ||
157 | |||
158 | static unsigned int __init smp_vpe_init(unsigned int tc, unsigned int mvpconf0, | ||
159 | unsigned int ncpu) | ||
160 | { | ||
161 | if (tc > ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)) | ||
162 | return ncpu; | ||
163 | |||
164 | /* Deactivate all but VPE 0 */ | ||
165 | if (tc != 0) { | ||
166 | unsigned long tmp = read_vpe_c0_vpeconf0(); | ||
167 | |||
168 | tmp &= ~VPECONF0_VPA; | ||
169 | |||
170 | /* master VPE */ | ||
171 | tmp |= VPECONF0_MVP; | ||
172 | write_vpe_c0_vpeconf0(tmp); | ||
173 | |||
174 | /* Record this as available CPU */ | ||
175 | cpu_set(tc, phys_cpu_present_map); | ||
176 | __cpu_number_map[tc] = ++ncpu; | ||
177 | __cpu_logical_map[ncpu] = tc; | ||
178 | } | ||
179 | |||
180 | /* Disable multi-threading with TC's */ | ||
181 | write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); | ||
182 | |||
183 | if (tc != 0) | ||
184 | smp_copy_vpe_config(); | ||
185 | |||
186 | return ncpu; | ||
187 | } | ||
188 | |||
189 | static void __init smp_tc_init(unsigned int tc, unsigned int mvpconf0) | ||
190 | { | ||
191 | unsigned long tmp; | ||
192 | |||
193 | if (!tc) | ||
194 | return; | ||
195 | |||
196 | /* bind a TC to each VPE, May as well put all excess TC's | ||
197 | on the last VPE */ | ||
198 | if (tc >= (((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)+1)) | ||
199 | write_tc_c0_tcbind(read_tc_c0_tcbind() | ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)); | ||
200 | else { | ||
201 | write_tc_c0_tcbind(read_tc_c0_tcbind() | tc); | ||
202 | |||
203 | /* and set XTC */ | ||
204 | write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | (tc << VPECONF0_XTC_SHIFT)); | ||
205 | } | ||
206 | |||
207 | tmp = read_tc_c0_tcstatus(); | ||
208 | |||
209 | /* mark not allocated and not dynamically allocatable */ | ||
210 | tmp &= ~(TCSTATUS_A | TCSTATUS_DA); | ||
211 | tmp |= TCSTATUS_IXMT; /* interrupt exempt */ | ||
212 | write_tc_c0_tcstatus(tmp); | ||
213 | |||
214 | write_tc_c0_tchalt(TCHALT_H); | ||
215 | } | ||
216 | |||
143 | /* | 217 | /* |
144 | * Common setup before any secondaries are started | 218 | * Common setup before any secondaries are started |
145 | * Make sure all CPU's are in a sensible state before we boot any of the | 219 | * Make sure all CPU's are in a sensible state before we boot any of the |
146 | * secondarys | 220 | * secondarys |
147 | */ | 221 | */ |
148 | void plat_smp_setup(void) | 222 | void __init plat_smp_setup(void) |
149 | { | 223 | { |
150 | unsigned long val; | 224 | unsigned int mvpconf0, ntc, tc, ncpu = 0; |
151 | int i, num; | ||
152 | 225 | ||
153 | #ifdef CONFIG_MIPS_MT_FPAFF | 226 | #ifdef CONFIG_MIPS_MT_FPAFF |
154 | /* If we have an FPU, enroll ourselves in the FPU-full mask */ | 227 | /* If we have an FPU, enroll ourselves in the FPU-full mask */ |
@@ -167,75 +240,16 @@ void plat_smp_setup(void) | |||
167 | /* Put MVPE's into 'configuration state' */ | 240 | /* Put MVPE's into 'configuration state' */ |
168 | set_c0_mvpcontrol(MVPCONTROL_VPC); | 241 | set_c0_mvpcontrol(MVPCONTROL_VPC); |
169 | 242 | ||
170 | val = read_c0_mvpconf0(); | 243 | mvpconf0 = read_c0_mvpconf0(); |
244 | ntc = (mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT; | ||
171 | 245 | ||
172 | /* we'll always have more TC's than VPE's, so loop setting everything | 246 | /* we'll always have more TC's than VPE's, so loop setting everything |
173 | to a sensible state */ | 247 | to a sensible state */ |
174 | for (i = 0, num = 0; i <= ((val & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT); i++) { | 248 | for (tc = 0; tc <= ntc; tc++) { |
175 | settc(i); | 249 | settc(tc); |
176 | |||
177 | /* VPE's */ | ||
178 | if (i <= ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)) { | ||
179 | |||
180 | /* deactivate all but vpe0 */ | ||
181 | if (i != 0) { | ||
182 | unsigned long tmp = read_vpe_c0_vpeconf0(); | ||
183 | |||
184 | tmp &= ~VPECONF0_VPA; | ||
185 | |||
186 | /* master VPE */ | ||
187 | tmp |= VPECONF0_MVP; | ||
188 | write_vpe_c0_vpeconf0(tmp); | ||
189 | |||
190 | /* Record this as available CPU */ | ||
191 | cpu_set(i, phys_cpu_present_map); | ||
192 | __cpu_number_map[i] = ++num; | ||
193 | __cpu_logical_map[num] = i; | ||
194 | } | ||
195 | |||
196 | /* disable multi-threading with TC's */ | ||
197 | write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); | ||
198 | |||
199 | if (i != 0) { | ||
200 | write_vpe_c0_status((read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0); | ||
201 | 250 | ||
202 | /* set config to be the same as vpe0, particularly kseg0 coherency alg */ | 251 | smp_tc_init(tc, mvpconf0); |
203 | write_vpe_c0_config( read_c0_config()); | 252 | ncpu = smp_vpe_init(tc, mvpconf0, ncpu); |
204 | |||
205 | /* make sure there are no software interrupts pending */ | ||
206 | write_vpe_c0_cause(0); | ||
207 | |||
208 | /* Propagate Config7 */ | ||
209 | write_vpe_c0_config7(read_c0_config7()); | ||
210 | } | ||
211 | |||
212 | } | ||
213 | |||
214 | /* TC's */ | ||
215 | |||
216 | if (i != 0) { | ||
217 | unsigned long tmp; | ||
218 | |||
219 | /* bind a TC to each VPE, May as well put all excess TC's | ||
220 | on the last VPE */ | ||
221 | if ( i >= (((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)+1) ) | ||
222 | write_tc_c0_tcbind(read_tc_c0_tcbind() | ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) ); | ||
223 | else { | ||
224 | write_tc_c0_tcbind( read_tc_c0_tcbind() | i); | ||
225 | |||
226 | /* and set XTC */ | ||
227 | write_vpe_c0_vpeconf0( read_vpe_c0_vpeconf0() | (i << VPECONF0_XTC_SHIFT)); | ||
228 | } | ||
229 | |||
230 | tmp = read_tc_c0_tcstatus(); | ||
231 | |||
232 | /* mark not allocated and not dynamically allocatable */ | ||
233 | tmp &= ~(TCSTATUS_A | TCSTATUS_DA); | ||
234 | tmp |= TCSTATUS_IXMT; /* interrupt exempt */ | ||
235 | write_tc_c0_tcstatus(tmp); | ||
236 | |||
237 | write_tc_c0_tchalt(TCHALT_H); | ||
238 | } | ||
239 | } | 253 | } |
240 | 254 | ||
241 | /* Release config state */ | 255 | /* Release config state */ |
@@ -243,7 +257,7 @@ void plat_smp_setup(void) | |||
243 | 257 | ||
244 | /* We'll wait until starting the secondaries before starting MVPE */ | 258 | /* We'll wait until starting the secondaries before starting MVPE */ |
245 | 259 | ||
246 | printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num); | 260 | printk(KERN_INFO "Detected %i available secondary CPU(s)\n", ncpu); |
247 | } | 261 | } |
248 | 262 | ||
249 | void __init plat_prepare_cpus(unsigned int max_cpus) | 263 | void __init plat_prepare_cpus(unsigned int max_cpus) |