diff options
author | Paul Mundt <lethal@linux-sh.org> | 2007-03-05 05:46:47 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2007-03-05 05:46:47 -0500 |
commit | 39e688a94b94eaba768b1494e19e96f828fc2688 (patch) | |
tree | 706ce255a95d0705241beafb8354fb7253a24af4 /arch | |
parent | c87a7111349891043cb0a62b0ba745264d4b600a (diff) |
sh: Revert lazy dcache writeback changes.
These ended up causing too many problems on older parts,
revert for now..
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sh/boards/renesas/r7780rp/io.c | 4 | ||||
-rw-r--r-- | arch/sh/kernel/io_generic.c | 3 | ||||
-rw-r--r-- | arch/sh/mm/cache-sh4.c | 12 | ||||
-rw-r--r-- | arch/sh/mm/cache-sh7705.c | 9 | ||||
-rw-r--r-- | arch/sh/mm/pg-sh4.c | 22 | ||||
-rw-r--r-- | arch/sh/mm/pg-sh7705.c | 31 | ||||
-rw-r--r-- | arch/sh/mm/tlb-flush.c | 55 | ||||
-rw-r--r-- | arch/sh/mm/tlb-sh3.c | 63 | ||||
-rw-r--r-- | arch/sh/mm/tlb-sh4.c | 68 |
9 files changed, 185 insertions, 82 deletions
diff --git a/arch/sh/boards/renesas/r7780rp/io.c b/arch/sh/boards/renesas/r7780rp/io.c index f74d2ffb3851..86dfe85ec440 100644 --- a/arch/sh/boards/renesas/r7780rp/io.c +++ b/arch/sh/boards/renesas/r7780rp/io.c | |||
@@ -156,8 +156,6 @@ void r7780rp_insw(unsigned long port, void *dst, unsigned long count) | |||
156 | 156 | ||
157 | while (count--) | 157 | while (count--) |
158 | *buf++ = *p; | 158 | *buf++ = *p; |
159 | |||
160 | flush_dcache_all(); | ||
161 | } | 159 | } |
162 | 160 | ||
163 | void r7780rp_insl(unsigned long port, void *dst, unsigned long count) | 161 | void r7780rp_insl(unsigned long port, void *dst, unsigned long count) |
@@ -204,8 +202,6 @@ void r7780rp_outsw(unsigned long port, const void *src, unsigned long count) | |||
204 | 202 | ||
205 | while (count--) | 203 | while (count--) |
206 | *p = *buf++; | 204 | *p = *buf++; |
207 | |||
208 | flush_dcache_all(); | ||
209 | } | 205 | } |
210 | 206 | ||
211 | void r7780rp_outsl(unsigned long port, const void *src, unsigned long count) | 207 | void r7780rp_outsl(unsigned long port, const void *src, unsigned long count) |
diff --git a/arch/sh/kernel/io_generic.c b/arch/sh/kernel/io_generic.c index 66626c03e1ee..771ea4230441 100644 --- a/arch/sh/kernel/io_generic.c +++ b/arch/sh/kernel/io_generic.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/io.h> | 15 | #include <linux/io.h> |
16 | #include <asm/machvec.h> | 16 | #include <asm/machvec.h> |
17 | #include <asm/cacheflush.h> | ||
18 | 17 | ||
19 | #ifdef CONFIG_CPU_SH3 | 18 | #ifdef CONFIG_CPU_SH3 |
20 | /* SH3 has a PCMCIA bug that needs a dummy read from area 6 for a | 19 | /* SH3 has a PCMCIA bug that needs a dummy read from area 6 for a |
@@ -96,7 +95,6 @@ void generic_insw(unsigned long port, void *dst, unsigned long count) | |||
96 | while (count--) | 95 | while (count--) |
97 | *buf++ = *port_addr; | 96 | *buf++ = *port_addr; |
98 | 97 | ||
99 | flush_dcache_all(); | ||
100 | dummy_read(); | 98 | dummy_read(); |
101 | } | 99 | } |
102 | 100 | ||
@@ -171,7 +169,6 @@ void generic_outsw(unsigned long port, const void *src, unsigned long count) | |||
171 | while (count--) | 169 | while (count--) |
172 | *port_addr = *buf++; | 170 | *port_addr = *buf++; |
173 | 171 | ||
174 | flush_dcache_all(); | ||
175 | dummy_read(); | 172 | dummy_read(); |
176 | } | 173 | } |
177 | 174 | ||
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index e0cd4b7f4aeb..981b04089055 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c | |||
@@ -237,20 +237,10 @@ static inline void flush_cache_4096(unsigned long start, | |||
237 | /* | 237 | /* |
238 | * Write back & invalidate the D-cache of the page. | 238 | * Write back & invalidate the D-cache of the page. |
239 | * (To avoid "alias" issues) | 239 | * (To avoid "alias" issues) |
240 | * | ||
241 | * This uses a lazy write-back on UP, which is explicitly | ||
242 | * disabled on SMP. | ||
243 | */ | 240 | */ |
244 | void flush_dcache_page(struct page *page) | 241 | void flush_dcache_page(struct page *page) |
245 | { | 242 | { |
246 | #ifndef CONFIG_SMP | 243 | if (test_bit(PG_mapped, &page->flags)) { |
247 | struct address_space *mapping = page_mapping(page); | ||
248 | |||
249 | if (mapping && !mapping_mapped(mapping)) | ||
250 | set_bit(PG_dcache_dirty, &page->flags); | ||
251 | else | ||
252 | #endif | ||
253 | { | ||
254 | unsigned long phys = PHYSADDR(page_address(page)); | 244 | unsigned long phys = PHYSADDR(page_address(page)); |
255 | unsigned long addr = CACHE_OC_ADDRESS_ARRAY; | 245 | unsigned long addr = CACHE_OC_ADDRESS_ARRAY; |
256 | int i, n; | 246 | int i, n; |
diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c index 31f8deb7a158..4896d7376926 100644 --- a/arch/sh/mm/cache-sh7705.c +++ b/arch/sh/mm/cache-sh7705.c | |||
@@ -3,11 +3,11 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 1999, 2000 Niibe Yutaka | 4 | * Copyright (C) 1999, 2000 Niibe Yutaka |
5 | * Copyright (C) 2004 Alex Song | 5 | * Copyright (C) 2004 Alex Song |
6 | * Copyright (C) 2006 Paul Mundt | ||
7 | * | 6 | * |
8 | * This file is subject to the terms and conditions of the GNU General Public | 7 | * This file is subject to the terms and conditions of the GNU General Public |
9 | * License. See the file "COPYING" in the main directory of this archive | 8 | * License. See the file "COPYING" in the main directory of this archive |
10 | * for more details. | 9 | * for more details. |
10 | * | ||
11 | */ | 11 | */ |
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/mman.h> | 13 | #include <linux/mman.h> |
@@ -51,6 +51,7 @@ static inline void cache_wback_all(void) | |||
51 | 51 | ||
52 | if ((data & v) == v) | 52 | if ((data & v) == v) |
53 | ctrl_outl(data & ~v, addr); | 53 | ctrl_outl(data & ~v, addr); |
54 | |||
54 | } | 55 | } |
55 | 56 | ||
56 | addrstart += current_cpu_data.dcache.way_incr; | 57 | addrstart += current_cpu_data.dcache.way_incr; |
@@ -127,11 +128,7 @@ static void __flush_dcache_page(unsigned long phys) | |||
127 | */ | 128 | */ |
128 | void flush_dcache_page(struct page *page) | 129 | void flush_dcache_page(struct page *page) |
129 | { | 130 | { |
130 | struct address_space *mapping = page_mapping(page); | 131 | if (test_bit(PG_mapped, &page->flags)) |
131 | |||
132 | if (mapping && !mapping_mapped(mapping)) | ||
133 | set_bit(PG_dcache_dirty, &page->flags); | ||
134 | else | ||
135 | __flush_dcache_page(PHYSADDR(page_address(page))); | 132 | __flush_dcache_page(PHYSADDR(page_address(page))); |
136 | } | 133 | } |
137 | 134 | ||
diff --git a/arch/sh/mm/pg-sh4.c b/arch/sh/mm/pg-sh4.c index 969efeceb928..df69da9ca69c 100644 --- a/arch/sh/mm/pg-sh4.c +++ b/arch/sh/mm/pg-sh4.c | |||
@@ -23,6 +23,7 @@ extern struct mutex p3map_mutex[]; | |||
23 | */ | 23 | */ |
24 | void clear_user_page(void *to, unsigned long address, struct page *page) | 24 | void clear_user_page(void *to, unsigned long address, struct page *page) |
25 | { | 25 | { |
26 | __set_bit(PG_mapped, &page->flags); | ||
26 | if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) | 27 | if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) |
27 | clear_page(to); | 28 | clear_page(to); |
28 | else { | 29 | else { |
@@ -58,6 +59,7 @@ void clear_user_page(void *to, unsigned long address, struct page *page) | |||
58 | void copy_user_page(void *to, void *from, unsigned long address, | 59 | void copy_user_page(void *to, void *from, unsigned long address, |
59 | struct page *page) | 60 | struct page *page) |
60 | { | 61 | { |
62 | __set_bit(PG_mapped, &page->flags); | ||
61 | if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) | 63 | if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) |
62 | copy_page(to, from); | 64 | copy_page(to, from); |
63 | else { | 65 | else { |
@@ -82,3 +84,23 @@ void copy_user_page(void *to, void *from, unsigned long address, | |||
82 | mutex_unlock(&p3map_mutex[(address & CACHE_ALIAS)>>12]); | 84 | mutex_unlock(&p3map_mutex[(address & CACHE_ALIAS)>>12]); |
83 | } | 85 | } |
84 | } | 86 | } |
87 | |||
88 | /* | ||
89 | * For SH-4, we have our own implementation for ptep_get_and_clear | ||
90 | */ | ||
91 | inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | ||
92 | { | ||
93 | pte_t pte = *ptep; | ||
94 | |||
95 | pte_clear(mm, addr, ptep); | ||
96 | if (!pte_not_present(pte)) { | ||
97 | unsigned long pfn = pte_pfn(pte); | ||
98 | if (pfn_valid(pfn)) { | ||
99 | struct page *page = pfn_to_page(pfn); | ||
100 | struct address_space *mapping = page_mapping(page); | ||
101 | if (!mapping || !mapping_writably_mapped(mapping)) | ||
102 | __clear_bit(PG_mapped, &page->flags); | ||
103 | } | ||
104 | } | ||
105 | return pte; | ||
106 | } | ||
diff --git a/arch/sh/mm/pg-sh7705.c b/arch/sh/mm/pg-sh7705.c index 887ab9d18ccd..a4b015f95a3a 100644 --- a/arch/sh/mm/pg-sh7705.c +++ b/arch/sh/mm/pg-sh7705.c | |||
@@ -7,7 +7,9 @@ | |||
7 | * This file is subject to the terms and conditions of the GNU General Public | 7 | * This file is subject to the terms and conditions of the GNU General Public |
8 | * License. See the file "COPYING" in the main directory of this archive | 8 | * License. See the file "COPYING" in the main directory of this archive |
9 | * for more details. | 9 | * for more details. |
10 | * | ||
10 | */ | 11 | */ |
12 | |||
11 | #include <linux/init.h> | 13 | #include <linux/init.h> |
12 | #include <linux/mman.h> | 14 | #include <linux/mman.h> |
13 | #include <linux/mm.h> | 15 | #include <linux/mm.h> |
@@ -74,6 +76,7 @@ void clear_user_page(void *to, unsigned long address, struct page *pg) | |||
74 | { | 76 | { |
75 | struct page *page = virt_to_page(to); | 77 | struct page *page = virt_to_page(to); |
76 | 78 | ||
79 | __set_bit(PG_mapped, &page->flags); | ||
77 | if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) { | 80 | if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) { |
78 | clear_page(to); | 81 | clear_page(to); |
79 | __flush_wback_region(to, PAGE_SIZE); | 82 | __flush_wback_region(to, PAGE_SIZE); |
@@ -92,11 +95,12 @@ void clear_user_page(void *to, unsigned long address, struct page *pg) | |||
92 | * @from: P1 address | 95 | * @from: P1 address |
93 | * @address: U0 address to be mapped | 96 | * @address: U0 address to be mapped |
94 | */ | 97 | */ |
95 | void copy_user_page(void *to, void *from, unsigned long address, | 98 | void copy_user_page(void *to, void *from, unsigned long address, struct page *pg) |
96 | struct page *pg) | ||
97 | { | 99 | { |
98 | struct page *page = virt_to_page(to); | 100 | struct page *page = virt_to_page(to); |
99 | 101 | ||
102 | |||
103 | __set_bit(PG_mapped, &page->flags); | ||
100 | if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) { | 104 | if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) { |
101 | copy_page(to, from); | 105 | copy_page(to, from); |
102 | __flush_wback_region(to, PAGE_SIZE); | 106 | __flush_wback_region(to, PAGE_SIZE); |
@@ -108,3 +112,26 @@ void copy_user_page(void *to, void *from, unsigned long address, | |||
108 | __flush_wback_region(to, PAGE_SIZE); | 112 | __flush_wback_region(to, PAGE_SIZE); |
109 | } | 113 | } |
110 | } | 114 | } |
115 | |||
116 | /* | ||
117 | * For SH7705, we have our own implementation for ptep_get_and_clear | ||
118 | * Copied from pg-sh4.c | ||
119 | */ | ||
120 | inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | ||
121 | { | ||
122 | pte_t pte = *ptep; | ||
123 | |||
124 | pte_clear(mm, addr, ptep); | ||
125 | if (!pte_not_present(pte)) { | ||
126 | unsigned long pfn = pte_pfn(pte); | ||
127 | if (pfn_valid(pfn)) { | ||
128 | struct page *page = pfn_to_page(pfn); | ||
129 | struct address_space *mapping = page_mapping(page); | ||
130 | if (!mapping || !mapping_writably_mapped(mapping)) | ||
131 | __clear_bit(PG_mapped, &page->flags); | ||
132 | } | ||
133 | } | ||
134 | |||
135 | return pte; | ||
136 | } | ||
137 | |||
diff --git a/arch/sh/mm/tlb-flush.c b/arch/sh/mm/tlb-flush.c index d2f7b4a2eb05..6f45c1f8a7fe 100644 --- a/arch/sh/mm/tlb-flush.c +++ b/arch/sh/mm/tlb-flush.c | |||
@@ -2,17 +2,15 @@ | |||
2 | * TLB flushing operations for SH with an MMU. | 2 | * TLB flushing operations for SH with an MMU. |
3 | * | 3 | * |
4 | * Copyright (C) 1999 Niibe Yutaka | 4 | * Copyright (C) 1999 Niibe Yutaka |
5 | * Copyright (C) 2003 - 2006 Paul Mundt | 5 | * Copyright (C) 2003 Paul Mundt |
6 | * | 6 | * |
7 | * This file is subject to the terms and conditions of the GNU General Public | 7 | * This file is subject to the terms and conditions of the GNU General Public |
8 | * License. See the file "COPYING" in the main directory of this archive | 8 | * License. See the file "COPYING" in the main directory of this archive |
9 | * for more details. | 9 | * for more details. |
10 | */ | 10 | */ |
11 | #include <linux/mm.h> | 11 | #include <linux/mm.h> |
12 | #include <linux/io.h> | ||
13 | #include <asm/mmu_context.h> | 12 | #include <asm/mmu_context.h> |
14 | #include <asm/tlbflush.h> | 13 | #include <asm/tlbflush.h> |
15 | #include <asm/cacheflush.h> | ||
16 | 14 | ||
17 | void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) | 15 | void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) |
18 | { | 16 | { |
@@ -140,54 +138,3 @@ void local_flush_tlb_all(void) | |||
140 | ctrl_barrier(); | 138 | ctrl_barrier(); |
141 | local_irq_restore(flags); | 139 | local_irq_restore(flags); |
142 | } | 140 | } |
143 | |||
144 | void update_mmu_cache(struct vm_area_struct *vma, | ||
145 | unsigned long address, pte_t pte) | ||
146 | { | ||
147 | unsigned long flags; | ||
148 | unsigned long pteval; | ||
149 | unsigned long vpn; | ||
150 | struct page *page; | ||
151 | unsigned long pfn = pte_pfn(pte); | ||
152 | struct address_space *mapping; | ||
153 | |||
154 | if (!pfn_valid(pfn)) | ||
155 | return; | ||
156 | |||
157 | page = pfn_to_page(pfn); | ||
158 | mapping = page_mapping(page); | ||
159 | if (mapping) { | ||
160 | unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; | ||
161 | int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags); | ||
162 | |||
163 | if (dirty) | ||
164 | __flush_wback_region((void *)P1SEGADDR(phys), | ||
165 | PAGE_SIZE); | ||
166 | } | ||
167 | |||
168 | local_irq_save(flags); | ||
169 | |||
170 | /* Set PTEH register */ | ||
171 | vpn = (address & MMU_VPN_MASK) | get_asid(); | ||
172 | ctrl_outl(vpn, MMU_PTEH); | ||
173 | |||
174 | pteval = pte_val(pte); | ||
175 | |||
176 | #ifdef CONFIG_CPU_HAS_PTEA | ||
177 | /* Set PTEA register */ | ||
178 | /* TODO: make this look less hacky */ | ||
179 | ctrl_outl(((pteval >> 28) & 0xe) | (pteval & 0x1), MMU_PTEA); | ||
180 | #endif | ||
181 | |||
182 | /* Set PTEL register */ | ||
183 | pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ | ||
184 | #if defined(CONFIG_SH_WRITETHROUGH) && defined(CONFIG_CPU_SH4) | ||
185 | pteval |= _PAGE_WT; | ||
186 | #endif | ||
187 | /* conveniently, we want all the software flags to be 0 anyway */ | ||
188 | ctrl_outl(pteval, MMU_PTEL); | ||
189 | |||
190 | /* Load the TLB */ | ||
191 | asm volatile("ldtlb": /* no output */ : /* no input */ : "memory"); | ||
192 | local_irq_restore(flags); | ||
193 | } | ||
diff --git a/arch/sh/mm/tlb-sh3.c b/arch/sh/mm/tlb-sh3.c index e5e76eb7ee09..7fbfd5a11ffa 100644 --- a/arch/sh/mm/tlb-sh3.c +++ b/arch/sh/mm/tlb-sh3.c | |||
@@ -8,9 +8,69 @@ | |||
8 | * | 8 | * |
9 | * Released under the terms of the GNU GPL v2.0. | 9 | * Released under the terms of the GNU GPL v2.0. |
10 | */ | 10 | */ |
11 | #include <linux/io.h> | 11 | #include <linux/signal.h> |
12 | #include <linux/sched.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/string.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/ptrace.h> | ||
18 | #include <linux/mman.h> | ||
19 | #include <linux/mm.h> | ||
20 | #include <linux/smp.h> | ||
21 | #include <linux/smp_lock.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | |||
12 | #include <asm/system.h> | 24 | #include <asm/system.h> |
25 | #include <asm/io.h> | ||
26 | #include <asm/uaccess.h> | ||
27 | #include <asm/pgalloc.h> | ||
13 | #include <asm/mmu_context.h> | 28 | #include <asm/mmu_context.h> |
29 | #include <asm/cacheflush.h> | ||
30 | |||
31 | void update_mmu_cache(struct vm_area_struct * vma, | ||
32 | unsigned long address, pte_t pte) | ||
33 | { | ||
34 | unsigned long flags; | ||
35 | unsigned long pteval; | ||
36 | unsigned long vpn; | ||
37 | |||
38 | /* Ptrace may call this routine. */ | ||
39 | if (vma && current->active_mm != vma->vm_mm) | ||
40 | return; | ||
41 | |||
42 | #if defined(CONFIG_SH7705_CACHE_32KB) | ||
43 | { | ||
44 | struct page *page = pte_page(pte); | ||
45 | unsigned long pfn = pte_pfn(pte); | ||
46 | |||
47 | if (pfn_valid(pfn) && !test_bit(PG_mapped, &page->flags)) { | ||
48 | unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; | ||
49 | |||
50 | __flush_wback_region((void *)P1SEGADDR(phys), | ||
51 | PAGE_SIZE); | ||
52 | __set_bit(PG_mapped, &page->flags); | ||
53 | } | ||
54 | } | ||
55 | #endif | ||
56 | |||
57 | local_irq_save(flags); | ||
58 | |||
59 | /* Set PTEH register */ | ||
60 | vpn = (address & MMU_VPN_MASK) | get_asid(); | ||
61 | ctrl_outl(vpn, MMU_PTEH); | ||
62 | |||
63 | pteval = pte_val(pte); | ||
64 | |||
65 | /* Set PTEL register */ | ||
66 | pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ | ||
67 | /* conveniently, we want all the software flags to be 0 anyway */ | ||
68 | ctrl_outl(pteval, MMU_PTEL); | ||
69 | |||
70 | /* Load the TLB */ | ||
71 | asm volatile("ldtlb": /* no output */ : /* no input */ : "memory"); | ||
72 | local_irq_restore(flags); | ||
73 | } | ||
14 | 74 | ||
15 | void local_flush_tlb_one(unsigned long asid, unsigned long page) | 75 | void local_flush_tlb_one(unsigned long asid, unsigned long page) |
16 | { | 76 | { |
@@ -34,3 +94,4 @@ void local_flush_tlb_one(unsigned long asid, unsigned long page) | |||
34 | for (i = 0; i < ways; i++) | 94 | for (i = 0; i < ways; i++) |
35 | ctrl_outl(data, addr + (i << 8)); | 95 | ctrl_outl(data, addr + (i << 8)); |
36 | } | 96 | } |
97 | |||
diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c index 221e7095473d..f74cf667c8fa 100644 --- a/arch/sh/mm/tlb-sh4.c +++ b/arch/sh/mm/tlb-sh4.c | |||
@@ -8,9 +8,74 @@ | |||
8 | * | 8 | * |
9 | * Released under the terms of the GNU GPL v2.0. | 9 | * Released under the terms of the GNU GPL v2.0. |
10 | */ | 10 | */ |
11 | #include <linux/io.h> | 11 | #include <linux/signal.h> |
12 | #include <linux/sched.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/string.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/ptrace.h> | ||
18 | #include <linux/mman.h> | ||
19 | #include <linux/mm.h> | ||
20 | #include <linux/smp.h> | ||
21 | #include <linux/smp_lock.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | |||
12 | #include <asm/system.h> | 24 | #include <asm/system.h> |
25 | #include <asm/io.h> | ||
26 | #include <asm/uaccess.h> | ||
27 | #include <asm/pgalloc.h> | ||
13 | #include <asm/mmu_context.h> | 28 | #include <asm/mmu_context.h> |
29 | #include <asm/cacheflush.h> | ||
30 | |||
31 | void update_mmu_cache(struct vm_area_struct * vma, | ||
32 | unsigned long address, pte_t pte) | ||
33 | { | ||
34 | unsigned long flags; | ||
35 | unsigned long pteval; | ||
36 | unsigned long vpn; | ||
37 | struct page *page; | ||
38 | unsigned long pfn; | ||
39 | |||
40 | /* Ptrace may call this routine. */ | ||
41 | if (vma && current->active_mm != vma->vm_mm) | ||
42 | return; | ||
43 | |||
44 | pfn = pte_pfn(pte); | ||
45 | if (pfn_valid(pfn)) { | ||
46 | page = pfn_to_page(pfn); | ||
47 | if (!test_bit(PG_mapped, &page->flags)) { | ||
48 | unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; | ||
49 | __flush_wback_region((void *)P1SEGADDR(phys), PAGE_SIZE); | ||
50 | __set_bit(PG_mapped, &page->flags); | ||
51 | } | ||
52 | } | ||
53 | |||
54 | local_irq_save(flags); | ||
55 | |||
56 | /* Set PTEH register */ | ||
57 | vpn = (address & MMU_VPN_MASK) | get_asid(); | ||
58 | ctrl_outl(vpn, MMU_PTEH); | ||
59 | |||
60 | pteval = pte_val(pte); | ||
61 | |||
62 | /* Set PTEA register */ | ||
63 | if (cpu_data->flags & CPU_HAS_PTEA) | ||
64 | /* TODO: make this look less hacky */ | ||
65 | ctrl_outl(((pteval >> 28) & 0xe) | (pteval & 0x1), MMU_PTEA); | ||
66 | |||
67 | /* Set PTEL register */ | ||
68 | pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ | ||
69 | #ifdef CONFIG_SH_WRITETHROUGH | ||
70 | pteval |= _PAGE_WT; | ||
71 | #endif | ||
72 | /* conveniently, we want all the software flags to be 0 anyway */ | ||
73 | ctrl_outl(pteval, MMU_PTEL); | ||
74 | |||
75 | /* Load the TLB */ | ||
76 | asm volatile("ldtlb": /* no output */ : /* no input */ : "memory"); | ||
77 | local_irq_restore(flags); | ||
78 | } | ||
14 | 79 | ||
15 | void local_flush_tlb_one(unsigned long asid, unsigned long page) | 80 | void local_flush_tlb_one(unsigned long asid, unsigned long page) |
16 | { | 81 | { |
@@ -28,3 +93,4 @@ void local_flush_tlb_one(unsigned long asid, unsigned long page) | |||
28 | ctrl_outl(data, addr); | 93 | ctrl_outl(data, addr); |
29 | back_to_P1(); | 94 | back_to_P1(); |
30 | } | 95 | } |
96 | |||