diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index bc7c4a4e26a1e24f53b62b735bf820baac104635..7e8d697aef36eac5b64d83cd42e5f09bbc238068 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -91,7 +91,8 @@ update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 
 		flush_kernel_dcache_page(page);
 		clear_bit(PG_dcache_dirty, &page->flags);
-	}
+	} else if (parisc_requires_coherency())
+		flush_kernel_dcache_page(page);
 }
 
 void
@@ -370,3 +371,45 @@ void parisc_setup_cache_timing(void)
 
 	printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus());
 }
+
+extern void purge_kernel_dcache_page(unsigned long);
+extern void clear_user_page_asm(void *page, unsigned long vaddr);
+
+void
+clear_user_page(void *page, unsigned long vaddr, struct page *pg)
+{
+	purge_kernel_dcache_page((unsigned long)page);
+	purge_tlb_start();
+	pdtlb_kernel(page);
+	purge_tlb_end();
+	clear_user_page_asm(page, vaddr);
+}
+
+void flush_kernel_dcache_page_addr(void *addr)
+{
+	flush_kernel_dcache_page_asm(addr);
+	purge_tlb_start();
+	pdtlb_kernel(addr);
+	purge_tlb_end();
+}
+EXPORT_SYMBOL(flush_kernel_dcache_page_addr);
+
+void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
+		    struct page *pg)
+{
+	/* no coherency needed (all in kmap/kunmap) */
+	copy_user_page_asm(vto, vfrom);
+	if (!parisc_requires_coherency())
+		flush_kernel_dcache_page_asm(vto);
+}
+EXPORT_SYMBOL(copy_user_page);
+
+#ifdef CONFIG_PA8X00
+
+void kunmap_parisc(void *addr)
+{
+	if (parisc_requires_coherency())
+		flush_kernel_dcache_page_addr(addr);
+}
+EXPORT_SYMBOL(kunmap_parisc);
+#endif
diff --git a/include/asm-parisc/cacheflush.h b/include/asm-parisc/cacheflush.h
index 0b459cdfbd6ffbe79d1b70781069d83949f1803e..2bc41f2e0271c21813c6c62273af0875a36db0df 100644
--- a/include/asm-parisc/cacheflush.h
+++ b/include/asm-parisc/cacheflush.h
@@ -191,16 +191,38 @@ flush_anon_page(struct page *page, unsigned long vmaddr)
 }
 #define ARCH_HAS_FLUSH_ANON_PAGE
 
-static inline void
-flush_kernel_dcache_page(struct page *page)
+#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
+void flush_kernel_dcache_page_addr(void *addr);
+static inline void flush_kernel_dcache_page(struct page *page)
 {
-	flush_kernel_dcache_page_asm(page_address(page));
+	flush_kernel_dcache_page_addr(page_address(page));
 }
-#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
 
 #ifdef CONFIG_DEBUG_RODATA
 void mark_rodata_ro(void);
 #endif
 
+#ifdef CONFIG_PA8X00
+/* Only pa8800, pa8900 needs this */
+#define ARCH_HAS_KMAP
+
+void kunmap_parisc(void *addr);
+
+static inline void *kmap(struct page *page)
+{
+	might_sleep();
+	return page_address(page);
+}
+
+#define kunmap(page)			kunmap_parisc(page_address(page))
+
+#define kmap_atomic(page, idx)		page_address(page)
+
+#define kunmap_atomic(addr, idx)	kunmap_parisc(addr)
+
+#define kmap_atomic_pfn(pfn, idx)	page_address(pfn_to_page(pfn))
+#define kmap_atomic_to_page(ptr)	virt_to_page(ptr)
+#endif
+
 #endif /* _PARISC_CACHEFLUSH_H */
 
diff --git a/include/asm-parisc/page.h b/include/asm-parisc/page.h
index 57d6d82756dd678d54a7f261859730f8c998e3bb..3567208191e37d09f47199a26a0a223dce1b6c28 100644
--- a/include/asm-parisc/page.h
+++ b/include/asm-parisc/page.h
@@ -26,24 +26,10 @@
 
 struct page;
 
-extern void purge_kernel_dcache_page(unsigned long);
-extern void copy_user_page_asm(void *to, void *from);
-extern void clear_user_page_asm(void *page, unsigned long vaddr);
-
-static inline void
-copy_user_page(void *vto, void *vfrom, unsigned long vaddr, struct page *pg)
-{
-	copy_user_page_asm(vto, vfrom);
-	flush_kernel_dcache_page_asm(vto);
-	/* XXX: ppc flushes icache too, should we? */
-}
-
-static inline void
-clear_user_page(void *page, unsigned long vaddr, struct page *pg)
-{
-	purge_kernel_dcache_page((unsigned long)page);
-	clear_user_page_asm(page, vaddr);
-}
+void copy_user_page_asm(void *to, void *from);
+void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
+			   struct page *pg);
+void clear_user_page(void *page, unsigned long vaddr, struct page *pg);
 
 /*
  * These are used to make use of C type-checking..
diff --git a/include/asm-parisc/processor.h b/include/asm-parisc/processor.h
index c72b8fa496862d00b05610f51a072bafcc543ca4..4313618c98ee036eeec45f2ce1cedf83a928159b 100644
--- a/include/asm-parisc/processor.h
+++ b/include/asm-parisc/processor.h
@@ -332,6 +332,19 @@ extern unsigned long get_wchan(struct task_struct *p);
 
 #define cpu_relax()	barrier()
 
+/* Used as a macro to identify the combined VIPT/PIPT cached
+ * CPUs which require a guarantee of coherency (no inequivalent
+ * aliases with different data, whether clean or not) to operate */
+static inline int parisc_requires_coherency(void)
+{
+#ifdef CONFIG_PA8X00
+	/* FIXME: also pa8900 - when we see one */
+	return boot_cpu_data.cpu_type == mako;
+#else
+	return 0;
+#endif
+}
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __ASM_PARISC_PROCESSOR_H */