diff options
Diffstat (limited to 'arch/mips/kernel/cps-vec.S')
-rw-r--r-- | arch/mips/kernel/cps-vec.S | 328 |
1 files changed, 312 insertions, 16 deletions
diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index f7a46db4b161..6f4f739dad96 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S | |||
@@ -14,19 +14,43 @@ | |||
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> | ||
18 | #include <asm/pm.h> | ||
17 | 19 | ||
18 | #define GCR_CL_COHERENCE_OFS 0x2008 | 20 | #define GCR_CL_COHERENCE_OFS 0x2008 |
21 | #define GCR_CL_ID_OFS 0x2028 | ||
22 | |||
23 | .extern mips_cm_base | ||
24 | |||
25 | .set noreorder | ||
26 | |||
27 | /* | ||
28 | * Set dest to non-zero if the core supports the MT ASE, else zero. If | ||
29 | * MT is not supported then branch to nomt. | ||
30 | */ | ||
31 | .macro has_mt dest, nomt | ||
32 | mfc0 \dest, CP0_CONFIG | ||
33 | bgez \dest, \nomt | ||
34 | mfc0 \dest, CP0_CONFIG, 1 | ||
35 | bgez \dest, \nomt | ||
36 | mfc0 \dest, CP0_CONFIG, 2 | ||
37 | bgez \dest, \nomt | ||
38 | mfc0 \dest, CP0_CONFIG, 3 | ||
39 | andi \dest, \dest, MIPS_CONF3_MT | ||
40 | beqz \dest, \nomt | ||
41 | .endm | ||
19 | 42 | ||
20 | .section .text.cps-vec | 43 | .section .text.cps-vec |
21 | .balign 0x1000 | 44 | .balign 0x1000 |
22 | .set noreorder | ||
23 | 45 | ||
24 | LEAF(mips_cps_core_entry) | 46 | LEAF(mips_cps_core_entry) |
25 | /* | 47 | /* |
26 | * These first 8 bytes will be patched by cps_smp_setup to load the | 48 | * These first 12 bytes will be patched by cps_smp_setup to load the |
27 | * base address of the CM GCRs into register v1. | 49 | * base address of the CM GCRs into register v1 and the CCA to use into |
50 | * register s0. | ||
28 | */ | 51 | */ |
29 | .quad 0 | 52 | .quad 0 |
53 | .word 0 | ||
30 | 54 | ||
31 | /* Check whether we're here due to an NMI */ | 55 | /* Check whether we're here due to an NMI */ |
32 | mfc0 k0, CP0_STATUS | 56 | mfc0 k0, CP0_STATUS |
@@ -117,10 +141,11 @@ icache_done: | |||
117 | add a0, a0, t0 | 141 | add a0, a0, t0 |
118 | dcache_done: | 142 | dcache_done: |
119 | 143 | ||
120 | /* Set Kseg0 cacheable, coherent, write-back, write-allocate */ | 144 | /* Set Kseg0 CCA to that in s0 */ |
121 | mfc0 t0, CP0_CONFIG | 145 | mfc0 t0, CP0_CONFIG |
122 | ori t0, 0x7 | 146 | ori t0, 0x7 |
123 | xori t0, 0x2 | 147 | xori t0, 0x7 |
148 | or t0, t0, s0 | ||
124 | mtc0 t0, CP0_CONFIG | 149 | mtc0 t0, CP0_CONFIG |
125 | ehb | 150 | ehb |
126 | 151 | ||
@@ -134,21 +159,24 @@ dcache_done: | |||
134 | jr t0 | 159 | jr t0 |
135 | nop | 160 | nop |
136 | 161 | ||
137 | 1: /* We're up, cached & coherent */ | 162 | /* |
163 | * We're up, cached & coherent. Perform any further required core-level | ||
164 | * initialisation. | ||
165 | */ | ||
166 | 1: jal mips_cps_core_init | ||
167 | nop | ||
138 | 168 | ||
139 | /* | 169 | /* |
140 | * TODO: We should check the VPE number we intended to boot here, and | 170 | * 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 | 171 | * 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 | */ | 172 | */ |
173 | jal mips_cps_boot_vpes | ||
174 | nop | ||
146 | 175 | ||
147 | /* Off we go! */ | 176 | /* Off we go! */ |
148 | la t0, mips_cps_bootcfg | 177 | lw t1, VPEBOOTCFG_PC(v0) |
149 | lw t1, BOOTCFG_PC(t0) | 178 | lw gp, VPEBOOTCFG_GP(v0) |
150 | lw gp, BOOTCFG_GP(t0) | 179 | lw sp, VPEBOOTCFG_SP(v0) |
151 | lw sp, BOOTCFG_SP(t0) | ||
152 | jr t1 | 180 | jr t1 |
153 | nop | 181 | nop |
154 | END(mips_cps_core_entry) | 182 | END(mips_cps_core_entry) |
@@ -189,3 +217,271 @@ LEAF(excep_ejtag) | |||
189 | jr k0 | 217 | jr k0 |
190 | nop | 218 | nop |
191 | END(excep_ejtag) | 219 | END(excep_ejtag) |
220 | |||
221 | LEAF(mips_cps_core_init) | ||
222 | #ifdef CONFIG_MIPS_MT | ||
223 | /* Check that the core implements the MT ASE */ | ||
224 | has_mt t0, 3f | ||
225 | nop | ||
226 | |||
227 | .set push | ||
228 | .set mt | ||
229 | |||
230 | /* Only allow 1 TC per VPE to execute... */ | ||
231 | dmt | ||
232 | |||
233 | /* ...and for the moment only 1 VPE */ | ||
234 | dvpe | ||
235 | la t1, 1f | ||
236 | jr.hb t1 | ||
237 | nop | ||
238 | |||
239 | /* Enter VPE configuration state */ | ||
240 | 1: mfc0 t0, CP0_MVPCONTROL | ||
241 | ori t0, t0, MVPCONTROL_VPC | ||
242 | mtc0 t0, CP0_MVPCONTROL | ||
243 | |||
244 | /* Retrieve the number of VPEs within the core */ | ||
245 | mfc0 t0, CP0_MVPCONF0 | ||
246 | srl t0, t0, MVPCONF0_PVPE_SHIFT | ||
247 | andi t0, t0, (MVPCONF0_PVPE >> MVPCONF0_PVPE_SHIFT) | ||
248 | addi t7, t0, 1 | ||
249 | |||
250 | /* If there's only 1, we're done */ | ||
251 | beqz t0, 2f | ||
252 | nop | ||
253 | |||
254 | /* Loop through each VPE within this core */ | ||
255 | li t5, 1 | ||
256 | |||
257 | 1: /* Operate on the appropriate TC */ | ||
258 | mtc0 t5, CP0_VPECONTROL | ||
259 | ehb | ||
260 | |||
261 | /* Bind TC to VPE (1:1 TC:VPE mapping) */ | ||
262 | mttc0 t5, CP0_TCBIND | ||
263 | |||
264 | /* Set exclusive TC, non-active, master */ | ||
265 | li t0, VPECONF0_MVP | ||
266 | sll t1, t5, VPECONF0_XTC_SHIFT | ||
267 | or t0, t0, t1 | ||
268 | mttc0 t0, CP0_VPECONF0 | ||
269 | |||
270 | /* Set TC non-active, non-allocatable */ | ||
271 | mttc0 zero, CP0_TCSTATUS | ||
272 | |||
273 | /* Set TC halted */ | ||
274 | li t0, TCHALT_H | ||
275 | mttc0 t0, CP0_TCHALT | ||
276 | |||
277 | /* Next VPE */ | ||
278 | addi t5, t5, 1 | ||
279 | slt t0, t5, t7 | ||
280 | bnez t0, 1b | ||
281 | nop | ||
282 | |||
283 | /* Leave VPE configuration state */ | ||
284 | 2: mfc0 t0, CP0_MVPCONTROL | ||
285 | xori t0, t0, MVPCONTROL_VPC | ||
286 | mtc0 t0, CP0_MVPCONTROL | ||
287 | |||
288 | 3: .set pop | ||
289 | #endif | ||
290 | jr ra | ||
291 | nop | ||
292 | END(mips_cps_core_init) | ||
293 | |||
294 | LEAF(mips_cps_boot_vpes) | ||
295 | /* Retrieve CM base address */ | ||
296 | la t0, mips_cm_base | ||
297 | lw t0, 0(t0) | ||
298 | |||
299 | /* Calculate a pointer to this cores struct core_boot_config */ | ||
300 | lw t0, GCR_CL_ID_OFS(t0) | ||
301 | li t1, COREBOOTCFG_SIZE | ||
302 | mul t0, t0, t1 | ||
303 | la t1, mips_cps_core_bootcfg | ||
304 | lw t1, 0(t1) | ||
305 | addu t0, t0, t1 | ||
306 | |||
307 | /* Calculate this VPEs ID. If the core doesn't support MT use 0 */ | ||
308 | has_mt t6, 1f | ||
309 | li t9, 0 | ||
310 | |||
311 | /* Find the number of VPEs present in the core */ | ||
312 | mfc0 t1, CP0_MVPCONF0 | ||
313 | srl t1, t1, MVPCONF0_PVPE_SHIFT | ||
314 | andi t1, t1, MVPCONF0_PVPE >> MVPCONF0_PVPE_SHIFT | ||
315 | addi t1, t1, 1 | ||
316 | |||
317 | /* Calculate a mask for the VPE ID from EBase.CPUNum */ | ||
318 | clz t1, t1 | ||
319 | li t2, 31 | ||
320 | subu t1, t2, t1 | ||
321 | li t2, 1 | ||
322 | sll t1, t2, t1 | ||
323 | addiu t1, t1, -1 | ||
324 | |||
325 | /* Retrieve the VPE ID from EBase.CPUNum */ | ||
326 | mfc0 t9, $15, 1 | ||
327 | and t9, t9, t1 | ||
328 | |||
329 | 1: /* Calculate a pointer to this VPEs struct vpe_boot_config */ | ||
330 | li t1, VPEBOOTCFG_SIZE | ||
331 | mul v0, t9, t1 | ||
332 | lw t7, COREBOOTCFG_VPECONFIG(t0) | ||
333 | addu v0, v0, t7 | ||
334 | |||
335 | #ifdef CONFIG_MIPS_MT | ||
336 | |||
337 | /* If the core doesn't support MT then return */ | ||
338 | bnez t6, 1f | ||
339 | nop | ||
340 | jr ra | ||
341 | nop | ||
342 | |||
343 | .set push | ||
344 | .set mt | ||
345 | |||
346 | 1: /* Enter VPE configuration state */ | ||
347 | dvpe | ||
348 | la t1, 1f | ||
349 | jr.hb t1 | ||
350 | nop | ||
351 | 1: mfc0 t1, CP0_MVPCONTROL | ||
352 | ori t1, t1, MVPCONTROL_VPC | ||
353 | mtc0 t1, CP0_MVPCONTROL | ||
354 | ehb | ||
355 | |||
356 | /* Loop through each VPE */ | ||
357 | lw t6, COREBOOTCFG_VPEMASK(t0) | ||
358 | move t8, t6 | ||
359 | li t5, 0 | ||
360 | |||
361 | /* Check whether the VPE should be running. If not, skip it */ | ||
362 | 1: andi t0, t6, 1 | ||
363 | beqz t0, 2f | ||
364 | nop | ||
365 | |||
366 | /* Operate on the appropriate TC */ | ||
367 | mfc0 t0, CP0_VPECONTROL | ||
368 | ori t0, t0, VPECONTROL_TARGTC | ||
369 | xori t0, t0, VPECONTROL_TARGTC | ||
370 | or t0, t0, t5 | ||
371 | mtc0 t0, CP0_VPECONTROL | ||
372 | ehb | ||
373 | |||
374 | /* Skip the VPE if its TC is not halted */ | ||
375 | mftc0 t0, CP0_TCHALT | ||
376 | beqz t0, 2f | ||
377 | nop | ||
378 | |||
379 | /* Calculate a pointer to the VPEs struct vpe_boot_config */ | ||
380 | li t0, VPEBOOTCFG_SIZE | ||
381 | mul t0, t0, t5 | ||
382 | addu t0, t0, t7 | ||
383 | |||
384 | /* Set the TC restart PC */ | ||
385 | lw t1, VPEBOOTCFG_PC(t0) | ||
386 | mttc0 t1, CP0_TCRESTART | ||
387 | |||
388 | /* Set the TC stack pointer */ | ||
389 | lw t1, VPEBOOTCFG_SP(t0) | ||
390 | mttgpr t1, sp | ||
391 | |||
392 | /* Set the TC global pointer */ | ||
393 | lw t1, VPEBOOTCFG_GP(t0) | ||
394 | mttgpr t1, gp | ||
395 | |||
396 | /* Copy config from this VPE */ | ||
397 | mfc0 t0, CP0_CONFIG | ||
398 | mttc0 t0, CP0_CONFIG | ||
399 | |||
400 | /* Ensure no software interrupts are pending */ | ||
401 | mttc0 zero, CP0_CAUSE | ||
402 | mttc0 zero, CP0_STATUS | ||
403 | |||
404 | /* Set TC active, not interrupt exempt */ | ||
405 | mftc0 t0, CP0_TCSTATUS | ||
406 | li t1, ~TCSTATUS_IXMT | ||
407 | and t0, t0, t1 | ||
408 | ori t0, t0, TCSTATUS_A | ||
409 | mttc0 t0, CP0_TCSTATUS | ||
410 | |||
411 | /* Clear the TC halt bit */ | ||
412 | mttc0 zero, CP0_TCHALT | ||
413 | |||
414 | /* Set VPE active */ | ||
415 | mftc0 t0, CP0_VPECONF0 | ||
416 | ori t0, t0, VPECONF0_VPA | ||
417 | mttc0 t0, CP0_VPECONF0 | ||
418 | |||
419 | /* Next VPE */ | ||
420 | 2: srl t6, t6, 1 | ||
421 | addi t5, t5, 1 | ||
422 | bnez t6, 1b | ||
423 | nop | ||
424 | |||
425 | /* Leave VPE configuration state */ | ||
426 | mfc0 t1, CP0_MVPCONTROL | ||
427 | xori t1, t1, MVPCONTROL_VPC | ||
428 | mtc0 t1, CP0_MVPCONTROL | ||
429 | ehb | ||
430 | evpe | ||
431 | |||
432 | /* Check whether this VPE is meant to be running */ | ||
433 | li t0, 1 | ||
434 | sll t0, t0, t9 | ||
435 | and t0, t0, t8 | ||
436 | bnez t0, 2f | ||
437 | nop | ||
438 | |||
439 | /* This VPE should be offline, halt the TC */ | ||
440 | li t0, TCHALT_H | ||
441 | mtc0 t0, CP0_TCHALT | ||
442 | la t0, 1f | ||
443 | 1: jr.hb t0 | ||
444 | nop | ||
445 | |||
446 | 2: .set pop | ||
447 | |||
448 | #endif /* CONFIG_MIPS_MT */ | ||
449 | |||
450 | /* Return */ | ||
451 | jr ra | ||
452 | nop | ||
453 | END(mips_cps_boot_vpes) | ||
454 | |||
455 | #if defined(CONFIG_MIPS_CPS_PM) && defined(CONFIG_CPU_PM) | ||
456 | |||
457 | /* Calculate a pointer to this CPUs struct mips_static_suspend_state */ | ||
458 | .macro psstate dest | ||
459 | .set push | ||
460 | .set noat | ||
461 | lw $1, TI_CPU(gp) | ||
462 | sll $1, $1, LONGLOG | ||
463 | la \dest, __per_cpu_offset | ||
464 | addu $1, $1, \dest | ||
465 | lw $1, 0($1) | ||
466 | la \dest, cps_cpu_state | ||
467 | addu \dest, \dest, $1 | ||
468 | .set pop | ||
469 | .endm | ||
470 | |||
471 | LEAF(mips_cps_pm_save) | ||
472 | /* Save CPU state */ | ||
473 | SUSPEND_SAVE_REGS | ||
474 | psstate t1 | ||
475 | SUSPEND_SAVE_STATIC | ||
476 | jr v0 | ||
477 | nop | ||
478 | END(mips_cps_pm_save) | ||
479 | |||
480 | LEAF(mips_cps_pm_restore) | ||
481 | /* Restore CPU state */ | ||
482 | psstate t1 | ||
483 | RESUME_RESTORE_STATIC | ||
484 | RESUME_RESTORE_REGS_RETURN | ||
485 | END(mips_cps_pm_restore) | ||
486 | |||
487 | #endif /* CONFIG_MIPS_CPS_PM && CONFIG_CPU_PM */ | ||