diff options
Diffstat (limited to 'arch/sparc64/kernel/tsb.S')
-rw-r--r-- | arch/sparc64/kernel/tsb.S | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/arch/sparc64/kernel/tsb.S b/arch/sparc64/kernel/tsb.S new file mode 100644 index 000000000000..44b9e6fed09f --- /dev/null +++ b/arch/sparc64/kernel/tsb.S | |||
@@ -0,0 +1,169 @@ | |||
1 | /* tsb.S: Sparc64 TSB table handling. | ||
2 | * | ||
3 | * Copyright (C) 2006 David S. Miller <davem@davemloft.net> | ||
4 | */ | ||
5 | |||
6 | #include <asm/tsb.h> | ||
7 | |||
8 | .text | ||
9 | .align 32 | ||
10 | |||
11 | /* Invoked from TLB miss handler, we are in the | ||
12 | * MMU global registers and they are setup like | ||
13 | * this: | ||
14 | * | ||
15 | * %g1: TSB entry pointer | ||
16 | * %g2: available temporary | ||
17 | * %g3: FAULT_CODE_{D,I}TLB | ||
18 | * %g4: available temporary | ||
19 | * %g5: available temporary | ||
20 | * %g6: TAG TARGET | ||
21 | * %g7: physical address base of the linux page | ||
22 | * tables for the current address space | ||
23 | */ | ||
24 | .globl tsb_miss_dtlb | ||
25 | tsb_miss_dtlb: | ||
26 | mov TLB_TAG_ACCESS, %g4 | ||
27 | ldxa [%g4] ASI_DMMU, %g4 | ||
28 | ba,pt %xcc, tsb_miss_page_table_walk | ||
29 | nop | ||
30 | |||
31 | .globl tsb_miss_itlb | ||
32 | tsb_miss_itlb: | ||
33 | mov TLB_TAG_ACCESS, %g4 | ||
34 | ldxa [%g4] ASI_IMMU, %g4 | ||
35 | ba,pt %xcc, tsb_miss_page_table_walk | ||
36 | nop | ||
37 | |||
38 | tsb_miss_page_table_walk: | ||
39 | USER_PGTABLE_WALK_TL1(%g4, %g7, %g5, %g2, tsb_do_fault) | ||
40 | |||
41 | tsb_reload: | ||
42 | TSB_LOCK_TAG(%g1, %g2, %g4) | ||
43 | |||
44 | /* Load and check PTE. */ | ||
45 | ldxa [%g5] ASI_PHYS_USE_EC, %g5 | ||
46 | brgez,a,pn %g5, tsb_do_fault | ||
47 | stx %g0, [%g1] | ||
48 | |||
49 | TSB_WRITE(%g1, %g5, %g6) | ||
50 | |||
51 | /* Finally, load TLB and return from trap. */ | ||
52 | tsb_tlb_reload: | ||
53 | cmp %g3, FAULT_CODE_DTLB | ||
54 | bne,pn %xcc, tsb_itlb_load | ||
55 | nop | ||
56 | |||
57 | tsb_dtlb_load: | ||
58 | stxa %g5, [%g0] ASI_DTLB_DATA_IN | ||
59 | retry | ||
60 | |||
61 | tsb_itlb_load: | ||
62 | stxa %g5, [%g0] ASI_ITLB_DATA_IN | ||
63 | retry | ||
64 | |||
65 | /* No valid entry in the page tables, do full fault | ||
66 | * processing. | ||
67 | */ | ||
68 | |||
69 | .globl tsb_do_fault | ||
70 | tsb_do_fault: | ||
71 | cmp %g3, FAULT_CODE_DTLB | ||
72 | rdpr %pstate, %g5 | ||
73 | bne,pn %xcc, tsb_do_itlb_fault | ||
74 | wrpr %g5, PSTATE_AG | PSTATE_MG, %pstate | ||
75 | |||
76 | tsb_do_dtlb_fault: | ||
77 | rdpr %tl, %g4 | ||
78 | cmp %g4, 1 | ||
79 | mov TLB_TAG_ACCESS, %g4 | ||
80 | ldxa [%g4] ASI_DMMU, %g5 | ||
81 | be,pt %xcc, sparc64_realfault_common | ||
82 | mov FAULT_CODE_DTLB, %g4 | ||
83 | ba,pt %xcc, winfix_trampoline | ||
84 | nop | ||
85 | |||
86 | tsb_do_itlb_fault: | ||
87 | rdpr %tpc, %g5 | ||
88 | ba,pt %xcc, sparc64_realfault_common | ||
89 | mov FAULT_CODE_ITLB, %g4 | ||
90 | |||
91 | .globl sparc64_realfault_common | ||
92 | sparc64_realfault_common: | ||
93 | stb %g4, [%g6 + TI_FAULT_CODE] ! Save fault code | ||
94 | stx %g5, [%g6 + TI_FAULT_ADDR] ! Save fault address | ||
95 | ba,pt %xcc, etrap ! Save trap state | ||
96 | 1: rd %pc, %g7 ! ... | ||
97 | call do_sparc64_fault ! Call fault handler | ||
98 | add %sp, PTREGS_OFF, %o0 ! Compute pt_regs arg | ||
99 | ba,pt %xcc, rtrap_clr_l6 ! Restore cpu state | ||
100 | nop ! Delay slot (fill me) | ||
101 | |||
102 | .globl winfix_trampoline | ||
103 | winfix_trampoline: | ||
104 | rdpr %tpc, %g3 ! Prepare winfixup TNPC | ||
105 | or %g3, 0x7c, %g3 ! Compute branch offset | ||
106 | wrpr %g3, %tnpc ! Write it into TNPC | ||
107 | done ! Trap return | ||
108 | |||
109 | /* Reload MMU related context switch state at | ||
110 | * schedule() time. | ||
111 | * | ||
112 | * %o0: page table physical address | ||
113 | * %o1: TSB address | ||
114 | */ | ||
115 | .globl tsb_context_switch | ||
116 | tsb_context_switch: | ||
117 | wrpr %g0, PSTATE_MG | PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV, %pstate | ||
118 | |||
119 | /* Set page table base alternate global. */ | ||
120 | mov %o0, %g7 | ||
121 | |||
122 | /* XXX can this happen? */ | ||
123 | brz,pn %o1, 9f | ||
124 | nop | ||
125 | |||
126 | /* Lock TSB into D-TLB. */ | ||
127 | sethi %hi(PAGE_SIZE), %o3 | ||
128 | and %o3, %o1, %o3 | ||
129 | sethi %hi(TSBMAP_BASE), %o2 | ||
130 | add %o2, %o3, %o2 | ||
131 | |||
132 | /* XXX handle PAGE_SIZE != 8K correctly... */ | ||
133 | mov TSB_REG, %g1 | ||
134 | stxa %o2, [%g1] ASI_DMMU | ||
135 | membar #Sync | ||
136 | |||
137 | stxa %o2, [%g1] ASI_IMMU | ||
138 | membar #Sync | ||
139 | |||
140 | #define KERN_HIGHBITS ((_PAGE_VALID|_PAGE_SZBITS)^0xfffff80000000000) | ||
141 | #define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W | _PAGE_L) | ||
142 | sethi %uhi(KERN_HIGHBITS), %g2 | ||
143 | or %g2, %ulo(KERN_HIGHBITS), %g2 | ||
144 | sllx %g2, 32, %g2 | ||
145 | or %g2, KERN_LOWBITS, %g2 | ||
146 | #undef KERN_HIGHBITS | ||
147 | #undef KERN_LOWBITS | ||
148 | |||
149 | xor %o1, %g2, %o1 | ||
150 | |||
151 | /* We use entry 61 for this locked entry. This is the spitfire | ||
152 | * TLB entry number, and luckily cheetah masks the value with | ||
153 | * 15 ending us up with entry 13 which is what we want in that | ||
154 | * case too. | ||
155 | * | ||
156 | * XXX Interactions with prom_world()... | ||
157 | */ | ||
158 | mov TLB_TAG_ACCESS, %g1 | ||
159 | stxa %o2, [%g1] ASI_DMMU | ||
160 | membar #Sync | ||
161 | mov (61 << 3), %g1 | ||
162 | stxa %o1, [%g1] ASI_DTLB_DATA_ACCESS | ||
163 | membar #Sync | ||
164 | |||
165 | 9: | ||
166 | wrpr %g0, PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE, %pstate | ||
167 | |||
168 | retl | ||
169 | mov %o2, %o0 | ||