2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
6 * Copyright (C) 2003, 04, 05 Ralf Baechle (ralf@linux-mips.org)
7 * Copyright (C) 2007 Maciej W. Rozycki
9 #include <linux/init.h>
10 #include <linux/kernel.h>
11 #include <linux/sched.h>
13 #include <linux/module.h>
14 #include <linux/proc_fs.h>
17 #include <asm/cacheops.h>
21 #include <asm/pgtable.h>
22 #include <asm/prefetch.h>
23 #include <asm/system.h>
24 #include <asm/bootinfo.h>
25 #include <asm/mipsregs.h>
26 #include <asm/mmu_context.h>
30 #define half_scache_line_size() (cpu_scache_line_size() >> 1)
31 #define cpu_is_r4600_v1_x() ((read_c0_prid() & 0xfffffff0) == 0x00002010)
32 #define cpu_is_r4600_v2_x() ((read_c0_prid() & 0xfffffff0) == 0x00002020)
38 * R4000 128 bytes S-cache: 0x58 bytes
39 * R4600 v1.7: 0x5c bytes
40 * R4600 v2.0: 0x60 bytes
41 * With prefetching, 16 byte strides 0xa0 bytes
44 static unsigned int clear_page_array
[0x130 / 4];
46 void clear_page(void * page
) __attribute__((alias("clear_page_array")));
48 EXPORT_SYMBOL(clear_page
);
53 * R4000 128 bytes S-cache: 0x11c bytes
54 * R4600 v1.7: 0x080 bytes
55 * R4600 v2.0: 0x07c bytes
56 * With prefetching, 16 byte strides 0x0b8 bytes
58 static unsigned int copy_page_array
[0x148 / 4];
60 void copy_page(void *to
, void *from
) __attribute__((alias("copy_page_array")));
62 EXPORT_SYMBOL(copy_page
);
65 * This is suboptimal for 32-bit kernels; we assume that R10000 is only used
66 * with 64-bit kernels. The prefetch offsets have been experimentally tuned
69 static int pref_offset_clear __initdata
= 512;
70 static int pref_offset_copy __initdata
= 256;
72 static unsigned int pref_src_mode __initdata
;
73 static unsigned int pref_dst_mode __initdata
;
75 static int load_offset __initdata
;
76 static int store_offset __initdata
;
78 static unsigned int __initdata
*dest
, *epc
;
80 static unsigned int instruction_pending
;
81 static union mips_instruction delayed_mi
;
83 static void __init
emit_instruction(union mips_instruction mi
)
85 if (instruction_pending
)
86 *epc
++ = delayed_mi
.word
;
88 instruction_pending
= 1;
92 static inline void flush_delay_slot_or_nop(void)
94 if (instruction_pending
) {
95 *epc
++ = delayed_mi
.word
;
96 instruction_pending
= 0;
103 static inline unsigned int *label(void)
105 if (instruction_pending
) {
106 *epc
++ = delayed_mi
.word
;
107 instruction_pending
= 0;
113 static inline void build_insn_word(unsigned int word
)
115 union mips_instruction mi
;
119 emit_instruction(mi
);
122 static inline void build_nop(void)
124 build_insn_word(0); /* nop */
127 static inline void build_src_pref(int advance
)
129 if (!(load_offset
& (cpu_dcache_line_size() - 1)) && advance
) {
130 union mips_instruction mi
;
132 mi
.i_format
.opcode
= pref_op
;
133 mi
.i_format
.rs
= 5; /* $a1 */
134 mi
.i_format
.rt
= pref_src_mode
;
135 mi
.i_format
.simmediate
= load_offset
+ advance
;
137 emit_instruction(mi
);
141 static inline void __build_load_reg(int reg
)
143 union mips_instruction mi
;
146 if (cpu_has_64bit_gp_regs
) {
147 mi
.i_format
.opcode
= ld_op
;
150 mi
.i_format
.opcode
= lw_op
;
153 mi
.i_format
.rs
= 5; /* $a1 */
154 mi
.i_format
.rt
= reg
; /* $reg */
155 mi
.i_format
.simmediate
= load_offset
;
157 load_offset
+= width
;
158 emit_instruction(mi
);
161 static inline void build_load_reg(int reg
)
163 if (cpu_has_prefetch
)
164 build_src_pref(pref_offset_copy
);
166 __build_load_reg(reg
);
169 static inline void build_dst_pref(int advance
)
171 if (!(store_offset
& (cpu_dcache_line_size() - 1)) && advance
) {
172 union mips_instruction mi
;
174 mi
.i_format
.opcode
= pref_op
;
175 mi
.i_format
.rs
= 4; /* $a0 */
176 mi
.i_format
.rt
= pref_dst_mode
;
177 mi
.i_format
.simmediate
= store_offset
+ advance
;
179 emit_instruction(mi
);
183 static inline void build_cdex_s(void)
185 union mips_instruction mi
;
187 if ((store_offset
& (cpu_scache_line_size() - 1)))
190 mi
.c_format
.opcode
= cache_op
;
191 mi
.c_format
.rs
= 4; /* $a0 */
192 mi
.c_format
.c_op
= 3; /* Create Dirty Exclusive */
193 mi
.c_format
.cache
= 3; /* Secondary Data Cache */
194 mi
.c_format
.simmediate
= store_offset
;
196 emit_instruction(mi
);
199 static inline void build_cdex_p(void)
201 union mips_instruction mi
;
203 if (store_offset
& (cpu_dcache_line_size() - 1))
206 if (R4600_V1_HIT_CACHEOP_WAR
&& cpu_is_r4600_v1_x()) {
213 if (R4600_V2_HIT_CACHEOP_WAR
&& cpu_is_r4600_v2_x())
214 build_insn_word(0x8c200000); /* lw $zero, ($at) */
216 mi
.c_format
.opcode
= cache_op
;
217 mi
.c_format
.rs
= 4; /* $a0 */
218 mi
.c_format
.c_op
= 3; /* Create Dirty Exclusive */
219 mi
.c_format
.cache
= 1; /* Data Cache */
220 mi
.c_format
.simmediate
= store_offset
;
222 emit_instruction(mi
);
225 static void __init
__build_store_reg(int reg
)
227 union mips_instruction mi
;
230 if (cpu_has_64bit_gp_regs
||
231 (cpu_has_64bit_zero_reg
&& reg
== 0)) {
232 mi
.i_format
.opcode
= sd_op
;
235 mi
.i_format
.opcode
= sw_op
;
238 mi
.i_format
.rs
= 4; /* $a0 */
239 mi
.i_format
.rt
= reg
; /* $reg */
240 mi
.i_format
.simmediate
= store_offset
;
242 store_offset
+= width
;
243 emit_instruction(mi
);
246 static inline void build_store_reg(int reg
)
248 int pref_off
= cpu_has_prefetch
?
249 (reg
? pref_offset_copy
: pref_offset_clear
) : 0;
251 build_dst_pref(pref_off
);
252 else if (cpu_has_cache_cdex_s
)
254 else if (cpu_has_cache_cdex_p
)
257 __build_store_reg(reg
);
260 static inline void build_addiu_rt_rs(unsigned int rt
, unsigned int rs
,
261 unsigned long offset
)
263 union mips_instruction mi
;
265 BUG_ON(offset
> 0x7fff);
267 if (cpu_has_64bit_gp_regs
&& DADDI_WAR
&& r4k_daddiu_bug()) {
268 mi
.i_format
.opcode
= addiu_op
;
269 mi
.i_format
.rs
= 0; /* $zero */
270 mi
.i_format
.rt
= 25; /* $t9 */
271 mi
.i_format
.simmediate
= offset
;
272 emit_instruction(mi
);
274 mi
.r_format
.opcode
= spec_op
;
276 mi
.r_format
.rt
= 25; /* $t9 */
279 mi
.r_format
.func
= daddu_op
;
281 mi
.i_format
.opcode
= cpu_has_64bit_gp_regs
?
282 daddiu_op
: addiu_op
;
285 mi
.i_format
.simmediate
= offset
;
287 emit_instruction(mi
);
290 static inline void build_addiu_a2_a0(unsigned long offset
)
292 build_addiu_rt_rs(6, 4, offset
); /* $a2, $a0, offset */
295 static inline void build_addiu_a2(unsigned long offset
)
297 build_addiu_rt_rs(6, 6, offset
); /* $a2, $a2, offset */
300 static inline void build_addiu_a1(unsigned long offset
)
302 build_addiu_rt_rs(5, 5, offset
); /* $a1, $a1, offset */
304 load_offset
-= offset
;
307 static inline void build_addiu_a0(unsigned long offset
)
309 build_addiu_rt_rs(4, 4, offset
); /* $a0, $a0, offset */
311 store_offset
-= offset
;
314 static inline void build_bne(unsigned int *dest
)
316 union mips_instruction mi
;
318 mi
.i_format
.opcode
= bne_op
;
319 mi
.i_format
.rs
= 6; /* $a2 */
320 mi
.i_format
.rt
= 4; /* $a0 */
321 mi
.i_format
.simmediate
= dest
- epc
- 1;
324 flush_delay_slot_or_nop();
327 static inline void build_jr_ra(void)
329 union mips_instruction mi
;
331 mi
.r_format
.opcode
= spec_op
;
336 mi
.r_format
.func
= jr_op
;
339 flush_delay_slot_or_nop();
342 void __init
build_clear_page(void)
344 unsigned int loop_start
;
348 epc
= (unsigned int *) &clear_page_array
;
349 instruction_pending
= 0;
352 if (cpu_has_prefetch
) {
353 switch (current_cpu_type()) {
355 /* TX49 supports only Pref_Load */
356 pref_offset_clear
= 0;
357 pref_offset_copy
= 0;
362 * As a workaround for erratum G105 which make the
363 * PrepareForStore hint unusable we fall back to
364 * StoreRetained on the RM9000. Once it is known which
365 * versions of the RM9000 we'll be able to condition-
372 pref_src_mode
= Pref_LoadStreamed
;
373 pref_dst_mode
= Pref_StoreStreamed
;
377 pref_src_mode
= Pref_LoadStreamed
;
378 pref_dst_mode
= Pref_PrepareForStore
;
383 off
= PAGE_SIZE
- (cpu_has_prefetch
? pref_offset_clear
: 0);
385 build_addiu_a2_a0(off
>> 1);
386 build_addiu_a2(off
>> 1);
388 build_addiu_a2_a0(off
);
390 if (R4600_V2_HIT_CACHEOP_WAR
&& cpu_is_r4600_v2_x())
391 build_insn_word(0x3c01a000); /* lui $at, 0xa000 */
399 } while (store_offset
< half_scache_line_size());
400 build_addiu_a0(2 * store_offset
);
401 loop_start
= store_offset
;
407 } while ((store_offset
- loop_start
) < half_scache_line_size());
410 if (cpu_has_prefetch
&& pref_offset_clear
) {
411 build_addiu_a2_a0(pref_offset_clear
);
413 loop_start
= store_offset
;
415 __build_store_reg(0);
416 __build_store_reg(0);
417 __build_store_reg(0);
418 __build_store_reg(0);
419 } while ((store_offset
- loop_start
) < half_scache_line_size());
420 build_addiu_a0(2 * store_offset
);
421 loop_start
= store_offset
;
423 __build_store_reg(0);
424 __build_store_reg(0);
425 __build_store_reg(0);
426 __build_store_reg(0);
427 } while ((store_offset
- loop_start
) < half_scache_line_size());
433 BUG_ON(epc
> clear_page_array
+ ARRAY_SIZE(clear_page_array
));
435 pr_info("Synthesized clear page handler (%u instructions).\n",
436 (unsigned int)(epc
- clear_page_array
));
438 pr_debug("\t.set push\n");
439 pr_debug("\t.set noreorder\n");
440 for (i
= 0; i
< (epc
- clear_page_array
); i
++)
441 pr_debug("\t.word 0x%08x\n", clear_page_array
[i
]);
442 pr_debug("\t.set pop\n");
445 void __init
build_copy_page(void)
447 unsigned int loop_start
;
451 epc
= (unsigned int *) ©_page_array
;
452 store_offset
= load_offset
= 0;
453 instruction_pending
= 0;
455 off
= PAGE_SIZE
- (cpu_has_prefetch
? pref_offset_copy
: 0);
457 build_addiu_a2_a0(off
>> 1);
458 build_addiu_a2(off
>> 1);
460 build_addiu_a2_a0(off
);
462 if (R4600_V2_HIT_CACHEOP_WAR
&& cpu_is_r4600_v2_x())
463 build_insn_word(0x3c01a000); /* lui $at, 0xa000 */
466 loop_start
= store_offset
;
476 } while ((store_offset
- loop_start
) < half_scache_line_size());
477 build_addiu_a0(2 * store_offset
);
478 build_addiu_a1(2 * load_offset
);
479 loop_start
= store_offset
;
489 } while ((store_offset
- loop_start
) < half_scache_line_size());
492 if (cpu_has_prefetch
&& pref_offset_copy
) {
493 build_addiu_a2_a0(pref_offset_copy
);
495 loop_start
= store_offset
;
497 __build_load_reg( 8);
498 __build_load_reg( 9);
499 __build_load_reg(10);
500 __build_load_reg(11);
501 __build_store_reg( 8);
502 __build_store_reg( 9);
503 __build_store_reg(10);
504 __build_store_reg(11);
505 } while ((store_offset
- loop_start
) < half_scache_line_size());
506 build_addiu_a0(2 * store_offset
);
507 build_addiu_a1(2 * load_offset
);
508 loop_start
= store_offset
;
510 __build_load_reg( 8);
511 __build_load_reg( 9);
512 __build_load_reg(10);
513 __build_load_reg(11);
514 __build_store_reg( 8);
515 __build_store_reg( 9);
516 __build_store_reg(10);
517 __build_store_reg(11);
518 } while ((store_offset
- loop_start
) < half_scache_line_size());
524 BUG_ON(epc
> copy_page_array
+ ARRAY_SIZE(copy_page_array
));
526 pr_info("Synthesized copy page handler (%u instructions).\n",
527 (unsigned int)(epc
- copy_page_array
));
529 pr_debug("\t.set push\n");
530 pr_debug("\t.set noreorder\n");
531 for (i
= 0; i
< (epc
- copy_page_array
); i
++)
532 pr_debug("\t.word 0x%08x\n", copy_page_array
[i
]);
533 pr_debug("\t.set pop\n");