summaryrefslogtreecommitdiffstats
path: root/arch/mips/mips4/pagetables.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/mips4/pagetables.c')
-rw-r--r--arch/mips/mips4/pagetables.c122
1 files changed, 122 insertions, 0 deletions
diff --git a/arch/mips/mips4/pagetables.c b/arch/mips/mips4/pagetables.c
new file mode 100644
index 000000000..b1b86290a
--- /dev/null
+++ b/arch/mips/mips4/pagetables.c
@@ -0,0 +1,122 @@
+/*
+ * 64 bit MIPS specific page handling.
+ *
+ * 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.
+ *
+ * Copyright (C) 1996 Ralf Baechle
+ */
+#include <linux/mm.h>
+#include <asm/cache.h>
+#include <asm/mipsconfig.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+void (*pgd_init)(unsigned long page);
+
+/*
+ * Initialize new page directory with pointers to invalid ptes
+ */
+void mips4_pgd_init(unsigned long page)
+{
+ unsigned long dummy1, dummy2;
+
+ /*
+ * We generate dirty lines in the datacache, overwrite these lines
+ * with zeros and then flush the cache. Sounds horribly complicated
+ * but is just a trick to avoid unnecessary loads of from memory
+ * and uncached stores which are very expensive.
+ * FIXME: This is the same like the R4000 version. We could do some
+ * R10000 trickery using caching mode "uncached accelerated".
+ */
+ __asm__ __volatile__(
+ ".set\tnoreorder\n\t"
+ ".set\tnoat\n\t"
+ ".set\tmips3\n\t"
+ "dsll32\t$1,%2,0\n\t"
+ "dsrl32\t%2,$1,0\n\t"
+ "or\t%2,$1\n"
+ "1:\t"
+ "cache\t%5,(%0)\n\t"
+ "sd\t%2,(%0)\n\t"
+ "sd\t%2,8(%0)\n\t"
+ "cache\t%5,16(%0)\n\t"
+ "sd\t%2,16(%0)\n\t"
+ "sd\t%2,24(%0)\n\t"
+ "cache\t%5,32(%0)\n\t"
+ "sd\t%2,32(%0)\n\t"
+ "sd\t%2,40(%0)\n\t"
+ "cache\t%5,48(%0)\n\t"
+ "sd\t%2,48(%0)\n\t"
+ "sd\t%2,56(%0)\n\t"
+ "subu\t%1,1\n\t"
+ "bnez\t%1,1b\n\t"
+ "addiu\t%0,64\n\t"
+ ".set\tmips0\n\t"
+ ".set\tat\n\t"
+ ".set\treorder"
+ :"=&r" (dummy1),
+ "=&r" (dummy2)
+ :"r" (((unsigned long) invalid_pte_table - PAGE_OFFSET) |
+ _PAGE_TABLE),
+ "0" (page),
+ "1" (PAGE_SIZE/(sizeof(pmd_t)*16)),
+ "i" (Create_Dirty_Excl_D)
+ :"$1");
+ /*
+ * Now force writeback to ashure values are in the RAM.
+ */
+ cacheflush(page, PAGE_SIZE, CF_DCACHE|CF_VIRTUAL);
+}
+
+void (*clear_page)(unsigned long page);
+
+/*
+ * To do: cache magic
+ */
+void mips4_clear_page(unsigned long page)
+{
+ __asm__ __volatile__(
+ ".set\tnoreorder\n\t"
+ ".set\tnoat\n\t"
+ "daddiu\t$1,%0,%2\n"
+ "1:\tsd\t$0,(%0)\n\t"
+ "sd\t$0,8(%0)\n\t"
+ "sd\t$0,16(%0)\n\t"
+ "sd\t$0,24(%0)\n\t"
+ "daddiu\t%0,64\n\t"
+ "sd\t$0,-32(%0)\n\t"
+ "sd\t$0,-24(%0)\n\t"
+ "sd\t$0,-16(%0)\n\t"
+ "bne\t$1,%0,1b\n\t"
+ "sd\t$0,-8(%0)\n\t"
+ ".set\tat\n\t"
+ ".set\treorder"
+ :"=r" (page)
+ :"0" (page),
+ "I" (PAGE_SIZE)
+ :"$1","memory");
+}
+
+void (*copy_page)(unsigned long to, unsigned long from);
+
+/*
+ * This is horribly inefficient ...
+ */
+void mips4_copy_page(unsigned long to, unsigned long from)
+{
+ /*
+ * Force writeback of old page to memory. We don't know the
+ * virtual address, so we have to flush the entire cache ...
+ */
+ cacheflush(0, ~0, CF_DCACHE|CF_VIRTUAL);
+ sync_mem();
+ memcpy((void *) to,
+ (void *) (from + (PT_OFFSET - PAGE_OFFSET)), PAGE_SIZE);
+ /*
+ * Now writeback the page again if colour has changed.
+ */
+ if (page_colour(from) != page_colour(to))
+ cacheflush(0, ~0, CF_DCACHE|CF_VIRTUAL);
+}