diff options
Diffstat (limited to 'arch/sparc64/kernel/entry.S')
| -rw-r--r-- | arch/sparc64/kernel/entry.S | 293 |
1 files changed, 181 insertions, 112 deletions
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 88332f00094a..cecdc0a7521f 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <asm/visasm.h> | 21 | #include <asm/visasm.h> |
| 22 | #include <asm/estate.h> | 22 | #include <asm/estate.h> |
| 23 | #include <asm/auxio.h> | 23 | #include <asm/auxio.h> |
| 24 | #include <asm/sfafsr.h> | ||
| 24 | 25 | ||
| 25 | #define curptr g6 | 26 | #define curptr g6 |
| 26 | 27 | ||
| @@ -690,14 +691,159 @@ netbsd_syscall: | |||
| 690 | retl | 691 | retl |
| 691 | nop | 692 | nop |
| 692 | 693 | ||
| 693 | /* These next few routines must be sure to clear the | 694 | /* We need to carefully read the error status, ACK |
| 694 | * SFSR FaultValid bit so that the fast tlb data protection | 695 | * the errors, prevent recursive traps, and pass the |
| 695 | * handler does not flush the wrong context and lock up the | 696 | * information on to C code for logging. |
| 696 | * box. | 697 | * |
| 698 | * We pass the AFAR in as-is, and we encode the status | ||
| 699 | * information as described in asm-sparc64/sfafsr.h | ||
| 700 | */ | ||
| 701 | .globl __spitfire_access_error | ||
| 702 | __spitfire_access_error: | ||
| 703 | /* Disable ESTATE error reporting so that we do not | ||
| 704 | * take recursive traps and RED state the processor. | ||
| 705 | */ | ||
| 706 | stxa %g0, [%g0] ASI_ESTATE_ERROR_EN | ||
| 707 | membar #Sync | ||
| 708 | |||
| 709 | mov UDBE_UE, %g1 | ||
| 710 | ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR | ||
| 711 | |||
| 712 | /* __spitfire_cee_trap branches here with AFSR in %g4 and | ||
| 713 | * UDBE_CE in %g1. It only clears ESTATE_ERR_CE in the | ||
| 714 | * ESTATE Error Enable register. | ||
| 715 | */ | ||
| 716 | __spitfire_cee_trap_continue: | ||
| 717 | ldxa [%g0] ASI_AFAR, %g5 ! Get AFAR | ||
| 718 | |||
| 719 | rdpr %tt, %g3 | ||
| 720 | and %g3, 0x1ff, %g3 ! Paranoia | ||
| 721 | sllx %g3, SFSTAT_TRAP_TYPE_SHIFT, %g3 | ||
| 722 | or %g4, %g3, %g4 | ||
| 723 | rdpr %tl, %g3 | ||
| 724 | cmp %g3, 1 | ||
| 725 | mov 1, %g3 | ||
| 726 | bleu %xcc, 1f | ||
| 727 | sllx %g3, SFSTAT_TL_GT_ONE_SHIFT, %g3 | ||
| 728 | |||
| 729 | or %g4, %g3, %g4 | ||
| 730 | |||
| 731 | /* Read in the UDB error register state, clearing the | ||
| 732 | * sticky error bits as-needed. We only clear them if | ||
| 733 | * the UE bit is set. Likewise, __spitfire_cee_trap | ||
| 734 | * below will only do so if the CE bit is set. | ||
| 735 | * | ||
| 736 | * NOTE: UltraSparc-I/II have high and low UDB error | ||
| 737 | * registers, corresponding to the two UDB units | ||
| 738 | * present on those chips. UltraSparc-IIi only | ||
| 739 | * has a single UDB, called "SDB" in the manual. | ||
| 740 | * For IIi the upper UDB register always reads | ||
| 741 | * as zero so for our purposes things will just | ||
| 742 | * work with the checks below. | ||
| 697 | */ | 743 | */ |
| 698 | .globl __do_data_access_exception | 744 | 1: ldxa [%g0] ASI_UDBH_ERROR_R, %g3 |
| 699 | .globl __do_data_access_exception_tl1 | 745 | and %g3, 0x3ff, %g7 ! Paranoia |
| 700 | __do_data_access_exception_tl1: | 746 | sllx %g7, SFSTAT_UDBH_SHIFT, %g7 |
| 747 | or %g4, %g7, %g4 | ||
| 748 | andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE | ||
| 749 | be,pn %xcc, 1f | ||
| 750 | nop | ||
| 751 | stxa %g3, [%g0] ASI_UDB_ERROR_W | ||
| 752 | membar #Sync | ||
| 753 | |||
| 754 | 1: mov 0x18, %g3 | ||
| 755 | ldxa [%g3] ASI_UDBL_ERROR_R, %g3 | ||
| 756 | and %g3, 0x3ff, %g7 ! Paranoia | ||
| 757 | sllx %g7, SFSTAT_UDBL_SHIFT, %g7 | ||
| 758 | or %g4, %g7, %g4 | ||
| 759 | andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE | ||
| 760 | be,pn %xcc, 1f | ||
| 761 | nop | ||
| 762 | mov 0x18, %g7 | ||
| 763 | stxa %g3, [%g7] ASI_UDB_ERROR_W | ||
| 764 | membar #Sync | ||
| 765 | |||
| 766 | 1: /* Ok, now that we've latched the error state, | ||
| 767 | * clear the sticky bits in the AFSR. | ||
| 768 | */ | ||
| 769 | stxa %g4, [%g0] ASI_AFSR | ||
| 770 | membar #Sync | ||
| 771 | |||
| 772 | rdpr %tl, %g2 | ||
| 773 | cmp %g2, 1 | ||
| 774 | rdpr %pil, %g2 | ||
| 775 | bleu,pt %xcc, 1f | ||
| 776 | wrpr %g0, 15, %pil | ||
| 777 | |||
| 778 | ba,pt %xcc, etraptl1 | ||
| 779 | rd %pc, %g7 | ||
| 780 | |||
| 781 | ba,pt %xcc, 2f | ||
| 782 | nop | ||
| 783 | |||
| 784 | 1: ba,pt %xcc, etrap_irq | ||
| 785 | rd %pc, %g7 | ||
| 786 | |||
| 787 | 2: mov %l4, %o1 | ||
| 788 | mov %l5, %o2 | ||
| 789 | call spitfire_access_error | ||
| 790 | add %sp, PTREGS_OFF, %o0 | ||
| 791 | ba,pt %xcc, rtrap | ||
| 792 | clr %l6 | ||
| 793 | |||
| 794 | /* This is the trap handler entry point for ECC correctable | ||
| 795 | * errors. They are corrected, but we listen for the trap | ||
| 796 | * so that the event can be logged. | ||
| 797 | * | ||
| 798 | * Disrupting errors are either: | ||
| 799 | * 1) single-bit ECC errors during UDB reads to system | ||
| 800 | * memory | ||
| 801 | * 2) data parity errors during write-back events | ||
| 802 | * | ||
| 803 | * As far as I can make out from the manual, the CEE trap | ||
| 804 | * is only for correctable errors during memory read | ||
| 805 | * accesses by the front-end of the processor. | ||
| 806 | * | ||
| 807 | * The code below is only for trap level 1 CEE events, | ||
| 808 | * as it is the only situation where we can safely record | ||
| 809 | * and log. For trap level >1 we just clear the CE bit | ||
| 810 | * in the AFSR and return. | ||
| 811 | * | ||
| 812 | * This is just like __spiftire_access_error above, but it | ||
| 813 | * specifically handles correctable errors. If an | ||
| 814 | * uncorrectable error is indicated in the AFSR we | ||
| 815 | * will branch directly above to __spitfire_access_error | ||
| 816 | * to handle it instead. Uncorrectable therefore takes | ||
| 817 | * priority over correctable, and the error logging | ||
| 818 | * C code will notice this case by inspecting the | ||
| 819 | * trap type. | ||
| 820 | */ | ||
| 821 | .globl __spitfire_cee_trap | ||
| 822 | __spitfire_cee_trap: | ||
| 823 | ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR | ||
| 824 | mov 1, %g3 | ||
| 825 | sllx %g3, SFAFSR_UE_SHIFT, %g3 | ||
| 826 | andcc %g4, %g3, %g0 ! Check for UE | ||
| 827 | bne,pn %xcc, __spitfire_access_error | ||
| 828 | nop | ||
| 829 | |||
| 830 | /* Ok, in this case we only have a correctable error. | ||
| 831 | * Indicate we only wish to capture that state in register | ||
| 832 | * %g1, and we only disable CE error reporting unlike UE | ||
| 833 | * handling which disables all errors. | ||
| 834 | */ | ||
| 835 | ldxa [%g0] ASI_ESTATE_ERROR_EN, %g3 | ||
| 836 | andn %g3, ESTATE_ERR_CE, %g3 | ||
| 837 | stxa %g3, [%g0] ASI_ESTATE_ERROR_EN | ||
| 838 | membar #Sync | ||
| 839 | |||
| 840 | /* Preserve AFSR in %g4, indicate UDB state to capture in %g1 */ | ||
| 841 | ba,pt %xcc, __spitfire_cee_trap_continue | ||
| 842 | mov UDBE_CE, %g1 | ||
| 843 | |||
| 844 | .globl __spitfire_data_access_exception | ||
| 845 | .globl __spitfire_data_access_exception_tl1 | ||
| 846 | __spitfire_data_access_exception_tl1: | ||
| 701 | rdpr %pstate, %g4 | 847 | rdpr %pstate, %g4 |
| 702 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate | 848 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate |
| 703 | mov TLB_SFSR, %g3 | 849 | mov TLB_SFSR, %g3 |
| @@ -706,9 +852,25 @@ __do_data_access_exception_tl1: | |||
| 706 | ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR | 852 | ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR |
| 707 | stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit | 853 | stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit |
| 708 | membar #Sync | 854 | membar #Sync |
| 855 | rdpr %tt, %g3 | ||
| 856 | cmp %g3, 0x80 ! first win spill/fill trap | ||
| 857 | blu,pn %xcc, 1f | ||
| 858 | cmp %g3, 0xff ! last win spill/fill trap | ||
| 859 | bgu,pn %xcc, 1f | ||
| 860 | nop | ||
| 709 | ba,pt %xcc, winfix_dax | 861 | ba,pt %xcc, winfix_dax |
| 710 | rdpr %tpc, %g3 | 862 | rdpr %tpc, %g3 |
| 711 | __do_data_access_exception: | 863 | 1: sethi %hi(109f), %g7 |
| 864 | ba,pt %xcc, etraptl1 | ||
| 865 | 109: or %g7, %lo(109b), %g7 | ||
| 866 | mov %l4, %o1 | ||
| 867 | mov %l5, %o2 | ||
| 868 | call spitfire_data_access_exception_tl1 | ||
| 869 | add %sp, PTREGS_OFF, %o0 | ||
| 870 | ba,pt %xcc, rtrap | ||
| 871 | clr %l6 | ||
| 872 | |||
| 873 | __spitfire_data_access_exception: | ||
| 712 | rdpr %pstate, %g4 | 874 | rdpr %pstate, %g4 |
| 713 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate | 875 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate |
| 714 | mov TLB_SFSR, %g3 | 876 | mov TLB_SFSR, %g3 |
| @@ -722,20 +884,19 @@ __do_data_access_exception: | |||
| 722 | 109: or %g7, %lo(109b), %g7 | 884 | 109: or %g7, %lo(109b), %g7 |
| 723 | mov %l4, %o1 | 885 | mov %l4, %o1 |
| 724 | mov %l5, %o2 | 886 | mov %l5, %o2 |
| 725 | call data_access_exception | 887 | call spitfire_data_access_exception |
| 726 | add %sp, PTREGS_OFF, %o0 | 888 | add %sp, PTREGS_OFF, %o0 |
| 727 | ba,pt %xcc, rtrap | 889 | ba,pt %xcc, rtrap |
| 728 | clr %l6 | 890 | clr %l6 |
| 729 | 891 | ||
| 730 | .globl __do_instruction_access_exception | 892 | .globl __spitfire_insn_access_exception |
| 731 | .globl __do_instruction_access_exception_tl1 | 893 | .globl __spitfire_insn_access_exception_tl1 |
| 732 | __do_instruction_access_exception_tl1: | 894 | __spitfire_insn_access_exception_tl1: |
| 733 | rdpr %pstate, %g4 | 895 | rdpr %pstate, %g4 |
| 734 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate | 896 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate |
| 735 | mov TLB_SFSR, %g3 | 897 | mov TLB_SFSR, %g3 |
| 736 | mov DMMU_SFAR, %g5 | 898 | ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR |
| 737 | ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR | 899 | rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC |
| 738 | ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR | ||
| 739 | stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit | 900 | stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit |
| 740 | membar #Sync | 901 | membar #Sync |
| 741 | sethi %hi(109f), %g7 | 902 | sethi %hi(109f), %g7 |
| @@ -743,18 +904,17 @@ __do_instruction_access_exception_tl1: | |||
| 743 | 109: or %g7, %lo(109b), %g7 | 904 | 109: or %g7, %lo(109b), %g7 |
| 744 | mov %l4, %o1 | 905 | mov %l4, %o1 |
| 745 | mov %l5, %o2 | 906 | mov %l5, %o2 |
| 746 | call instruction_access_exception_tl1 | 907 | call spitfire_insn_access_exception_tl1 |
| 747 | add %sp, PTREGS_OFF, %o0 | 908 | add %sp, PTREGS_OFF, %o0 |
| 748 | ba,pt %xcc, rtrap | 909 | ba,pt %xcc, rtrap |
| 749 | clr %l6 | 910 | clr %l6 |
| 750 | 911 | ||
| 751 | __do_instruction_access_exception: | 912 | __spitfire_insn_access_exception: |
| 752 | rdpr %pstate, %g4 | 913 | rdpr %pstate, %g4 |
| 753 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate | 914 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate |
| 754 | mov TLB_SFSR, %g3 | 915 | mov TLB_SFSR, %g3 |
| 755 | mov DMMU_SFAR, %g5 | 916 | ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR |
| 756 | ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR | 917 | rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC |
| 757 | ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR | ||
| 758 | stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit | 918 | stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit |
| 759 | membar #Sync | 919 | membar #Sync |
| 760 | sethi %hi(109f), %g7 | 920 | sethi %hi(109f), %g7 |
| @@ -762,102 +922,11 @@ __do_instruction_access_exception: | |||
| 762 | 109: or %g7, %lo(109b), %g7 | 922 | 109: or %g7, %lo(109b), %g7 |
| 763 | mov %l4, %o1 | 923 | mov %l4, %o1 |
| 764 | mov %l5, %o2 | 924 | mov %l5, %o2 |
| 765 | call instruction_access_exception | 925 | call spitfire_insn_access_exception |
| 766 | add %sp, PTREGS_OFF, %o0 | 926 | add %sp, PTREGS_OFF, %o0 |
| 767 | ba,pt %xcc, rtrap | 927 | ba,pt %xcc, rtrap |
| 768 | clr %l6 | 928 | clr %l6 |
| 769 | 929 | ||
| 770 | /* This is the trap handler entry point for ECC correctable | ||
| 771 | * errors. They are corrected, but we listen for the trap | ||
| 772 | * so that the event can be logged. | ||
| 773 | * | ||
| 774 | * Disrupting errors are either: | ||
| 775 | * 1) single-bit ECC errors during UDB reads to system | ||
| 776 | * memory | ||
| 777 | * 2) data parity errors during write-back events | ||
| 778 | * | ||
| 779 | * As far as I can make out from the manual, the CEE trap | ||
| 780 | * is only for correctable errors during memory read | ||
| 781 | * accesses by the front-end of the processor. | ||
| 782 | * | ||
| 783 | * The code below is only for trap level 1 CEE events, | ||
| 784 | * as it is the only situation where we can safely record | ||
| 785 | * and log. For trap level >1 we just clear the CE bit | ||
| 786 | * in the AFSR and return. | ||
| 787 | */ | ||
| 788 | |||
| 789 | /* Our trap handling infrastructure allows us to preserve | ||
| 790 | * two 64-bit values during etrap for arguments to | ||
| 791 | * subsequent C code. Therefore we encode the information | ||
| 792 | * as follows: | ||
| 793 | * | ||
| 794 | * value 1) Full 64-bits of AFAR | ||
| 795 | * value 2) Low 33-bits of AFSR, then bits 33-->42 | ||
| 796 | * are UDBL error status and bits 43-->52 | ||
| 797 | * are UDBH error status | ||
| 798 | */ | ||
| 799 | .align 64 | ||
| 800 | .globl cee_trap | ||
| 801 | cee_trap: | ||
| 802 | ldxa [%g0] ASI_AFSR, %g1 ! Read AFSR | ||
| 803 | ldxa [%g0] ASI_AFAR, %g2 ! Read AFAR | ||
| 804 | sllx %g1, 31, %g1 ! Clear reserved bits | ||
| 805 | srlx %g1, 31, %g1 ! in AFSR | ||
| 806 | |||
| 807 | /* NOTE: UltraSparc-I/II have high and low UDB error | ||
| 808 | * registers, corresponding to the two UDB units | ||
| 809 | * present on those chips. UltraSparc-IIi only | ||
| 810 | * has a single UDB, called "SDB" in the manual. | ||
| 811 | * For IIi the upper UDB register always reads | ||
| 812 | * as zero so for our purposes things will just | ||
| 813 | * work with the checks below. | ||
| 814 | */ | ||
| 815 | ldxa [%g0] ASI_UDBL_ERROR_R, %g3 ! Read UDB-Low error status | ||
| 816 | andcc %g3, (1 << 8), %g4 ! Check CE bit | ||
| 817 | sllx %g3, (64 - 10), %g3 ! Clear reserved bits | ||
| 818 | srlx %g3, (64 - 10), %g3 ! in UDB-Low error status | ||
| 819 | |||
| 820 | sllx %g3, (33 + 0), %g3 ! Shift up to encoding area | ||
| 821 | or %g1, %g3, %g1 ! Or it in | ||
| 822 | be,pn %xcc, 1f ! Branch if CE bit was clear | ||
| 823 | nop | ||
| 824 | stxa %g4, [%g0] ASI_UDB_ERROR_W ! Clear CE sticky bit in UDBL | ||
| 825 | membar #Sync ! Synchronize ASI stores | ||
| 826 | 1: mov 0x18, %g5 ! Addr of UDB-High error status | ||
| 827 | ldxa [%g5] ASI_UDBH_ERROR_R, %g3 ! Read it | ||
| 828 | |||
| 829 | andcc %g3, (1 << 8), %g4 ! Check CE bit | ||
| 830 | sllx %g3, (64 - 10), %g3 ! Clear reserved bits | ||
| 831 | srlx %g3, (64 - 10), %g3 ! in UDB-High error status | ||
| 832 | sllx %g3, (33 + 10), %g3 ! Shift up to encoding area | ||
| 833 | or %g1, %g3, %g1 ! Or it in | ||
| 834 | be,pn %xcc, 1f ! Branch if CE bit was clear | ||
| 835 | nop | ||
| 836 | nop | ||
| 837 | |||
| 838 | stxa %g4, [%g5] ASI_UDB_ERROR_W ! Clear CE sticky bit in UDBH | ||
| 839 | membar #Sync ! Synchronize ASI stores | ||
| 840 | 1: mov 1, %g5 ! AFSR CE bit is | ||
| 841 | sllx %g5, 20, %g5 ! bit 20 | ||
| 842 | stxa %g5, [%g0] ASI_AFSR ! Clear CE sticky bit in AFSR | ||
| 843 | membar #Sync ! Synchronize ASI stores | ||
| 844 | sllx %g2, (64 - 41), %g2 ! Clear reserved bits | ||
| 845 | srlx %g2, (64 - 41), %g2 ! in latched AFAR | ||
| 846 | |||
| 847 | andn %g2, 0x0f, %g2 ! Finish resv bit clearing | ||
| 848 | mov %g1, %g4 ! Move AFSR+UDB* into save reg | ||
| 849 | mov %g2, %g5 ! Move AFAR into save reg | ||
| 850 | rdpr %pil, %g2 | ||
| 851 | wrpr %g0, 15, %pil | ||
| 852 | ba,pt %xcc, etrap_irq | ||
| 853 | rd %pc, %g7 | ||
| 854 | mov %l4, %o0 | ||
| 855 | |||
| 856 | mov %l5, %o1 | ||
| 857 | call cee_log | ||
| 858 | add %sp, PTREGS_OFF, %o2 | ||
| 859 | ba,a,pt %xcc, rtrap_irq | ||
| 860 | |||
| 861 | /* Capture I/D/E-cache state into per-cpu error scoreboard. | 930 | /* Capture I/D/E-cache state into per-cpu error scoreboard. |
| 862 | * | 931 | * |
| 863 | * %g1: (TL>=0) ? 1 : 0 | 932 | * %g1: (TL>=0) ? 1 : 0 |
