diff options
author | David S. Miller <davem@davemloft.net> | 2005-08-29 15:45:11 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2005-08-29 15:45:11 -0400 |
commit | 6c52a96e6cacb35403b85c3b42db0faf26f3ed85 (patch) | |
tree | 07ebe2ce68511ffb75575603b0c58bf00c78f8c7 /arch/sparc64/kernel/entry.S | |
parent | bde4e4ee9f90142d550e2684dec2c8df302f5f8e (diff) |
[SPARC64]: Revamp Spitfire error trap handling.
Current uncorrectable error handling was poor enough
that the processor could just loop taking the same
trap over and over again. Fix things up so that we
at least get a log message and perhaps even some register
state.
In the process, much consolidation became possible,
particularly with the correctable error handler.
Prefix assembler and C function names with "spitfire"
to indicate that these are for Ultra-I/II/IIi/IIe only.
More work is needed to make these routines robust and
featureful to the level of the Ultra-III error handlers.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/entry.S')
-rw-r--r-- | arch/sparc64/kernel/entry.S | 266 |
1 files changed, 163 insertions, 103 deletions
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 214cd0ebe832..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,9 +691,159 @@ netbsd_syscall: | |||
690 | retl | 691 | retl |
691 | nop | 692 | nop |
692 | 693 | ||
693 | .globl __do_data_access_exception | 694 | /* We need to carefully read the error status, ACK |
694 | .globl __do_data_access_exception_tl1 | 695 | * the errors, prevent recursive traps, and pass the |
695 | __do_data_access_exception_tl1: | 696 | * information on to C code for logging. |
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. | ||
743 | */ | ||
744 | 1: ldxa [%g0] ASI_UDBH_ERROR_R, %g3 | ||
745 | and %g3, 0x3ff, %g7 ! Paranoia | ||
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: | ||
696 | rdpr %pstate, %g4 | 847 | rdpr %pstate, %g4 |
697 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate | 848 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate |
698 | mov TLB_SFSR, %g3 | 849 | mov TLB_SFSR, %g3 |
@@ -714,12 +865,12 @@ __do_data_access_exception_tl1: | |||
714 | 109: or %g7, %lo(109b), %g7 | 865 | 109: or %g7, %lo(109b), %g7 |
715 | mov %l4, %o1 | 866 | mov %l4, %o1 |
716 | mov %l5, %o2 | 867 | mov %l5, %o2 |
717 | call data_access_exception_tl1 | 868 | call spitfire_data_access_exception_tl1 |
718 | add %sp, PTREGS_OFF, %o0 | 869 | add %sp, PTREGS_OFF, %o0 |
719 | ba,pt %xcc, rtrap | 870 | ba,pt %xcc, rtrap |
720 | clr %l6 | 871 | clr %l6 |
721 | 872 | ||
722 | __do_data_access_exception: | 873 | __spitfire_data_access_exception: |
723 | rdpr %pstate, %g4 | 874 | rdpr %pstate, %g4 |
724 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate | 875 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate |
725 | mov TLB_SFSR, %g3 | 876 | mov TLB_SFSR, %g3 |
@@ -733,14 +884,14 @@ __do_data_access_exception: | |||
733 | 109: or %g7, %lo(109b), %g7 | 884 | 109: or %g7, %lo(109b), %g7 |
734 | mov %l4, %o1 | 885 | mov %l4, %o1 |
735 | mov %l5, %o2 | 886 | mov %l5, %o2 |
736 | call data_access_exception | 887 | call spitfire_data_access_exception |
737 | add %sp, PTREGS_OFF, %o0 | 888 | add %sp, PTREGS_OFF, %o0 |
738 | ba,pt %xcc, rtrap | 889 | ba,pt %xcc, rtrap |
739 | clr %l6 | 890 | clr %l6 |
740 | 891 | ||
741 | .globl __do_instruction_access_exception | 892 | .globl __spitfire_insn_access_exception |
742 | .globl __do_instruction_access_exception_tl1 | 893 | .globl __spitfire_insn_access_exception_tl1 |
743 | __do_instruction_access_exception_tl1: | 894 | __spitfire_insn_access_exception_tl1: |
744 | rdpr %pstate, %g4 | 895 | rdpr %pstate, %g4 |
745 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate | 896 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate |
746 | mov TLB_SFSR, %g3 | 897 | mov TLB_SFSR, %g3 |
@@ -753,12 +904,12 @@ __do_instruction_access_exception_tl1: | |||
753 | 109: or %g7, %lo(109b), %g7 | 904 | 109: or %g7, %lo(109b), %g7 |
754 | mov %l4, %o1 | 905 | mov %l4, %o1 |
755 | mov %l5, %o2 | 906 | mov %l5, %o2 |
756 | call instruction_access_exception_tl1 | 907 | call spitfire_insn_access_exception_tl1 |
757 | add %sp, PTREGS_OFF, %o0 | 908 | add %sp, PTREGS_OFF, %o0 |
758 | ba,pt %xcc, rtrap | 909 | ba,pt %xcc, rtrap |
759 | clr %l6 | 910 | clr %l6 |
760 | 911 | ||
761 | __do_instruction_access_exception: | 912 | __spitfire_insn_access_exception: |
762 | rdpr %pstate, %g4 | 913 | rdpr %pstate, %g4 |
763 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate | 914 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate |
764 | mov TLB_SFSR, %g3 | 915 | mov TLB_SFSR, %g3 |
@@ -771,102 +922,11 @@ __do_instruction_access_exception: | |||
771 | 109: or %g7, %lo(109b), %g7 | 922 | 109: or %g7, %lo(109b), %g7 |
772 | mov %l4, %o1 | 923 | mov %l4, %o1 |
773 | mov %l5, %o2 | 924 | mov %l5, %o2 |
774 | call instruction_access_exception | 925 | call spitfire_insn_access_exception |
775 | add %sp, PTREGS_OFF, %o0 | 926 | add %sp, PTREGS_OFF, %o0 |
776 | ba,pt %xcc, rtrap | 927 | ba,pt %xcc, rtrap |
777 | clr %l6 | 928 | clr %l6 |
778 | 929 | ||
779 | /* This is the trap handler entry point for ECC correctable | ||
780 | * errors. They are corrected, but we listen for the trap | ||
781 | * so that the event can be logged. | ||
782 | * | ||
783 | * Disrupting errors are either: | ||
784 | * 1) single-bit ECC errors during UDB reads to system | ||
785 | * memory | ||
786 | * 2) data parity errors during write-back events | ||
787 | * | ||
788 | * As far as I can make out from the manual, the CEE trap | ||
789 | * is only for correctable errors during memory read | ||
790 | * accesses by the front-end of the processor. | ||
791 | * | ||
792 | * The code below is only for trap level 1 CEE events, | ||
793 | * as it is the only situation where we can safely record | ||
794 | * and log. For trap level >1 we just clear the CE bit | ||
795 | * in the AFSR and return. | ||
796 | */ | ||
797 | |||
798 | /* Our trap handling infrastructure allows us to preserve | ||
799 | * two 64-bit values during etrap for arguments to | ||
800 | * subsequent C code. Therefore we encode the information | ||
801 | * as follows: | ||
802 | * | ||
803 | * value 1) Full 64-bits of AFAR | ||
804 | * value 2) Low 33-bits of AFSR, then bits 33-->42 | ||
805 | * are UDBL error status and bits 43-->52 | ||
806 | * are UDBH error status | ||
807 | */ | ||
808 | .align 64 | ||
809 | .globl cee_trap | ||
810 | cee_trap: | ||
811 | ldxa [%g0] ASI_AFSR, %g1 ! Read AFSR | ||
812 | ldxa [%g0] ASI_AFAR, %g2 ! Read AFAR | ||
813 | sllx %g1, 31, %g1 ! Clear reserved bits | ||
814 | srlx %g1, 31, %g1 ! in AFSR | ||
815 | |||
816 | /* NOTE: UltraSparc-I/II have high and low UDB error | ||
817 | * registers, corresponding to the two UDB units | ||
818 | * present on those chips. UltraSparc-IIi only | ||
819 | * has a single UDB, called "SDB" in the manual. | ||
820 | * For IIi the upper UDB register always reads | ||
821 | * as zero so for our purposes things will just | ||
822 | * work with the checks below. | ||
823 | */ | ||
824 | ldxa [%g0] ASI_UDBL_ERROR_R, %g3 ! Read UDB-Low error status | ||
825 | andcc %g3, (1 << 8), %g4 ! Check CE bit | ||
826 | sllx %g3, (64 - 10), %g3 ! Clear reserved bits | ||
827 | srlx %g3, (64 - 10), %g3 ! in UDB-Low error status | ||
828 | |||
829 | sllx %g3, (33 + 0), %g3 ! Shift up to encoding area | ||
830 | or %g1, %g3, %g1 ! Or it in | ||
831 | be,pn %xcc, 1f ! Branch if CE bit was clear | ||
832 | nop | ||
833 | stxa %g4, [%g0] ASI_UDB_ERROR_W ! Clear CE sticky bit in UDBL | ||
834 | membar #Sync ! Synchronize ASI stores | ||
835 | 1: mov 0x18, %g5 ! Addr of UDB-High error status | ||
836 | ldxa [%g5] ASI_UDBH_ERROR_R, %g3 ! Read it | ||
837 | |||
838 | andcc %g3, (1 << 8), %g4 ! Check CE bit | ||
839 | sllx %g3, (64 - 10), %g3 ! Clear reserved bits | ||
840 | srlx %g3, (64 - 10), %g3 ! in UDB-High error status | ||
841 | sllx %g3, (33 + 10), %g3 ! Shift up to encoding area | ||
842 | or %g1, %g3, %g1 ! Or it in | ||
843 | be,pn %xcc, 1f ! Branch if CE bit was clear | ||
844 | nop | ||
845 | nop | ||
846 | |||
847 | stxa %g4, [%g5] ASI_UDB_ERROR_W ! Clear CE sticky bit in UDBH | ||
848 | membar #Sync ! Synchronize ASI stores | ||
849 | 1: mov 1, %g5 ! AFSR CE bit is | ||
850 | sllx %g5, 20, %g5 ! bit 20 | ||
851 | stxa %g5, [%g0] ASI_AFSR ! Clear CE sticky bit in AFSR | ||
852 | membar #Sync ! Synchronize ASI stores | ||
853 | sllx %g2, (64 - 41), %g2 ! Clear reserved bits | ||
854 | srlx %g2, (64 - 41), %g2 ! in latched AFAR | ||
855 | |||
856 | andn %g2, 0x0f, %g2 ! Finish resv bit clearing | ||
857 | mov %g1, %g4 ! Move AFSR+UDB* into save reg | ||
858 | mov %g2, %g5 ! Move AFAR into save reg | ||
859 | rdpr %pil, %g2 | ||
860 | wrpr %g0, 15, %pil | ||
861 | ba,pt %xcc, etrap_irq | ||
862 | rd %pc, %g7 | ||
863 | mov %l4, %o0 | ||
864 | |||
865 | mov %l5, %o1 | ||
866 | call cee_log | ||
867 | add %sp, PTREGS_OFF, %o2 | ||
868 | ba,a,pt %xcc, rtrap_irq | ||
869 | |||
870 | /* Capture I/D/E-cache state into per-cpu error scoreboard. | 930 | /* Capture I/D/E-cache state into per-cpu error scoreboard. |
871 | * | 931 | * |
872 | * %g1: (TL>=0) ? 1 : 0 | 932 | * %g1: (TL>=0) ? 1 : 0 |