X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fmips%2Fmm%2Fpg-r4k.c;h=dc795be62807d1d1bf22af966ad961d0918794bf;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=467fdfe2108cccf23da6aad0252b082c7d6a5cc0;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/mips/mm/pg-r4k.c b/arch/mips/mm/pg-r4k.c index 467fdfe21..dc795be62 100644 --- a/arch/mips/mm/pg-r4k.c +++ b/arch/mips/mm/pg-r4k.c @@ -3,9 +3,8 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2003, 04, 05 Ralf Baechle (ralf@linux-mips.org) */ -#include #include #include #include @@ -26,7 +25,10 @@ #include #include -#define half_scache_line_size() (cpu_scache_line_size() >> 1) +#define half_scache_line_size() (cpu_scache_line_size() >> 1) +#define cpu_is_r4600_v1_x() ((read_c0_prid() & 0xfffffff0) == 0x00002010) +#define cpu_is_r4600_v2_x() ((read_c0_prid() & 0xfffffff0) == 0x00002020) + /* * Maximum sizes: @@ -57,12 +59,6 @@ void copy_page(void *to, void *from) __attribute__((alias("copy_page_array"))); EXPORT_SYMBOL(copy_page); -/* - * An address fits into a single register so it's safe to use 64-bit registers - * if we have 64-bit adresses. - */ -#define cpu_has_64bit_registers cpu_has_64bit_addresses - /* * This is suboptimal for 32-bit kernels; we assume that R10000 is only used * with 64-bit kernels. The prefetch offsets have been experimentally tuned @@ -128,7 +124,7 @@ static inline void build_nop(void) static inline void build_src_pref(int advance) { - if (!(load_offset & (cpu_dcache_line_size() - 1))) { + if (!(load_offset & (cpu_dcache_line_size() - 1)) && advance) { union mips_instruction mi; mi.i_format.opcode = pref_op; @@ -145,7 +141,7 @@ static inline void __build_load_reg(int reg) union mips_instruction mi; unsigned int width; - if (cpu_has_64bit_registers) { + if (cpu_has_64bit_gp_regs) { mi.i_format.opcode = ld_op; width = 8; } else { @@ -170,7 +166,7 @@ static inline void build_load_reg(int reg) static inline void build_dst_pref(int advance) { - if (!(store_offset & (cpu_dcache_line_size() - 1))) { + if (!(store_offset & (cpu_dcache_line_size() - 1)) && advance) { union mips_instruction mi; mi.i_format.opcode = pref_op; @@ -205,15 +201,15 @@ static inline void build_cdex_p(void) if (store_offset & (cpu_dcache_line_size() - 1)) return; - if (R4600_V1_HIT_CACHEOP_WAR && ((read_c0_prid() & 0xfff0) == 0x2010)) { + if (R4600_V1_HIT_CACHEOP_WAR && cpu_is_r4600_v1_x()) { build_nop(); build_nop(); build_nop(); build_nop(); } - if (R4600_V2_HIT_CACHEOP_WAR && ((read_c0_prid() & 0xfff0) == 0x2020)) - build_insn_word(0x8c200000); /* lw $zero, ($at) */ + if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x()) + build_insn_word(0x3c01a000); /* lui $at, 0xa000 */ mi.c_format.opcode = cache_op; mi.c_format.rs = 4; /* $a0 */ @@ -224,7 +220,7 @@ static inline void build_cdex_p(void) emit_instruction(mi); } -static void __build_store_reg(int reg) +static void __init __build_store_reg(int reg) { union mips_instruction mi; unsigned int width; @@ -247,11 +243,10 @@ static void __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) @@ -266,7 +261,7 @@ static inline void build_addiu_a2_a0(unsigned long offset) BUG_ON(offset > 0x7fff); - mi.i_format.opcode = cpu_has_64bit_addresses ? daddiu_op : addiu_op; + 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; @@ -274,13 +269,27 @@ static inline void build_addiu_a2_a0(unsigned long offset) emit_instruction(mi); } +static inline void build_addiu_a2(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; + + emit_instruction(mi); +} + static inline void build_addiu_a1(unsigned long offset) { union mips_instruction mi; BUG_ON(offset > 0x7fff); - mi.i_format.opcode = cpu_has_64bit_addresses ? daddiu_op : addiu_op; + 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; @@ -296,7 +305,7 @@ static inline void build_addiu_a0(unsigned long offset) BUG_ON(offset > 0x7fff); - mi.i_format.opcode = cpu_has_64bit_addresses ? daddiu_op : addiu_op; + 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; @@ -337,6 +346,7 @@ static inline void build_jr_ra(void) void __init build_clear_page(void) { unsigned int loop_start; + unsigned long off; epc = (unsigned int *) &clear_page_array; instruction_pending = 0; @@ -344,6 +354,12 @@ void __init build_clear_page(void) if (cpu_has_prefetch) { switch (current_cpu_data.cputype) { + case CPU_TX49XX: + /* TX49 supports only Pref_Load */ + pref_offset_clear = 0; + pref_offset_copy = 0; + break; + case CPU_RM9000: /* * As a workaround for erratum G105 which make the @@ -355,8 +371,9 @@ void __init build_clear_page(void) case CPU_R10000: case CPU_R12000: + case CPU_R14000: pref_src_mode = Pref_LoadStreamed; - pref_dst_mode = Pref_StoreRetained; + pref_dst_mode = Pref_StoreStreamed; break; default: @@ -366,9 +383,14 @@ void __init build_clear_page(void) } } - build_addiu_a2_a0(PAGE_SIZE - (cpu_has_prefetch ? pref_offset_clear : 0)); + off = PAGE_SIZE - (cpu_has_prefetch ? pref_offset_clear : 0); + if (off > 0x7fff) { + build_addiu_a2_a0(off >> 1); + build_addiu_a2(off >> 1); + } else + build_addiu_a2_a0(off); - if (R4600_V2_HIT_CACHEOP_WAR && ((read_c0_prid() & 0xfff0) == 0x2020)) + if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x()) build_insn_word(0x3c01a000); /* lui $at, 0xa000 */ dest = label(); @@ -411,23 +433,26 @@ dest = label(); build_jr_ra(); - flush_icache_range((unsigned long)&clear_page_array, - (unsigned long) epc); - BUG_ON(epc > clear_page_array + ARRAY_SIZE(clear_page_array)); } void __init build_copy_page(void) { unsigned int loop_start; + unsigned long off; epc = (unsigned int *) ©_page_array; store_offset = load_offset = 0; instruction_pending = 0; - build_addiu_a2_a0(PAGE_SIZE - (cpu_has_prefetch ? pref_offset_copy : 0)); + off = PAGE_SIZE - (cpu_has_prefetch ? pref_offset_copy : 0); + if (off > 0x7fff) { + build_addiu_a2_a0(off >> 1); + build_addiu_a2(off >> 1); + } else + build_addiu_a2_a0(off); - if (R4600_V2_HIT_CACHEOP_WAR && ((read_c0_prid() & 0xfff0) == 0x2020)) + if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x()) build_insn_word(0x3c01a000); /* lui $at, 0xa000 */ dest = label(); @@ -489,8 +514,5 @@ dest = label(); build_jr_ra(); - flush_icache_range((unsigned long)©_page_array, - (unsigned long) epc); - BUG_ON(epc > copy_page_array + ARRAY_SIZE(copy_page_array)); }