cpu_data->dcache.ways = 1;
 #endif
 
-#ifdef CONFIG_CPU_HAS_PTEA
-       cpu_data->flags |= CPU_HAS_PTEA;
-#endif
-
        /*
         * On anything that's not a direct-mapped cache, look to the CVR
         * for I/D-cache specifics.
 
        bool
        select CPU_HAS_INTEVT
        select CPU_HAS_SR_RB
-       select CPU_HAS_PTEA if !CPU_SUBTYPE_ST40
+       select CPU_HAS_PTEA if (!CPU_SUBTYPE_ST40 && !CPU_SH4A) || CPU_SHX2
 
 config CPU_SH4A
        bool
 
 /*
  * Write back & invalidate the D-cache of the page.
  * (To avoid "alias" issues)
+ *
+ * This uses a lazy write-back on UP, which is explicitly
+ * disabled on SMP.
  */
 void flush_dcache_page(struct page *page)
 {
-       if (test_bit(PG_mapped, &page->flags)) {
+#ifndef CONFIG_SMP
+       struct address_space *mapping = page_mapping(page);
+
+       if (mapping && !mapping_mapped(mapping))
+               set_bit(PG_dcache_dirty, &page->flags);
+       else
+#endif
+       {
                unsigned long phys = PHYSADDR(page_address(page));
                unsigned long addr = CACHE_OC_ADDRESS_ARRAY;
                int i, n;
 
  *
  * Copyright (C) 1999, 2000  Niibe Yutaka
  * Copyright (C) 2004  Alex Song
+ * Copyright (C) 2006  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
- *
  */
 #include <linux/init.h>
 #include <linux/mman.h>
 
                        if ((data & v) == v)
                                ctrl_outl(data & ~v, addr);
-
                }
 
                addrstart += cpu_data->dcache.way_incr;
  */
 void flush_dcache_page(struct page *page)
 {
-       if (test_bit(PG_mapped, &page->flags))
+       struct address_space *mapping = page_mapping(page);
+
+       if (mapping && !mapping_mapped(mapping))
+               set_bit(PG_dcache_dirty, &page->flags);
+       else
                __flush_dcache_page(PHYSADDR(page_address(page)));
 }
 
 
  */
 void clear_user_page(void *to, unsigned long address, struct page *page)
 {
-       __set_bit(PG_mapped, &page->flags);
        if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0)
                clear_page(to);
        else {
 void copy_user_page(void *to, void *from, unsigned long address,
                    struct page *page)
 {
-       __set_bit(PG_mapped, &page->flags);
        if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0)
                copy_page(to, from);
        else {
                mutex_unlock(&p3map_mutex[(address & CACHE_ALIAS)>>12]);
        }
 }
-
-/*
- * For SH-4, we have our own implementation for ptep_get_and_clear
- */
-inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
-{
-       pte_t pte = *ptep;
-
-       pte_clear(mm, addr, ptep);
-       if (!pte_not_present(pte)) {
-               unsigned long pfn = pte_pfn(pte);
-               if (pfn_valid(pfn)) {
-                       struct page *page = pfn_to_page(pfn);
-                       struct address_space *mapping = page_mapping(page);
-                       if (!mapping || !mapping_writably_mapped(mapping))
-                               __clear_bit(PG_mapped, &page->flags);
-               }
-       }
-       return pte;
-}
 
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
- *
  */
-
 #include <linux/init.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
 {
        struct page *page = virt_to_page(to);
 
-       __set_bit(PG_mapped, &page->flags);
        if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) {
                clear_page(to);
                __flush_wback_region(to, PAGE_SIZE);
  * @from: P1 address
  * @address: U0 address to be mapped
  */
-void copy_user_page(void *to, void *from, unsigned long address, struct page *pg)
+void copy_user_page(void *to, void *from, unsigned long address,
+                   struct page *pg)
 {
        struct page *page = virt_to_page(to);
 
-
-       __set_bit(PG_mapped, &page->flags);
        if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) {
                copy_page(to, from);
                __flush_wback_region(to, PAGE_SIZE);
                __flush_wback_region(to, PAGE_SIZE);
        }
 }
-
-/*
- * For SH7705, we have our own implementation for ptep_get_and_clear
- * Copied from pg-sh4.c
- */
-inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
-{
-       pte_t pte = *ptep;
-
-       pte_clear(mm, addr, ptep);
-       if (!pte_not_present(pte)) {
-               unsigned long pfn = pte_pfn(pte);
-               if (pfn_valid(pfn)) {
-                       struct page *page = pfn_to_page(pfn);
-                       struct address_space *mapping = page_mapping(page);
-                       if (!mapping || !mapping_writably_mapped(mapping))
-                               __clear_bit(PG_mapped, &page->flags);
-               }
-       }
-
-       return pte;
-}
-
 
  * TLB flushing operations for SH with an MMU.
  *
  *  Copyright (C) 1999  Niibe Yutaka
- *  Copyright (C) 2003  Paul Mundt
+ *  Copyright (C) 2003 - 2006  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  */
 #include <linux/mm.h>
+#include <linux/io.h>
 #include <asm/mmu_context.h>
 #include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
 
 void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 {
        ctrl_barrier();
        local_irq_restore(flags);
 }
+
+void update_mmu_cache(struct vm_area_struct *vma,
+                     unsigned long address, pte_t pte)
+{
+       unsigned long flags;
+       unsigned long pteval;
+       unsigned long vpn;
+       struct page *page;
+       unsigned long pfn = pte_pfn(pte);
+       struct address_space *mapping;
+
+       if (!pfn_valid(pfn))
+               return;
+
+       page = pfn_to_page(pfn);
+       mapping = page_mapping(page);
+       if (mapping) {
+               unsigned long phys = pte_val(pte) & PTE_PHYS_MASK;
+               int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags);
+
+               if (dirty)
+                       __flush_wback_region((void *)P1SEGADDR(phys),
+                                            PAGE_SIZE);
+       }
+
+       local_irq_save(flags);
+
+       /* Set PTEH register */
+       vpn = (address & MMU_VPN_MASK) | get_asid();
+       ctrl_outl(vpn, MMU_PTEH);
+
+       pteval = pte_val(pte);
+
+#ifdef CONFIG_CPU_HAS_PTEA
+       /* Set PTEA register */
+       /* TODO: make this look less hacky */
+       ctrl_outl(((pteval >> 28) & 0xe) | (pteval & 0x1), MMU_PTEA);
+#endif
+
+       /* Set PTEL register */
+       pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
+#ifdef CONFIG_SH_WRITETHROUGH
+       pteval |= _PAGE_WT;
+#endif
+       /* conveniently, we want all the software flags to be 0 anyway */
+       ctrl_outl(pteval, MMU_PTEL);
+
+       /* Load the TLB */
+       asm volatile("ldtlb": /* no output */ : /* no input */ : "memory");
+       local_irq_restore(flags);
+}
 
  *
  * Released under the terms of the GNU GPL v2.0.
  */
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-
+#include <linux/io.h>
 #include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
-#include <asm/cacheflush.h>
-
-void update_mmu_cache(struct vm_area_struct * vma,
-                     unsigned long address, pte_t pte)
-{
-       unsigned long flags;
-       unsigned long pteval;
-       unsigned long vpn;
-
-       /* Ptrace may call this routine. */
-       if (vma && current->active_mm != vma->vm_mm)
-               return;
-
-#if defined(CONFIG_SH7705_CACHE_32KB)
-       {
-               struct page *page = pte_page(pte);
-               unsigned long pfn = pte_pfn(pte);
-
-               if (pfn_valid(pfn) && !test_bit(PG_mapped, &page->flags)) {
-                       unsigned long phys = pte_val(pte) & PTE_PHYS_MASK;
-
-                       __flush_wback_region((void *)P1SEGADDR(phys),
-                                            PAGE_SIZE);
-                       __set_bit(PG_mapped, &page->flags);
-               }
-       }
-#endif
-
-       local_irq_save(flags);
-
-       /* Set PTEH register */
-       vpn = (address & MMU_VPN_MASK) | get_asid();
-       ctrl_outl(vpn, MMU_PTEH);
-
-       pteval = pte_val(pte);
-
-       /* Set PTEL register */
-       pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
-       /* conveniently, we want all the software flags to be 0 anyway */
-       ctrl_outl(pteval, MMU_PTEL);
-
-       /* Load the TLB */
-       asm volatile("ldtlb": /* no output */ : /* no input */ : "memory");
-       local_irq_restore(flags);
-}
 
 void __flush_tlb_page(unsigned long asid, unsigned long page)
 {
        for (i = 0; i < ways; i++)
                ctrl_outl(data, addr + (i << 8));
 }
-
 
  *
  * Released under the terms of the GNU GPL v2.0.
  */
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-
+#include <linux/io.h>
 #include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
-#include <asm/cacheflush.h>
-
-void update_mmu_cache(struct vm_area_struct * vma,
-                     unsigned long address, pte_t pte)
-{
-       unsigned long flags;
-       unsigned long pteval;
-       unsigned long vpn;
-       struct page *page;
-       unsigned long pfn;
-
-       /* Ptrace may call this routine. */
-       if (vma && current->active_mm != vma->vm_mm)
-               return;
-
-       pfn = pte_pfn(pte);
-       if (pfn_valid(pfn)) {
-               page = pfn_to_page(pfn);
-               if (!test_bit(PG_mapped, &page->flags)) {
-                       unsigned long phys = pte_val(pte) & PTE_PHYS_MASK;
-                       __flush_wback_region((void *)P1SEGADDR(phys), PAGE_SIZE);
-                       __set_bit(PG_mapped, &page->flags);
-               }
-       }
-
-       local_irq_save(flags);
-
-       /* Set PTEH register */
-       vpn = (address & MMU_VPN_MASK) | get_asid();
-       ctrl_outl(vpn, MMU_PTEH);
-
-       pteval = pte_val(pte);
-
-       /* Set PTEA register */
-       if (cpu_data->flags & CPU_HAS_PTEA)
-               /* TODO: make this look less hacky */
-               ctrl_outl(((pteval >> 28) & 0xe) | (pteval & 0x1), MMU_PTEA);
-
-       /* Set PTEL register */
-       pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
-#ifdef CONFIG_SH_WRITETHROUGH
-       pteval |= _PAGE_WT;
-#endif
-       /* conveniently, we want all the software flags to be 0 anyway */
-       ctrl_outl(pteval, MMU_PTEL);
-
-       /* Load the TLB */
-       asm volatile("ldtlb": /* no output */ : /* no input */ : "memory");
-       local_irq_restore(flags);
-}
 
 void __flush_tlb_page(unsigned long asid, unsigned long page)
 {
        ctrl_outl(data, addr);
        back_to_P1();
 }
-
 
 
 #define HAVE_ARCH_UNMAPPED_AREA
 
+/* Page flag for lazy dcache write-back for the aliasing UP caches */
+#define PG_dcache_dirty        PG_arch_1
+
 #endif /* __KERNEL__ */
 #endif /* __ASM_SH_CACHEFLUSH_H */
 
  /* 32KB cache, 4kb PAGE sizes need to check bit 12 */
 #define CACHE_ALIAS 0x00001000
 
-#define PG_mapped      PG_arch_1
-
 void flush_cache_all(void);
 void flush_cache_mm(struct mm_struct *mm);
 #define flush_cache_dup_mm(mm) flush_cache_mm(mm)
 
 /* Initialization of P3 area for copy_user_page */
 void p3_cache_init(void);
 
-#define PG_mapped      PG_arch_1
-
-#ifdef CONFIG_MMU
-extern int remap_area_pages(unsigned long addr, unsigned long phys_addr,
-                           unsigned long size, unsigned long flags);
-#else /* CONFIG_MMU */
-static inline int remap_area_pages(unsigned long addr, unsigned long phys_addr,
-                                  unsigned long size, unsigned long flags)
-{
-       return 0;
-}
-#endif /* CONFIG_MMU */
 #endif /* __ASM_CPU_SH4_CACHEFLUSH_H */
 
 extern unsigned int kobjsize(const void *objp);
 #endif /* !CONFIG_MMU */
 
-#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
-#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
-extern pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
-#endif
-
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 extern void paging_init(void);