aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/entry.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel/entry.S')
-rw-r--r--arch/sparc/kernel/entry.S432
1 files changed, 71 insertions, 361 deletions
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index f445e98463e6..2dbe1806e530 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -7,6 +7,7 @@
7 * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au) 7 * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au)
8 */ 8 */
9 9
10#include <linux/linkage.h>
10#include <linux/errno.h> 11#include <linux/errno.h>
11 12
12#include <asm/head.h> 13#include <asm/head.h>
@@ -17,10 +18,8 @@
17#include <asm/asm-offsets.h> 18#include <asm/asm-offsets.h>
18#include <asm/psr.h> 19#include <asm/psr.h>
19#include <asm/vaddrs.h> 20#include <asm/vaddrs.h>
20#include <asm/memreg.h>
21#include <asm/page.h> 21#include <asm/page.h>
22#include <asm/pgtable.h> 22#include <asm/pgtable.h>
23#include <asm/pgtsun4c.h>
24#include <asm/winmacro.h> 23#include <asm/winmacro.h>
25#include <asm/signal.h> 24#include <asm/signal.h>
26#include <asm/obio.h> 25#include <asm/obio.h>
@@ -125,22 +124,11 @@ floppy_tdone:
125 set auxio_register, %l7 124 set auxio_register, %l7
126 ld [%l7], %l7 125 ld [%l7], %l7
127 126
128 set sparc_cpu_model, %l5 127 ldub [%l7], %l5
129 ld [%l5], %l5
130 subcc %l5, 1, %g0 /* enum { sun4c = 1 }; */
131 be 1f
132 ldub [%l7], %l5
133 128
134 or %l5, 0xc2, %l5 129 or %l5, 0xc2, %l5
135 stb %l5, [%l7] 130 stb %l5, [%l7]
136 andn %l5, 0x02, %l5 131 andn %l5, 0x02, %l5
137 b 2f
138 nop
139
1401:
141 or %l5, 0xf4, %l5
142 stb %l5, [%l7]
143 andn %l5, 0x04, %l5
144 132
1452: 1332:
146 /* Kill some time so the bits set */ 134 /* Kill some time so the bits set */
@@ -266,6 +254,11 @@ smp4m_ticker:
266 WRITE_PAUSE 254 WRITE_PAUSE
267 RESTORE_ALL 255 RESTORE_ALL
268 256
257#define GET_PROCESSOR4M_ID(reg) \
258 rd %tbr, %reg; \
259 srl %reg, 12, %reg; \
260 and %reg, 3, %reg;
261
269 /* Here is where we check for possible SMP IPI passed to us 262 /* Here is where we check for possible SMP IPI passed to us
270 * on some level other than 15 which is the NMI and only used 263 * on some level other than 15 which is the NMI and only used
271 * for cross calls. That has a separate entry point below. 264 * for cross calls. That has a separate entry point below.
@@ -328,7 +321,7 @@ linux_trap_ipi15_sun4m:
328 ld [%o5 + %o0], %o5 321 ld [%o5 + %o0], %o5
329 ld [%o5 + 0x00], %o3 ! sun4m_irq_percpu[cpu]->pending 322 ld [%o5 + 0x00], %o3 ! sun4m_irq_percpu[cpu]->pending
330 andcc %o3, %o2, %g0 323 andcc %o3, %o2, %g0
331 be 1f ! Must be an NMI async memory error 324 be sun4m_nmi_error ! Must be an NMI async memory error
332 st %o2, [%o5 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x80000000 325 st %o2, [%o5 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x80000000
333 WRITE_PAUSE 326 WRITE_PAUSE
334 ld [%o5 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending 327 ld [%o5 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending
@@ -342,27 +335,6 @@ linux_trap_ipi15_sun4m:
342 nop 335 nop
343 b ret_trap_lockless_ipi 336 b ret_trap_lockless_ipi
344 clr %l6 337 clr %l6
3451:
346 /* NMI async memory error handling. */
347 sethi %hi(0x80000000), %l4
348 sethi %hi(sun4m_irq_global), %o5
349 ld [%o5 + %lo(sun4m_irq_global)], %l5
350 st %l4, [%l5 + 0x0c] ! sun4m_irq_global->mask_set=0x80000000
351 WRITE_PAUSE
352 ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending
353 WRITE_PAUSE
354 or %l0, PSR_PIL, %l4
355 wr %l4, 0x0, %psr
356 WRITE_PAUSE
357 wr %l4, PSR_ET, %psr
358 WRITE_PAUSE
359 call sun4m_nmi
360 nop
361 st %l4, [%l5 + 0x08] ! sun4m_irq_global->mask_clear=0x80000000
362 WRITE_PAUSE
363 ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending
364 WRITE_PAUSE
365 RESTORE_ALL
366 338
367 .globl smp4d_ticker 339 .globl smp4d_ticker
368 /* SMP per-cpu ticker interrupts are handled specially. */ 340 /* SMP per-cpu ticker interrupts are handled specially. */
@@ -760,326 +732,37 @@ setcc_trap_handler:
760 jmp %l2 ! advance over trap instruction 732 jmp %l2 ! advance over trap instruction
761 rett %l2 + 0x4 ! like this... 733 rett %l2 + 0x4 ! like this...
762 734
763 .align 4 735sun4m_nmi_error:
764 .globl linux_trap_nmi_sun4c 736 /* NMI async memory error handling. */
765linux_trap_nmi_sun4c: 737 sethi %hi(0x80000000), %l4
766 SAVE_ALL 738 sethi %hi(sun4m_irq_global), %o5
767 739 ld [%o5 + %lo(sun4m_irq_global)], %l5
768 /* Ugh, we need to clear the IRQ line. This is now 740 st %l4, [%l5 + 0x0c] ! sun4m_irq_global->mask_set=0x80000000
769 * a very sun4c specific trap handler...
770 */
771 sethi %hi(interrupt_enable), %l5
772 ld [%l5 + %lo(interrupt_enable)], %l5
773 ldub [%l5], %l6
774 andn %l6, INTS_ENAB, %l6
775 stb %l6, [%l5]
776
777 /* Now it is safe to re-enable traps without recursion. */
778 or %l0, PSR_PIL, %l0
779 wr %l0, PSR_ET, %psr
780 WRITE_PAUSE 741 WRITE_PAUSE
781 742 ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending
782 /* Now call the c-code with the pt_regs frame ptr and the
783 * memory error registers as arguments. The ordering chosen
784 * here is due to unlatching semantics.
785 */
786 sethi %hi(AC_SYNC_ERR), %o0
787 add %o0, 0x4, %o0
788 lda [%o0] ASI_CONTROL, %o2 ! sync vaddr
789 sub %o0, 0x4, %o0
790 lda [%o0] ASI_CONTROL, %o1 ! sync error
791 add %o0, 0xc, %o0
792 lda [%o0] ASI_CONTROL, %o4 ! async vaddr
793 sub %o0, 0x4, %o0
794 lda [%o0] ASI_CONTROL, %o3 ! async error
795 call sparc_lvl15_nmi
796 add %sp, STACKFRAME_SZ, %o0
797
798 RESTORE_ALL
799
800 .align 4
801 .globl invalid_segment_patch1_ff
802 .globl invalid_segment_patch2_ff
803invalid_segment_patch1_ff: cmp %l4, 0xff
804invalid_segment_patch2_ff: mov 0xff, %l3
805
806 .align 4
807 .globl invalid_segment_patch1_1ff
808 .globl invalid_segment_patch2_1ff
809invalid_segment_patch1_1ff: cmp %l4, 0x1ff
810invalid_segment_patch2_1ff: mov 0x1ff, %l3
811
812 .align 4
813 .globl num_context_patch1_16, num_context_patch2_16
814num_context_patch1_16: mov 0x10, %l7
815num_context_patch2_16: mov 0x10, %l7
816
817 .align 4
818 .globl vac_linesize_patch_32
819vac_linesize_patch_32: subcc %l7, 32, %l7
820
821 .align 4
822 .globl vac_hwflush_patch1_on, vac_hwflush_patch2_on
823
824/*
825 * Ugly, but we can't use hardware flushing on the sun4 and we'd require
826 * two instructions (Anton)
827 */
828vac_hwflush_patch1_on: addcc %l7, -PAGE_SIZE, %l7
829
830vac_hwflush_patch2_on: sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG
831
832 .globl invalid_segment_patch1, invalid_segment_patch2
833 .globl num_context_patch1
834 .globl vac_linesize_patch, vac_hwflush_patch1
835 .globl vac_hwflush_patch2
836
837 .align 4
838 .globl sun4c_fault
839
840! %l0 = %psr
841! %l1 = %pc
842! %l2 = %npc
843! %l3 = %wim
844! %l7 = 1 for textfault
845! We want error in %l5, vaddr in %l6
846sun4c_fault:
847 sethi %hi(AC_SYNC_ERR), %l4
848 add %l4, 0x4, %l6 ! AC_SYNC_VA in %l6
849 lda [%l6] ASI_CONTROL, %l5 ! Address
850 lda [%l4] ASI_CONTROL, %l6 ! Error, retained for a bit
851
852 andn %l5, 0xfff, %l5 ! Encode all info into l7
853 srl %l6, 14, %l4
854
855 and %l4, 2, %l4
856 or %l5, %l4, %l4
857
858 or %l4, %l7, %l7 ! l7 = [addr,write,txtfault]
859
860 andcc %l0, PSR_PS, %g0
861 be sun4c_fault_fromuser
862 andcc %l7, 1, %g0 ! Text fault?
863
864 be 1f
865 sethi %hi(KERNBASE), %l4
866
867 mov %l1, %l5 ! PC
868
8691:
870 cmp %l5, %l4
871 blu sun4c_fault_fromuser
872 sethi %hi(~((1 << SUN4C_REAL_PGDIR_SHIFT) - 1)), %l4
873
874 /* If the kernel references a bum kernel pointer, or a pte which
875 * points to a non existent page in ram, we will run this code
876 * _forever_ and lock up the machine!!!!! So we must check for
877 * this condition, the AC_SYNC_ERR bits are what we must examine.
878 * Also a parity error would make this happen as well. So we just
879 * check that we are in fact servicing a tlb miss and not some
880 * other type of fault for the kernel.
881 */
882 andcc %l6, 0x80, %g0
883 be sun4c_fault_fromuser
884 and %l5, %l4, %l5
885
886 /* Test for NULL pte_t * in vmalloc area. */
887 sethi %hi(VMALLOC_START), %l4
888 cmp %l5, %l4
889 blu,a invalid_segment_patch1
890 lduXa [%l5] ASI_SEGMAP, %l4
891
892 sethi %hi(swapper_pg_dir), %l4
893 srl %l5, SUN4C_PGDIR_SHIFT, %l6
894 or %l4, %lo(swapper_pg_dir), %l4
895 sll %l6, 2, %l6
896 ld [%l4 + %l6], %l4
897 andcc %l4, PAGE_MASK, %g0
898 be sun4c_fault_fromuser
899 lduXa [%l5] ASI_SEGMAP, %l4
900
901invalid_segment_patch1:
902 cmp %l4, 0x7f
903 bne 1f
904 sethi %hi(sun4c_kfree_ring), %l4
905 or %l4, %lo(sun4c_kfree_ring), %l4
906 ld [%l4 + 0x18], %l3
907 deccc %l3 ! do we have a free entry?
908 bcs,a 2f ! no, unmap one.
909 sethi %hi(sun4c_kernel_ring), %l4
910
911 st %l3, [%l4 + 0x18] ! sun4c_kfree_ring.num_entries--
912
913 ld [%l4 + 0x00], %l6 ! entry = sun4c_kfree_ring.ringhd.next
914 st %l5, [%l6 + 0x08] ! entry->vaddr = address
915
916 ld [%l6 + 0x00], %l3 ! next = entry->next
917 ld [%l6 + 0x04], %l7 ! entry->prev
918
919 st %l7, [%l3 + 0x04] ! next->prev = entry->prev
920 st %l3, [%l7 + 0x00] ! entry->prev->next = next
921
922 sethi %hi(sun4c_kernel_ring), %l4
923 or %l4, %lo(sun4c_kernel_ring), %l4
924 ! head = &sun4c_kernel_ring.ringhd
925
926 ld [%l4 + 0x00], %l7 ! head->next
927
928 st %l4, [%l6 + 0x04] ! entry->prev = head
929 st %l7, [%l6 + 0x00] ! entry->next = head->next
930 st %l6, [%l7 + 0x04] ! head->next->prev = entry
931
932 st %l6, [%l4 + 0x00] ! head->next = entry
933
934 ld [%l4 + 0x18], %l3
935 inc %l3 ! sun4c_kernel_ring.num_entries++
936 st %l3, [%l4 + 0x18]
937 b 4f
938 ld [%l6 + 0x08], %l5
939
9402:
941 or %l4, %lo(sun4c_kernel_ring), %l4
942 ! head = &sun4c_kernel_ring.ringhd
943
944 ld [%l4 + 0x04], %l6 ! entry = head->prev
945
946 ld [%l6 + 0x08], %l3 ! tmp = entry->vaddr
947
948 ! Flush segment from the cache.
949 sethi %hi((64 * 1024)), %l7
9509:
951vac_hwflush_patch1:
952vac_linesize_patch:
953 subcc %l7, 16, %l7
954 bne 9b
955vac_hwflush_patch2:
956 sta %g0, [%l3 + %l7] ASI_FLUSHSEG
957
958 st %l5, [%l6 + 0x08] ! entry->vaddr = address
959
960 ld [%l6 + 0x00], %l5 ! next = entry->next
961 ld [%l6 + 0x04], %l7 ! entry->prev
962
963 st %l7, [%l5 + 0x04] ! next->prev = entry->prev
964 st %l5, [%l7 + 0x00] ! entry->prev->next = next
965 st %l4, [%l6 + 0x04] ! entry->prev = head
966
967 ld [%l4 + 0x00], %l7 ! head->next
968
969 st %l7, [%l6 + 0x00] ! entry->next = head->next
970 st %l6, [%l7 + 0x04] ! head->next->prev = entry
971 st %l6, [%l4 + 0x00] ! head->next = entry
972
973 mov %l3, %l5 ! address = tmp
974
9754:
976num_context_patch1:
977 mov 0x08, %l7
978
979 ld [%l6 + 0x08], %l4
980 ldub [%l6 + 0x0c], %l3
981 or %l4, %l3, %l4 ! encode new vaddr/pseg into l4
982
983 sethi %hi(AC_CONTEXT), %l3
984 lduba [%l3] ASI_CONTROL, %l6
985
986 /* Invalidate old mapping, instantiate new mapping,
987 * for each context. Registers l6/l7 are live across
988 * this loop.
989 */
9903: deccc %l7
991 sethi %hi(AC_CONTEXT), %l3
992 stba %l7, [%l3] ASI_CONTROL
993invalid_segment_patch2:
994 mov 0x7f, %l3
995 stXa %l3, [%l5] ASI_SEGMAP
996 andn %l4, 0x1ff, %l3
997 bne 3b
998 stXa %l4, [%l3] ASI_SEGMAP
999
1000 sethi %hi(AC_CONTEXT), %l3
1001 stba %l6, [%l3] ASI_CONTROL
1002
1003 andn %l4, 0x1ff, %l5
1004
10051:
1006 sethi %hi(VMALLOC_START), %l4
1007 cmp %l5, %l4
1008
1009 bgeu 1f
1010 mov 1 << (SUN4C_REAL_PGDIR_SHIFT - PAGE_SHIFT), %l7
1011
1012 sethi %hi(KERNBASE), %l6
1013
1014 sub %l5, %l6, %l4
1015 srl %l4, PAGE_SHIFT, %l4
1016 sethi %hi((SUN4C_PAGE_KERNEL & 0xf4000000)), %l3
1017 or %l3, %l4, %l3
1018
1019 sethi %hi(PAGE_SIZE), %l4
1020
10212:
1022 sta %l3, [%l5] ASI_PTE
1023 deccc %l7
1024 inc %l3
1025 bne 2b
1026 add %l5, %l4, %l5
1027
1028 b 7f
1029 sethi %hi(sun4c_kernel_faults), %l4
1030
10311:
1032 srl %l5, SUN4C_PGDIR_SHIFT, %l3
1033 sethi %hi(swapper_pg_dir), %l4
1034 or %l4, %lo(swapper_pg_dir), %l4
1035 sll %l3, 2, %l3
1036 ld [%l4 + %l3], %l4
1037 and %l4, PAGE_MASK, %l4
1038
1039 srl %l5, (PAGE_SHIFT - 2), %l6
1040 and %l6, ((SUN4C_PTRS_PER_PTE - 1) << 2), %l6
1041 add %l6, %l4, %l6
1042
1043 sethi %hi(PAGE_SIZE), %l4
1044
10452:
1046 ld [%l6], %l3
1047 deccc %l7
1048 sta %l3, [%l5] ASI_PTE
1049 add %l6, 0x4, %l6
1050 bne 2b
1051 add %l5, %l4, %l5
1052
1053 sethi %hi(sun4c_kernel_faults), %l4
10547:
1055 ld [%l4 + %lo(sun4c_kernel_faults)], %l3
1056 inc %l3
1057 st %l3, [%l4 + %lo(sun4c_kernel_faults)]
1058
1059 /* Restore condition codes */
1060 wr %l0, 0x0, %psr
1061 WRITE_PAUSE 743 WRITE_PAUSE
1062 jmp %l1 744 or %l0, PSR_PIL, %l4
1063 rett %l2 745 wr %l4, 0x0, %psr
1064 746 WRITE_PAUSE
1065sun4c_fault_fromuser: 747 wr %l4, PSR_ET, %psr
1066 SAVE_ALL 748 WRITE_PAUSE
749 call sun4m_nmi
1067 nop 750 nop
1068 751 st %l4, [%l5 + 0x08] ! sun4m_irq_global->mask_clear=0x80000000
1069 mov %l7, %o1 ! Decode the info from %l7
1070 mov %l7, %o2
1071 and %o1, 1, %o1 ! arg2 = text_faultp
1072 mov %l7, %o3
1073 and %o2, 2, %o2 ! arg3 = writep
1074 andn %o3, 0xfff, %o3 ! arg4 = faulting address
1075
1076 wr %l0, PSR_ET, %psr
1077 WRITE_PAUSE 752 WRITE_PAUSE
753 ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending
754 WRITE_PAUSE
755 RESTORE_ALL
1078 756
1079 call do_sun4c_fault 757#ifndef CONFIG_SMP
1080 add %sp, STACKFRAME_SZ, %o0 ! arg1 = pt_regs ptr 758 .align 4
759 .globl linux_trap_ipi15_sun4m
760linux_trap_ipi15_sun4m:
761 SAVE_ALL
1081 762
1082 RESTORE_ALL 763 ba sun4m_nmi_error
764 nop
765#endif /* CONFIG_SMP */
1083 766
1084 .align 4 767 .align 4
1085 .globl srmmu_fault 768 .globl srmmu_fault
@@ -1483,11 +1166,13 @@ fpload:
1483 .globl __ndelay 1166 .globl __ndelay
1484__ndelay: 1167__ndelay:
1485 save %sp, -STACKFRAME_SZ, %sp 1168 save %sp, -STACKFRAME_SZ, %sp
1486 mov %i0, %o0 1169 mov %i0, %o0 ! round multiplier up so large ns ok
1487 call .umul ! round multiplier up so large ns ok 1170 mov 0x1ae, %o1 ! 2**32 / (1 000 000 000 / HZ)
1488 mov 0x1ae, %o1 ! 2**32 / (1 000 000 000 / HZ) 1171 umul %o0, %o1, %o0
1489 call .umul 1172 rd %y, %o1
1490 mov %i1, %o1 ! udelay_val 1173 mov %i1, %o1 ! udelay_val
1174 umul %o0, %o1, %o0
1175 rd %y, %o1
1491 ba delay_continue 1176 ba delay_continue
1492 mov %o1, %o0 ! >>32 later for better resolution 1177 mov %o1, %o0 ! >>32 later for better resolution
1493 1178
@@ -1496,18 +1181,21 @@ __udelay:
1496 save %sp, -STACKFRAME_SZ, %sp 1181 save %sp, -STACKFRAME_SZ, %sp
1497 mov %i0, %o0 1182 mov %i0, %o0
1498 sethi %hi(0x10c7), %o1 ! round multiplier up so large us ok 1183 sethi %hi(0x10c7), %o1 ! round multiplier up so large us ok
1499 call .umul 1184 or %o1, %lo(0x10c7), %o1 ! 2**32 / 1 000 000
1500 or %o1, %lo(0x10c7), %o1 ! 2**32 / 1 000 000 1185 umul %o0, %o1, %o0
1501 call .umul 1186 rd %y, %o1
1502 mov %i1, %o1 ! udelay_val 1187 mov %i1, %o1 ! udelay_val
1188 umul %o0, %o1, %o0
1189 rd %y, %o1
1503 sethi %hi(0x028f4b62), %l0 ! Add in rounding constant * 2**32, 1190 sethi %hi(0x028f4b62), %l0 ! Add in rounding constant * 2**32,
1504 or %g0, %lo(0x028f4b62), %l0 1191 or %g0, %lo(0x028f4b62), %l0
1505 addcc %o0, %l0, %o0 ! 2**32 * 0.009 999 1192 addcc %o0, %l0, %o0 ! 2**32 * 0.009 999
1506 bcs,a 3f 1193 bcs,a 3f
1507 add %o1, 0x01, %o1 1194 add %o1, 0x01, %o1
15083: 11953:
1509 call .umul 1196 mov HZ, %o0 ! >>32 earlier for wider range
1510 mov HZ, %o0 ! >>32 earlier for wider range 1197 umul %o0, %o1, %o0
1198 rd %y, %o1
1511 1199
1512delay_continue: 1200delay_continue:
1513 cmp %o0, 0x0 1201 cmp %o0, 0x0
@@ -1670,4 +1358,26 @@ flushw_all:
1670 ret 1358 ret
1671 restore 1359 restore
1672 1360
1361#ifdef CONFIG_SMP
1362ENTRY(hard_smp_processor_id)
1363661: rd %tbr, %g1
1364 srl %g1, 12, %o0
1365 and %o0, 3, %o0
1366 .section .cpuid_patch, "ax"
1367 /* Instruction location. */
1368 .word 661b
1369 /* SUN4D implementation. */
1370 lda [%g0] ASI_M_VIKING_TMP1, %o0
1371 nop
1372 nop
1373 /* LEON implementation. */
1374 rd %asr17, %o0
1375 srl %o0, 0x1c, %o0
1376 nop
1377 .previous
1378 retl
1379 nop
1380ENDPROC(hard_smp_processor_id)
1381#endif
1382
1673/* End of entry.S */ 1383/* End of entry.S */