diff options
Diffstat (limited to 'arch/powerpc/mm/pgtable.c')
-rw-r--r-- | arch/powerpc/mm/pgtable.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c index 83f1551ec2c9..53040931de32 100644 --- a/arch/powerpc/mm/pgtable.c +++ b/arch/powerpc/mm/pgtable.c | |||
@@ -30,6 +30,8 @@ | |||
30 | #include <asm/tlbflush.h> | 30 | #include <asm/tlbflush.h> |
31 | #include <asm/tlb.h> | 31 | #include <asm/tlb.h> |
32 | 32 | ||
33 | #include "mmu_decl.h" | ||
34 | |||
33 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); | 35 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); |
34 | 36 | ||
35 | #ifdef CONFIG_SMP | 37 | #ifdef CONFIG_SMP |
@@ -166,7 +168,7 @@ struct page * maybe_pte_to_page(pte_t pte) | |||
166 | * support falls into the same category. | 168 | * support falls into the same category. |
167 | */ | 169 | */ |
168 | 170 | ||
169 | static pte_t set_pte_filter(pte_t pte) | 171 | static pte_t set_pte_filter(pte_t pte, unsigned long addr) |
170 | { | 172 | { |
171 | pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS); | 173 | pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS); |
172 | if (pte_looks_normal(pte) && !(cpu_has_feature(CPU_FTR_COHERENT_ICACHE) || | 174 | if (pte_looks_normal(pte) && !(cpu_has_feature(CPU_FTR_COHERENT_ICACHE) || |
@@ -175,6 +177,17 @@ static pte_t set_pte_filter(pte_t pte) | |||
175 | if (!pg) | 177 | if (!pg) |
176 | return pte; | 178 | return pte; |
177 | if (!test_bit(PG_arch_1, &pg->flags)) { | 179 | if (!test_bit(PG_arch_1, &pg->flags)) { |
180 | #ifdef CONFIG_8xx | ||
181 | /* On 8xx, cache control instructions (particularly | ||
182 | * "dcbst" from flush_dcache_icache) fault as write | ||
183 | * operation if there is an unpopulated TLB entry | ||
184 | * for the address in question. To workaround that, | ||
185 | * we invalidate the TLB here, thus avoiding dcbst | ||
186 | * misbehaviour. | ||
187 | */ | ||
188 | /* 8xx doesn't care about PID, size or ind args */ | ||
189 | _tlbil_va(addr, 0, 0, 0); | ||
190 | #endif /* CONFIG_8xx */ | ||
178 | flush_dcache_icache_page(pg); | 191 | flush_dcache_icache_page(pg); |
179 | set_bit(PG_arch_1, &pg->flags); | 192 | set_bit(PG_arch_1, &pg->flags); |
180 | } | 193 | } |
@@ -194,7 +207,7 @@ static pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma, | |||
194 | * as we don't have two bits to spare for _PAGE_EXEC and _PAGE_HWEXEC so | 207 | * as we don't have two bits to spare for _PAGE_EXEC and _PAGE_HWEXEC so |
195 | * instead we "filter out" the exec permission for non clean pages. | 208 | * instead we "filter out" the exec permission for non clean pages. |
196 | */ | 209 | */ |
197 | static pte_t set_pte_filter(pte_t pte) | 210 | static pte_t set_pte_filter(pte_t pte, unsigned long addr) |
198 | { | 211 | { |
199 | struct page *pg; | 212 | struct page *pg; |
200 | 213 | ||
@@ -276,7 +289,7 @@ void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, | |||
276 | * this context might not have been activated yet when this | 289 | * this context might not have been activated yet when this |
277 | * is called. | 290 | * is called. |
278 | */ | 291 | */ |
279 | pte = set_pte_filter(pte); | 292 | pte = set_pte_filter(pte, addr); |
280 | 293 | ||
281 | /* Perform the setting of the PTE */ | 294 | /* Perform the setting of the PTE */ |
282 | __set_pte_at(mm, addr, ptep, pte, 0); | 295 | __set_pte_at(mm, addr, ptep, pte, 0); |