Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[pandora-kernel.git] / arch / mips / mm / pg-r4k.c
index d41fc58..9185fbf 100644 (file)
@@ -4,6 +4,7 @@
  * for more details.
  *
  * Copyright (C) 2003, 04, 05 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2007  Maciej W. Rozycki
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -12,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 
+#include <asm/bugs.h>
 #include <asm/cacheops.h>
 #include <asm/inst.h>
 #include <asm/io.h>
@@ -209,7 +211,7 @@ static inline void build_cdex_p(void)
        }
 
        if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x())
-               build_insn_word(0x3c01a000);    /* lui     $at, 0xa000  */
+               build_insn_word(0x8c200000);    /* lw      $zero, ($at) */
 
        mi.c_format.opcode     = cache_op;
        mi.c_format.rs         = 4;             /* $a0 */
@@ -243,11 +245,10 @@ static void __init __build_store_reg(int reg)
 
 static inline void build_store_reg(int reg)
 {
-       if (cpu_has_prefetch)
-               if (reg)
-                       build_dst_pref(pref_offset_copy);
-               else
-                       build_dst_pref(pref_offset_clear);
+       int pref_off = cpu_has_prefetch ?
+               (reg ? pref_offset_copy : pref_offset_clear) : 0;
+       if (pref_off)
+               build_dst_pref(pref_off);
        else if (cpu_has_cache_cdex_s)
                build_cdex_s();
        else if (cpu_has_cache_cdex_p)
@@ -256,64 +257,58 @@ static inline void build_store_reg(int reg)
        __build_store_reg(reg);
 }
 
-static inline void build_addiu_a2_a0(unsigned long offset)
+static inline void build_addiu_rt_rs(unsigned int rt, unsigned int rs,
+                                    unsigned long offset)
 {
        union mips_instruction mi;
 
        BUG_ON(offset > 0x7fff);
 
-       mi.i_format.opcode     = cpu_has_64bit_gp_regs ? daddiu_op : addiu_op;
-       mi.i_format.rs         = 4;             /* $a0 */
-       mi.i_format.rt         = 6;             /* $a2 */
-       mi.i_format.simmediate = offset;
+       if (cpu_has_64bit_gp_regs && DADDI_WAR && r4k_daddiu_bug()) {
+               mi.i_format.opcode     = addiu_op;
+               mi.i_format.rs         = 0;     /* $zero */
+               mi.i_format.rt         = 25;    /* $t9 */
+               mi.i_format.simmediate = offset;
+               emit_instruction(mi);
 
+               mi.r_format.opcode     = spec_op;
+               mi.r_format.rs         = rs;
+               mi.r_format.rt         = 25;    /* $t9 */
+               mi.r_format.rd         = rt;
+               mi.r_format.re         = 0;
+               mi.r_format.func       = daddu_op;
+       } else {
+               mi.i_format.opcode     = cpu_has_64bit_gp_regs ?
+                                        daddiu_op : addiu_op;
+               mi.i_format.rs         = rs;
+               mi.i_format.rt         = rt;
+               mi.i_format.simmediate = offset;
+       }
        emit_instruction(mi);
 }
 
-static inline void build_addiu_a2(unsigned long offset)
+static inline void build_addiu_a2_a0(unsigned long offset)
 {
-       union mips_instruction mi;
-
-       BUG_ON(offset > 0x7fff);
-
-       mi.i_format.opcode     = cpu_has_64bit_gp_regs ? daddiu_op : addiu_op;
-       mi.i_format.rs         = 6;             /* $a2 */
-       mi.i_format.rt         = 6;             /* $a2 */
-       mi.i_format.simmediate = offset;
+       build_addiu_rt_rs(6, 4, offset);        /* $a2, $a0, offset */
+}
 
-       emit_instruction(mi);
+static inline void build_addiu_a2(unsigned long offset)
+{
+       build_addiu_rt_rs(6, 6, offset);        /* $a2, $a2, offset */
 }
 
 static inline void build_addiu_a1(unsigned long offset)
 {
-       union mips_instruction mi;
-
-       BUG_ON(offset > 0x7fff);
-
-       mi.i_format.opcode     = cpu_has_64bit_gp_regs ? daddiu_op : addiu_op;
-       mi.i_format.rs         = 5;             /* $a1 */
-       mi.i_format.rt         = 5;             /* $a1 */
-       mi.i_format.simmediate = offset;
+       build_addiu_rt_rs(5, 5, offset);        /* $a1, $a1, offset */
 
        load_offset -= offset;
-
-       emit_instruction(mi);
 }
 
 static inline void build_addiu_a0(unsigned long offset)
 {
-       union mips_instruction mi;
-
-       BUG_ON(offset > 0x7fff);
-
-       mi.i_format.opcode     = cpu_has_64bit_gp_regs ? daddiu_op : addiu_op;
-       mi.i_format.rs         = 4;             /* $a0 */
-       mi.i_format.rt         = 4;             /* $a0 */
-       mi.i_format.simmediate = offset;
+       build_addiu_rt_rs(4, 4, offset);        /* $a0, $a0, offset */
 
        store_offset -= offset;
-
-       emit_instruction(mi);
 }
 
 static inline void build_bne(unsigned int *dest)
@@ -348,13 +343,14 @@ void __init build_clear_page(void)
 {
        unsigned int loop_start;
        unsigned long off;
+       int i;
 
        epc = (unsigned int *) &clear_page_array;
        instruction_pending = 0;
        store_offset = 0;
 
        if (cpu_has_prefetch) {
-               switch (current_cpu_data.cputype) {
+               switch (current_cpu_type()) {
                case CPU_TX49XX:
                        /* TX49 supports only Pref_Load */
                        pref_offset_clear = 0;
@@ -435,12 +431,22 @@ dest = label();
        build_jr_ra();
 
        BUG_ON(epc > clear_page_array + ARRAY_SIZE(clear_page_array));
+
+       pr_info("Synthesized clear page handler (%u instructions).\n",
+               (unsigned int)(epc - clear_page_array));
+
+       pr_debug("\t.set push\n");
+       pr_debug("\t.set noreorder\n");
+       for (i = 0; i < (epc - clear_page_array); i++)
+               pr_debug("\t.word 0x%08x\n", clear_page_array[i]);
+       pr_debug("\t.set pop\n");
 }
 
 void __init build_copy_page(void)
 {
        unsigned int loop_start;
        unsigned long off;
+       int i;
 
        epc = (unsigned int *) &copy_page_array;
        store_offset = load_offset = 0;
@@ -516,4 +522,13 @@ dest = label();
        build_jr_ra();
 
        BUG_ON(epc > copy_page_array + ARRAY_SIZE(copy_page_array));
+
+       pr_info("Synthesized copy page handler (%u instructions).\n",
+               (unsigned int)(epc - copy_page_array));
+
+       pr_debug("\t.set push\n");
+       pr_debug("\t.set noreorder\n");
+       for (i = 0; i < (epc - copy_page_array); i++)
+               pr_debug("\t.word 0x%08x\n", copy_page_array[i]);
+       pr_debug("\t.set pop\n");
 }