diff options
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r-- | arch/powerpc/mm/44x_mmu.c | 13 | ||||
-rw-r--r-- | arch/powerpc/mm/init_32.c | 32 | ||||
-rw-r--r-- | arch/powerpc/mm/init_64.c | 16 | ||||
-rw-r--r-- | arch/powerpc/mm/mem.c | 35 | ||||
-rw-r--r-- | arch/powerpc/mm/tlb_hash32.c | 4 | ||||
-rw-r--r-- | arch/powerpc/mm/tlb_low_64e.S | 206 | ||||
-rw-r--r-- | arch/powerpc/mm/tlb_nohash.c | 64 |
7 files changed, 301 insertions, 69 deletions
diff --git a/arch/powerpc/mm/44x_mmu.c b/arch/powerpc/mm/44x_mmu.c index 024acab588fd..f60e006d90c3 100644 --- a/arch/powerpc/mm/44x_mmu.c +++ b/arch/powerpc/mm/44x_mmu.c | |||
@@ -186,10 +186,11 @@ void __init MMU_init_hw(void) | |||
186 | unsigned long __init mmu_mapin_ram(unsigned long top) | 186 | unsigned long __init mmu_mapin_ram(unsigned long top) |
187 | { | 187 | { |
188 | unsigned long addr; | 188 | unsigned long addr; |
189 | unsigned long memstart = memstart_addr & ~(PPC_PIN_SIZE - 1); | ||
189 | 190 | ||
190 | /* Pin in enough TLBs to cover any lowmem not covered by the | 191 | /* Pin in enough TLBs to cover any lowmem not covered by the |
191 | * initial 256M mapping established in head_44x.S */ | 192 | * initial 256M mapping established in head_44x.S */ |
192 | for (addr = PPC_PIN_SIZE; addr < lowmem_end_addr; | 193 | for (addr = memstart + PPC_PIN_SIZE; addr < lowmem_end_addr; |
193 | addr += PPC_PIN_SIZE) { | 194 | addr += PPC_PIN_SIZE) { |
194 | if (mmu_has_feature(MMU_FTR_TYPE_47x)) | 195 | if (mmu_has_feature(MMU_FTR_TYPE_47x)) |
195 | ppc47x_pin_tlb(addr + PAGE_OFFSET, addr); | 196 | ppc47x_pin_tlb(addr + PAGE_OFFSET, addr); |
@@ -218,19 +219,25 @@ unsigned long __init mmu_mapin_ram(unsigned long top) | |||
218 | void setup_initial_memory_limit(phys_addr_t first_memblock_base, | 219 | void setup_initial_memory_limit(phys_addr_t first_memblock_base, |
219 | phys_addr_t first_memblock_size) | 220 | phys_addr_t first_memblock_size) |
220 | { | 221 | { |
222 | u64 size; | ||
223 | |||
224 | #ifndef CONFIG_RELOCATABLE | ||
221 | /* We don't currently support the first MEMBLOCK not mapping 0 | 225 | /* We don't currently support the first MEMBLOCK not mapping 0 |
222 | * physical on those processors | 226 | * physical on those processors |
223 | */ | 227 | */ |
224 | BUG_ON(first_memblock_base != 0); | 228 | BUG_ON(first_memblock_base != 0); |
229 | #endif | ||
225 | 230 | ||
226 | /* 44x has a 256M TLB entry pinned at boot */ | 231 | /* 44x has a 256M TLB entry pinned at boot */ |
227 | memblock_set_current_limit(min_t(u64, first_memblock_size, PPC_PIN_SIZE)); | 232 | size = (min_t(u64, first_memblock_size, PPC_PIN_SIZE)); |
233 | memblock_set_current_limit(first_memblock_base + size); | ||
228 | } | 234 | } |
229 | 235 | ||
230 | #ifdef CONFIG_SMP | 236 | #ifdef CONFIG_SMP |
231 | void __cpuinit mmu_init_secondary(int cpu) | 237 | void __cpuinit mmu_init_secondary(int cpu) |
232 | { | 238 | { |
233 | unsigned long addr; | 239 | unsigned long addr; |
240 | unsigned long memstart = memstart_addr & ~(PPC_PIN_SIZE - 1); | ||
234 | 241 | ||
235 | /* Pin in enough TLBs to cover any lowmem not covered by the | 242 | /* Pin in enough TLBs to cover any lowmem not covered by the |
236 | * initial 256M mapping established in head_44x.S | 243 | * initial 256M mapping established in head_44x.S |
@@ -241,7 +248,7 @@ void __cpuinit mmu_init_secondary(int cpu) | |||
241 | * stack. current (r2) isn't initialized, smp_processor_id() | 248 | * stack. current (r2) isn't initialized, smp_processor_id() |
242 | * will not work, current thread info isn't accessible, ... | 249 | * will not work, current thread info isn't accessible, ... |
243 | */ | 250 | */ |
244 | for (addr = PPC_PIN_SIZE; addr < lowmem_end_addr; | 251 | for (addr = memstart + PPC_PIN_SIZE; addr < lowmem_end_addr; |
245 | addr += PPC_PIN_SIZE) { | 252 | addr += PPC_PIN_SIZE) { |
246 | if (mmu_has_feature(MMU_FTR_TYPE_47x)) | 253 | if (mmu_has_feature(MMU_FTR_TYPE_47x)) |
247 | ppc47x_pin_tlb(addr + PAGE_OFFSET, addr); | 254 | ppc47x_pin_tlb(addr + PAGE_OFFSET, addr); |
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c index 5de0f254dbb5..c77fef56dad6 100644 --- a/arch/powerpc/mm/init_32.c +++ b/arch/powerpc/mm/init_32.c | |||
@@ -191,38 +191,6 @@ void __init *early_get_page(void) | |||
191 | return __va(memblock_alloc(PAGE_SIZE, PAGE_SIZE)); | 191 | return __va(memblock_alloc(PAGE_SIZE, PAGE_SIZE)); |
192 | } | 192 | } |
193 | 193 | ||
194 | /* Free up now-unused memory */ | ||
195 | static void free_sec(unsigned long start, unsigned long end, const char *name) | ||
196 | { | ||
197 | unsigned long cnt = 0; | ||
198 | |||
199 | while (start < end) { | ||
200 | ClearPageReserved(virt_to_page(start)); | ||
201 | init_page_count(virt_to_page(start)); | ||
202 | free_page(start); | ||
203 | cnt++; | ||
204 | start += PAGE_SIZE; | ||
205 | } | ||
206 | if (cnt) { | ||
207 | printk(" %ldk %s", cnt << (PAGE_SHIFT - 10), name); | ||
208 | totalram_pages += cnt; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | void free_initmem(void) | ||
213 | { | ||
214 | #define FREESEC(TYPE) \ | ||
215 | free_sec((unsigned long)(&__ ## TYPE ## _begin), \ | ||
216 | (unsigned long)(&__ ## TYPE ## _end), \ | ||
217 | #TYPE); | ||
218 | |||
219 | printk ("Freeing unused kernel memory:"); | ||
220 | FREESEC(init); | ||
221 | printk("\n"); | ||
222 | ppc_md.progress = NULL; | ||
223 | #undef FREESEC | ||
224 | } | ||
225 | |||
226 | #ifdef CONFIG_8xx /* No 8xx specific .c file to put that in ... */ | 194 | #ifdef CONFIG_8xx /* No 8xx specific .c file to put that in ... */ |
227 | void setup_initial_memory_limit(phys_addr_t first_memblock_base, | 195 | void setup_initial_memory_limit(phys_addr_t first_memblock_base, |
228 | phys_addr_t first_memblock_size) | 196 | phys_addr_t first_memblock_size) |
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index f6dbb4c20e64..e94b57fb79a0 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c | |||
@@ -83,22 +83,6 @@ EXPORT_SYMBOL_GPL(memstart_addr); | |||
83 | phys_addr_t kernstart_addr; | 83 | phys_addr_t kernstart_addr; |
84 | EXPORT_SYMBOL_GPL(kernstart_addr); | 84 | EXPORT_SYMBOL_GPL(kernstart_addr); |
85 | 85 | ||
86 | void free_initmem(void) | ||
87 | { | ||
88 | unsigned long addr; | ||
89 | |||
90 | addr = (unsigned long)__init_begin; | ||
91 | for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) { | ||
92 | memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE); | ||
93 | ClearPageReserved(virt_to_page(addr)); | ||
94 | init_page_count(virt_to_page(addr)); | ||
95 | free_page(addr); | ||
96 | totalram_pages++; | ||
97 | } | ||
98 | printk ("Freeing unused kernel memory: %luk freed\n", | ||
99 | ((unsigned long)__init_end - (unsigned long)__init_begin) >> 10); | ||
100 | } | ||
101 | |||
102 | static void pgd_ctor(void *addr) | 86 | static void pgd_ctor(void *addr) |
103 | { | 87 | { |
104 | memset(addr, 0, PGD_TABLE_SIZE); | 88 | memset(addr, 0, PGD_TABLE_SIZE); |
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 29d4dde65c45..c781bbcf7338 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c | |||
@@ -249,7 +249,7 @@ static int __init mark_nonram_nosave(void) | |||
249 | */ | 249 | */ |
250 | void __init paging_init(void) | 250 | void __init paging_init(void) |
251 | { | 251 | { |
252 | unsigned long total_ram = memblock_phys_mem_size(); | 252 | unsigned long long total_ram = memblock_phys_mem_size(); |
253 | phys_addr_t top_of_ram = memblock_end_of_DRAM(); | 253 | phys_addr_t top_of_ram = memblock_end_of_DRAM(); |
254 | unsigned long max_zone_pfns[MAX_NR_ZONES]; | 254 | unsigned long max_zone_pfns[MAX_NR_ZONES]; |
255 | 255 | ||
@@ -269,7 +269,7 @@ void __init paging_init(void) | |||
269 | kmap_prot = PAGE_KERNEL; | 269 | kmap_prot = PAGE_KERNEL; |
270 | #endif /* CONFIG_HIGHMEM */ | 270 | #endif /* CONFIG_HIGHMEM */ |
271 | 271 | ||
272 | printk(KERN_DEBUG "Top of RAM: 0x%llx, Total RAM: 0x%lx\n", | 272 | printk(KERN_DEBUG "Top of RAM: 0x%llx, Total RAM: 0x%llx\n", |
273 | (unsigned long long)top_of_ram, total_ram); | 273 | (unsigned long long)top_of_ram, total_ram); |
274 | printk(KERN_DEBUG "Memory hole size: %ldMB\n", | 274 | printk(KERN_DEBUG "Memory hole size: %ldMB\n", |
275 | (long int)((top_of_ram - total_ram) >> 20)); | 275 | (long int)((top_of_ram - total_ram) >> 20)); |
@@ -337,8 +337,9 @@ void __init mem_init(void) | |||
337 | 337 | ||
338 | highmem_mapnr = lowmem_end_addr >> PAGE_SHIFT; | 338 | highmem_mapnr = lowmem_end_addr >> PAGE_SHIFT; |
339 | for (pfn = highmem_mapnr; pfn < max_mapnr; ++pfn) { | 339 | for (pfn = highmem_mapnr; pfn < max_mapnr; ++pfn) { |
340 | phys_addr_t paddr = (phys_addr_t)pfn << PAGE_SHIFT; | ||
340 | struct page *page = pfn_to_page(pfn); | 341 | struct page *page = pfn_to_page(pfn); |
341 | if (memblock_is_reserved(pfn << PAGE_SHIFT)) | 342 | if (memblock_is_reserved(paddr)) |
342 | continue; | 343 | continue; |
343 | ClearPageReserved(page); | 344 | ClearPageReserved(page); |
344 | init_page_count(page); | 345 | init_page_count(page); |
@@ -352,6 +353,15 @@ void __init mem_init(void) | |||
352 | } | 353 | } |
353 | #endif /* CONFIG_HIGHMEM */ | 354 | #endif /* CONFIG_HIGHMEM */ |
354 | 355 | ||
356 | #if defined(CONFIG_PPC_FSL_BOOK3E) && !defined(CONFIG_SMP) | ||
357 | /* | ||
358 | * If smp is enabled, next_tlbcam_idx is initialized in the cpu up | ||
359 | * functions.... do it here for the non-smp case. | ||
360 | */ | ||
361 | per_cpu(next_tlbcam_idx, smp_processor_id()) = | ||
362 | (mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) - 1; | ||
363 | #endif | ||
364 | |||
355 | printk(KERN_INFO "Memory: %luk/%luk available (%luk kernel code, " | 365 | printk(KERN_INFO "Memory: %luk/%luk available (%luk kernel code, " |
356 | "%luk reserved, %luk data, %luk bss, %luk init)\n", | 366 | "%luk reserved, %luk data, %luk bss, %luk init)\n", |
357 | nr_free_pages() << (PAGE_SHIFT-10), | 367 | nr_free_pages() << (PAGE_SHIFT-10), |
@@ -382,6 +392,25 @@ void __init mem_init(void) | |||
382 | mem_init_done = 1; | 392 | mem_init_done = 1; |
383 | } | 393 | } |
384 | 394 | ||
395 | void free_initmem(void) | ||
396 | { | ||
397 | unsigned long addr; | ||
398 | |||
399 | ppc_md.progress = ppc_printk_progress; | ||
400 | |||
401 | addr = (unsigned long)__init_begin; | ||
402 | for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) { | ||
403 | memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE); | ||
404 | ClearPageReserved(virt_to_page(addr)); | ||
405 | init_page_count(virt_to_page(addr)); | ||
406 | free_page(addr); | ||
407 | totalram_pages++; | ||
408 | } | ||
409 | pr_info("Freeing unused kernel memory: %luk freed\n", | ||
410 | ((unsigned long)__init_end - | ||
411 | (unsigned long)__init_begin) >> 10); | ||
412 | } | ||
413 | |||
385 | #ifdef CONFIG_BLK_DEV_INITRD | 414 | #ifdef CONFIG_BLK_DEV_INITRD |
386 | void __init free_initrd_mem(unsigned long start, unsigned long end) | 415 | void __init free_initrd_mem(unsigned long start, unsigned long end) |
387 | { | 416 | { |
diff --git a/arch/powerpc/mm/tlb_hash32.c b/arch/powerpc/mm/tlb_hash32.c index 27b863c14941..9a445f64accd 100644 --- a/arch/powerpc/mm/tlb_hash32.c +++ b/arch/powerpc/mm/tlb_hash32.c | |||
@@ -177,3 +177,7 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, | |||
177 | flush_range(vma->vm_mm, start, end); | 177 | flush_range(vma->vm_mm, start, end); |
178 | } | 178 | } |
179 | EXPORT_SYMBOL(flush_tlb_range); | 179 | EXPORT_SYMBOL(flush_tlb_range); |
180 | |||
181 | void __init early_init_mmu(void) | ||
182 | { | ||
183 | } | ||
diff --git a/arch/powerpc/mm/tlb_low_64e.S b/arch/powerpc/mm/tlb_low_64e.S index af0892209417..4ebb34bc01d6 100644 --- a/arch/powerpc/mm/tlb_low_64e.S +++ b/arch/powerpc/mm/tlb_low_64e.S | |||
@@ -30,6 +30,212 @@ | |||
30 | #define VPTE_PGD_SHIFT (VPTE_PUD_SHIFT + PUD_INDEX_SIZE) | 30 | #define VPTE_PGD_SHIFT (VPTE_PUD_SHIFT + PUD_INDEX_SIZE) |
31 | #define VPTE_INDEX_SIZE (VPTE_PGD_SHIFT + PGD_INDEX_SIZE) | 31 | #define VPTE_INDEX_SIZE (VPTE_PGD_SHIFT + PGD_INDEX_SIZE) |
32 | 32 | ||
33 | /********************************************************************** | ||
34 | * * | ||
35 | * TLB miss handling for Book3E with a bolted linear mapping * | ||
36 | * No virtual page table, no nested TLB misses * | ||
37 | * * | ||
38 | **********************************************************************/ | ||
39 | |||
40 | .macro tlb_prolog_bolted addr | ||
41 | mtspr SPRN_SPRG_TLB_SCRATCH,r13 | ||
42 | mfspr r13,SPRN_SPRG_PACA | ||
43 | std r10,PACA_EXTLB+EX_TLB_R10(r13) | ||
44 | mfcr r10 | ||
45 | std r11,PACA_EXTLB+EX_TLB_R11(r13) | ||
46 | std r16,PACA_EXTLB+EX_TLB_R16(r13) | ||
47 | mfspr r16,\addr /* get faulting address */ | ||
48 | std r14,PACA_EXTLB+EX_TLB_R14(r13) | ||
49 | ld r14,PACAPGD(r13) | ||
50 | std r15,PACA_EXTLB+EX_TLB_R15(r13) | ||
51 | std r10,PACA_EXTLB+EX_TLB_CR(r13) | ||
52 | TLB_MISS_PROLOG_STATS_BOLTED | ||
53 | .endm | ||
54 | |||
55 | .macro tlb_epilog_bolted | ||
56 | ld r14,PACA_EXTLB+EX_TLB_CR(r13) | ||
57 | ld r10,PACA_EXTLB+EX_TLB_R10(r13) | ||
58 | ld r11,PACA_EXTLB+EX_TLB_R11(r13) | ||
59 | mtcr r14 | ||
60 | ld r14,PACA_EXTLB+EX_TLB_R14(r13) | ||
61 | ld r15,PACA_EXTLB+EX_TLB_R15(r13) | ||
62 | TLB_MISS_RESTORE_STATS_BOLTED | ||
63 | ld r16,PACA_EXTLB+EX_TLB_R16(r13) | ||
64 | mfspr r13,SPRN_SPRG_TLB_SCRATCH | ||
65 | .endm | ||
66 | |||
67 | /* Data TLB miss */ | ||
68 | START_EXCEPTION(data_tlb_miss_bolted) | ||
69 | tlb_prolog_bolted SPRN_DEAR | ||
70 | |||
71 | /* We need _PAGE_PRESENT and _PAGE_ACCESSED set */ | ||
72 | |||
73 | /* We do the user/kernel test for the PID here along with the RW test | ||
74 | */ | ||
75 | /* We pre-test some combination of permissions to avoid double | ||
76 | * faults: | ||
77 | * | ||
78 | * We move the ESR:ST bit into the position of _PAGE_BAP_SW in the PTE | ||
79 | * ESR_ST is 0x00800000 | ||
80 | * _PAGE_BAP_SW is 0x00000010 | ||
81 | * So the shift is >> 19. This tests for supervisor writeability. | ||
82 | * If the page happens to be supervisor writeable and not user | ||
83 | * writeable, we will take a new fault later, but that should be | ||
84 | * a rare enough case. | ||
85 | * | ||
86 | * We also move ESR_ST in _PAGE_DIRTY position | ||
87 | * _PAGE_DIRTY is 0x00001000 so the shift is >> 11 | ||
88 | * | ||
89 | * MAS1 is preset for all we need except for TID that needs to | ||
90 | * be cleared for kernel translations | ||
91 | */ | ||
92 | |||
93 | mfspr r11,SPRN_ESR | ||
94 | |||
95 | srdi r15,r16,60 /* get region */ | ||
96 | rldicl. r10,r16,64-PGTABLE_EADDR_SIZE,PGTABLE_EADDR_SIZE+4 | ||
97 | bne- dtlb_miss_fault_bolted | ||
98 | |||
99 | rlwinm r10,r11,32-19,27,27 | ||
100 | rlwimi r10,r11,32-16,19,19 | ||
101 | cmpwi r15,0 | ||
102 | ori r10,r10,_PAGE_PRESENT | ||
103 | oris r11,r10,_PAGE_ACCESSED@h | ||
104 | |||
105 | TLB_MISS_STATS_SAVE_INFO_BOLTED | ||
106 | bne tlb_miss_kernel_bolted | ||
107 | |||
108 | tlb_miss_common_bolted: | ||
109 | /* | ||
110 | * This is the guts of the TLB miss handler for bolted-linear. | ||
111 | * We are entered with: | ||
112 | * | ||
113 | * r16 = faulting address | ||
114 | * r15 = crap (free to use) | ||
115 | * r14 = page table base | ||
116 | * r13 = PACA | ||
117 | * r11 = PTE permission mask | ||
118 | * r10 = crap (free to use) | ||
119 | */ | ||
120 | rldicl r15,r16,64-PGDIR_SHIFT+3,64-PGD_INDEX_SIZE-3 | ||
121 | cmpldi cr0,r14,0 | ||
122 | clrrdi r15,r15,3 | ||
123 | beq tlb_miss_fault_bolted | ||
124 | |||
125 | BEGIN_MMU_FTR_SECTION | ||
126 | /* Set the TLB reservation and search for existing entry. Then load | ||
127 | * the entry. | ||
128 | */ | ||
129 | PPC_TLBSRX_DOT(0,r16) | ||
130 | ldx r14,r14,r15 | ||
131 | beq normal_tlb_miss_done | ||
132 | MMU_FTR_SECTION_ELSE | ||
133 | ldx r14,r14,r15 | ||
134 | ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_USE_TLBRSRV) | ||
135 | |||
136 | #ifndef CONFIG_PPC_64K_PAGES | ||
137 | rldicl r15,r16,64-PUD_SHIFT+3,64-PUD_INDEX_SIZE-3 | ||
138 | clrrdi r15,r15,3 | ||
139 | |||
140 | cmpldi cr0,r14,0 | ||
141 | beq tlb_miss_fault_bolted | ||
142 | |||
143 | ldx r14,r14,r15 | ||
144 | #endif /* CONFIG_PPC_64K_PAGES */ | ||
145 | |||
146 | rldicl r15,r16,64-PMD_SHIFT+3,64-PMD_INDEX_SIZE-3 | ||
147 | clrrdi r15,r15,3 | ||
148 | |||
149 | cmpldi cr0,r14,0 | ||
150 | beq tlb_miss_fault_bolted | ||
151 | |||
152 | ldx r14,r14,r15 | ||
153 | |||
154 | rldicl r15,r16,64-PAGE_SHIFT+3,64-PTE_INDEX_SIZE-3 | ||
155 | clrrdi r15,r15,3 | ||
156 | |||
157 | cmpldi cr0,r14,0 | ||
158 | beq tlb_miss_fault_bolted | ||
159 | |||
160 | ldx r14,r14,r15 | ||
161 | |||
162 | /* Check if required permissions are met */ | ||
163 | andc. r15,r11,r14 | ||
164 | rldicr r15,r14,64-(PTE_RPN_SHIFT-PAGE_SHIFT),63-PAGE_SHIFT | ||
165 | bne- tlb_miss_fault_bolted | ||
166 | |||
167 | /* Now we build the MAS: | ||
168 | * | ||
169 | * MAS 0 : Fully setup with defaults in MAS4 and TLBnCFG | ||
170 | * MAS 1 : Almost fully setup | ||
171 | * - PID already updated by caller if necessary | ||
172 | * - TSIZE need change if !base page size, not | ||
173 | * yet implemented for now | ||
174 | * MAS 2 : Defaults not useful, need to be redone | ||
175 | * MAS 3+7 : Needs to be done | ||
176 | */ | ||
177 | clrrdi r11,r16,12 /* Clear low crap in EA */ | ||
178 | clrldi r15,r15,12 /* Clear crap at the top */ | ||
179 | rlwimi r11,r14,32-19,27,31 /* Insert WIMGE */ | ||
180 | rlwimi r15,r14,32-8,22,25 /* Move in U bits */ | ||
181 | mtspr SPRN_MAS2,r11 | ||
182 | andi. r11,r14,_PAGE_DIRTY | ||
183 | rlwimi r15,r14,32-2,26,31 /* Move in BAP bits */ | ||
184 | |||
185 | /* Mask out SW and UW if !DIRTY (XXX optimize this !) */ | ||
186 | bne 1f | ||
187 | li r11,MAS3_SW|MAS3_UW | ||
188 | andc r15,r15,r11 | ||
189 | 1: | ||
190 | mtspr SPRN_MAS7_MAS3,r15 | ||
191 | tlbwe | ||
192 | |||
193 | TLB_MISS_STATS_X(MMSTAT_TLB_MISS_NORM_OK) | ||
194 | tlb_epilog_bolted | ||
195 | rfi | ||
196 | |||
197 | itlb_miss_kernel_bolted: | ||
198 | li r11,_PAGE_PRESENT|_PAGE_BAP_SX /* Base perm */ | ||
199 | oris r11,r11,_PAGE_ACCESSED@h | ||
200 | tlb_miss_kernel_bolted: | ||
201 | mfspr r10,SPRN_MAS1 | ||
202 | ld r14,PACA_KERNELPGD(r13) | ||
203 | cmpldi cr0,r15,8 /* Check for vmalloc region */ | ||
204 | rlwinm r10,r10,0,16,1 /* Clear TID */ | ||
205 | mtspr SPRN_MAS1,r10 | ||
206 | beq+ tlb_miss_common_bolted | ||
207 | |||
208 | tlb_miss_fault_bolted: | ||
209 | /* We need to check if it was an instruction miss */ | ||
210 | andi. r10,r11,_PAGE_EXEC|_PAGE_BAP_SX | ||
211 | bne itlb_miss_fault_bolted | ||
212 | dtlb_miss_fault_bolted: | ||
213 | TLB_MISS_STATS_D(MMSTAT_TLB_MISS_NORM_FAULT) | ||
214 | tlb_epilog_bolted | ||
215 | b exc_data_storage_book3e | ||
216 | itlb_miss_fault_bolted: | ||
217 | TLB_MISS_STATS_I(MMSTAT_TLB_MISS_NORM_FAULT) | ||
218 | tlb_epilog_bolted | ||
219 | b exc_instruction_storage_book3e | ||
220 | |||
221 | /* Instruction TLB miss */ | ||
222 | START_EXCEPTION(instruction_tlb_miss_bolted) | ||
223 | tlb_prolog_bolted SPRN_SRR0 | ||
224 | |||
225 | rldicl. r10,r16,64-PGTABLE_EADDR_SIZE,PGTABLE_EADDR_SIZE+4 | ||
226 | srdi r15,r16,60 /* get region */ | ||
227 | TLB_MISS_STATS_SAVE_INFO_BOLTED | ||
228 | bne- itlb_miss_fault_bolted | ||
229 | |||
230 | li r11,_PAGE_PRESENT|_PAGE_EXEC /* Base perm */ | ||
231 | |||
232 | /* We do the user/kernel test for the PID here along with the RW test | ||
233 | */ | ||
234 | |||
235 | cmpldi cr0,r15,0 /* Check for user region */ | ||
236 | oris r11,r11,_PAGE_ACCESSED@h | ||
237 | beq tlb_miss_common_bolted | ||
238 | b itlb_miss_kernel_bolted | ||
33 | 239 | ||
34 | /********************************************************************** | 240 | /********************************************************************** |
35 | * * | 241 | * * |
diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c index 0bdad3aecc67..d32ec643c231 100644 --- a/arch/powerpc/mm/tlb_nohash.c +++ b/arch/powerpc/mm/tlb_nohash.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/preempt.h> | 35 | #include <linux/preempt.h> |
36 | #include <linux/spinlock.h> | 36 | #include <linux/spinlock.h> |
37 | #include <linux/memblock.h> | 37 | #include <linux/memblock.h> |
38 | #include <linux/of_fdt.h> | ||
38 | 39 | ||
39 | #include <asm/tlbflush.h> | 40 | #include <asm/tlbflush.h> |
40 | #include <asm/tlb.h> | 41 | #include <asm/tlb.h> |
@@ -102,6 +103,12 @@ unsigned long linear_map_top; /* Top of linear mapping */ | |||
102 | 103 | ||
103 | #endif /* CONFIG_PPC64 */ | 104 | #endif /* CONFIG_PPC64 */ |
104 | 105 | ||
106 | #ifdef CONFIG_PPC_FSL_BOOK3E | ||
107 | /* next_tlbcam_idx is used to round-robin tlbcam entry assignment */ | ||
108 | DEFINE_PER_CPU(int, next_tlbcam_idx); | ||
109 | EXPORT_PER_CPU_SYMBOL(next_tlbcam_idx); | ||
110 | #endif | ||
111 | |||
105 | /* | 112 | /* |
106 | * Base TLB flushing operations: | 113 | * Base TLB flushing operations: |
107 | * | 114 | * |
@@ -266,6 +273,17 @@ EXPORT_SYMBOL(flush_tlb_page); | |||
266 | 273 | ||
267 | #endif /* CONFIG_SMP */ | 274 | #endif /* CONFIG_SMP */ |
268 | 275 | ||
276 | #ifdef CONFIG_PPC_47x | ||
277 | void __init early_init_mmu_47x(void) | ||
278 | { | ||
279 | #ifdef CONFIG_SMP | ||
280 | unsigned long root = of_get_flat_dt_root(); | ||
281 | if (of_get_flat_dt_prop(root, "cooperative-partition", NULL)) | ||
282 | mmu_clear_feature(MMU_FTR_USE_TLBIVAX_BCAST); | ||
283 | #endif /* CONFIG_SMP */ | ||
284 | } | ||
285 | #endif /* CONFIG_PPC_47x */ | ||
286 | |||
269 | /* | 287 | /* |
270 | * Flush kernel TLB entries in the given range | 288 | * Flush kernel TLB entries in the given range |
271 | */ | 289 | */ |
@@ -443,14 +461,27 @@ static void setup_page_sizes(void) | |||
443 | } | 461 | } |
444 | } | 462 | } |
445 | 463 | ||
446 | static void setup_mmu_htw(void) | 464 | static void __patch_exception(int exc, unsigned long addr) |
447 | { | 465 | { |
448 | extern unsigned int interrupt_base_book3e; | 466 | extern unsigned int interrupt_base_book3e; |
449 | extern unsigned int exc_data_tlb_miss_htw_book3e; | 467 | unsigned int *ibase = &interrupt_base_book3e; |
450 | extern unsigned int exc_instruction_tlb_miss_htw_book3e; | 468 | |
469 | /* Our exceptions vectors start with a NOP and -then- a branch | ||
470 | * to deal with single stepping from userspace which stops on | ||
471 | * the second instruction. Thus we need to patch the second | ||
472 | * instruction of the exception, not the first one | ||
473 | */ | ||
451 | 474 | ||
452 | unsigned int *ibase = &interrupt_base_book3e; | 475 | patch_branch(ibase + (exc / 4) + 1, addr, 0); |
476 | } | ||
477 | |||
478 | #define patch_exception(exc, name) do { \ | ||
479 | extern unsigned int name; \ | ||
480 | __patch_exception((exc), (unsigned long)&name); \ | ||
481 | } while (0) | ||
453 | 482 | ||
483 | static void setup_mmu_htw(void) | ||
484 | { | ||
454 | /* Check if HW tablewalk is present, and if yes, enable it by: | 485 | /* Check if HW tablewalk is present, and if yes, enable it by: |
455 | * | 486 | * |
456 | * - patching the TLB miss handlers to branch to the | 487 | * - patching the TLB miss handlers to branch to the |
@@ -462,19 +493,12 @@ static void setup_mmu_htw(void) | |||
462 | 493 | ||
463 | if ((tlb0cfg & TLBnCFG_IND) && | 494 | if ((tlb0cfg & TLBnCFG_IND) && |
464 | (tlb0cfg & TLBnCFG_PT)) { | 495 | (tlb0cfg & TLBnCFG_PT)) { |
465 | /* Our exceptions vectors start with a NOP and -then- a branch | 496 | patch_exception(0x1c0, exc_data_tlb_miss_htw_book3e); |
466 | * to deal with single stepping from userspace which stops on | 497 | patch_exception(0x1e0, exc_instruction_tlb_miss_htw_book3e); |
467 | * the second instruction. Thus we need to patch the second | ||
468 | * instruction of the exception, not the first one | ||
469 | */ | ||
470 | patch_branch(ibase + (0x1c0 / 4) + 1, | ||
471 | (unsigned long)&exc_data_tlb_miss_htw_book3e, 0); | ||
472 | patch_branch(ibase + (0x1e0 / 4) + 1, | ||
473 | (unsigned long)&exc_instruction_tlb_miss_htw_book3e, 0); | ||
474 | book3e_htw_enabled = 1; | 498 | book3e_htw_enabled = 1; |
475 | } | 499 | } |
476 | pr_info("MMU: Book3E Page Tables %s\n", | 500 | pr_info("MMU: Book3E HW tablewalk %s\n", |
477 | book3e_htw_enabled ? "Enabled" : "Disabled"); | 501 | book3e_htw_enabled ? "enabled" : "not supported"); |
478 | } | 502 | } |
479 | 503 | ||
480 | /* | 504 | /* |
@@ -549,6 +573,9 @@ static void __early_init_mmu(int boot_cpu) | |||
549 | /* limit memory so we dont have linear faults */ | 573 | /* limit memory so we dont have linear faults */ |
550 | memblock_enforce_memory_limit(linear_map_top); | 574 | memblock_enforce_memory_limit(linear_map_top); |
551 | memblock_analyze(); | 575 | memblock_analyze(); |
576 | |||
577 | patch_exception(0x1c0, exc_data_tlb_miss_bolted_book3e); | ||
578 | patch_exception(0x1e0, exc_instruction_tlb_miss_bolted_book3e); | ||
552 | } | 579 | } |
553 | #endif | 580 | #endif |
554 | 581 | ||
@@ -584,4 +611,11 @@ void setup_initial_memory_limit(phys_addr_t first_memblock_base, | |||
584 | /* Finally limit subsequent allocations */ | 611 | /* Finally limit subsequent allocations */ |
585 | memblock_set_current_limit(first_memblock_base + ppc64_rma_size); | 612 | memblock_set_current_limit(first_memblock_base + ppc64_rma_size); |
586 | } | 613 | } |
614 | #else /* ! CONFIG_PPC64 */ | ||
615 | void __init early_init_mmu(void) | ||
616 | { | ||
617 | #ifdef CONFIG_PPC_47x | ||
618 | early_init_mmu_47x(); | ||
619 | #endif | ||
620 | } | ||
587 | #endif /* CONFIG_PPC64 */ | 621 | #endif /* CONFIG_PPC64 */ |