diff options
author | Paul Burton <paul.burton@imgtec.com> | 2014-04-14 07:04:27 -0400 |
---|---|---|
committer | Paul Burton <paul.burton@imgtec.com> | 2014-05-28 11:20:28 -0400 |
commit | 245a7868d2f2e54a9a9b084de00d003a9badb2a5 (patch) | |
tree | 1b00bb19dfdc29b1ba27930db698c2d3fd21f16f /arch/mips/kernel/cps-vec.S | |
parent | d674dd14e85c49ca0e422de53a4c2b5bf44a339a (diff) |
MIPS: smp-cps: rework core/VPE initialisation
When hotplug and/or a powered down idle state are supported cases will
arise where a non-zero VPE must be brought online without VPE 0, and it
where multiple VPEs must be onlined simultaneously. This patch prepares
for that by:
- Splitting struct boot_config into core & VPE boot config structures,
allocated one per core or VPE respectively. This allows for multiple
VPEs to be onlined simultaneously without clobbering each others
configuration.
- Indicating which VPEs should be online within a core at any given
time using a bitmap. This allows multiple VPEs to be brought online
simultaneously and also indicates to VPE 0 whether it should halt
after starting any non-zero VPEs that should be online within the
core. For example if all VPEs within a core are offlined via hotplug
and the user onlines the second VPE within that core:
1) The core will be powered up.
2) VPE 0 will run from the BEV (ie. mips_cps_core_entry) to
initialise the core.
3) VPE 0 will start VPE 1 because its bit is set in the cores
bitmap.
4) VPE 0 will halt itself because its bit is clear in the cores
bitmap.
- Moving the core & VPE initialisation to assembly code which does not
make any use of the stack. This is because if a non-zero VPE is to
be brought online in a powered down core then when VPE 0 of that
core runs it may not have a valid stack, and even if it did then
it's messy to run through parts of generic kernel code on VPE 0
before starting the correct VPE.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Diffstat (limited to 'arch/mips/kernel/cps-vec.S')
-rw-r--r-- | arch/mips/kernel/cps-vec.S | 282 |
1 files changed, 270 insertions, 12 deletions
diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index f7a46db4b161..57ec18c7d17f 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S | |||
@@ -14,12 +14,33 @@ | |||
14 | #include <asm/asmmacro.h> | 14 | #include <asm/asmmacro.h> |
15 | #include <asm/cacheops.h> | 15 | #include <asm/cacheops.h> |
16 | #include <asm/mipsregs.h> | 16 | #include <asm/mipsregs.h> |
17 | #include <asm/mipsmtregs.h> | ||
17 | 18 | ||
18 | #define GCR_CL_COHERENCE_OFS 0x2008 | 19 | #define GCR_CL_COHERENCE_OFS 0x2008 |
20 | #define GCR_CL_ID_OFS 0x2028 | ||
21 | |||
22 | .extern mips_cm_base | ||
23 | |||
24 | .set noreorder | ||
25 | |||
26 | /* | ||
27 | * Set dest to non-zero if the core supports the MT ASE, else zero. If | ||
28 | * MT is not supported then branch to nomt. | ||
29 | */ | ||
30 | .macro has_mt dest, nomt | ||
31 | mfc0 \dest, CP0_CONFIG | ||
32 | bgez \dest, \nomt | ||
33 | mfc0 \dest, CP0_CONFIG, 1 | ||
34 | bgez \dest, \nomt | ||
35 | mfc0 \dest, CP0_CONFIG, 2 | ||
36 | bgez \dest, \nomt | ||
37 | mfc0 \dest, CP0_CONFIG, 3 | ||
38 | andi \dest, \dest, MIPS_CONF3_MT | ||
39 | beqz \dest, \nomt | ||
40 | .endm | ||
19 | 41 | ||
20 | .section .text.cps-vec | 42 | .section .text.cps-vec |
21 | .balign 0x1000 | 43 | .balign 0x1000 |
22 | .set noreorder | ||
23 | 44 | ||
24 | LEAF(mips_cps_core_entry) | 45 | LEAF(mips_cps_core_entry) |
25 | /* | 46 | /* |
@@ -134,21 +155,24 @@ dcache_done: | |||
134 | jr t0 | 155 | jr t0 |
135 | nop | 156 | nop |
136 | 157 | ||
137 | 1: /* We're up, cached & coherent */ | 158 | /* |
159 | * We're up, cached & coherent. Perform any further required core-level | ||
160 | * initialisation. | ||
161 | */ | ||
162 | 1: jal mips_cps_core_init | ||
163 | nop | ||
138 | 164 | ||
139 | /* | 165 | /* |
140 | * TODO: We should check the VPE number we intended to boot here, and | 166 | * Boot any other VPEs within this core that should be online, and |
141 | * if non-zero we should start that VPE and stop this one. For | 167 | * deactivate this VPE if it should be offline. |
142 | * the moment this doesn't matter since CPUs are brought up | ||
143 | * sequentially and in order, but once hotplug is implemented | ||
144 | * this will need revisiting. | ||
145 | */ | 168 | */ |
169 | jal mips_cps_boot_vpes | ||
170 | nop | ||
146 | 171 | ||
147 | /* Off we go! */ | 172 | /* Off we go! */ |
148 | la t0, mips_cps_bootcfg | 173 | lw t1, VPEBOOTCFG_PC(v0) |
149 | lw t1, BOOTCFG_PC(t0) | 174 | lw gp, VPEBOOTCFG_GP(v0) |
150 | lw gp, BOOTCFG_GP(t0) | 175 | lw sp, VPEBOOTCFG_SP(v0) |
151 | lw sp, BOOTCFG_SP(t0) | ||
152 | jr t1 | 176 | jr t1 |
153 | nop | 177 | nop |
154 | END(mips_cps_core_entry) | 178 | END(mips_cps_core_entry) |
@@ -189,3 +213,237 @@ LEAF(excep_ejtag) | |||
189 | jr k0 | 213 | jr k0 |
190 | nop | 214 | nop |
191 | END(excep_ejtag) | 215 | END(excep_ejtag) |
216 | |||
217 | LEAF(mips_cps_core_init) | ||
218 | #ifdef CONFIG_MIPS_MT | ||
219 | /* Check that the core implements the MT ASE */ | ||
220 | has_mt t0, 3f | ||
221 | nop | ||
222 | |||
223 | .set push | ||
224 | .set mt | ||
225 | |||
226 | /* Only allow 1 TC per VPE to execute... */ | ||
227 | dmt | ||
228 | |||
229 | /* ...and for the moment only 1 VPE */ | ||
230 | dvpe | ||
231 | la t1, 1f | ||
232 | jr.hb t1 | ||
233 | nop | ||
234 | |||
235 | /* Enter VPE configuration state */ | ||
236 | 1: mfc0 t0, CP0_MVPCONTROL | ||
237 | ori t0, t0, MVPCONTROL_VPC | ||
238 | mtc0 t0, CP0_MVPCONTROL | ||
239 | |||
240 | /* Retrieve the number of VPEs within the core */ | ||
241 | mfc0 t0, CP0_MVPCONF0 | ||
242 | srl t0, t0, MVPCONF0_PVPE_SHIFT | ||
243 | andi t0, t0, (MVPCONF0_PVPE >> MVPCONF0_PVPE_SHIFT) | ||
244 | addi t7, t0, 1 | ||
245 | |||
246 | /* If there's only 1, we're done */ | ||
247 | beqz t0, 2f | ||
248 | nop | ||
249 | |||
250 | /* Loop through each VPE within this core */ | ||
251 | li t5, 1 | ||
252 | |||
253 | 1: /* Operate on the appropriate TC */ | ||
254 | mtc0 t5, CP0_VPECONTROL | ||
255 | ehb | ||
256 | |||
257 | /* Bind TC to VPE (1:1 TC:VPE mapping) */ | ||
258 | mttc0 t5, CP0_TCBIND | ||
259 | |||
260 | /* Set exclusive TC, non-active, master */ | ||
261 | li t0, VPECONF0_MVP | ||
262 | sll t1, t5, VPECONF0_XTC_SHIFT | ||
263 | or t0, t0, t1 | ||
264 | mttc0 t0, CP0_VPECONF0 | ||
265 | |||
266 | /* Set TC non-active, non-allocatable */ | ||
267 | mttc0 zero, CP0_TCSTATUS | ||
268 | |||
269 | /* Set TC halted */ | ||
270 | li t0, TCHALT_H | ||
271 | mttc0 t0, CP0_TCHALT | ||
272 | |||
273 | /* Next VPE */ | ||
274 | addi t5, t5, 1 | ||
275 | slt t0, t5, t7 | ||
276 | bnez t0, 1b | ||
277 | nop | ||
278 | |||
279 | /* Leave VPE configuration state */ | ||
280 | 2: mfc0 t0, CP0_MVPCONTROL | ||
281 | xori t0, t0, MVPCONTROL_VPC | ||
282 | mtc0 t0, CP0_MVPCONTROL | ||
283 | |||
284 | 3: .set pop | ||
285 | #endif | ||
286 | jr ra | ||
287 | nop | ||
288 | END(mips_cps_core_init) | ||
289 | |||
290 | LEAF(mips_cps_boot_vpes) | ||
291 | /* Retrieve CM base address */ | ||
292 | la t0, mips_cm_base | ||
293 | lw t0, 0(t0) | ||
294 | |||
295 | /* Calculate a pointer to this cores struct core_boot_config */ | ||
296 | lw t0, GCR_CL_ID_OFS(t0) | ||
297 | li t1, COREBOOTCFG_SIZE | ||
298 | mul t0, t0, t1 | ||
299 | la t1, mips_cps_core_bootcfg | ||
300 | lw t1, 0(t1) | ||
301 | addu t0, t0, t1 | ||
302 | |||
303 | /* Calculate this VPEs ID. If the core doesn't support MT use 0 */ | ||
304 | has_mt t6, 1f | ||
305 | li t9, 0 | ||
306 | |||
307 | /* Find the number of VPEs present in the core */ | ||
308 | mfc0 t1, CP0_MVPCONF0 | ||
309 | srl t1, t1, MVPCONF0_PVPE_SHIFT | ||
310 | andi t1, t1, MVPCONF0_PVPE >> MVPCONF0_PVPE_SHIFT | ||
311 | addi t1, t1, 1 | ||
312 | |||
313 | /* Calculate a mask for the VPE ID from EBase.CPUNum */ | ||
314 | clz t1, t1 | ||
315 | li t2, 31 | ||
316 | subu t1, t2, t1 | ||
317 | li t2, 1 | ||
318 | sll t1, t2, t1 | ||
319 | addiu t1, t1, -1 | ||
320 | |||
321 | /* Retrieve the VPE ID from EBase.CPUNum */ | ||
322 | mfc0 t9, $15, 1 | ||
323 | and t9, t9, t1 | ||
324 | |||
325 | 1: /* Calculate a pointer to this VPEs struct vpe_boot_config */ | ||
326 | li t1, VPEBOOTCFG_SIZE | ||
327 | mul v0, t9, t1 | ||
328 | lw t7, COREBOOTCFG_VPECONFIG(t0) | ||
329 | addu v0, v0, t7 | ||
330 | |||
331 | #ifdef CONFIG_MIPS_MT | ||
332 | |||
333 | /* If the core doesn't support MT then return */ | ||
334 | bnez t6, 1f | ||
335 | nop | ||
336 | jr ra | ||
337 | nop | ||
338 | |||
339 | .set push | ||
340 | .set mt | ||
341 | |||
342 | 1: /* Enter VPE configuration state */ | ||
343 | dvpe | ||
344 | la t1, 1f | ||
345 | jr.hb t1 | ||
346 | nop | ||
347 | 1: mfc0 t1, CP0_MVPCONTROL | ||
348 | ori t1, t1, MVPCONTROL_VPC | ||
349 | mtc0 t1, CP0_MVPCONTROL | ||
350 | ehb | ||
351 | |||
352 | /* Loop through each VPE */ | ||
353 | lw t6, COREBOOTCFG_VPEMASK(t0) | ||
354 | move t8, t6 | ||
355 | li t5, 0 | ||
356 | |||
357 | /* Check whether the VPE should be running. If not, skip it */ | ||
358 | 1: andi t0, t6, 1 | ||
359 | beqz t0, 2f | ||
360 | nop | ||
361 | |||
362 | /* Operate on the appropriate TC */ | ||
363 | mfc0 t0, CP0_VPECONTROL | ||
364 | ori t0, t0, VPECONTROL_TARGTC | ||
365 | xori t0, t0, VPECONTROL_TARGTC | ||
366 | or t0, t0, t5 | ||
367 | mtc0 t0, CP0_VPECONTROL | ||
368 | ehb | ||
369 | |||
370 | /* Skip the VPE if its TC is not halted */ | ||
371 | mftc0 t0, CP0_TCHALT | ||
372 | beqz t0, 2f | ||
373 | nop | ||
374 | |||
375 | /* Calculate a pointer to the VPEs struct vpe_boot_config */ | ||
376 | li t0, VPEBOOTCFG_SIZE | ||
377 | mul t0, t0, t5 | ||
378 | addu t0, t0, t7 | ||
379 | |||
380 | /* Set the TC restart PC */ | ||
381 | lw t1, VPEBOOTCFG_PC(t0) | ||
382 | mttc0 t1, CP0_TCRESTART | ||
383 | |||
384 | /* Set the TC stack pointer */ | ||
385 | lw t1, VPEBOOTCFG_SP(t0) | ||
386 | mttgpr t1, sp | ||
387 | |||
388 | /* Set the TC global pointer */ | ||
389 | lw t1, VPEBOOTCFG_GP(t0) | ||
390 | mttgpr t1, gp | ||
391 | |||
392 | /* Copy config from this VPE */ | ||
393 | mfc0 t0, CP0_CONFIG | ||
394 | mttc0 t0, CP0_CONFIG | ||
395 | |||
396 | /* Ensure no software interrupts are pending */ | ||
397 | mttc0 zero, CP0_CAUSE | ||
398 | mttc0 zero, CP0_STATUS | ||
399 | |||
400 | /* Set TC active, not interrupt exempt */ | ||
401 | mftc0 t0, CP0_TCSTATUS | ||
402 | li t1, ~TCSTATUS_IXMT | ||
403 | and t0, t0, t1 | ||
404 | ori t0, t0, TCSTATUS_A | ||
405 | mttc0 t0, CP0_TCSTATUS | ||
406 | |||
407 | /* Clear the TC halt bit */ | ||
408 | mttc0 zero, CP0_TCHALT | ||
409 | |||
410 | /* Set VPE active */ | ||
411 | mftc0 t0, CP0_VPECONF0 | ||
412 | ori t0, t0, VPECONF0_VPA | ||
413 | mttc0 t0, CP0_VPECONF0 | ||
414 | |||
415 | /* Next VPE */ | ||
416 | 2: srl t6, t6, 1 | ||
417 | addi t5, t5, 1 | ||
418 | bnez t6, 1b | ||
419 | nop | ||
420 | |||
421 | /* Leave VPE configuration state */ | ||
422 | mfc0 t1, CP0_MVPCONTROL | ||
423 | xori t1, t1, MVPCONTROL_VPC | ||
424 | mtc0 t1, CP0_MVPCONTROL | ||
425 | ehb | ||
426 | evpe | ||
427 | |||
428 | /* Check whether this VPE is meant to be running */ | ||
429 | li t0, 1 | ||
430 | sll t0, t0, t9 | ||
431 | and t0, t0, t8 | ||
432 | bnez t0, 2f | ||
433 | nop | ||
434 | |||
435 | /* This VPE should be offline, halt the TC */ | ||
436 | li t0, TCHALT_H | ||
437 | mtc0 t0, CP0_TCHALT | ||
438 | la t0, 1f | ||
439 | 1: jr.hb t0 | ||
440 | nop | ||
441 | |||
442 | 2: .set pop | ||
443 | |||
444 | #endif /* CONFIG_MIPS_MT */ | ||
445 | |||
446 | /* Return */ | ||
447 | jr ra | ||
448 | nop | ||
449 | END(mips_cps_boot_vpes) | ||