OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [mips64/] [mm/] [pg-r4k.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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
4
 * for more details.
5
 *
6
 * Copyright (C) 2003 Ralf Baechle (ralf@linux-mips.org)
7
 */
8
#include <linux/config.h>
9
#include <linux/init.h>
10
#include <linux/kernel.h>
11
#include <linux/sched.h>
12
#include <linux/mm.h>
13
#include <linux/module.h>
14
 
15
#include <asm/cacheops.h>
16
#include <asm/inst.h>
17
#include <asm/io.h>
18
#include <asm/page.h>
19
#include <asm/pgtable.h>
20
#include <asm/prefetch.h>
21
#include <asm/system.h>
22
#include <asm/bootinfo.h>
23
#include <asm/mipsregs.h>
24
#include <asm/mmu_context.h>
25
#include <asm/cpu.h>
26
#include <asm/war.h>
27
 
28
/*
29
 * Maximum sizes:
30
 *
31
 * R4000 16 bytes D-cache, 128 bytes S-cache:           0x78 bytes
32
 * R4600 v1.7:                                          0x5c bytes
33
 * R4600 v2.0:                                          0x60 bytes
34
 * With prefetching, 16 byte strides                    0xa0 bytes
35
 */
36
 
37
static unsigned int clear_page_array[0xa0 / 4];
38
 
39
void clear_page(void * page) __attribute__((alias("clear_page_array")));
40
 
41
/*
42
 * Maximum sizes:
43
 *
44
 * R4000 16 bytes D-cache, 128 bytes S-cache:           0xbc bytes
45
 * R4600 v1.7:                                          0x80 bytes
46
 * R4600 v2.0:                                          0x84 bytes
47
 * With prefetching, 16 byte strides                    0xb8 bytes
48
 */
49
static unsigned int copy_page_array[0xb8 / 4];
50
 
51
void copy_page(void *to, void *from) __attribute__((alias("copy_page_array")));
52
 
53
/*
54
 * An address fits into a single register so it's safe to use 64-bit registers
55
 * if we have 64-bit adresses.
56
 */
57
#define cpu_has_64bit_registers cpu_has_64bit_addresses
58
 
59
/*
60
 * This is suboptimal for 32-bit kernels; we assume that R10000 is only used
61
 * with 64-bit kernels.  The prefetch offsets have been experimentally tuned
62
 * an Origin 200.
63
 */
64
static int pref_offset_clear __initdata = 512;
65
static int pref_offset_copy  __initdata = 256;
66
 
67
static unsigned int pref_src_mode __initdata;
68
static unsigned int pref_dst_mode __initdata;
69
 
70
static int has_scache __initdata = 0;
71
static int load_offset __initdata = 0;
72
static int store_offset __initdata = 0;
73
 
74
static unsigned int __initdata *dest, *epc;
75
 
76
static inline void build_src_pref(int advance)
77
{
78
        if (!(load_offset & (cpu_dcache_line_size() - 1))) {
79
                union mips_instruction mi;
80
 
81
                mi.i_format.opcode     = pref_op;
82
                mi.i_format.rs         = 5;             /* $a1 */
83
                mi.i_format.rt         = pref_src_mode;
84
                mi.i_format.simmediate = load_offset + advance;
85
 
86
                *epc++ = mi.word;
87
        }
88
}
89
 
90
static inline void __build_load_reg(int reg)
91
{
92
        union mips_instruction mi;
93
 
94
        if (cpu_has_64bit_registers)
95
                mi.i_format.opcode     = ld_op;
96
        else
97
                mi.i_format.opcode     = lw_op;
98
        mi.i_format.rs         = 5;             /* $a1 */
99
        mi.i_format.rt         = reg;           /* $zero */
100
        mi.i_format.simmediate = load_offset;
101
 
102
        load_offset += (cpu_has_64bit_registers ? 8 : 4);
103
 
104
        *epc++ = mi.word;
105
}
106
 
107
static inline void build_load_reg(int reg)
108
{
109
        if (cpu_has_prefetch)
110
                build_src_pref(pref_offset_copy);
111
 
112
        __build_load_reg(reg);
113
}
114
 
115
static inline void build_dst_pref(int advance)
116
{
117
        if (!(store_offset & (cpu_dcache_line_size() - 1))) {
118
                union mips_instruction mi;
119
 
120
                mi.i_format.opcode     = pref_op;
121
                mi.i_format.rs         = 4;             /* $a0 */
122
                mi.i_format.rt         = pref_dst_mode;
123
                mi.i_format.simmediate = store_offset + advance;
124
 
125
                *epc++ = mi.word;
126
        }
127
}
128
 
129
static inline void build_cdex(void)
130
{
131
        union mips_instruction mi;
132
 
133
        if (cpu_has_cache_cdex_s &&
134
            !(store_offset & (cpu_scache_line_size() - 1))) {
135
 
136
                mi.c_format.opcode     = cache_op;
137
                mi.c_format.rs         = 4;     /* $a0 */
138
                mi.c_format.c_op       = 3;     /* Create Dirty Exclusive */
139
                mi.c_format.cache      = 3;     /* Secondary Data Cache */
140
                mi.c_format.simmediate = store_offset;
141
 
142
                *epc++ = mi.word;
143
        }
144
 
145
        if (store_offset & (cpu_dcache_line_size() - 1))
146
                return;
147
 
148
        if (R4600_V1_HIT_CACHEOP_WAR && ((read_c0_prid() & 0xfff0) == 0x2010)) {
149
                *epc++ = 0;                      /* nop */
150
                *epc++ = 0;                      /* nop */
151
                *epc++ = 0;                      /* nop */
152
                *epc++ = 0;                      /* nop */
153
        }
154
 
155
        mi.c_format.opcode     = cache_op;
156
        mi.c_format.rs         = 4;             /* $a0 */
157
        mi.c_format.c_op       = 3;             /* Create Dirty Exclusive */
158
        mi.c_format.cache      = 1;             /* Data Cache */
159
        mi.c_format.simmediate = store_offset;
160
 
161
        *epc++ = mi.word;
162
}
163
 
164
static inline void __build_store_zero_reg(void)
165
{
166
        union mips_instruction mi;
167
 
168
        if (cpu_has_64bits)
169
                mi.i_format.opcode     = sd_op;
170
        else
171
                mi.i_format.opcode     = sw_op;
172
        mi.i_format.rs         = 4;             /* $a0 */
173
        mi.i_format.rt         = 0;              /* $zero */
174
        mi.i_format.simmediate = store_offset;
175
 
176
        store_offset += (cpu_has_64bits ? 8 : 4);
177
 
178
        *epc++ = mi.word;
179
}
180
 
181
static inline void __build_store_reg(int reg)
182
{
183
        union mips_instruction mi;
184
        int reg_size;
185
 
186
#ifdef CONFIG_MIPS32
187
        if (cpu_has_64bit_registers && reg == 0) {
188
                mi.i_format.opcode     = sd_op;
189
                reg_size               = 8;
190
        } else {
191
                mi.i_format.opcode     = sw_op;
192
                reg_size               = 4;
193
        }
194
#endif
195
#ifdef CONFIG_MIPS64
196
        mi.i_format.opcode     = sd_op;
197
        reg_size               = 8;
198
#endif
199
        mi.i_format.rs         = 4;             /* $a0 */
200
        mi.i_format.rt         = reg;           /* $zero */
201
        mi.i_format.simmediate = store_offset;
202
 
203
        store_offset += reg_size;
204
 
205
        *epc++ = mi.word;
206
}
207
 
208
static inline void build_store_reg(int reg)
209
{
210
        if (cpu_has_prefetch)
211
                if (reg)
212
                        build_dst_pref(pref_offset_copy);
213
                else
214
                        build_dst_pref(pref_offset_clear);
215
        else if (cpu_has_cache_cdex_p)
216
                build_cdex();
217
 
218
        __build_store_reg(reg);
219
}
220
 
221
static inline void build_addiu_at_a0(unsigned long offset)
222
{
223
        union mips_instruction mi;
224
 
225
        BUG_ON(offset > 0x7fff);
226
 
227
        mi.i_format.opcode     = cpu_has_64bit_addresses ? daddiu_op : addiu_op;
228
        mi.i_format.rs         = 4;             /* $a0 */
229
        mi.i_format.rt         = 1;             /* $at */
230
        mi.i_format.simmediate = offset;
231
 
232
        *epc++ = mi.word;
233
}
234
 
235
static inline void build_addiu_a1(unsigned long offset)
236
{
237
        union mips_instruction mi;
238
 
239
        BUG_ON(offset > 0x7fff);
240
 
241
        mi.i_format.opcode     = cpu_has_64bit_addresses ? daddiu_op : addiu_op;
242
        mi.i_format.rs         = 5;             /* $a1 */
243
        mi.i_format.rt         = 5;             /* $a1 */
244
        mi.i_format.simmediate = offset;
245
 
246
        load_offset -= offset;
247
 
248
        *epc++ = mi.word;
249
}
250
 
251
static inline void build_addiu_a0(unsigned long offset)
252
{
253
        union mips_instruction mi;
254
 
255
        BUG_ON(offset > 0x7fff);
256
 
257
        mi.i_format.opcode     = cpu_has_64bit_addresses ? daddiu_op : addiu_op;
258
        mi.i_format.rs         = 4;             /* $a0 */
259
        mi.i_format.rt         = 4;             /* $a0 */
260
        mi.i_format.simmediate = offset;
261
 
262
        store_offset -= offset;
263
 
264
        *epc++ = mi.word;
265
}
266
 
267
static inline void build_bne(unsigned int *dest)
268
{
269
        union mips_instruction mi;
270
 
271
        mi.i_format.opcode = bne_op;
272
        mi.i_format.rs     = 1;                 /* $at */
273
        mi.i_format.rt     = 4;                 /* $a0 */
274
        mi.i_format.simmediate = dest - epc - 1;
275
 
276
        *epc++ = mi.word;
277
}
278
 
279
static inline void build_nop(void)
280
{
281
        *epc++ = 0;
282
}
283
 
284
static inline void build_jr_ra(void)
285
{
286
        union mips_instruction mi;
287
 
288
        mi.r_format.opcode = spec_op;
289
        mi.r_format.rs     = 31;
290
        mi.r_format.rt     = 0;
291
        mi.r_format.rd     = 0;
292
        mi.r_format.re     = 0;
293
        mi.r_format.func   = jr_op;
294
 
295
        *epc++ = mi.word;
296
}
297
 
298
void __init build_clear_page(void)
299
{
300
        epc = (unsigned int *) &clear_page_array;
301
 
302
        if (cpu_has_prefetch) {
303
                switch (current_cpu_data.cputype) {
304
                case CPU_R10000:
305
                case CPU_R12000:
306
                        pref_src_mode = Pref_LoadStreamed;
307
                        pref_dst_mode = Pref_StoreRetained;
308
                        break;
309
                default:
310
                        pref_src_mode = Pref_LoadStreamed;
311
                        pref_dst_mode = Pref_PrepareForStore;
312
                        break;
313
                }
314
        }
315
 
316
        build_addiu_at_a0(PAGE_SIZE - (cpu_has_prefetch ? pref_offset_clear : 0));
317
 
318
        if (R4600_V2_HIT_CACHEOP_WAR && ((read_c0_prid() & 0xfff0) == 0x2020)) {
319
                *epc++ = 0x40026000;            /* mfc0    $v0, $12     */
320
                *epc++ = 0x34410001;            /* ori     $at, v0, 0x1 */
321
                *epc++ = 0x38210001;            /* xori    $at, at, 0x1 */
322
                *epc++ = 0x40816000;            /* mtc0    $at, $12     */
323
                *epc++ = 0x00000000;            /* nop                  */
324
                *epc++ = 0x00000000;            /* nop                  */
325
                *epc++ = 0x00000000;            /* nop                  */
326
                *epc++ = 0x3c01a000;            /* lui     $at, 0xa000  */
327
                *epc++ = 0x8c200000;            /* lw      $zero, ($at) */
328
        }
329
 
330
dest = epc;
331
        build_store_reg(0);
332
        build_store_reg(0);
333
        build_store_reg(0);
334
        build_store_reg(0);
335
        if (has_scache && cpu_scache_line_size() == 128) {
336
                build_store_reg(0);
337
                build_store_reg(0);
338
                build_store_reg(0);
339
                build_store_reg(0);
340
        }
341
        build_addiu_a0(2 * store_offset);
342
        build_store_reg(0);
343
        build_store_reg(0);
344
        if (has_scache && cpu_scache_line_size() == 128) {
345
                build_store_reg(0);
346
                build_store_reg(0);
347
                build_store_reg(0);
348
                build_store_reg(0);
349
        }
350
        build_store_reg(0);
351
        build_bne(dest);
352
         build_store_reg(0);
353
 
354
        if (cpu_has_prefetch && pref_offset_clear) {
355
                build_addiu_at_a0(pref_offset_clear);
356
        dest = epc;
357
                __build_store_reg(0);
358
                __build_store_reg(0);
359
                __build_store_reg(0);
360
                __build_store_reg(0);
361
                build_addiu_a0(2 * store_offset);
362
                __build_store_reg(0);
363
                __build_store_reg(0);
364
                __build_store_reg(0);
365
                build_bne(dest);
366
                 __build_store_reg(0);
367
        }
368
 
369
        build_jr_ra();
370
        if (R4600_V2_HIT_CACHEOP_WAR && ((read_c0_prid() & 0xfff0) == 0x2020))
371
                *epc++ = 0x40826000;            /* mtc0    $v0, $12     */
372
        else
373
                build_nop();
374
 
375
        flush_icache_range((unsigned long)&clear_page_array,
376
                           (unsigned long) epc);
377
 
378
        BUG_ON(epc > clear_page_array + ARRAY_SIZE(clear_page_array));
379
}
380
 
381
void __init build_copy_page(void)
382
{
383
        epc = (unsigned int *) &copy_page_array;
384
 
385
        build_addiu_at_a0(PAGE_SIZE - (cpu_has_prefetch ? pref_offset_copy : 0));
386
 
387
        if (R4600_V2_HIT_CACHEOP_WAR && ((read_c0_prid() & 0xfff0) == 0x2020)) {
388
                *epc++ = 0x40026000;            /* mfc0    $v0, $12     */
389
                *epc++ = 0x34410001;            /* ori     $at, v0, 0x1 */
390
                *epc++ = 0x38210001;            /* xori    $at, at, 0x1 */
391
                *epc++ = 0x40816000;            /* mtc0    $at, $12     */
392
                *epc++ = 0x00000000;            /* nop                  */
393
                *epc++ = 0x00000000;            /* nop                  */
394
                *epc++ = 0x00000000;            /* nop                  */
395
                *epc++ = 0x3c01a000;            /* lui     $at, 0xa000  */
396
                *epc++ = 0x8c200000;            /* lw      $zero, ($at) */
397
        }
398
 
399
dest = epc;
400
        build_load_reg( 8);
401
        build_load_reg( 9);
402
        build_load_reg(10);
403
        build_load_reg(11);
404
        build_store_reg( 8);
405
        build_store_reg( 9);
406
        build_store_reg(10);
407
        build_store_reg(11);
408
        if (has_scache && cpu_scache_line_size() == 128) {
409
                build_load_reg( 8);
410
                build_load_reg( 9);
411
                build_load_reg(10);
412
                build_load_reg(11);
413
                build_store_reg( 8);
414
                build_store_reg( 9);
415
                build_store_reg(10);
416
                build_store_reg(11);
417
        }
418
        build_addiu_a0(2 * store_offset);
419
        build_addiu_a1(2 * load_offset);
420
        build_load_reg( 8);
421
        build_load_reg( 9);
422
        build_load_reg(10);
423
        build_load_reg(11);
424
        build_store_reg( 8);
425
        build_store_reg( 9);
426
        build_store_reg(10);
427
        if (has_scache && cpu_scache_line_size() == 128) {
428
                build_store_reg(11);
429
                build_load_reg( 8);
430
                build_load_reg( 9);
431
                build_load_reg(10);
432
                build_load_reg(11);
433
                build_store_reg( 8);
434
                build_store_reg( 9);
435
                build_store_reg(10);
436
        }
437
        build_bne(dest);
438
         build_store_reg(11);
439
 
440
        if (cpu_has_prefetch && pref_offset_copy) {
441
                build_addiu_at_a0(pref_offset_copy);
442
        dest = epc;
443
                __build_load_reg( 8);
444
                __build_load_reg( 9);
445
                __build_load_reg(10);
446
                __build_load_reg(11);
447
                __build_store_reg( 8);
448
                __build_store_reg( 9);
449
                __build_store_reg(10);
450
                __build_store_reg(11);
451
                build_addiu_a0(2 * store_offset);
452
                build_addiu_a1(2 * load_offset);
453
                __build_load_reg( 8);
454
                __build_load_reg( 9);
455
                __build_load_reg(10);
456
                __build_load_reg(11);
457
                __build_store_reg( 8);
458
                __build_store_reg( 9);
459
                __build_store_reg(10);
460
                build_bne(dest);
461
                 __build_store_reg(11);
462
        }
463
 
464
        build_jr_ra();
465
        if (R4600_V2_HIT_CACHEOP_WAR && ((read_c0_prid() & 0xfff0) == 0x2020))
466
                *epc++ = 0x40826000;            /* mtc0    $v0, $12     */
467
        else
468
                build_nop();
469
 
470
        BUG_ON(epc > copy_page_array + ARRAY_SIZE(copy_page_array));
471
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.