diff options
Diffstat (limited to 'include/asm-mips/stackframe.h')
-rw-r--r-- | include/asm-mips/stackframe.h | 187 |
1 files changed, 184 insertions, 3 deletions
diff --git a/include/asm-mips/stackframe.h b/include/asm-mips/stackframe.h index 2acf3e844f00..c4856a874965 100644 --- a/include/asm-mips/stackframe.h +++ b/include/asm-mips/stackframe.h | |||
@@ -14,9 +14,14 @@ | |||
14 | #include <linux/threads.h> | 14 | #include <linux/threads.h> |
15 | 15 | ||
16 | #include <asm/asm.h> | 16 | #include <asm/asm.h> |
17 | #include <asm/asmmacro.h> | ||
17 | #include <asm/mipsregs.h> | 18 | #include <asm/mipsregs.h> |
18 | #include <asm/asm-offsets.h> | 19 | #include <asm/asm-offsets.h> |
19 | 20 | ||
21 | #ifdef CONFIG_MIPS_MT_SMTC | ||
22 | #include <asm/mipsmtregs.h> | ||
23 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
24 | |||
20 | .macro SAVE_AT | 25 | .macro SAVE_AT |
21 | .set push | 26 | .set push |
22 | .set noat | 27 | .set noat |
@@ -57,13 +62,30 @@ | |||
57 | #ifdef CONFIG_SMP | 62 | #ifdef CONFIG_SMP |
58 | .macro get_saved_sp /* SMP variation */ | 63 | .macro get_saved_sp /* SMP variation */ |
59 | #ifdef CONFIG_32BIT | 64 | #ifdef CONFIG_32BIT |
65 | #ifdef CONFIG_MIPS_MT_SMTC | ||
66 | .set mips32 | ||
67 | mfc0 k0, CP0_TCBIND; | ||
68 | .set mips0 | ||
69 | lui k1, %hi(kernelsp) | ||
70 | srl k0, k0, 19 | ||
71 | /* No need to shift down and up to clear bits 0-1 */ | ||
72 | #else | ||
60 | mfc0 k0, CP0_CONTEXT | 73 | mfc0 k0, CP0_CONTEXT |
61 | lui k1, %hi(kernelsp) | 74 | lui k1, %hi(kernelsp) |
62 | srl k0, k0, 23 | 75 | srl k0, k0, 23 |
76 | #endif | ||
63 | addu k1, k0 | 77 | addu k1, k0 |
64 | LONG_L k1, %lo(kernelsp)(k1) | 78 | LONG_L k1, %lo(kernelsp)(k1) |
65 | #endif | 79 | #endif |
66 | #ifdef CONFIG_64BIT | 80 | #ifdef CONFIG_64BIT |
81 | #ifdef CONFIG_MIPS_MT_SMTC | ||
82 | .set mips64 | ||
83 | mfc0 k0, CP0_TCBIND; | ||
84 | .set mips0 | ||
85 | lui k0, %highest(kernelsp) | ||
86 | dsrl k1, 19 | ||
87 | /* No need to shift down and up to clear bits 0-2 */ | ||
88 | #else | ||
67 | MFC0 k1, CP0_CONTEXT | 89 | MFC0 k1, CP0_CONTEXT |
68 | lui k0, %highest(kernelsp) | 90 | lui k0, %highest(kernelsp) |
69 | dsrl k1, 23 | 91 | dsrl k1, 23 |
@@ -71,20 +93,31 @@ | |||
71 | dsll k0, k0, 16 | 93 | dsll k0, k0, 16 |
72 | daddiu k0, %hi(kernelsp) | 94 | daddiu k0, %hi(kernelsp) |
73 | dsll k0, k0, 16 | 95 | dsll k0, k0, 16 |
96 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
74 | daddu k1, k1, k0 | 97 | daddu k1, k1, k0 |
75 | LONG_L k1, %lo(kernelsp)(k1) | 98 | LONG_L k1, %lo(kernelsp)(k1) |
76 | #endif | 99 | #endif /* CONFIG_64BIT */ |
77 | .endm | 100 | .endm |
78 | 101 | ||
79 | .macro set_saved_sp stackp temp temp2 | 102 | .macro set_saved_sp stackp temp temp2 |
80 | #ifdef CONFIG_32BIT | 103 | #ifdef CONFIG_32BIT |
104 | #ifdef CONFIG_MIPS_MT_SMTC | ||
105 | mfc0 \temp, CP0_TCBIND | ||
106 | srl \temp, 19 | ||
107 | #else | ||
81 | mfc0 \temp, CP0_CONTEXT | 108 | mfc0 \temp, CP0_CONTEXT |
82 | srl \temp, 23 | 109 | srl \temp, 23 |
83 | #endif | 110 | #endif |
111 | #endif | ||
84 | #ifdef CONFIG_64BIT | 112 | #ifdef CONFIG_64BIT |
113 | #ifdef CONFIG_MIPS_MT_SMTC | ||
114 | mfc0 \temp, CP0_TCBIND | ||
115 | dsrl \temp, 19 | ||
116 | #else | ||
85 | MFC0 \temp, CP0_CONTEXT | 117 | MFC0 \temp, CP0_CONTEXT |
86 | dsrl \temp, 23 | 118 | dsrl \temp, 23 |
87 | #endif | 119 | #endif |
120 | #endif | ||
88 | LONG_S \stackp, kernelsp(\temp) | 121 | LONG_S \stackp, kernelsp(\temp) |
89 | .endm | 122 | .endm |
90 | #else | 123 | #else |
@@ -122,10 +155,25 @@ | |||
122 | PTR_SUBU sp, k1, PT_SIZE | 155 | PTR_SUBU sp, k1, PT_SIZE |
123 | LONG_S k0, PT_R29(sp) | 156 | LONG_S k0, PT_R29(sp) |
124 | LONG_S $3, PT_R3(sp) | 157 | LONG_S $3, PT_R3(sp) |
158 | /* | ||
159 | * You might think that you don't need to save $0, | ||
160 | * but the FPU emulator and gdb remote debug stub | ||
161 | * need it to operate correctly | ||
162 | */ | ||
125 | LONG_S $0, PT_R0(sp) | 163 | LONG_S $0, PT_R0(sp) |
126 | mfc0 v1, CP0_STATUS | 164 | mfc0 v1, CP0_STATUS |
127 | LONG_S $2, PT_R2(sp) | 165 | LONG_S $2, PT_R2(sp) |
128 | LONG_S v1, PT_STATUS(sp) | 166 | LONG_S v1, PT_STATUS(sp) |
167 | #ifdef CONFIG_MIPS_MT_SMTC | ||
168 | /* | ||
169 | * Ideally, these instructions would be shuffled in | ||
170 | * to cover the pipeline delay. | ||
171 | */ | ||
172 | .set mips32 | ||
173 | mfc0 v1, CP0_TCSTATUS | ||
174 | .set mips0 | ||
175 | LONG_S v1, PT_TCSTATUS(sp) | ||
176 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
129 | LONG_S $4, PT_R4(sp) | 177 | LONG_S $4, PT_R4(sp) |
130 | mfc0 v1, CP0_CAUSE | 178 | mfc0 v1, CP0_CAUSE |
131 | LONG_S $5, PT_R5(sp) | 179 | LONG_S $5, PT_R5(sp) |
@@ -234,14 +282,36 @@ | |||
234 | .endm | 282 | .endm |
235 | 283 | ||
236 | #else | 284 | #else |
285 | /* | ||
286 | * For SMTC kernel, global IE should be left set, and interrupts | ||
287 | * controlled exclusively via IXMT. | ||
288 | */ | ||
237 | 289 | ||
290 | #ifdef CONFIG_MIPS_MT_SMTC | ||
291 | #define STATMASK 0x1e | ||
292 | #else | ||
293 | #define STATMASK 0x1f | ||
294 | #endif | ||
238 | .macro RESTORE_SOME | 295 | .macro RESTORE_SOME |
239 | .set push | 296 | .set push |
240 | .set reorder | 297 | .set reorder |
241 | .set noat | 298 | .set noat |
299 | #ifdef CONFIG_MIPS_MT_SMTC | ||
300 | .set mips32r2 | ||
301 | /* | ||
302 | * This may not really be necessary if ints are already | ||
303 | * inhibited here. | ||
304 | */ | ||
305 | mfc0 v0, CP0_TCSTATUS | ||
306 | ori v0, TCSTATUS_IXMT | ||
307 | mtc0 v0, CP0_TCSTATUS | ||
308 | ehb | ||
309 | DMT 5 # dmt a1 | ||
310 | jal mips_ihb | ||
311 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
242 | mfc0 a0, CP0_STATUS | 312 | mfc0 a0, CP0_STATUS |
243 | ori a0, 0x1f | 313 | ori a0, STATMASK |
244 | xori a0, 0x1f | 314 | xori a0, STATMASK |
245 | mtc0 a0, CP0_STATUS | 315 | mtc0 a0, CP0_STATUS |
246 | li v1, 0xff00 | 316 | li v1, 0xff00 |
247 | and a0, v1 | 317 | and a0, v1 |
@@ -250,6 +320,26 @@ | |||
250 | and v0, v1 | 320 | and v0, v1 |
251 | or v0, a0 | 321 | or v0, a0 |
252 | mtc0 v0, CP0_STATUS | 322 | mtc0 v0, CP0_STATUS |
323 | #ifdef CONFIG_MIPS_MT_SMTC | ||
324 | /* | ||
325 | * Only after EXL/ERL have been restored to status can we | ||
326 | * restore TCStatus.IXMT. | ||
327 | */ | ||
328 | LONG_L v1, PT_TCSTATUS(sp) | ||
329 | ehb | ||
330 | mfc0 v0, CP0_TCSTATUS | ||
331 | andi v1, TCSTATUS_IXMT | ||
332 | /* We know that TCStatua.IXMT should be set from above */ | ||
333 | xori v0, v0, TCSTATUS_IXMT | ||
334 | or v0, v0, v1 | ||
335 | mtc0 v0, CP0_TCSTATUS | ||
336 | ehb | ||
337 | andi a1, a1, VPECONTROL_TE | ||
338 | beqz a1, 1f | ||
339 | emt | ||
340 | 1: | ||
341 | .set mips0 | ||
342 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
253 | LONG_L v1, PT_EPC(sp) | 343 | LONG_L v1, PT_EPC(sp) |
254 | MTC0 v1, CP0_EPC | 344 | MTC0 v1, CP0_EPC |
255 | LONG_L $31, PT_R31(sp) | 345 | LONG_L $31, PT_R31(sp) |
@@ -302,11 +392,33 @@ | |||
302 | * Set cp0 enable bit as sign that we're running on the kernel stack | 392 | * Set cp0 enable bit as sign that we're running on the kernel stack |
303 | */ | 393 | */ |
304 | .macro CLI | 394 | .macro CLI |
395 | #if !defined(CONFIG_MIPS_MT_SMTC) | ||
305 | mfc0 t0, CP0_STATUS | 396 | mfc0 t0, CP0_STATUS |
306 | li t1, ST0_CU0 | 0x1f | 397 | li t1, ST0_CU0 | 0x1f |
307 | or t0, t1 | 398 | or t0, t1 |
308 | xori t0, 0x1f | 399 | xori t0, 0x1f |
309 | mtc0 t0, CP0_STATUS | 400 | mtc0 t0, CP0_STATUS |
401 | #else /* CONFIG_MIPS_MT_SMTC */ | ||
402 | /* | ||
403 | * For SMTC, we need to set privilege | ||
404 | * and disable interrupts only for the | ||
405 | * current TC, using the TCStatus register. | ||
406 | */ | ||
407 | mfc0 t0,CP0_TCSTATUS | ||
408 | /* Fortunately CU 0 is in the same place in both registers */ | ||
409 | /* Set TCU0, TMX, TKSU (for later inversion) and IXMT */ | ||
410 | li t1, ST0_CU0 | 0x08001c00 | ||
411 | or t0,t1 | ||
412 | /* Clear TKSU, leave IXMT */ | ||
413 | xori t0, 0x00001800 | ||
414 | mtc0 t0, CP0_TCSTATUS | ||
415 | ehb | ||
416 | /* We need to leave the global IE bit set, but clear EXL...*/ | ||
417 | mfc0 t0, CP0_STATUS | ||
418 | ori t0, ST0_EXL | ST0_ERL | ||
419 | xori t0, ST0_EXL | ST0_ERL | ||
420 | mtc0 t0, CP0_STATUS | ||
421 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
310 | irq_disable_hazard | 422 | irq_disable_hazard |
311 | .endm | 423 | .endm |
312 | 424 | ||
@@ -315,11 +427,35 @@ | |||
315 | * Set cp0 enable bit as sign that we're running on the kernel stack | 427 | * Set cp0 enable bit as sign that we're running on the kernel stack |
316 | */ | 428 | */ |
317 | .macro STI | 429 | .macro STI |
430 | #if !defined(CONFIG_MIPS_MT_SMTC) | ||
318 | mfc0 t0, CP0_STATUS | 431 | mfc0 t0, CP0_STATUS |
319 | li t1, ST0_CU0 | 0x1f | 432 | li t1, ST0_CU0 | 0x1f |
320 | or t0, t1 | 433 | or t0, t1 |
321 | xori t0, 0x1e | 434 | xori t0, 0x1e |
322 | mtc0 t0, CP0_STATUS | 435 | mtc0 t0, CP0_STATUS |
436 | #else /* CONFIG_MIPS_MT_SMTC */ | ||
437 | /* | ||
438 | * For SMTC, we need to set privilege | ||
439 | * and enable interrupts only for the | ||
440 | * current TC, using the TCStatus register. | ||
441 | */ | ||
442 | ehb | ||
443 | mfc0 t0,CP0_TCSTATUS | ||
444 | /* Fortunately CU 0 is in the same place in both registers */ | ||
445 | /* Set TCU0, TKSU (for later inversion) and IXMT */ | ||
446 | li t1, ST0_CU0 | 0x08001c00 | ||
447 | or t0,t1 | ||
448 | /* Clear TKSU *and* IXMT */ | ||
449 | xori t0, 0x00001c00 | ||
450 | mtc0 t0, CP0_TCSTATUS | ||
451 | ehb | ||
452 | /* We need to leave the global IE bit set, but clear EXL...*/ | ||
453 | mfc0 t0, CP0_STATUS | ||
454 | ori t0, ST0_EXL | ||
455 | xori t0, ST0_EXL | ||
456 | mtc0 t0, CP0_STATUS | ||
457 | /* irq_enable_hazard below should expand to EHB for 24K/34K cpus */ | ||
458 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
323 | irq_enable_hazard | 459 | irq_enable_hazard |
324 | .endm | 460 | .endm |
325 | 461 | ||
@@ -328,11 +464,56 @@ | |||
328 | * Set cp0 enable bit as sign that we're running on the kernel stack | 464 | * Set cp0 enable bit as sign that we're running on the kernel stack |
329 | */ | 465 | */ |
330 | .macro KMODE | 466 | .macro KMODE |
467 | #ifdef CONFIG_MIPS_MT_SMTC | ||
468 | /* | ||
469 | * This gets baroque in SMTC. We want to | ||
470 | * protect the non-atomic clearing of EXL | ||
471 | * with DMT/EMT, but we don't want to take | ||
472 | * an interrupt while DMT is still in effect. | ||
473 | */ | ||
474 | |||
475 | /* KMODE gets invoked from both reorder and noreorder code */ | ||
476 | .set push | ||
477 | .set mips32r2 | ||
478 | .set noreorder | ||
479 | mfc0 v0, CP0_TCSTATUS | ||
480 | andi v1, v0, TCSTATUS_IXMT | ||
481 | ori v0, TCSTATUS_IXMT | ||
482 | mtc0 v0, CP0_TCSTATUS | ||
483 | ehb | ||
484 | DMT 2 # dmt v0 | ||
485 | /* | ||
486 | * We don't know a priori if ra is "live" | ||
487 | */ | ||
488 | move t0, ra | ||
489 | jal mips_ihb | ||
490 | nop /* delay slot */ | ||
491 | move ra, t0 | ||
492 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
331 | mfc0 t0, CP0_STATUS | 493 | mfc0 t0, CP0_STATUS |
332 | li t1, ST0_CU0 | 0x1e | 494 | li t1, ST0_CU0 | 0x1e |
333 | or t0, t1 | 495 | or t0, t1 |
334 | xori t0, 0x1e | 496 | xori t0, 0x1e |
335 | mtc0 t0, CP0_STATUS | 497 | mtc0 t0, CP0_STATUS |
498 | #ifdef CONFIG_MIPS_MT_SMTC | ||
499 | ehb | ||
500 | andi v0, v0, VPECONTROL_TE | ||
501 | beqz v0, 2f | ||
502 | nop /* delay slot */ | ||
503 | emt | ||
504 | 2: | ||
505 | mfc0 v0, CP0_TCSTATUS | ||
506 | /* Clear IXMT, then OR in previous value */ | ||
507 | ori v0, TCSTATUS_IXMT | ||
508 | xori v0, TCSTATUS_IXMT | ||
509 | or v0, v1, v0 | ||
510 | mtc0 v0, CP0_TCSTATUS | ||
511 | /* | ||
512 | * irq_disable_hazard below should expand to EHB | ||
513 | * on 24K/34K CPUS | ||
514 | */ | ||
515 | .set pop | ||
516 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
336 | irq_disable_hazard | 517 | irq_disable_hazard |
337 | .endm | 518 | .endm |
338 | 519 | ||