aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/cps-vec.S
diff options
context:
space:
mode:
authorPaul Burton <paul.burton@imgtec.com>2014-04-14 07:04:27 -0400
committerPaul Burton <paul.burton@imgtec.com>2014-05-28 11:20:28 -0400
commit245a7868d2f2e54a9a9b084de00d003a9badb2a5 (patch)
tree1b00bb19dfdc29b1ba27930db698c2d3fd21f16f /arch/mips/kernel/cps-vec.S
parentd674dd14e85c49ca0e422de53a4c2b5bf44a339a (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.S282
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
24LEAF(mips_cps_core_entry) 45LEAF(mips_cps_core_entry)
25 /* 46 /*
@@ -134,21 +155,24 @@ dcache_done:
134 jr t0 155 jr t0
135 nop 156 nop
136 157
1371: /* We're up, cached & coherent */ 158 /*
159 * We're up, cached & coherent. Perform any further required core-level
160 * initialisation.
161 */
1621: 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
217LEAF(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 */
2361: 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
2531: /* 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 */
2802: mfc0 t0, CP0_MVPCONTROL
281 xori t0, t0, MVPCONTROL_VPC
282 mtc0 t0, CP0_MVPCONTROL
283
2843: .set pop
285#endif
286 jr ra
287 nop
288 END(mips_cps_core_init)
289
290LEAF(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
3251: /* 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
3421: /* Enter VPE configuration state */
343 dvpe
344 la t1, 1f
345 jr.hb t1
346 nop
3471: 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 */
3581: 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 */
4162: 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
4391: jr.hb t0
440 nop
441
4422: .set pop
443
444#endif /* CONFIG_MIPS_MT */
445
446 /* Return */
447 jr ra
448 nop
449 END(mips_cps_boot_vpes)