diff options
Diffstat (limited to 'arch/sparc/include/asm/tsb.h')
-rw-r--r-- | arch/sparc/include/asm/tsb.h | 47 |
1 files changed, 41 insertions, 6 deletions
diff --git a/arch/sparc/include/asm/tsb.h b/arch/sparc/include/asm/tsb.h index a2f541905715..ecb49cfa3be9 100644 --- a/arch/sparc/include/asm/tsb.h +++ b/arch/sparc/include/asm/tsb.h | |||
@@ -133,9 +133,24 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end; | |||
133 | sub TSB, 0x8, TSB; \ | 133 | sub TSB, 0x8, TSB; \ |
134 | TSB_STORE(TSB, TAG); | 134 | TSB_STORE(TSB, TAG); |
135 | 135 | ||
136 | /* Do a kernel page table walk. Leaves physical PTE pointer in | 136 | /* Do a kernel page table walk. Leaves valid PTE value in |
137 | * REG1. Jumps to FAIL_LABEL on early page table walk termination. | 137 | * REG1. Jumps to FAIL_LABEL on early page table walk |
138 | * VADDR will not be clobbered, but REG2 will. | 138 | * termination. VADDR will not be clobbered, but REG2 will. |
139 | * | ||
140 | * There are two masks we must apply to propagate bits from | ||
141 | * the virtual address into the PTE physical address field | ||
142 | * when dealing with huge pages. This is because the page | ||
143 | * table boundaries do not match the huge page size(s) the | ||
144 | * hardware supports. | ||
145 | * | ||
146 | * In these cases we propagate the bits that are below the | ||
147 | * page table level where we saw the huge page mapping, but | ||
148 | * are still within the relevant physical bits for the huge | ||
149 | * page size in question. So for PMD mappings (which fall on | ||
150 | * bit 23, for 8MB per PMD) we must propagate bit 22 for a | ||
151 | * 4MB huge page. For huge PUDs (which fall on bit 33, for | ||
152 | * 8GB per PUD), we have to accomodate 256MB and 2GB huge | ||
153 | * pages. So for those we propagate bits 32 to 28. | ||
139 | */ | 154 | */ |
140 | #define KERN_PGTABLE_WALK(VADDR, REG1, REG2, FAIL_LABEL) \ | 155 | #define KERN_PGTABLE_WALK(VADDR, REG1, REG2, FAIL_LABEL) \ |
141 | sethi %hi(swapper_pg_dir), REG1; \ | 156 | sethi %hi(swapper_pg_dir), REG1; \ |
@@ -150,15 +165,35 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end; | |||
150 | andn REG2, 0x7, REG2; \ | 165 | andn REG2, 0x7, REG2; \ |
151 | ldxa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \ | 166 | ldxa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \ |
152 | brz,pn REG1, FAIL_LABEL; \ | 167 | brz,pn REG1, FAIL_LABEL; \ |
153 | sllx VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \ | 168 | sethi %uhi(_PAGE_PUD_HUGE), REG2; \ |
169 | brz,pn REG1, FAIL_LABEL; \ | ||
170 | sllx REG2, 32, REG2; \ | ||
171 | andcc REG1, REG2, %g0; \ | ||
172 | sethi %hi(0xf8000000), REG2; \ | ||
173 | bne,pt %xcc, 697f; \ | ||
174 | sllx REG2, 1, REG2; \ | ||
175 | sllx VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \ | ||
154 | srlx REG2, 64 - PAGE_SHIFT, REG2; \ | 176 | srlx REG2, 64 - PAGE_SHIFT, REG2; \ |
155 | andn REG2, 0x7, REG2; \ | 177 | andn REG2, 0x7, REG2; \ |
156 | ldxa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \ | 178 | ldxa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \ |
179 | sethi %uhi(_PAGE_PMD_HUGE), REG2; \ | ||
157 | brz,pn REG1, FAIL_LABEL; \ | 180 | brz,pn REG1, FAIL_LABEL; \ |
158 | sllx VADDR, 64 - PMD_SHIFT, REG2; \ | 181 | sllx REG2, 32, REG2; \ |
182 | andcc REG1, REG2, %g0; \ | ||
183 | be,pn %xcc, 698f; \ | ||
184 | sethi %hi(0x400000), REG2; \ | ||
185 | 697: brgez,pn REG1, FAIL_LABEL; \ | ||
186 | andn REG1, REG2, REG1; \ | ||
187 | and VADDR, REG2, REG2; \ | ||
188 | ba,pt %xcc, 699f; \ | ||
189 | or REG1, REG2, REG1; \ | ||
190 | 698: sllx VADDR, 64 - PMD_SHIFT, REG2; \ | ||
159 | srlx REG2, 64 - PAGE_SHIFT, REG2; \ | 191 | srlx REG2, 64 - PAGE_SHIFT, REG2; \ |
160 | andn REG2, 0x7, REG2; \ | 192 | andn REG2, 0x7, REG2; \ |
161 | add REG1, REG2, REG1; | 193 | ldxa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \ |
194 | brgez,pn REG1, FAIL_LABEL; \ | ||
195 | nop; \ | ||
196 | 699: | ||
162 | 197 | ||
163 | /* PMD has been loaded into REG1, interpret the value, seeing | 198 | /* PMD has been loaded into REG1, interpret the value, seeing |
164 | * if it is a HUGE PMD or a normal one. If it is not valid | 199 | * if it is a HUGE PMD or a normal one. If it is not valid |