1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
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);
}
|