diff options
author | Magnus Damm <damm@igel.co.jp> | 2009-02-23 02:14:02 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-02-27 02:26:10 -0500 |
commit | 1d015cf02a1fd46385c03cf3ce8958dbea705dd3 (patch) | |
tree | 833e2ab294be74d7ecb3512a24bfefbc86189c59 | |
parent | b233b28eac0cc37d07c2d007ea08c86c778c5af4 (diff) |
sh: shared register saving code for sh3/sh4/sh4a
This patch reworks the sh3/sh4/sh4a register saving code in
the following ways:
- break out prepare_stack_save_dsp() from handle_exception()
- break out save_regs() from handle_exception()
- the register saving order is unchanged
- align new functions to fit in cache lines
- separate exception code from interrupt code
- keep main code flow in a single cache line per exception vector
- use bsr/rts for regular functions (save pr first)
- keep data in one shared cache line (exception_data)
- document the functions
- tie in the hp6xx code
Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r-- | arch/sh/boards/mach-hp6xx/pm_wakeup.S | 31 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh3/entry.S | 273 |
2 files changed, 155 insertions, 149 deletions
diff --git a/arch/sh/boards/mach-hp6xx/pm_wakeup.S b/arch/sh/boards/mach-hp6xx/pm_wakeup.S index 44b648cf6f23..4f18d44e0541 100644 --- a/arch/sh/boards/mach-hp6xx/pm_wakeup.S +++ b/arch/sh/boards/mach-hp6xx/pm_wakeup.S | |||
@@ -10,47 +10,32 @@ | |||
10 | #include <linux/linkage.h> | 10 | #include <linux/linkage.h> |
11 | #include <cpu/mmu_context.h> | 11 | #include <cpu/mmu_context.h> |
12 | 12 | ||
13 | #define k0 r0 | ||
14 | #define k1 r1 | ||
15 | #define k2 r2 | ||
16 | #define k3 r3 | ||
17 | #define k4 r4 | ||
18 | |||
19 | /* | 13 | /* |
20 | * Kernel mode register usage: | 14 | * Kernel mode register usage: |
21 | * k0 scratch | 15 | * k0 scratch |
22 | * k1 scratch | 16 | * k1 scratch |
23 | * k2 scratch (Exception code) | 17 | * For more details, please have a look at entry.S |
24 | * k3 scratch (Return address) | ||
25 | * k4 scratch | ||
26 | * k5 reserved | ||
27 | * k6 Global Interrupt Mask (0--15 << 4) | ||
28 | * k7 CURRENT_THREAD_INFO (pointer to current thread info) | ||
29 | */ | 18 | */ |
30 | 19 | ||
20 | #define k0 r0 | ||
21 | #define k1 r1 | ||
22 | |||
31 | ENTRY(wakeup_start) | 23 | ENTRY(wakeup_start) |
32 | ! clear STBY bit | 24 | ! clear STBY bit |
33 | mov #-126, k2 | 25 | mov #-126, k1 |
34 | and #127, k0 | 26 | and #127, k0 |
35 | mov.b k0, @k2 | 27 | mov.b k0, @k1 |
36 | ! enable refresh | 28 | ! enable refresh |
37 | mov.l 5f, k1 | 29 | mov.l 5f, k1 |
38 | mov.w 6f, k0 | 30 | mov.w 6f, k0 |
39 | mov.w k0, @k1 | 31 | mov.w k0, @k1 |
40 | ! jump to handler | 32 | ! jump to handler |
41 | mov.l 2f, k2 | ||
42 | mov.l 3f, k3 | ||
43 | mov.l @k2, k2 | ||
44 | |||
45 | mov.l 4f, k1 | 33 | mov.l 4f, k1 |
46 | jmp @k1 | 34 | jmp @k1 |
47 | nop | 35 | nop |
48 | 36 | ||
49 | .align 2 | 37 | .align 2 |
50 | 1: .long EXPEVT | 38 | 4: .long handle_interrupt |
51 | 2: .long INTEVT | ||
52 | 3: .long ret_from_irq | ||
53 | 4: .long handle_exception | ||
54 | 5: .long 0xffffff68 | 39 | 5: .long 0xffffff68 |
55 | 6: .word 0x0524 | 40 | 6: .word 0x0524 |
56 | 41 | ||
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S index b4106d0c68ec..f3db143e70b2 100644 --- a/arch/sh/kernel/cpu/sh3/entry.S +++ b/arch/sh/kernel/cpu/sh3/entry.S | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <asm/unistd.h> | 16 | #include <asm/unistd.h> |
17 | #include <cpu/mmu_context.h> | 17 | #include <cpu/mmu_context.h> |
18 | #include <asm/page.h> | 18 | #include <asm/page.h> |
19 | #include <asm/cache.h> | ||
19 | 20 | ||
20 | ! NOTE: | 21 | ! NOTE: |
21 | ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address | 22 | ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address |
@@ -294,7 +295,7 @@ skip_restore: | |||
294 | mov #0xf0, k1 | 295 | mov #0xf0, k1 |
295 | extu.b k1, k1 | 296 | extu.b k1, k1 |
296 | not k1, k1 | 297 | not k1, k1 |
297 | and k1, k2 ! Mask orignal SR value | 298 | and k1, k2 ! Mask original SR value |
298 | ! | 299 | ! |
299 | mov k3, k0 ! Calculate IMASK-bits | 300 | mov k3, k0 ! Calculate IMASK-bits |
300 | shlr2 k0 | 301 | shlr2 k0 |
@@ -336,81 +337,53 @@ skip_restore: | |||
336 | ENTRY(vbr_base) | 337 | ENTRY(vbr_base) |
337 | .long 0 | 338 | .long 0 |
338 | ! | 339 | ! |
340 | ! 0x100: General exception vector | ||
341 | ! | ||
339 | .balign 256,0,256 | 342 | .balign 256,0,256 |
340 | general_exception: | 343 | general_exception: |
341 | mov.l 1f, k2 | 344 | #ifndef CONFIG_CPU_SUBTYPE_SHX3 |
342 | mov.l 2f, k3 | 345 | bra handle_exception |
343 | #ifdef CONFIG_CPU_SUBTYPE_SHX3 | 346 | sts pr, k3 ! save original pr value in k3 |
344 | mov.l @k2, k2 | 347 | #else |
348 | mov.l 1f, k4 | ||
349 | mov.l @k4, k4 | ||
345 | 350 | ||
346 | ! Is EXPEVT larger than 0x800? | 351 | ! Is EXPEVT larger than 0x800? |
347 | mov #0x8, k0 | 352 | mov #0x8, k0 |
348 | shll8 k0 | 353 | shll8 k0 |
349 | cmp/hs k0, k2 | 354 | cmp/hs k0, k4 |
350 | bf 0f | 355 | bf 0f |
351 | 356 | ||
352 | ! then add 0x580 (k2 is 0xd80 or 0xda0) | 357 | ! then add 0x580 (k2 is 0xd80 or 0xda0) |
353 | mov #0x58, k0 | 358 | mov #0x58, k0 |
354 | shll2 k0 | 359 | shll2 k0 |
355 | shll2 k0 | 360 | shll2 k0 |
356 | add k0, k2 | 361 | add k0, k4 |
357 | 0: | 362 | 0: |
358 | bra handle_exception | 363 | ! Setup stack and save DSP context (k0 contains original r15 on return) |
364 | bsr prepare_stack_save_dsp | ||
359 | nop | 365 | nop |
360 | #else | ||
361 | bra handle_exception | ||
362 | mov.l @k2, k2 | ||
363 | #endif | ||
364 | .align 2 | ||
365 | 1: .long EXPEVT | ||
366 | 2: .long ret_from_exception | ||
367 | ! | ||
368 | ! | ||
369 | 366 | ||
370 | .balign 1024,0,1024 | 367 | ! Save registers / Switch to bank 0 |
371 | tlb_miss: | 368 | bsr save_regs ! needs original pr value in k3 |
372 | mov.l 1f, k2 | 369 | mov.l k4, k2 ! keep vector in k2 |
373 | mov.l 4f, k3 | 370 | |
374 | bra handle_exception | 371 | bra handle_exception_special |
375 | mov.l @k2, k2 | ||
376 | ! | ||
377 | .balign 512,0,512 | ||
378 | interrupt: | ||
379 | mov.l 3f, k3 | ||
380 | #if defined(CONFIG_KGDB) | ||
381 | mov.l 2f, k2 | ||
382 | ! Debounce (filter nested NMI) | ||
383 | mov.l @k2, k0 | ||
384 | mov.l 5f, k1 | ||
385 | cmp/eq k1, k0 | ||
386 | bf 0f | ||
387 | mov.l 6f, k1 | ||
388 | tas.b @k1 | ||
389 | bt 0f | ||
390 | rte | ||
391 | nop | 372 | nop |
392 | .align 2 | ||
393 | 2: .long INTEVT | ||
394 | 5: .long NMI_VEC | ||
395 | 6: .long in_nmi | ||
396 | 0: | ||
397 | #endif /* defined(CONFIG_KGDB) */ | ||
398 | bra handle_exception | ||
399 | mov #-1, k2 ! interrupt exception marker | ||
400 | 373 | ||
401 | .align 2 | 374 | .align 2 |
402 | 1: .long EXPEVT | 375 | 1: .long EXPEVT |
403 | 3: .long ret_from_irq | 376 | #endif |
404 | 4: .long ret_from_exception | ||
405 | 377 | ||
406 | ! | 378 | ! prepare_stack_save_dsp() |
407 | ! | 379 | ! - roll back gRB |
408 | .align 2 | 380 | ! - switch to kernel stack |
409 | ENTRY(handle_exception) | 381 | ! - save DSP |
410 | ! Using k0, k1 for scratch registers (r0_bank1, r1_bank), | 382 | ! k0 returns original sp (after roll back) |
411 | ! save all registers onto stack. | 383 | ! k1 trashed |
412 | ! | 384 | ! k2 trashed |
413 | 385 | ||
386 | prepare_stack_save_dsp: | ||
414 | #ifdef CONFIG_GUSA | 387 | #ifdef CONFIG_GUSA |
415 | ! Check for roll back gRB (User and Kernel) | 388 | ! Check for roll back gRB (User and Kernel) |
416 | mov r15, k0 | 389 | mov r15, k0 |
@@ -430,7 +403,7 @@ ENTRY(handle_exception) | |||
430 | 2: mov k1, r15 ! SP = r1 | 403 | 2: mov k1, r15 ! SP = r1 |
431 | 1: | 404 | 1: |
432 | #endif | 405 | #endif |
433 | 406 | ! Switch to kernel stack if needed | |
434 | stc ssr, k0 ! Is it from kernel space? | 407 | stc ssr, k0 ! Is it from kernel space? |
435 | shll k0 ! Check MD bit (bit30) by shifting it into... | 408 | shll k0 ! Check MD bit (bit30) by shifting it into... |
436 | shll k0 ! ...the T bit | 409 | shll k0 ! ...the T bit |
@@ -443,18 +416,17 @@ ENTRY(handle_exception) | |||
443 | add current, k1 | 416 | add current, k1 |
444 | mov k1, r15 ! change to kernel stack | 417 | mov k1, r15 ! change to kernel stack |
445 | ! | 418 | ! |
446 | 1: mov.l 2f, k1 | 419 | 1: |
447 | ! | ||
448 | #ifdef CONFIG_SH_DSP | 420 | #ifdef CONFIG_SH_DSP |
449 | mov.l r2, @-r15 ! Save r2, we need another reg | 421 | ! Save DSP context if needed |
450 | stc sr, k4 | 422 | stc sr, k1 |
451 | mov.l 1f, r2 | 423 | mov #0x10, k2 |
452 | tst r2, k4 ! Check if in DSP mode | 424 | shll8 k2 ! DSP=1 (0x00001000) |
453 | mov.l @r15+, r2 ! Restore r2 now | 425 | tst k2, k1 ! Check if in DSP mode (passed in k2) |
454 | bt/s skip_save | 426 | bt/s skip_save |
455 | mov #0, k4 ! Set marker for no stack frame | 427 | mov #0, k1 ! Set marker for no stack frame |
456 | 428 | ||
457 | mov r2, k4 ! Backup r2 (in k4) for later | 429 | mov k2, k1 ! Save has-frame marker |
458 | 430 | ||
459 | ! Save DSP registers on stack | 431 | ! Save DSP registers on stack |
460 | stc.l mod, @-r15 | 432 | stc.l mod, @-r15 |
@@ -473,35 +445,73 @@ ENTRY(handle_exception) | |||
473 | ! as we're not at all interested in supporting ancient toolchains at | 445 | ! as we're not at all interested in supporting ancient toolchains at |
474 | ! this point. -- PFM. | 446 | ! this point. -- PFM. |
475 | 447 | ||
476 | mov r15, r2 | 448 | mov r15, k2 |
477 | .word 0xf653 ! movs.l a1, @-r2 | 449 | .word 0xf653 ! movs.l a1, @-r2 |
478 | .word 0xf6f3 ! movs.l a0g, @-r2 | 450 | .word 0xf6f3 ! movs.l a0g, @-r2 |
479 | .word 0xf6d3 ! movs.l a1g, @-r2 | 451 | .word 0xf6d3 ! movs.l a1g, @-r2 |
480 | .word 0xf6c3 ! movs.l m0, @-r2 | 452 | .word 0xf6c3 ! movs.l m0, @-r2 |
481 | .word 0xf6e3 ! movs.l m1, @-r2 | 453 | .word 0xf6e3 ! movs.l m1, @-r2 |
482 | mov r2, r15 | 454 | mov k2, r15 |
483 | 455 | ||
484 | mov k4, r2 ! Restore r2 | ||
485 | mov.l 1f, k4 ! Force DSP stack frame | ||
486 | skip_save: | 456 | skip_save: |
487 | mov.l k4, @-r15 ! Push DSP mode marker onto stack | 457 | mov.l k1, @-r15 ! Push DSP mode marker onto stack |
488 | #endif | 458 | #endif |
489 | ! Save the user registers on the stack. | 459 | rts |
490 | mov.l k2, @-r15 ! EXPEVT | 460 | nop |
461 | ! | ||
462 | ! 0x400: Instruction and Data TLB miss exception vector | ||
463 | ! | ||
464 | .balign 1024,0,1024 | ||
465 | tlb_miss: | ||
466 | sts pr, k3 ! save original pr value in k3 | ||
491 | 467 | ||
492 | mov #-1, k4 | 468 | handle_exception: |
493 | mov.l k4, @-r15 ! set TRA (default: -1) | 469 | ! Setup stack and save DSP context (k0 contains original r15 on return) |
494 | ! | 470 | bsr prepare_stack_save_dsp |
471 | nop | ||
472 | |||
473 | ! Save registers / Switch to bank 0 | ||
474 | mov.l 5f, k2 ! vector register address | ||
475 | bsr save_regs ! needs original pr value in k3 | ||
476 | mov.l @k2, k2 ! read out vector and keep in k2 | ||
477 | |||
478 | handle_exception_special: | ||
479 | ! Setup return address and jump to exception handler | ||
480 | mov.l 7f, r9 ! fetch return address | ||
481 | stc r2_bank, r0 ! k2 (vector) | ||
482 | mov.l 6f, r10 | ||
483 | shlr2 r0 | ||
484 | shlr r0 | ||
485 | mov.l @(r0, r10), r10 | ||
486 | jmp @r10 | ||
487 | lds r9, pr ! put return address in pr | ||
488 | |||
489 | .align L1_CACHE_SHIFT | ||
490 | |||
491 | ! save_regs() | ||
492 | ! - save vector, default tra, macl, mach, gbr, ssr, pr* and spc on the stack | ||
493 | ! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack | ||
494 | ! - switch bank | ||
495 | ! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack | ||
496 | ! k0 contains original stack pointer* | ||
497 | ! k1 trashed | ||
498 | ! k2 passes vector (EXPEVT) | ||
499 | ! k3 passes original pr* | ||
500 | ! k4 trashed | ||
501 | ! BL=1 on entry, on exit BL=0. | ||
502 | |||
503 | save_regs: | ||
504 | mov #-1, r1 | ||
505 | mov.l k2, @-r15 ! vector in k2 | ||
506 | mov.l k1, @-r15 ! set TRA (default: -1) | ||
495 | sts.l macl, @-r15 | 507 | sts.l macl, @-r15 |
496 | sts.l mach, @-r15 | 508 | sts.l mach, @-r15 |
497 | stc.l gbr, @-r15 | 509 | stc.l gbr, @-r15 |
498 | stc.l ssr, @-r15 | 510 | stc.l ssr, @-r15 |
499 | sts.l pr, @-r15 | 511 | mov.l k3, @-r15 ! original pr in k3 |
500 | stc.l spc, @-r15 | 512 | stc.l spc, @-r15 |
501 | ! | 513 | |
502 | lds k3, pr ! Set the return address to pr | 514 | mov.l k0, @-r15 ! original stack pointer in k0 |
503 | ! | ||
504 | mov.l k0, @-r15 ! save orignal stack | ||
505 | mov.l r14, @-r15 | 515 | mov.l r14, @-r15 |
506 | mov.l r13, @-r15 | 516 | mov.l r13, @-r15 |
507 | mov.l r12, @-r15 | 517 | mov.l r12, @-r15 |
@@ -509,13 +519,15 @@ skip_save: | |||
509 | mov.l r10, @-r15 | 519 | mov.l r10, @-r15 |
510 | mov.l r9, @-r15 | 520 | mov.l r9, @-r15 |
511 | mov.l r8, @-r15 | 521 | mov.l r8, @-r15 |
512 | ! | 522 | |
513 | stc sr, r8 ! Back to normal register bank, and | 523 | mov.l 0f, k3 ! SR bits to set in k3 |
514 | or k1, r8 ! Block all interrupts | 524 | mov.l 1f, k4 ! SR bits to clear in k4 |
515 | mov.l 3f, k1 | 525 | |
516 | and k1, r8 ! ... | 526 | stc sr, r8 |
517 | ldc r8, sr ! ...changed here. | 527 | or k3, r8 |
518 | ! | 528 | and k4, r8 |
529 | ldc r8, sr | ||
530 | |||
519 | mov.l r7, @-r15 | 531 | mov.l r7, @-r15 |
520 | mov.l r6, @-r15 | 532 | mov.l r6, @-r15 |
521 | mov.l r5, @-r15 | 533 | mov.l r5, @-r15 |
@@ -523,52 +535,61 @@ skip_save: | |||
523 | mov.l r3, @-r15 | 535 | mov.l r3, @-r15 |
524 | mov.l r2, @-r15 | 536 | mov.l r2, @-r15 |
525 | mov.l r1, @-r15 | 537 | mov.l r1, @-r15 |
526 | mov.l r0, @-r15 | ||
527 | |||
528 | /* | ||
529 | * This gets a bit tricky.. in the INTEVT case we don't want to use | ||
530 | * the VBR offset as a destination in the jump call table, since all | ||
531 | * of the destinations are the same. In this case, (interrupt) sets | ||
532 | * a marker in r2 (now r2_bank since SR.RB changed), which we check | ||
533 | * to determine the exception type. For all other exceptions, we | ||
534 | * forcibly read EXPEVT from memory and fix up the jump address, in | ||
535 | * the interrupt exception case we jump to do_IRQ() and defer the | ||
536 | * INTEVT read until there. As a bonus, we can also clean up the SR.RB | ||
537 | * checks that do_IRQ() was doing.. | ||
538 | */ | ||
539 | stc r2_bank, r8 | ||
540 | cmp/pz r8 | ||
541 | bf interrupt_exception | ||
542 | shlr2 r8 | ||
543 | shlr r8 | ||
544 | mov.l 4f, r9 | ||
545 | add r8, r9 | ||
546 | mov.l @r9, r9 | ||
547 | jmp @r9 | ||
548 | nop | ||
549 | rts | 538 | rts |
550 | nop | 539 | mov.l r0, @-r15 |
551 | 540 | ||
541 | ! | ||
542 | ! 0x600: Interrupt / NMI vector | ||
543 | ! | ||
544 | .balign 512,0,512 | ||
545 | ENTRY(handle_interrupt) | ||
546 | #if defined(CONFIG_KGDB) | ||
547 | mov.l 2f, k2 | ||
548 | ! Debounce (filter nested NMI) | ||
549 | mov.l @k2, k0 | ||
550 | mov.l 9f, k1 | ||
551 | cmp/eq k1, k0 | ||
552 | bf 11f | ||
553 | mov.l 10f, k1 | ||
554 | tas.b @k1 | ||
555 | bt 11f | ||
556 | rte | ||
557 | nop | ||
552 | .align 2 | 558 | .align 2 |
553 | 1: .long 0x00001000 ! DSP=1 | 559 | 9: .long NMI_VEC |
554 | 2: .long 0x000080f0 ! FD=1, IMASK=15 | 560 | 10: .long in_nmi |
555 | 3: .long 0xcfffffff ! RB=0, BL=0 | 561 | 11: |
556 | 4: .long exception_handling_table | 562 | #endif /* defined(CONFIG_KGDB) */ |
563 | sts pr, k3 ! save original pr value in k3 | ||
557 | 564 | ||
558 | interrupt_exception: | 565 | ! Setup stack and save DSP context (k0 contains original r15 on return) |
559 | mov.l 1f, r9 | 566 | bsr prepare_stack_save_dsp |
560 | mov.l 2f, r4 | ||
561 | mov.l @r4, r4 | ||
562 | jmp @r9 | ||
563 | mov r15, r5 | ||
564 | rts | ||
565 | nop | 567 | nop |
566 | 568 | ||
567 | .align 2 | 569 | ! Save registers / Switch to bank 0 |
568 | 1: .long do_IRQ | 570 | bsr save_regs ! needs original pr value in k3 |
569 | 2: .long INTEVT | 571 | mov #-1, k2 ! default vector kept in k2 |
572 | |||
573 | ! Setup return address and jump to do_IRQ | ||
574 | mov.l 4f, r9 ! fetch return address | ||
575 | lds r9, pr ! put return address in pr | ||
576 | mov.l 2f, r4 | ||
577 | mov.l 3f, r9 | ||
578 | mov.l @r4, r4 ! pass INTEVT vector as arg0 | ||
579 | jmp @r9 | ||
580 | mov r15, r5 ! pass saved registers as arg1 | ||
570 | 581 | ||
571 | .align 2 | ||
572 | ENTRY(exception_none) | 582 | ENTRY(exception_none) |
573 | rts | 583 | rts |
574 | nop | 584 | nop |
585 | |||
586 | .align L1_CACHE_SHIFT | ||
587 | exception_data: | ||
588 | 0: .long 0x000080f0 ! FD=1, IMASK=15 | ||
589 | 1: .long 0xcfffffff ! RB=0, BL=0 | ||
590 | 2: .long INTEVT | ||
591 | 3: .long do_IRQ | ||
592 | 4: .long ret_from_irq | ||
593 | 5: .long EXPEVT | ||
594 | 6: .long exception_handling_table | ||
595 | 7: .long ret_from_exception | ||