aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc
diff options
context:
space:
mode:
authorMarcelo Tosatti <marcelo.tosatti@cyclades.com>2005-11-14 02:38:31 -0500
committerPaul Mackerras <paulus@samba.org>2005-11-15 21:28:22 -0500
commiteb07d964b4491d1bb5864cd3d7e7633ccdda9a53 (patch)
treeb76d2cdf2159ee2d11ae708ee876a21dbf0838e3 /arch/ppc
parent1e185b97b4364063f1135604b87f8d8469944233 (diff)
[PATCH] ppc32 8xx: update_mmu_cache() needs unconditional tlbie
Currently 8xx fails to boot due to endless pagefaults. Seems the bug is exposed by the change which avoids flushing the TLB when not necessary (in case the pte has not changed), introduced recently: __handle_mm_fault(): entry = pte_mkyoung(entry); if (!pte_same(old_entry, entry)) { ptep_set_access_flags(vma, address, pte, entry, write_access); update_mmu_cache(vma, address, entry); lazy_mmu_prot_update(entry); } else { /* * This is needed only for protection faults but the arch code * is not yet telling us if this is a protection fault or not. * This still avoids useless tlb flushes for .text page faults * with threads. */ if (write_access) flush_tlb_page(vma, address); } The "update_mmu_cache()" call was unconditional before, which caused the TLB to be flushed by: if (pfn_valid(pfn)) { struct page *page = pfn_to_page(pfn); if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags)) { if (vma->vm_mm == current->active_mm) { #ifdef CONFIG_8xx /* On 8xx, cache control instructions (particularly * "dcbst" from flush_dcache_icache) fault as write * operation if there is an unpopulated TLB entry * for the address in question. To workaround that, * we invalidate the TLB here, thus avoiding dcbst * misbehaviour. */ _tlbie(address); #endif __flush_dcache_icache((void *) address); } else flush_dcache_icache_page(page); set_bit(PG_arch_1, &page->flags); } Which worked to due to pure luck: PG_arch_1 was always unset before, but now it isnt. The root of the problem are the changes against the 8xx TLB handlers introduced during v2.6. What happens is the TLBMiss handlers load the zeroed pte into the TLB, causing the TLBError handler to be invoked (thats two TLB faults per pagefault), which then jumps to the generic MM code to setup the pte. The bug is that the zeroed TLB is not invalidated (the same reason for the "dcbst" misbehaviour), resulting in infinite TLBError faults. The "two exception" approach requires a TLB flush (to nuke the zeroed TLB) at each PTE update for correct behaviour: Signed-off-by: Marcelo Tosatti <marcelo.tosatti@cyclades.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/ppc')
-rw-r--r--arch/ppc/mm/init.c23
1 files changed, 11 insertions, 12 deletions
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index 99b48abd3296..45f0782059f1 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -597,21 +597,20 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
597 597
598 if (pfn_valid(pfn)) { 598 if (pfn_valid(pfn)) {
599 struct page *page = pfn_to_page(pfn); 599 struct page *page = pfn_to_page(pfn);
600 if (!PageReserved(page)
601 && !test_bit(PG_arch_1, &page->flags)) {
602 if (vma->vm_mm == current->active_mm) {
603#ifdef CONFIG_8xx 600#ifdef CONFIG_8xx
604 /* On 8xx, cache control instructions (particularly 601 /* On 8xx, the TLB handlers work in 2 stages:
605 * "dcbst" from flush_dcache_icache) fault as write 602 * First, a zeroed entry is loaded by TLBMiss handler,
606 * operation if there is an unpopulated TLB entry 603 * which causes the TLBError handler to be triggered.
607 * for the address in question. To workaround that, 604 * That means the zeroed TLB has to be invalidated
608 * we invalidate the TLB here, thus avoiding dcbst 605 * whenever a page miss occurs.
609 * misbehaviour. 606 */
610 */ 607 _tlbie(address);
611 _tlbie(address);
612#endif 608#endif
609 if (!PageReserved(page)
610 && !test_bit(PG_arch_1, &page->flags)) {
611 if (vma->vm_mm == current->active_mm)
613 __flush_dcache_icache((void *) address); 612 __flush_dcache_icache((void *) address);
614 } else 613 else
615 flush_dcache_icache_page(page); 614 flush_dcache_icache_page(page);
616 set_bit(PG_arch_1, &page->flags); 615 set_bit(PG_arch_1, &page->flags);
617 } 616 }