aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/mm')
-rw-r--r--arch/sh/mm/Kconfig78
-rw-r--r--arch/sh/mm/Makefile16
-rw-r--r--arch/sh/mm/cache-debugfs.c147
-rw-r--r--arch/sh/mm/cache-sh4.c685
-rw-r--r--arch/sh/mm/cache-sh7705.c19
-rw-r--r--arch/sh/mm/clear_page.S99
-rw-r--r--arch/sh/mm/consistent.c2
-rw-r--r--arch/sh/mm/fault.c207
-rw-r--r--arch/sh/mm/hugetlbpage.c52
-rw-r--r--arch/sh/mm/init.c32
-rw-r--r--arch/sh/mm/ioremap.c17
-rw-r--r--arch/sh/mm/pg-nommu.c17
-rw-r--r--arch/sh/mm/pg-sh4.c24
-rw-r--r--arch/sh/mm/pmb.c400
-rw-r--r--arch/sh/mm/tlb-flush.c134
-rw-r--r--arch/sh/mm/tlb-sh4.c8
16 files changed, 1454 insertions, 483 deletions
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index fb586b1cf8bb..9dd606464d23 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -20,7 +20,10 @@ config CPU_SH4
20config CPU_SH4A 20config CPU_SH4A
21 bool 21 bool
22 select CPU_SH4 22 select CPU_SH4
23 select CPU_HAS_INTC2_IRQ 23
24config CPU_SH4AL_DSP
25 bool
26 select CPU_SH4A
24 27
25config CPU_SUBTYPE_ST40 28config CPU_SUBTYPE_ST40
26 bool 29 bool
@@ -48,6 +51,12 @@ config CPU_SUBTYPE_SH7705
48 select CPU_SH3 51 select CPU_SH3
49 select CPU_HAS_PINT_IRQ 52 select CPU_HAS_PINT_IRQ
50 53
54config CPU_SUBTYPE_SH7706
55 bool "Support SH7706 processor"
56 select CPU_SH3
57 help
58 Select SH7706 if you have a 133 Mhz SH-3 HD6417706 CPU.
59
51config CPU_SUBTYPE_SH7707 60config CPU_SUBTYPE_SH7707
52 bool "Support SH7707 processor" 61 bool "Support SH7707 processor"
53 select CPU_SH3 62 select CPU_SH3
@@ -69,6 +78,12 @@ config CPU_SUBTYPE_SH7709
69 help 78 help
70 Select SH7709 if you have a 80 Mhz SH-3 HD6417709 CPU. 79 Select SH7709 if you have a 80 Mhz SH-3 HD6417709 CPU.
71 80
81config CPU_SUBTYPE_SH7710
82 bool "Support SH7710 processor"
83 select CPU_SH3
84 help
85 Select SH7710 if you have a SH3-DSP SH7710 CPU.
86
72comment "SH-4 Processor Support" 87comment "SH-4 Processor Support"
73 88
74config CPU_SUBTYPE_SH7750 89config CPU_SUBTYPE_SH7750
@@ -133,10 +148,6 @@ config CPU_SUBTYPE_ST40GX1
133 148
134comment "SH-4A Processor Support" 149comment "SH-4A Processor Support"
135 150
136config CPU_SUBTYPE_SH73180
137 bool "Support SH73180 processor"
138 select CPU_SH4A
139
140config CPU_SUBTYPE_SH7770 151config CPU_SUBTYPE_SH7770
141 bool "Support SH7770 processor" 152 bool "Support SH7770 processor"
142 select CPU_SH4A 153 select CPU_SH4A
@@ -144,6 +155,17 @@ config CPU_SUBTYPE_SH7770
144config CPU_SUBTYPE_SH7780 155config CPU_SUBTYPE_SH7780
145 bool "Support SH7780 processor" 156 bool "Support SH7780 processor"
146 select CPU_SH4A 157 select CPU_SH4A
158 select CPU_HAS_INTC2_IRQ
159
160comment "SH4AL-DSP Processor Support"
161
162config CPU_SUBTYPE_SH73180
163 bool "Support SH73180 processor"
164 select CPU_SH4AL_DSP
165
166config CPU_SUBTYPE_SH7343
167 bool "Support SH7343 processor"
168 select CPU_SH4AL_DSP
147 169
148endmenu 170endmenu
149 171
@@ -161,15 +183,59 @@ config MMU
161 turning this off will boot the kernel on these machines with the 183 turning this off will boot the kernel on these machines with the
162 MMU implicitly switched off. 184 MMU implicitly switched off.
163 185
186config PAGE_OFFSET
187 hex
188 default "0x80000000" if MMU
189 default "0x00000000"
190
191config MEMORY_START
192 hex "Physical memory start address"
193 default "0x08000000"
194 ---help---
195 Computers built with Hitachi SuperH processors always
196 map the ROM starting at address zero. But the processor
197 does not specify the range that RAM takes.
198
199 The physical memory (RAM) start address will be automatically
200 set to 08000000. Other platforms, such as the Solution Engine
201 boards typically map RAM at 0C000000.
202
203 Tweak this only when porting to a new machine which does not
204 already have a defconfig. Changing it from the known correct
205 value on any of the known systems will only lead to disaster.
206
207config MEMORY_SIZE
208 hex "Physical memory size"
209 default "0x00400000"
210 help
211 This sets the default memory size assumed by your SH kernel. It can
212 be overridden as normal by the 'mem=' argument on the kernel command
213 line. If unsure, consult your board specifications or just leave it
214 as 0x00400000 which was the default value before this became
215 configurable.
216
164config 32BIT 217config 32BIT
165 bool "Support 32-bit physical addressing through PMB" 218 bool "Support 32-bit physical addressing through PMB"
166 depends on CPU_SH4A 219 depends on CPU_SH4A && MMU
167 default y 220 default y
168 help 221 help
169 If you say Y here, physical addressing will be extended to 222 If you say Y here, physical addressing will be extended to
170 32-bits through the SH-4A PMB. If this is not set, legacy 223 32-bits through the SH-4A PMB. If this is not set, legacy
171 29-bit physical addressing will be used. 224 29-bit physical addressing will be used.
172 225
226config VSYSCALL
227 bool "Support vsyscall page"
228 depends on MMU
229 default y
230 help
231 This will enable support for the kernel mapping a vDSO page
232 in process space, and subsequently handing down the entry point
233 to the libc through the ELF auxiliary vector.
234
235 From the kernel side this is used for the signal trampoline.
236 For systems with an MMU that can afford to give up a page,
237 (the default value) say Y.
238
173choice 239choice
174 prompt "HugeTLB page size" 240 prompt "HugeTLB page size"
175 depends on HUGETLB_PAGE && CPU_SH4 && MMU 241 depends on HUGETLB_PAGE && CPU_SH4 && MMU
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
index 9489a1424644..3ffd7f68c0a2 100644
--- a/arch/sh/mm/Makefile
+++ b/arch/sh/mm/Makefile
@@ -6,20 +6,26 @@ obj-y := init.o extable.o consistent.o
6 6
7obj-$(CONFIG_CPU_SH2) += cache-sh2.o 7obj-$(CONFIG_CPU_SH2) += cache-sh2.o
8obj-$(CONFIG_CPU_SH3) += cache-sh3.o 8obj-$(CONFIG_CPU_SH3) += cache-sh3.o
9obj-$(CONFIG_CPU_SH4) += cache-sh4.o pg-sh4.o 9obj-$(CONFIG_CPU_SH4) += cache-sh4.o
10 10
11obj-$(CONFIG_DMA_PAGE_OPS) += pg-dma.o 11obj-$(CONFIG_DMA_PAGE_OPS) += pg-dma.o
12obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o 12obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
13 13
14mmu-y := fault-nommu.o tlb-nommu.o pg-nommu.o 14mmu-y := fault-nommu.o tlb-nommu.o pg-nommu.o
15mmu-$(CONFIG_MMU) := fault.o clear_page.o copy_page.o 15mmu-$(CONFIG_MMU) := fault.o clear_page.o copy_page.o tlb-flush.o \
16 ioremap.o
16 17
17obj-y += $(mmu-y) 18obj-y += $(mmu-y)
18 19
20ifdef CONFIG_DEBUG_FS
21obj-$(CONFIG_CPU_SH4) += cache-debugfs.o
22endif
23
19ifdef CONFIG_MMU 24ifdef CONFIG_MMU
20obj-$(CONFIG_CPU_SH3) += tlb-sh3.o 25obj-$(CONFIG_CPU_SH3) += tlb-sh3.o
21obj-$(CONFIG_CPU_SH4) += tlb-sh4.o ioremap.o 26obj-$(CONFIG_CPU_SH4) += tlb-sh4.o pg-sh4.o
22obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o 27obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o
23endif 28endif
24 29
25obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o 30obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o
31obj-$(CONFIG_32BIT) += pmb.o
diff --git a/arch/sh/mm/cache-debugfs.c b/arch/sh/mm/cache-debugfs.c
new file mode 100644
index 000000000000..a22d914e4d15
--- /dev/null
+++ b/arch/sh/mm/cache-debugfs.c
@@ -0,0 +1,147 @@
1/*
2 * debugfs ops for the L1 cache
3 *
4 * Copyright (C) 2006 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/init.h>
11#include <linux/module.h>
12#include <linux/debugfs.h>
13#include <linux/seq_file.h>
14#include <asm/processor.h>
15#include <asm/uaccess.h>
16#include <asm/cache.h>
17#include <asm/io.h>
18
19enum cache_type {
20 CACHE_TYPE_ICACHE,
21 CACHE_TYPE_DCACHE,
22 CACHE_TYPE_UNIFIED,
23};
24
25static int cache_seq_show(struct seq_file *file, void *iter)
26{
27 unsigned int cache_type = (unsigned int)file->private;
28 struct cache_info *cache;
29 unsigned int waysize, way, cache_size;
30 unsigned long ccr, base;
31 static unsigned long addrstart = 0;
32
33 /*
34 * Go uncached immediately so we don't skew the results any
35 * more than we already are..
36 */
37 jump_to_P2();
38
39 ccr = ctrl_inl(CCR);
40 if ((ccr & CCR_CACHE_ENABLE) == 0) {
41 back_to_P1();
42
43 seq_printf(file, "disabled\n");
44 return 0;
45 }
46
47 if (cache_type == CACHE_TYPE_DCACHE) {
48 base = CACHE_OC_ADDRESS_ARRAY;
49 cache = &cpu_data->dcache;
50 } else {
51 base = CACHE_IC_ADDRESS_ARRAY;
52 cache = &cpu_data->icache;
53 }
54
55 /*
56 * Due to the amount of data written out (depending on the cache size),
57 * we may be iterated over multiple times. In this case, keep track of
58 * the entry position in addrstart, and rewind it when we've hit the
59 * end of the cache.
60 *
61 * Likewise, the same code is used for multiple caches, so care must
62 * be taken for bouncing addrstart back and forth so the appropriate
63 * cache is hit.
64 */
65 cache_size = cache->ways * cache->sets * cache->linesz;
66 if (((addrstart & 0xff000000) != base) ||
67 (addrstart & 0x00ffffff) > cache_size)
68 addrstart = base;
69
70 waysize = cache->sets;
71
72 /*
73 * If the OC is already in RAM mode, we only have
74 * half of the entries to consider..
75 */
76 if ((ccr & CCR_CACHE_ORA) && cache_type == CACHE_TYPE_DCACHE)
77 waysize >>= 1;
78
79 waysize <<= cache->entry_shift;
80
81 for (way = 0; way < cache->ways; way++) {
82 unsigned long addr;
83 unsigned int line;
84
85 seq_printf(file, "-----------------------------------------\n");
86 seq_printf(file, "Way %d\n", way);
87 seq_printf(file, "-----------------------------------------\n");
88
89 for (addr = addrstart, line = 0;
90 addr < addrstart + waysize;
91 addr += cache->linesz, line++) {
92 unsigned long data = ctrl_inl(addr);
93
94 /* Check the V bit, ignore invalid cachelines */
95 if ((data & 1) == 0)
96 continue;
97
98 /* U: Dirty, cache tag is 10 bits up */
99 seq_printf(file, "%3d: %c 0x%lx\n",
100 line, data & 2 ? 'U' : ' ',
101 data & 0x1ffffc00);
102 }
103
104 addrstart += cache->way_incr;
105 }
106
107 back_to_P1();
108
109 return 0;
110}
111
112static int cache_debugfs_open(struct inode *inode, struct file *file)
113{
114 return single_open(file, cache_seq_show, inode->u.generic_ip);
115}
116
117static struct file_operations cache_debugfs_fops = {
118 .owner = THIS_MODULE,
119 .open = cache_debugfs_open,
120 .read = seq_read,
121 .llseek = seq_lseek,
122 .release = seq_release,
123};
124
125static int __init cache_debugfs_init(void)
126{
127 struct dentry *dcache_dentry, *icache_dentry;
128
129 dcache_dentry = debugfs_create_file("dcache", S_IRUSR, NULL,
130 (unsigned int *)CACHE_TYPE_DCACHE,
131 &cache_debugfs_fops);
132 if (IS_ERR(dcache_dentry))
133 return PTR_ERR(dcache_dentry);
134
135 icache_dentry = debugfs_create_file("icache", S_IRUSR, NULL,
136 (unsigned int *)CACHE_TYPE_ICACHE,
137 &cache_debugfs_fops);
138 if (IS_ERR(icache_dentry)) {
139 debugfs_remove(dcache_dentry);
140 return PTR_ERR(icache_dentry);
141 }
142
143 return 0;
144}
145module_init(cache_debugfs_init);
146
147MODULE_LICENSE("GPL v2");
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c
index 524cea5b47f9..e48cc22724d9 100644
--- a/arch/sh/mm/cache-sh4.c
+++ b/arch/sh/mm/cache-sh4.c
@@ -2,49 +2,120 @@
2 * arch/sh/mm/cache-sh4.c 2 * arch/sh/mm/cache-sh4.c
3 * 3 *
4 * Copyright (C) 1999, 2000, 2002 Niibe Yutaka 4 * Copyright (C) 1999, 2000, 2002 Niibe Yutaka
5 * Copyright (C) 2001, 2002, 2003, 2004 Paul Mundt 5 * Copyright (C) 2001 - 2006 Paul Mundt
6 * Copyright (C) 2003 Richard Curnow 6 * Copyright (C) 2003 Richard Curnow
7 * 7 *
8 * This file is subject to the terms and conditions of the GNU General Public 8 * 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 9 * License. See the file "COPYING" in the main directory of this archive
10 * for more details. 10 * for more details.
11 */ 11 */
12
13#include <linux/init.h> 12#include <linux/init.h>
14#include <linux/mman.h>
15#include <linux/mm.h> 13#include <linux/mm.h>
16#include <linux/threads.h>
17#include <asm/addrspace.h> 14#include <asm/addrspace.h>
18#include <asm/page.h>
19#include <asm/pgtable.h> 15#include <asm/pgtable.h>
20#include <asm/processor.h> 16#include <asm/processor.h>
21#include <asm/cache.h> 17#include <asm/cache.h>
22#include <asm/io.h> 18#include <asm/io.h>
23#include <asm/uaccess.h>
24#include <asm/pgalloc.h> 19#include <asm/pgalloc.h>
25#include <asm/mmu_context.h> 20#include <asm/mmu_context.h>
26#include <asm/cacheflush.h> 21#include <asm/cacheflush.h>
27 22
28extern void __flush_cache_4096_all(unsigned long start); 23/*
29static void __flush_cache_4096_all_ex(unsigned long start); 24 * The maximum number of pages we support up to when doing ranged dcache
30extern void __flush_dcache_all(void); 25 * flushing. Anything exceeding this will simply flush the dcache in its
31static void __flush_dcache_all_ex(void); 26 * entirety.
27 */
28#define MAX_DCACHE_PAGES 64 /* XXX: Tune for ways */
29
30static void __flush_dcache_segment_1way(unsigned long start,
31 unsigned long extent);
32static void __flush_dcache_segment_2way(unsigned long start,
33 unsigned long extent);
34static void __flush_dcache_segment_4way(unsigned long start,
35 unsigned long extent);
36
37static void __flush_cache_4096(unsigned long addr, unsigned long phys,
38 unsigned long exec_offset);
39
40/*
41 * This is initialised here to ensure that it is not placed in the BSS. If
42 * that were to happen, note that cache_init gets called before the BSS is
43 * cleared, so this would get nulled out which would be hopeless.
44 */
45static void (*__flush_dcache_segment_fn)(unsigned long, unsigned long) =
46 (void (*)(unsigned long, unsigned long))0xdeadbeef;
47
48static void compute_alias(struct cache_info *c)
49{
50 c->alias_mask = ((c->sets - 1) << c->entry_shift) & ~(PAGE_SIZE - 1);
51 c->n_aliases = (c->alias_mask >> PAGE_SHIFT) + 1;
52}
53
54static void __init emit_cache_params(void)
55{
56 printk("PVR=%08x CVR=%08x PRR=%08x\n",
57 ctrl_inl(CCN_PVR),
58 ctrl_inl(CCN_CVR),
59 ctrl_inl(CCN_PRR));
60 printk("I-cache : n_ways=%d n_sets=%d way_incr=%d\n",
61 cpu_data->icache.ways,
62 cpu_data->icache.sets,
63 cpu_data->icache.way_incr);
64 printk("I-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n",
65 cpu_data->icache.entry_mask,
66 cpu_data->icache.alias_mask,
67 cpu_data->icache.n_aliases);
68 printk("D-cache : n_ways=%d n_sets=%d way_incr=%d\n",
69 cpu_data->dcache.ways,
70 cpu_data->dcache.sets,
71 cpu_data->dcache.way_incr);
72 printk("D-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n",
73 cpu_data->dcache.entry_mask,
74 cpu_data->dcache.alias_mask,
75 cpu_data->dcache.n_aliases);
76
77 if (!__flush_dcache_segment_fn)
78 panic("unknown number of cache ways\n");
79}
32 80
33/* 81/*
34 * SH-4 has virtually indexed and physically tagged cache. 82 * SH-4 has virtually indexed and physically tagged cache.
35 */ 83 */
36 84
37struct semaphore p3map_sem[4]; 85/* Worst case assumed to be 64k cache, direct-mapped i.e. 4 synonym bits. */
86#define MAX_P3_SEMAPHORES 16
87
88struct semaphore p3map_sem[MAX_P3_SEMAPHORES];
38 89
39void __init p3_cache_init(void) 90void __init p3_cache_init(void)
40{ 91{
41 if (remap_area_pages(P3SEG, 0, PAGE_SIZE*4, _PAGE_CACHABLE)) 92 int i;
93
94 compute_alias(&cpu_data->icache);
95 compute_alias(&cpu_data->dcache);
96
97 switch (cpu_data->dcache.ways) {
98 case 1:
99 __flush_dcache_segment_fn = __flush_dcache_segment_1way;
100 break;
101 case 2:
102 __flush_dcache_segment_fn = __flush_dcache_segment_2way;
103 break;
104 case 4:
105 __flush_dcache_segment_fn = __flush_dcache_segment_4way;
106 break;
107 default:
108 __flush_dcache_segment_fn = NULL;
109 break;
110 }
111
112 emit_cache_params();
113
114 if (remap_area_pages(P3SEG, 0, PAGE_SIZE * 4, _PAGE_CACHABLE))
42 panic("%s failed.", __FUNCTION__); 115 panic("%s failed.", __FUNCTION__);
43 116
44 sema_init (&p3map_sem[0], 1); 117 for (i = 0; i < cpu_data->dcache.n_aliases; i++)
45 sema_init (&p3map_sem[1], 1); 118 sema_init(&p3map_sem[i], 1);
46 sema_init (&p3map_sem[2], 1);
47 sema_init (&p3map_sem[3], 1);
48} 119}
49 120
50/* 121/*
@@ -89,7 +160,6 @@ void __flush_purge_region(void *start, int size)
89 } 160 }
90} 161}
91 162
92
93/* 163/*
94 * No write back please 164 * No write back please
95 */ 165 */
@@ -108,40 +178,6 @@ void __flush_invalidate_region(void *start, int size)
108 } 178 }
109} 179}
110 180
111static void __flush_dcache_all_ex(void)
112{
113 unsigned long addr, end_addr, entry_offset;
114
115 end_addr = CACHE_OC_ADDRESS_ARRAY + (cpu_data->dcache.sets << cpu_data->dcache.entry_shift) * cpu_data->dcache.ways;
116 entry_offset = 1 << cpu_data->dcache.entry_shift;
117 for (addr = CACHE_OC_ADDRESS_ARRAY; addr < end_addr; addr += entry_offset) {
118 ctrl_outl(0, addr);
119 }
120}
121
122static void __flush_cache_4096_all_ex(unsigned long start)
123{
124 unsigned long addr, entry_offset;
125 int i;
126
127 entry_offset = 1 << cpu_data->dcache.entry_shift;
128 for (i = 0; i < cpu_data->dcache.ways; i++, start += cpu_data->dcache.way_incr) {
129 for (addr = CACHE_OC_ADDRESS_ARRAY + start;
130 addr < CACHE_OC_ADDRESS_ARRAY + 4096 + start;
131 addr += entry_offset) {
132 ctrl_outl(0, addr);
133 }
134 }
135}
136
137void flush_cache_4096_all(unsigned long start)
138{
139 if (cpu_data->dcache.ways == 1)
140 __flush_cache_4096_all(start);
141 else
142 __flush_cache_4096_all_ex(start);
143}
144
145/* 181/*
146 * Write back the range of D-cache, and purge the I-cache. 182 * Write back the range of D-cache, and purge the I-cache.
147 * 183 *
@@ -153,14 +189,14 @@ void flush_icache_range(unsigned long start, unsigned long end)
153} 189}
154 190
155/* 191/*
156 * Write back the D-cache and purge the I-cache for signal trampoline. 192 * Write back the D-cache and purge the I-cache for signal trampoline.
157 * .. which happens to be the same behavior as flush_icache_range(). 193 * .. which happens to be the same behavior as flush_icache_range().
158 * So, we simply flush out a line. 194 * So, we simply flush out a line.
159 */ 195 */
160void flush_cache_sigtramp(unsigned long addr) 196void flush_cache_sigtramp(unsigned long addr)
161{ 197{
162 unsigned long v, index; 198 unsigned long v, index;
163 unsigned long flags; 199 unsigned long flags;
164 int i; 200 int i;
165 201
166 v = addr & ~(L1_CACHE_BYTES-1); 202 v = addr & ~(L1_CACHE_BYTES-1);
@@ -172,30 +208,33 @@ void flush_cache_sigtramp(unsigned long addr)
172 208
173 local_irq_save(flags); 209 local_irq_save(flags);
174 jump_to_P2(); 210 jump_to_P2();
175 for(i = 0; i < cpu_data->icache.ways; i++, index += cpu_data->icache.way_incr) 211
212 for (i = 0; i < cpu_data->icache.ways;
213 i++, index += cpu_data->icache.way_incr)
176 ctrl_outl(0, index); /* Clear out Valid-bit */ 214 ctrl_outl(0, index); /* Clear out Valid-bit */
215
177 back_to_P1(); 216 back_to_P1();
217 wmb();
178 local_irq_restore(flags); 218 local_irq_restore(flags);
179} 219}
180 220
181static inline void flush_cache_4096(unsigned long start, 221static inline void flush_cache_4096(unsigned long start,
182 unsigned long phys) 222 unsigned long phys)
183{ 223{
184 unsigned long flags; 224 unsigned long flags, exec_offset = 0;
185 extern void __flush_cache_4096(unsigned long addr, unsigned long phys, unsigned long exec_offset);
186 225
187 /* 226 /*
188 * SH7751, SH7751R, and ST40 have no restriction to handle cache. 227 * All types of SH-4 require PC to be in P2 to operate on the I-cache.
189 * (While SH7750 must do that at P2 area.) 228 * Some types of SH-4 require PC to be in P2 to operate on the D-cache.
190 */ 229 */
191 if ((cpu_data->flags & CPU_HAS_P2_FLUSH_BUG) 230 if ((cpu_data->flags & CPU_HAS_P2_FLUSH_BUG) ||
192 || start < CACHE_OC_ADDRESS_ARRAY) { 231 (start < CACHE_OC_ADDRESS_ARRAY))
193 local_irq_save(flags); 232 exec_offset = 0x20000000;
194 __flush_cache_4096(start | SH_CACHE_ASSOC, P1SEGADDR(phys), 0x20000000); 233
195 local_irq_restore(flags); 234 local_irq_save(flags);
196 } else { 235 __flush_cache_4096(start | SH_CACHE_ASSOC,
197 __flush_cache_4096(start | SH_CACHE_ASSOC, P1SEGADDR(phys), 0); 236 P1SEGADDR(phys), exec_offset);
198 } 237 local_irq_restore(flags);
199} 238}
200 239
201/* 240/*
@@ -206,15 +245,19 @@ void flush_dcache_page(struct page *page)
206{ 245{
207 if (test_bit(PG_mapped, &page->flags)) { 246 if (test_bit(PG_mapped, &page->flags)) {
208 unsigned long phys = PHYSADDR(page_address(page)); 247 unsigned long phys = PHYSADDR(page_address(page));
248 unsigned long addr = CACHE_OC_ADDRESS_ARRAY;
249 int i, n;
209 250
210 /* Loop all the D-cache */ 251 /* Loop all the D-cache */
211 flush_cache_4096(CACHE_OC_ADDRESS_ARRAY, phys); 252 n = cpu_data->dcache.n_aliases;
212 flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x1000, phys); 253 for (i = 0; i < n; i++, addr += PAGE_SIZE)
213 flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x2000, phys); 254 flush_cache_4096(addr, phys);
214 flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x3000, phys);
215 } 255 }
256
257 wmb();
216} 258}
217 259
260/* TODO: Selective icache invalidation through IC address array.. */
218static inline void flush_icache_all(void) 261static inline void flush_icache_all(void)
219{ 262{
220 unsigned long flags, ccr; 263 unsigned long flags, ccr;
@@ -227,34 +270,142 @@ static inline void flush_icache_all(void)
227 ccr |= CCR_CACHE_ICI; 270 ccr |= CCR_CACHE_ICI;
228 ctrl_outl(ccr, CCR); 271 ctrl_outl(ccr, CCR);
229 272
273 /*
274 * back_to_P1() will take care of the barrier for us, don't add
275 * another one!
276 */
277
230 back_to_P1(); 278 back_to_P1();
231 local_irq_restore(flags); 279 local_irq_restore(flags);
232} 280}
233 281
282void flush_dcache_all(void)
283{
284 (*__flush_dcache_segment_fn)(0UL, cpu_data->dcache.way_size);
285 wmb();
286}
287
234void flush_cache_all(void) 288void flush_cache_all(void)
235{ 289{
236 if (cpu_data->dcache.ways == 1) 290 flush_dcache_all();
237 __flush_dcache_all();
238 else
239 __flush_dcache_all_ex();
240 flush_icache_all(); 291 flush_icache_all();
241} 292}
242 293
294static void __flush_cache_mm(struct mm_struct *mm, unsigned long start,
295 unsigned long end)
296{
297 unsigned long d = 0, p = start & PAGE_MASK;
298 unsigned long alias_mask = cpu_data->dcache.alias_mask;
299 unsigned long n_aliases = cpu_data->dcache.n_aliases;
300 unsigned long select_bit;
301 unsigned long all_aliases_mask;
302 unsigned long addr_offset;
303 pgd_t *dir;
304 pmd_t *pmd;
305 pud_t *pud;
306 pte_t *pte;
307 int i;
308
309 dir = pgd_offset(mm, p);
310 pud = pud_offset(dir, p);
311 pmd = pmd_offset(pud, p);
312 end = PAGE_ALIGN(end);
313
314 all_aliases_mask = (1 << n_aliases) - 1;
315
316 do {
317 if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) {
318 p &= PMD_MASK;
319 p += PMD_SIZE;
320 pmd++;
321
322 continue;
323 }
324
325 pte = pte_offset_kernel(pmd, p);
326
327 do {
328 unsigned long phys;
329 pte_t entry = *pte;
330
331 if (!(pte_val(entry) & _PAGE_PRESENT)) {
332 pte++;
333 p += PAGE_SIZE;
334 continue;
335 }
336
337 phys = pte_val(entry) & PTE_PHYS_MASK;
338
339 if ((p ^ phys) & alias_mask) {
340 d |= 1 << ((p & alias_mask) >> PAGE_SHIFT);
341 d |= 1 << ((phys & alias_mask) >> PAGE_SHIFT);
342
343 if (d == all_aliases_mask)
344 goto loop_exit;
345 }
346
347 pte++;
348 p += PAGE_SIZE;
349 } while (p < end && ((unsigned long)pte & ~PAGE_MASK));
350 pmd++;
351 } while (p < end);
352
353loop_exit:
354 addr_offset = 0;
355 select_bit = 1;
356
357 for (i = 0; i < n_aliases; i++) {
358 if (d & select_bit) {
359 (*__flush_dcache_segment_fn)(addr_offset, PAGE_SIZE);
360 wmb();
361 }
362
363 select_bit <<= 1;
364 addr_offset += PAGE_SIZE;
365 }
366}
367
368/*
369 * Note : (RPC) since the caches are physically tagged, the only point
370 * of flush_cache_mm for SH-4 is to get rid of aliases from the
371 * D-cache. The assumption elsewhere, e.g. flush_cache_range, is that
372 * lines can stay resident so long as the virtual address they were
373 * accessed with (hence cache set) is in accord with the physical
374 * address (i.e. tag). It's no different here. So I reckon we don't
375 * need to flush the I-cache, since aliases don't matter for that. We
376 * should try that.
377 *
378 * Caller takes mm->mmap_sem.
379 */
243void flush_cache_mm(struct mm_struct *mm) 380void flush_cache_mm(struct mm_struct *mm)
244{ 381{
245 /* Is there any good way? */ 382 /*
246 /* XXX: possibly call flush_cache_range for each vm area */ 383 * If cache is only 4k-per-way, there are never any 'aliases'. Since
247 /* 384 * the cache is physically tagged, the data can just be left in there.
248 * FIXME: Really, the optimal solution here would be able to flush out
249 * individual lines created by the specified context, but this isn't
250 * feasible for a number of architectures (such as MIPS, and some
251 * SPARC) .. is this possible for SuperH?
252 *
253 * In the meantime, we'll just flush all of the caches.. this
254 * seems to be the simplest way to avoid at least a few wasted
255 * cache flushes. -Lethal
256 */ 385 */
257 flush_cache_all(); 386 if (cpu_data->dcache.n_aliases == 0)
387 return;
388
389 /*
390 * Don't bother groveling around the dcache for the VMA ranges
391 * if there are too many PTEs to make it worthwhile.
392 */
393 if (mm->nr_ptes >= MAX_DCACHE_PAGES)
394 flush_dcache_all();
395 else {
396 struct vm_area_struct *vma;
397
398 /*
399 * In this case there are reasonably sized ranges to flush,
400 * iterate through the VMA list and take care of any aliases.
401 */
402 for (vma = mm->mmap; vma; vma = vma->vm_next)
403 __flush_cache_mm(mm, vma->vm_start, vma->vm_end);
404 }
405
406 /* Only touch the icache if one of the VMAs has VM_EXEC set. */
407 if (mm->exec_vm)
408 flush_icache_all();
258} 409}
259 410
260/* 411/*
@@ -263,27 +414,40 @@ void flush_cache_mm(struct mm_struct *mm)
263 * ADDR: Virtual Address (U0 address) 414 * ADDR: Virtual Address (U0 address)
264 * PFN: Physical page number 415 * PFN: Physical page number
265 */ 416 */
266void flush_cache_page(struct vm_area_struct *vma, unsigned long address, unsigned long pfn) 417void flush_cache_page(struct vm_area_struct *vma, unsigned long address,
418 unsigned long pfn)
267{ 419{
268 unsigned long phys = pfn << PAGE_SHIFT; 420 unsigned long phys = pfn << PAGE_SHIFT;
421 unsigned int alias_mask;
422
423 alias_mask = cpu_data->dcache.alias_mask;
269 424
270 /* We only need to flush D-cache when we have alias */ 425 /* We only need to flush D-cache when we have alias */
271 if ((address^phys) & CACHE_ALIAS) { 426 if ((address^phys) & alias_mask) {
272 /* Loop 4K of the D-cache */ 427 /* Loop 4K of the D-cache */
273 flush_cache_4096( 428 flush_cache_4096(
274 CACHE_OC_ADDRESS_ARRAY | (address & CACHE_ALIAS), 429 CACHE_OC_ADDRESS_ARRAY | (address & alias_mask),
275 phys); 430 phys);
276 /* Loop another 4K of the D-cache */ 431 /* Loop another 4K of the D-cache */
277 flush_cache_4096( 432 flush_cache_4096(
278 CACHE_OC_ADDRESS_ARRAY | (phys & CACHE_ALIAS), 433 CACHE_OC_ADDRESS_ARRAY | (phys & alias_mask),
279 phys); 434 phys);
280 } 435 }
281 436
282 if (vma->vm_flags & VM_EXEC) 437 alias_mask = cpu_data->icache.alias_mask;
283 /* Loop 4K (half) of the I-cache */ 438 if (vma->vm_flags & VM_EXEC) {
439 /*
440 * Evict entries from the portion of the cache from which code
441 * may have been executed at this address (virtual). There's
442 * no need to evict from the portion corresponding to the
443 * physical address as for the D-cache, because we know the
444 * kernel has never executed the code through its identity
445 * translation.
446 */
284 flush_cache_4096( 447 flush_cache_4096(
285 CACHE_IC_ADDRESS_ARRAY | (address & 0x1000), 448 CACHE_IC_ADDRESS_ARRAY | (address & alias_mask),
286 phys); 449 phys);
450 }
287} 451}
288 452
289/* 453/*
@@ -298,52 +462,31 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long address, unsigne
298void flush_cache_range(struct vm_area_struct *vma, unsigned long start, 462void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
299 unsigned long end) 463 unsigned long end)
300{ 464{
301 unsigned long p = start & PAGE_MASK; 465 /*
302 pgd_t *dir; 466 * If cache is only 4k-per-way, there are never any 'aliases'. Since
303 pmd_t *pmd; 467 * the cache is physically tagged, the data can just be left in there.
304 pte_t *pte; 468 */
305 pte_t entry; 469 if (cpu_data->dcache.n_aliases == 0)
306 unsigned long phys; 470 return;
307 unsigned long d = 0;
308
309 dir = pgd_offset(vma->vm_mm, p);
310 pmd = pmd_offset(dir, p);
311 471
312 do { 472 /*
313 if (pmd_none(*pmd) || pmd_bad(*pmd)) { 473 * Don't bother with the lookup and alias check if we have a
314 p &= ~((1 << PMD_SHIFT) -1); 474 * wide range to cover, just blow away the dcache in its
315 p += (1 << PMD_SHIFT); 475 * entirety instead. -- PFM.
316 pmd++; 476 */
317 continue; 477 if (((end - start) >> PAGE_SHIFT) >= MAX_DCACHE_PAGES)
318 } 478 flush_dcache_all();
319 pte = pte_offset_kernel(pmd, p); 479 else
320 do { 480 __flush_cache_mm(vma->vm_mm, start, end);
321 entry = *pte; 481
322 if ((pte_val(entry) & _PAGE_PRESENT)) { 482 if (vma->vm_flags & VM_EXEC) {
323 phys = pte_val(entry)&PTE_PHYS_MASK; 483 /*
324 if ((p^phys) & CACHE_ALIAS) { 484 * TODO: Is this required??? Need to look at how I-cache
325 d |= 1 << ((p & CACHE_ALIAS)>>12); 485 * coherency is assured when new programs are loaded to see if
326 d |= 1 << ((phys & CACHE_ALIAS)>>12); 486 * this matters.
327 if (d == 0x0f) 487 */
328 goto loop_exit;
329 }
330 }
331 pte++;
332 p += PAGE_SIZE;
333 } while (p < end && ((unsigned long)pte & ~PAGE_MASK));
334 pmd++;
335 } while (p < end);
336 loop_exit:
337 if (d & 1)
338 flush_cache_4096_all(0);
339 if (d & 2)
340 flush_cache_4096_all(0x1000);
341 if (d & 4)
342 flush_cache_4096_all(0x2000);
343 if (d & 8)
344 flush_cache_4096_all(0x3000);
345 if (vma->vm_flags & VM_EXEC)
346 flush_icache_all(); 488 flush_icache_all();
489 }
347} 490}
348 491
349/* 492/*
@@ -357,5 +500,273 @@ void flush_icache_user_range(struct vm_area_struct *vma,
357 struct page *page, unsigned long addr, int len) 500 struct page *page, unsigned long addr, int len)
358{ 501{
359 flush_cache_page(vma, addr, page_to_pfn(page)); 502 flush_cache_page(vma, addr, page_to_pfn(page));
503 mb();
504}
505
506/**
507 * __flush_cache_4096
508 *
509 * @addr: address in memory mapped cache array
510 * @phys: P1 address to flush (has to match tags if addr has 'A' bit
511 * set i.e. associative write)
512 * @exec_offset: set to 0x20000000 if flush has to be executed from P2
513 * region else 0x0
514 *
515 * The offset into the cache array implied by 'addr' selects the
516 * 'colour' of the virtual address range that will be flushed. The
517 * operation (purge/write-back) is selected by the lower 2 bits of
518 * 'phys'.
519 */
520static void __flush_cache_4096(unsigned long addr, unsigned long phys,
521 unsigned long exec_offset)
522{
523 int way_count;
524 unsigned long base_addr = addr;
525 struct cache_info *dcache;
526 unsigned long way_incr;
527 unsigned long a, ea, p;
528 unsigned long temp_pc;
529
530 dcache = &cpu_data->dcache;
531 /* Write this way for better assembly. */
532 way_count = dcache->ways;
533 way_incr = dcache->way_incr;
534
535 /*
536 * Apply exec_offset (i.e. branch to P2 if required.).
537 *
538 * FIXME:
539 *
540 * If I write "=r" for the (temp_pc), it puts this in r6 hence
541 * trashing exec_offset before it's been added on - why? Hence
542 * "=&r" as a 'workaround'
543 */
544 asm volatile("mov.l 1f, %0\n\t"
545 "add %1, %0\n\t"
546 "jmp @%0\n\t"
547 "nop\n\t"
548 ".balign 4\n\t"
549 "1: .long 2f\n\t"
550 "2:\n" : "=&r" (temp_pc) : "r" (exec_offset));
551
552 /*
553 * We know there will be >=1 iteration, so write as do-while to avoid
554 * pointless nead-of-loop check for 0 iterations.
555 */
556 do {
557 ea = base_addr + PAGE_SIZE;
558 a = base_addr;
559 p = phys;
560
561 do {
562 *(volatile unsigned long *)a = p;
563 /*
564 * Next line: intentionally not p+32, saves an add, p
565 * will do since only the cache tag bits need to
566 * match.
567 */
568 *(volatile unsigned long *)(a+32) = p;
569 a += 64;
570 p += 64;
571 } while (a < ea);
572
573 base_addr += way_incr;
574 } while (--way_count != 0);
360} 575}
361 576
577/*
578 * Break the 1, 2 and 4 way variants of this out into separate functions to
579 * avoid nearly all the overhead of having the conditional stuff in the function
580 * bodies (+ the 1 and 2 way cases avoid saving any registers too).
581 */
582static void __flush_dcache_segment_1way(unsigned long start,
583 unsigned long extent_per_way)
584{
585 unsigned long orig_sr, sr_with_bl;
586 unsigned long base_addr;
587 unsigned long way_incr, linesz, way_size;
588 struct cache_info *dcache;
589 register unsigned long a0, a0e;
590
591 asm volatile("stc sr, %0" : "=r" (orig_sr));
592 sr_with_bl = orig_sr | (1<<28);
593 base_addr = ((unsigned long)&empty_zero_page[0]);
594
595 /*
596 * The previous code aligned base_addr to 16k, i.e. the way_size of all
597 * existing SH-4 D-caches. Whilst I don't see a need to have this
598 * aligned to any better than the cache line size (which it will be
599 * anyway by construction), let's align it to at least the way_size of
600 * any existing or conceivable SH-4 D-cache. -- RPC
601 */
602 base_addr = ((base_addr >> 16) << 16);
603 base_addr |= start;
604
605 dcache = &cpu_data->dcache;
606 linesz = dcache->linesz;
607 way_incr = dcache->way_incr;
608 way_size = dcache->way_size;
609
610 a0 = base_addr;
611 a0e = base_addr + extent_per_way;
612 do {
613 asm volatile("ldc %0, sr" : : "r" (sr_with_bl));
614 asm volatile("movca.l r0, @%0\n\t"
615 "ocbi @%0" : : "r" (a0));
616 a0 += linesz;
617 asm volatile("movca.l r0, @%0\n\t"
618 "ocbi @%0" : : "r" (a0));
619 a0 += linesz;
620 asm volatile("movca.l r0, @%0\n\t"
621 "ocbi @%0" : : "r" (a0));
622 a0 += linesz;
623 asm volatile("movca.l r0, @%0\n\t"
624 "ocbi @%0" : : "r" (a0));
625 asm volatile("ldc %0, sr" : : "r" (orig_sr));
626 a0 += linesz;
627 } while (a0 < a0e);
628}
629
630static void __flush_dcache_segment_2way(unsigned long start,
631 unsigned long extent_per_way)
632{
633 unsigned long orig_sr, sr_with_bl;
634 unsigned long base_addr;
635 unsigned long way_incr, linesz, way_size;
636 struct cache_info *dcache;
637 register unsigned long a0, a1, a0e;
638
639 asm volatile("stc sr, %0" : "=r" (orig_sr));
640 sr_with_bl = orig_sr | (1<<28);
641 base_addr = ((unsigned long)&empty_zero_page[0]);
642
643 /* See comment under 1-way above */
644 base_addr = ((base_addr >> 16) << 16);
645 base_addr |= start;
646
647 dcache = &cpu_data->dcache;
648 linesz = dcache->linesz;
649 way_incr = dcache->way_incr;
650 way_size = dcache->way_size;
651
652 a0 = base_addr;
653 a1 = a0 + way_incr;
654 a0e = base_addr + extent_per_way;
655 do {
656 asm volatile("ldc %0, sr" : : "r" (sr_with_bl));
657 asm volatile("movca.l r0, @%0\n\t"
658 "movca.l r0, @%1\n\t"
659 "ocbi @%0\n\t"
660 "ocbi @%1" : :
661 "r" (a0), "r" (a1));
662 a0 += linesz;
663 a1 += linesz;
664 asm volatile("movca.l r0, @%0\n\t"
665 "movca.l r0, @%1\n\t"
666 "ocbi @%0\n\t"
667 "ocbi @%1" : :
668 "r" (a0), "r" (a1));
669 a0 += linesz;
670 a1 += linesz;
671 asm volatile("movca.l r0, @%0\n\t"
672 "movca.l r0, @%1\n\t"
673 "ocbi @%0\n\t"
674 "ocbi @%1" : :
675 "r" (a0), "r" (a1));
676 a0 += linesz;
677 a1 += linesz;
678 asm volatile("movca.l r0, @%0\n\t"
679 "movca.l r0, @%1\n\t"
680 "ocbi @%0\n\t"
681 "ocbi @%1" : :
682 "r" (a0), "r" (a1));
683 asm volatile("ldc %0, sr" : : "r" (orig_sr));
684 a0 += linesz;
685 a1 += linesz;
686 } while (a0 < a0e);
687}
688
689static void __flush_dcache_segment_4way(unsigned long start,
690 unsigned long extent_per_way)
691{
692 unsigned long orig_sr, sr_with_bl;
693 unsigned long base_addr;
694 unsigned long way_incr, linesz, way_size;
695 struct cache_info *dcache;
696 register unsigned long a0, a1, a2, a3, a0e;
697
698 asm volatile("stc sr, %0" : "=r" (orig_sr));
699 sr_with_bl = orig_sr | (1<<28);
700 base_addr = ((unsigned long)&empty_zero_page[0]);
701
702 /* See comment under 1-way above */
703 base_addr = ((base_addr >> 16) << 16);
704 base_addr |= start;
705
706 dcache = &cpu_data->dcache;
707 linesz = dcache->linesz;
708 way_incr = dcache->way_incr;
709 way_size = dcache->way_size;
710
711 a0 = base_addr;
712 a1 = a0 + way_incr;
713 a2 = a1 + way_incr;
714 a3 = a2 + way_incr;
715 a0e = base_addr + extent_per_way;
716 do {
717 asm volatile("ldc %0, sr" : : "r" (sr_with_bl));
718 asm volatile("movca.l r0, @%0\n\t"
719 "movca.l r0, @%1\n\t"
720 "movca.l r0, @%2\n\t"
721 "movca.l r0, @%3\n\t"
722 "ocbi @%0\n\t"
723 "ocbi @%1\n\t"
724 "ocbi @%2\n\t"
725 "ocbi @%3\n\t" : :
726 "r" (a0), "r" (a1), "r" (a2), "r" (a3));
727 a0 += linesz;
728 a1 += linesz;
729 a2 += linesz;
730 a3 += linesz;
731 asm volatile("movca.l r0, @%0\n\t"
732 "movca.l r0, @%1\n\t"
733 "movca.l r0, @%2\n\t"
734 "movca.l r0, @%3\n\t"
735 "ocbi @%0\n\t"
736 "ocbi @%1\n\t"
737 "ocbi @%2\n\t"
738 "ocbi @%3\n\t" : :
739 "r" (a0), "r" (a1), "r" (a2), "r" (a3));
740 a0 += linesz;
741 a1 += linesz;
742 a2 += linesz;
743 a3 += linesz;
744 asm volatile("movca.l r0, @%0\n\t"
745 "movca.l r0, @%1\n\t"
746 "movca.l r0, @%2\n\t"
747 "movca.l r0, @%3\n\t"
748 "ocbi @%0\n\t"
749 "ocbi @%1\n\t"
750 "ocbi @%2\n\t"
751 "ocbi @%3\n\t" : :
752 "r" (a0), "r" (a1), "r" (a2), "r" (a3));
753 a0 += linesz;
754 a1 += linesz;
755 a2 += linesz;
756 a3 += linesz;
757 asm volatile("movca.l r0, @%0\n\t"
758 "movca.l r0, @%1\n\t"
759 "movca.l r0, @%2\n\t"
760 "movca.l r0, @%3\n\t"
761 "ocbi @%0\n\t"
762 "ocbi @%1\n\t"
763 "ocbi @%2\n\t"
764 "ocbi @%3\n\t" : :
765 "r" (a0), "r" (a1), "r" (a2), "r" (a3));
766 asm volatile("ldc %0, sr" : : "r" (orig_sr));
767 a0 += linesz;
768 a1 += linesz;
769 a2 += linesz;
770 a3 += linesz;
771 } while (a0 < a0e);
772}
diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c
index bf94eedb0a8e..045abdf078f5 100644
--- a/arch/sh/mm/cache-sh7705.c
+++ b/arch/sh/mm/cache-sh7705.c
@@ -9,7 +9,6 @@
9 * for more details. 9 * for more details.
10 * 10 *
11 */ 11 */
12
13#include <linux/init.h> 12#include <linux/init.h>
14#include <linux/mman.h> 13#include <linux/mman.h>
15#include <linux/mm.h> 14#include <linux/mm.h>
@@ -25,14 +24,10 @@
25#include <asm/mmu_context.h> 24#include <asm/mmu_context.h>
26#include <asm/cacheflush.h> 25#include <asm/cacheflush.h>
27 26
28/* The 32KB cache on the SH7705 suffers from the same synonym problem 27/*
29 * as SH4 CPUs */ 28 * The 32KB cache on the SH7705 suffers from the same synonym problem
30 29 * as SH4 CPUs
31#define __pte_offset(address) \ 30 */
32 ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
33#define pte_offset(dir, address) ((pte_t *) pmd_page_vaddr(*(dir)) + \
34 __pte_offset(address))
35
36static inline void cache_wback_all(void) 31static inline void cache_wback_all(void)
37{ 32{
38 unsigned long ways, waysize, addrstart; 33 unsigned long ways, waysize, addrstart;
@@ -73,7 +68,6 @@ void flush_icache_range(unsigned long start, unsigned long end)
73 __flush_wback_region((void *)start, end - start); 68 __flush_wback_region((void *)start, end - start);
74} 69}
75 70
76
77/* 71/*
78 * Writeback&Invalidate the D-cache of the page 72 * Writeback&Invalidate the D-cache of the page
79 */ 73 */
@@ -128,7 +122,6 @@ static void __flush_dcache_page(unsigned long phys)
128 local_irq_restore(flags); 122 local_irq_restore(flags);
129} 123}
130 124
131
132/* 125/*
133 * Write back & invalidate the D-cache of the page. 126 * Write back & invalidate the D-cache of the page.
134 * (To avoid "alias" issues) 127 * (To avoid "alias" issues)
@@ -186,7 +179,8 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
186 * 179 *
187 * ADDRESS: Virtual Address (U0 address) 180 * ADDRESS: Virtual Address (U0 address)
188 */ 181 */
189void flush_cache_page(struct vm_area_struct *vma, unsigned long address, unsigned long pfn) 182void flush_cache_page(struct vm_area_struct *vma, unsigned long address,
183 unsigned long pfn)
190{ 184{
191 __flush_dcache_page(pfn << PAGE_SHIFT); 185 __flush_dcache_page(pfn << PAGE_SHIFT);
192} 186}
@@ -203,4 +197,3 @@ void flush_icache_page(struct vm_area_struct *vma, struct page *page)
203{ 197{
204 __flush_purge_region(page_address(page), PAGE_SIZE); 198 __flush_purge_region(page_address(page), PAGE_SIZE);
205} 199}
206
diff --git a/arch/sh/mm/clear_page.S b/arch/sh/mm/clear_page.S
index 08acead7b2a1..7b96425ae270 100644
--- a/arch/sh/mm/clear_page.S
+++ b/arch/sh/mm/clear_page.S
@@ -193,102 +193,5 @@ ENTRY(__clear_user_page)
193 nop 193 nop
194.L4096: .word 4096 194.L4096: .word 4096
195 195
196ENTRY(__flush_cache_4096)
197 mov.l 1f,r3
198 add r6,r3
199 mov r4,r0
200 mov #64,r2
201 shll r2
202 mov #64,r6
203 jmp @r3
204 mov #96,r7
205 .align 2
2061: .long 2f
2072:
208 .rept 32
209 mov.l r5,@r0
210 mov.l r5,@(32,r0)
211 mov.l r5,@(r0,r6)
212 mov.l r5,@(r0,r7)
213 add r2,r5
214 add r2,r0
215 .endr
216 nop
217 nop
218 nop
219 nop
220 nop
221 nop
222 nop
223 rts
224 nop
225
226ENTRY(__flush_dcache_all)
227 mov.l 2f,r0
228 mov.l 3f,r4
229 and r0,r4 ! r4 = (unsigned long)&empty_zero_page[0] & ~0xffffc000
230 stc sr,r1 ! save SR
231 mov.l 4f,r2
232 or r1,r2
233 mov #32,r3
234 shll2 r3
2351:
236 ldc r2,sr ! set BL bit
237 movca.l r0,@r4
238 ocbi @r4
239 add #32,r4
240 movca.l r0,@r4
241 ocbi @r4
242 add #32,r4
243 movca.l r0,@r4
244 ocbi @r4
245 add #32,r4
246 movca.l r0,@r4
247 ocbi @r4
248 ldc r1,sr ! restore SR
249 dt r3
250 bf/s 1b
251 add #32,r4
252
253 rts
254 nop
255 .align 2
2562: .long 0xffffc000
2573: .long empty_zero_page
2584: .long 0x10000000 ! BL bit
259
260/* __flush_cache_4096_all(unsigned long addr) */
261ENTRY(__flush_cache_4096_all)
262 mov.l 2f,r0
263 mov.l 3f,r2
264 and r0,r2
265 or r2,r4 ! r4 = addr | (unsigned long)&empty_zero_page[0] & ~0x3fff
266 stc sr,r1 ! save SR
267 mov.l 4f,r2
268 or r1,r2
269 mov #32,r3
2701:
271 ldc r2,sr ! set BL bit
272 movca.l r0,@r4
273 ocbi @r4
274 add #32,r4
275 movca.l r0,@r4
276 ocbi @r4
277 add #32,r4
278 movca.l r0,@r4
279 ocbi @r4
280 add #32,r4
281 movca.l r0,@r4
282 ocbi @r4
283 ldc r1,sr ! restore SR
284 dt r3
285 bf/s 1b
286 add #32,r4
287
288 rts
289 nop
290 .align 2
2912: .long 0xffffc000
2923: .long empty_zero_page
2934: .long 0x10000000 ! BL bit
294#endif 196#endif
197
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
index ee73e30263af..c81e6b67ad30 100644
--- a/arch/sh/mm/consistent.c
+++ b/arch/sh/mm/consistent.c
@@ -9,6 +9,8 @@
9 */ 9 */
10#include <linux/mm.h> 10#include <linux/mm.h>
11#include <linux/dma-mapping.h> 11#include <linux/dma-mapping.h>
12#include <asm/cacheflush.h>
13#include <asm/addrspace.h>
12#include <asm/io.h> 14#include <asm/io.h>
13 15
14void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *handle) 16void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *handle)
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c
index 775f86cd3fe8..c69fd603226a 100644
--- a/arch/sh/mm/fault.c
+++ b/arch/sh/mm/fault.c
@@ -1,33 +1,22 @@
1/* $Id: fault.c,v 1.14 2004/01/13 05:52:11 kkojima Exp $ 1/*
2 * Page fault handler for SH with an MMU.
2 * 3 *
3 * linux/arch/sh/mm/fault.c
4 * Copyright (C) 1999 Niibe Yutaka 4 * Copyright (C) 1999 Niibe Yutaka
5 * Copyright (C) 2003 Paul Mundt 5 * Copyright (C) 2003 Paul Mundt
6 * 6 *
7 * Based on linux/arch/i386/mm/fault.c: 7 * Based on linux/arch/i386/mm/fault.c:
8 * Copyright (C) 1995 Linus Torvalds 8 * Copyright (C) 1995 Linus Torvalds
9 *
10 * This file is subject to the terms and conditions of the GNU General Public
11 * License. See the file "COPYING" in the main directory of this archive
12 * for more details.
9 */ 13 */
10
11#include <linux/signal.h>
12#include <linux/sched.h>
13#include <linux/kernel.h> 14#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> 15#include <linux/mm.h>
20#include <linux/smp.h> 16#include <linux/hardirq.h>
21#include <linux/smp_lock.h> 17#include <linux/kprobes.h>
22#include <linux/interrupt.h>
23#include <linux/module.h>
24
25#include <asm/system.h> 18#include <asm/system.h>
26#include <asm/io.h>
27#include <asm/uaccess.h>
28#include <asm/pgalloc.h>
29#include <asm/mmu_context.h> 19#include <asm/mmu_context.h>
30#include <asm/cacheflush.h>
31#include <asm/kgdb.h> 20#include <asm/kgdb.h>
32 21
33extern void die(const char *,struct pt_regs *,long); 22extern void die(const char *,struct pt_regs *,long);
@@ -187,18 +176,30 @@ do_sigbus:
187 goto no_context; 176 goto no_context;
188} 177}
189 178
179#ifdef CONFIG_SH_STORE_QUEUES
190/* 180/*
191 * Called with interrupt disabled. 181 * This is a special case for the SH-4 store queues, as pages for this
182 * space still need to be faulted in before it's possible to flush the
183 * store queue cache for writeout to the remapped region.
192 */ 184 */
193asmlinkage int __do_page_fault(struct pt_regs *regs, unsigned long writeaccess, 185#define P3_ADDR_MAX (P4SEG_STORE_QUE + 0x04000000)
194 unsigned long address) 186#else
187#define P3_ADDR_MAX P4SEG
188#endif
189
190/*
191 * Called with interrupts disabled.
192 */
193asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs,
194 unsigned long writeaccess,
195 unsigned long address)
195{ 196{
196 unsigned long addrmax = P4SEG;
197 pgd_t *pgd; 197 pgd_t *pgd;
198 pud_t *pud;
198 pmd_t *pmd; 199 pmd_t *pmd;
199 pte_t *pte; 200 pte_t *pte;
200 pte_t entry; 201 pte_t entry;
201 struct mm_struct *mm; 202 struct mm_struct *mm = current->mm;
202 spinlock_t *ptl; 203 spinlock_t *ptl;
203 int ret = 1; 204 int ret = 1;
204 205
@@ -207,31 +208,37 @@ asmlinkage int __do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
207 kgdb_bus_err_hook(); 208 kgdb_bus_err_hook();
208#endif 209#endif
209 210
210#ifdef CONFIG_SH_STORE_QUEUES 211 /*
211 addrmax = P4SEG_STORE_QUE + 0x04000000; 212 * We don't take page faults for P1, P2, and parts of P4, these
212#endif 213 * are always mapped, whether it be due to legacy behaviour in
213 214 * 29-bit mode, or due to PMB configuration in 32-bit mode.
214 if (address >= P3SEG && address < addrmax) { 215 */
216 if (address >= P3SEG && address < P3_ADDR_MAX) {
215 pgd = pgd_offset_k(address); 217 pgd = pgd_offset_k(address);
216 mm = NULL; 218 mm = NULL;
217 } else if (address >= TASK_SIZE) 219 } else {
218 return 1; 220 if (unlikely(address >= TASK_SIZE || !mm))
219 else if (!(mm = current->mm)) 221 return 1;
220 return 1; 222
221 else
222 pgd = pgd_offset(mm, address); 223 pgd = pgd_offset(mm, address);
224 }
223 225
224 pmd = pmd_offset(pgd, address); 226 pud = pud_offset(pgd, address);
227 if (pud_none_or_clear_bad(pud))
228 return 1;
229 pmd = pmd_offset(pud, address);
225 if (pmd_none_or_clear_bad(pmd)) 230 if (pmd_none_or_clear_bad(pmd))
226 return 1; 231 return 1;
232
227 if (mm) 233 if (mm)
228 pte = pte_offset_map_lock(mm, pmd, address, &ptl); 234 pte = pte_offset_map_lock(mm, pmd, address, &ptl);
229 else 235 else
230 pte = pte_offset_kernel(pmd, address); 236 pte = pte_offset_kernel(pmd, address);
231 237
232 entry = *pte; 238 entry = *pte;
233 if (pte_none(entry) || pte_not_present(entry) 239 if (unlikely(pte_none(entry) || pte_not_present(entry)))
234 || (writeaccess && !pte_write(entry))) 240 goto unlock;
241 if (unlikely(writeaccess && !pte_write(entry)))
235 goto unlock; 242 goto unlock;
236 243
237 if (writeaccess) 244 if (writeaccess)
@@ -243,13 +250,7 @@ asmlinkage int __do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
243 * ITLB is not affected by "ldtlb" instruction. 250 * ITLB is not affected by "ldtlb" instruction.
244 * So, we need to flush the entry by ourselves. 251 * So, we need to flush the entry by ourselves.
245 */ 252 */
246 253 __flush_tlb_page(get_asid(), address & PAGE_MASK);
247 {
248 unsigned long flags;
249 local_irq_save(flags);
250 __flush_tlb_page(get_asid(), address&PAGE_MASK);
251 local_irq_restore(flags);
252 }
253#endif 254#endif
254 255
255 set_pte(pte, entry); 256 set_pte(pte, entry);
@@ -260,121 +261,3 @@ unlock:
260 pte_unmap_unlock(pte, ptl); 261 pte_unmap_unlock(pte, ptl);
261 return ret; 262 return ret;
262} 263}
263
264void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
265{
266 if (vma->vm_mm && vma->vm_mm->context != NO_CONTEXT) {
267 unsigned long flags;
268 unsigned long asid;
269 unsigned long saved_asid = MMU_NO_ASID;
270
271 asid = vma->vm_mm->context & MMU_CONTEXT_ASID_MASK;
272 page &= PAGE_MASK;
273
274 local_irq_save(flags);
275 if (vma->vm_mm != current->mm) {
276 saved_asid = get_asid();
277 set_asid(asid);
278 }
279 __flush_tlb_page(asid, page);
280 if (saved_asid != MMU_NO_ASID)
281 set_asid(saved_asid);
282 local_irq_restore(flags);
283 }
284}
285
286void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
287 unsigned long end)
288{
289 struct mm_struct *mm = vma->vm_mm;
290
291 if (mm->context != NO_CONTEXT) {
292 unsigned long flags;
293 int size;
294
295 local_irq_save(flags);
296 size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
297 if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
298 mm->context = NO_CONTEXT;
299 if (mm == current->mm)
300 activate_context(mm);
301 } else {
302 unsigned long asid = mm->context&MMU_CONTEXT_ASID_MASK;
303 unsigned long saved_asid = MMU_NO_ASID;
304
305 start &= PAGE_MASK;
306 end += (PAGE_SIZE - 1);
307 end &= PAGE_MASK;
308 if (mm != current->mm) {
309 saved_asid = get_asid();
310 set_asid(asid);
311 }
312 while (start < end) {
313 __flush_tlb_page(asid, start);
314 start += PAGE_SIZE;
315 }
316 if (saved_asid != MMU_NO_ASID)
317 set_asid(saved_asid);
318 }
319 local_irq_restore(flags);
320 }
321}
322
323void flush_tlb_kernel_range(unsigned long start, unsigned long end)
324{
325 unsigned long flags;
326 int size;
327
328 local_irq_save(flags);
329 size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
330 if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
331 flush_tlb_all();
332 } else {
333 unsigned long asid = init_mm.context&MMU_CONTEXT_ASID_MASK;
334 unsigned long saved_asid = get_asid();
335
336 start &= PAGE_MASK;
337 end += (PAGE_SIZE - 1);
338 end &= PAGE_MASK;
339 set_asid(asid);
340 while (start < end) {
341 __flush_tlb_page(asid, start);
342 start += PAGE_SIZE;
343 }
344 set_asid(saved_asid);
345 }
346 local_irq_restore(flags);
347}
348
349void flush_tlb_mm(struct mm_struct *mm)
350{
351 /* Invalidate all TLB of this process. */
352 /* Instead of invalidating each TLB, we get new MMU context. */
353 if (mm->context != NO_CONTEXT) {
354 unsigned long flags;
355
356 local_irq_save(flags);
357 mm->context = NO_CONTEXT;
358 if (mm == current->mm)
359 activate_context(mm);
360 local_irq_restore(flags);
361 }
362}
363
364void flush_tlb_all(void)
365{
366 unsigned long flags, status;
367
368 /*
369 * Flush all the TLB.
370 *
371 * Write to the MMU control register's bit:
372 * TF-bit for SH-3, TI-bit for SH-4.
373 * It's same position, bit #2.
374 */
375 local_irq_save(flags);
376 status = ctrl_inl(MMUCR);
377 status |= 0x04;
378 ctrl_outl(status, MMUCR);
379 local_irq_restore(flags);
380}
diff --git a/arch/sh/mm/hugetlbpage.c b/arch/sh/mm/hugetlbpage.c
index 2a85bc15a412..329059d6b54a 100644
--- a/arch/sh/mm/hugetlbpage.c
+++ b/arch/sh/mm/hugetlbpage.c
@@ -26,61 +26,41 @@
26pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) 26pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
27{ 27{
28 pgd_t *pgd; 28 pgd_t *pgd;
29 pud_t *pud;
29 pmd_t *pmd; 30 pmd_t *pmd;
30 pte_t *pte = NULL; 31 pte_t *pte = NULL;
31 32
32 pgd = pgd_offset(mm, addr); 33 pgd = pgd_offset(mm, addr);
33 if (pgd) { 34 if (pgd) {
34 pmd = pmd_alloc(mm, pgd, addr); 35 pud = pud_alloc(mm, pgd, addr);
35 if (pmd) 36 if (pud) {
36 pte = pte_alloc_map(mm, pmd, addr); 37 pmd = pmd_alloc(mm, pud, addr);
38 if (pmd)
39 pte = pte_alloc_map(mm, pmd, addr);
40 }
37 } 41 }
42
38 return pte; 43 return pte;
39} 44}
40 45
41pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) 46pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
42{ 47{
43 pgd_t *pgd; 48 pgd_t *pgd;
49 pud_t *pud;
44 pmd_t *pmd; 50 pmd_t *pmd;
45 pte_t *pte = NULL; 51 pte_t *pte = NULL;
46 52
47 pgd = pgd_offset(mm, addr); 53 pgd = pgd_offset(mm, addr);
48 if (pgd) { 54 if (pgd) {
49 pmd = pmd_offset(pgd, addr); 55 pud = pud_offset(pgd, addr);
50 if (pmd) 56 if (pud) {
51 pte = pte_offset_map(pmd, addr); 57 pmd = pmd_offset(pud, addr);
52 } 58 if (pmd)
53 return pte; 59 pte = pte_offset_map(pmd, addr);
54} 60 }
55
56void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
57 pte_t *ptep, pte_t entry)
58{
59 int i;
60
61 for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
62 set_pte_at(mm, addr, ptep, entry);
63 ptep++;
64 addr += PAGE_SIZE;
65 pte_val(entry) += PAGE_SIZE;
66 } 61 }
67}
68
69pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
70 pte_t *ptep)
71{
72 pte_t entry;
73 int i;
74
75 entry = *ptep;
76 62
77 for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { 63 return pte;
78 pte_clear(mm, addr, ptep);
79 addr += PAGE_SIZE;
80 ptep++;
81 }
82
83 return entry;
84} 64}
85 65
86struct page *follow_huge_addr(struct mm_struct *mm, 66struct page *follow_huge_addr(struct mm_struct *mm,
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index 8ea27ca4b700..7154d1ce9785 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -24,7 +24,7 @@
24#include <linux/highmem.h> 24#include <linux/highmem.h>
25#include <linux/bootmem.h> 25#include <linux/bootmem.h>
26#include <linux/pagemap.h> 26#include <linux/pagemap.h>
27 27#include <linux/proc_fs.h>
28#include <asm/processor.h> 28#include <asm/processor.h>
29#include <asm/system.h> 29#include <asm/system.h>
30#include <asm/uaccess.h> 30#include <asm/uaccess.h>
@@ -80,6 +80,7 @@ void show_mem(void)
80static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot) 80static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
81{ 81{
82 pgd_t *pgd; 82 pgd_t *pgd;
83 pud_t *pud;
83 pmd_t *pmd; 84 pmd_t *pmd;
84 pte_t *pte; 85 pte_t *pte;
85 86
@@ -89,7 +90,17 @@ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
89 return; 90 return;
90 } 91 }
91 92
92 pmd = pmd_offset(pgd, addr); 93 pud = pud_offset(pgd, addr);
94 if (pud_none(*pud)) {
95 pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC);
96 set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE | _PAGE_USER));
97 if (pmd != pmd_offset(pud, 0)) {
98 pud_ERROR(*pud);
99 return;
100 }
101 }
102
103 pmd = pmd_offset(pud, addr);
93 if (pmd_none(*pmd)) { 104 if (pmd_none(*pmd)) {
94 pte = (pte_t *)get_zeroed_page(GFP_ATOMIC); 105 pte = (pte_t *)get_zeroed_page(GFP_ATOMIC);
95 set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE | _PAGE_USER)); 106 set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE | _PAGE_USER));
@@ -212,6 +223,8 @@ void __init paging_init(void)
212 free_area_init_node(0, NODE_DATA(0), zones_size, __MEMORY_START >> PAGE_SHIFT, 0); 223 free_area_init_node(0, NODE_DATA(0), zones_size, __MEMORY_START >> PAGE_SHIFT, 0);
213} 224}
214 225
226static struct kcore_list kcore_mem, kcore_vmalloc;
227
215void __init mem_init(void) 228void __init mem_init(void)
216{ 229{
217 extern unsigned long empty_zero_page[1024]; 230 extern unsigned long empty_zero_page[1024];
@@ -237,8 +250,13 @@ void __init mem_init(void)
237 * Setup wrappers for copy/clear_page(), these will get overridden 250 * Setup wrappers for copy/clear_page(), these will get overridden
238 * later in the boot process if a better method is available. 251 * later in the boot process if a better method is available.
239 */ 252 */
253#ifdef CONFIG_MMU
240 copy_page = copy_page_slow; 254 copy_page = copy_page_slow;
241 clear_page = clear_page_slow; 255 clear_page = clear_page_slow;
256#else
257 copy_page = copy_page_nommu;
258 clear_page = clear_page_nommu;
259#endif
242 260
243 /* this will put all low memory onto the freelists */ 261 /* this will put all low memory onto the freelists */
244 totalram_pages += free_all_bootmem_node(NODE_DATA(0)); 262 totalram_pages += free_all_bootmem_node(NODE_DATA(0));
@@ -254,7 +272,12 @@ void __init mem_init(void)
254 datasize = (unsigned long) &_edata - (unsigned long) &_etext; 272 datasize = (unsigned long) &_edata - (unsigned long) &_etext;
255 initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; 273 initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
256 274
257 printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n", 275 kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT);
276 kclist_add(&kcore_vmalloc, (void *)VMALLOC_START,
277 VMALLOC_END - VMALLOC_START);
278
279 printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
280 "%dk reserved, %dk data, %dk init)\n",
258 (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), 281 (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
259 max_mapnr << (PAGE_SHIFT-10), 282 max_mapnr << (PAGE_SHIFT-10),
260 codesize >> 10, 283 codesize >> 10,
@@ -263,6 +286,9 @@ void __init mem_init(void)
263 initsize >> 10); 286 initsize >> 10);
264 287
265 p3_cache_init(); 288 p3_cache_init();
289
290 /* Initialize the vDSO */
291 vsyscall_init();
266} 292}
267 293
268void free_initmem(void) 294void free_initmem(void)
diff --git a/arch/sh/mm/ioremap.c b/arch/sh/mm/ioremap.c
index 96fa4a999e2a..a9fe80cfc233 100644
--- a/arch/sh/mm/ioremap.c
+++ b/arch/sh/mm/ioremap.c
@@ -15,6 +15,7 @@
15#include <linux/vmalloc.h> 15#include <linux/vmalloc.h>
16#include <linux/module.h> 16#include <linux/module.h>
17#include <linux/mm.h> 17#include <linux/mm.h>
18#include <linux/pci.h>
18#include <asm/io.h> 19#include <asm/io.h>
19#include <asm/page.h> 20#include <asm/page.h>
20#include <asm/pgalloc.h> 21#include <asm/pgalloc.h>
@@ -135,6 +136,20 @@ void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
135 return (void __iomem *)phys_to_virt(phys_addr); 136 return (void __iomem *)phys_to_virt(phys_addr);
136 137
137 /* 138 /*
139 * If we're on an SH7751 or SH7780 PCI controller, PCI memory is
140 * mapped at the end of the address space (typically 0xfd000000)
141 * in a non-translatable area, so mapping through page tables for
142 * this area is not only pointless, but also fundamentally
143 * broken. Just return the physical address instead.
144 *
145 * For boards that map a small PCI memory aperture somewhere in
146 * P1/P2 space, ioremap() will already do the right thing,
147 * and we'll never get this far.
148 */
149 if (is_pci_memaddr(phys_addr) && is_pci_memaddr(last_addr))
150 return (void __iomem *)phys_addr;
151
152 /*
138 * Don't allow anybody to remap normal RAM that we're using.. 153 * Don't allow anybody to remap normal RAM that we're using..
139 */ 154 */
140 if (phys_addr < virt_to_phys(high_memory)) 155 if (phys_addr < virt_to_phys(high_memory))
@@ -192,7 +207,7 @@ void __iounmap(void __iomem *addr)
192 unsigned long vaddr = (unsigned long __force)addr; 207 unsigned long vaddr = (unsigned long __force)addr;
193 struct vm_struct *p; 208 struct vm_struct *p;
194 209
195 if (PXSEG(vaddr) < P3SEG) 210 if (PXSEG(vaddr) < P3SEG || is_pci_memaddr(vaddr))
196 return; 211 return;
197 212
198#ifdef CONFIG_32BIT 213#ifdef CONFIG_32BIT
diff --git a/arch/sh/mm/pg-nommu.c b/arch/sh/mm/pg-nommu.c
index 8f9165a4e333..d15221beaa16 100644
--- a/arch/sh/mm/pg-nommu.c
+++ b/arch/sh/mm/pg-nommu.c
@@ -14,23 +14,24 @@
14#include <linux/string.h> 14#include <linux/string.h>
15#include <asm/page.h> 15#include <asm/page.h>
16 16
17static void copy_page_nommu(void *to, void *from) 17void copy_page_nommu(void *to, void *from)
18{ 18{
19 memcpy(to, from, PAGE_SIZE); 19 memcpy(to, from, PAGE_SIZE);
20} 20}
21 21
22static void clear_page_nommu(void *to) 22void clear_page_nommu(void *to)
23{ 23{
24 memset(to, 0, PAGE_SIZE); 24 memset(to, 0, PAGE_SIZE);
25} 25}
26 26
27static int __init pg_nommu_init(void) 27__kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n)
28{ 28{
29 copy_page = copy_page_nommu; 29 memcpy(to, from, n);
30 clear_page = clear_page_nommu;
31
32 return 0; 30 return 0;
33} 31}
34 32
35subsys_initcall(pg_nommu_init); 33__kernel_size_t __clear_user(void *to, __kernel_size_t n)
36 34{
35 memset(to, 0, n);
36 return 0;
37}
diff --git a/arch/sh/mm/pg-sh4.c b/arch/sh/mm/pg-sh4.c
index c776b60fc250..07371ed7a313 100644
--- a/arch/sh/mm/pg-sh4.c
+++ b/arch/sh/mm/pg-sh4.c
@@ -2,7 +2,7 @@
2 * arch/sh/mm/pg-sh4.c 2 * arch/sh/mm/pg-sh4.c
3 * 3 *
4 * Copyright (C) 1999, 2000, 2002 Niibe Yutaka 4 * Copyright (C) 1999, 2000, 2002 Niibe Yutaka
5 * Copyright (C) 2002 Paul Mundt 5 * Copyright (C) 2002 - 2005 Paul Mundt
6 * 6 *
7 * Released under the terms of the GNU GPL v2.0. 7 * Released under the terms of the GNU GPL v2.0.
8 */ 8 */
@@ -23,6 +23,8 @@
23 23
24extern struct semaphore p3map_sem[]; 24extern struct semaphore p3map_sem[];
25 25
26#define CACHE_ALIAS (cpu_data->dcache.alias_mask)
27
26/* 28/*
27 * clear_user_page 29 * clear_user_page
28 * @to: P1 address 30 * @to: P1 address
@@ -35,14 +37,15 @@ void clear_user_page(void *to, unsigned long address, struct page *page)
35 if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) 37 if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0)
36 clear_page(to); 38 clear_page(to);
37 else { 39 else {
38 pgprot_t pgprot = __pgprot(_PAGE_PRESENT | 40 pgprot_t pgprot = __pgprot(_PAGE_PRESENT |
39 _PAGE_RW | _PAGE_CACHABLE | 41 _PAGE_RW | _PAGE_CACHABLE |
40 _PAGE_DIRTY | _PAGE_ACCESSED | 42 _PAGE_DIRTY | _PAGE_ACCESSED |
41 _PAGE_HW_SHARED | _PAGE_FLAGS_HARD); 43 _PAGE_HW_SHARED | _PAGE_FLAGS_HARD);
42 unsigned long phys_addr = PHYSADDR(to); 44 unsigned long phys_addr = PHYSADDR(to);
43 unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS); 45 unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS);
44 pgd_t *dir = pgd_offset_k(p3_addr); 46 pgd_t *pgd = pgd_offset_k(p3_addr);
45 pmd_t *pmd = pmd_offset(dir, p3_addr); 47 pud_t *pud = pud_offset(pgd, p3_addr);
48 pmd_t *pmd = pmd_offset(pud, p3_addr);
46 pte_t *pte = pte_offset_kernel(pmd, p3_addr); 49 pte_t *pte = pte_offset_kernel(pmd, p3_addr);
47 pte_t entry; 50 pte_t entry;
48 unsigned long flags; 51 unsigned long flags;
@@ -67,21 +70,22 @@ void clear_user_page(void *to, unsigned long address, struct page *page)
67 * @address: U0 address to be mapped 70 * @address: U0 address to be mapped
68 * @page: page (virt_to_page(to)) 71 * @page: page (virt_to_page(to))
69 */ 72 */
70void copy_user_page(void *to, void *from, unsigned long address, 73void copy_user_page(void *to, void *from, unsigned long address,
71 struct page *page) 74 struct page *page)
72{ 75{
73 __set_bit(PG_mapped, &page->flags); 76 __set_bit(PG_mapped, &page->flags);
74 if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) 77 if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0)
75 copy_page(to, from); 78 copy_page(to, from);
76 else { 79 else {
77 pgprot_t pgprot = __pgprot(_PAGE_PRESENT | 80 pgprot_t pgprot = __pgprot(_PAGE_PRESENT |
78 _PAGE_RW | _PAGE_CACHABLE | 81 _PAGE_RW | _PAGE_CACHABLE |
79 _PAGE_DIRTY | _PAGE_ACCESSED | 82 _PAGE_DIRTY | _PAGE_ACCESSED |
80 _PAGE_HW_SHARED | _PAGE_FLAGS_HARD); 83 _PAGE_HW_SHARED | _PAGE_FLAGS_HARD);
81 unsigned long phys_addr = PHYSADDR(to); 84 unsigned long phys_addr = PHYSADDR(to);
82 unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS); 85 unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS);
83 pgd_t *dir = pgd_offset_k(p3_addr); 86 pgd_t *pgd = pgd_offset_k(p3_addr);
84 pmd_t *pmd = pmd_offset(dir, p3_addr); 87 pud_t *pud = pud_offset(pgd, p3_addr);
88 pmd_t *pmd = pmd_offset(pud, p3_addr);
85 pte_t *pte = pte_offset_kernel(pmd, p3_addr); 89 pte_t *pte = pte_offset_kernel(pmd, p3_addr);
86 pte_t entry; 90 pte_t entry;
87 unsigned long flags; 91 unsigned long flags;
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
new file mode 100644
index 000000000000..92e745341e4d
--- /dev/null
+++ b/arch/sh/mm/pmb.c
@@ -0,0 +1,400 @@
1/*
2 * arch/sh/mm/pmb.c
3 *
4 * Privileged Space Mapping Buffer (PMB) Support.
5 *
6 * Copyright (C) 2005, 2006 Paul Mundt
7 *
8 * P1/P2 Section mapping definitions from map32.h, which was:
9 *
10 * Copyright 2003 (c) Lineo Solutions,Inc.
11 *
12 * This file is subject to the terms and conditions of the GNU General Public
13 * License. See the file "COPYING" in the main directory of this archive
14 * for more details.
15 */
16#include <linux/init.h>
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/slab.h>
20#include <linux/bitops.h>
21#include <linux/debugfs.h>
22#include <linux/fs.h>
23#include <linux/seq_file.h>
24#include <linux/err.h>
25#include <asm/system.h>
26#include <asm/uaccess.h>
27#include <asm/pgtable.h>
28#include <asm/mmu.h>
29#include <asm/io.h>
30
31#define NR_PMB_ENTRIES 16
32
33static kmem_cache_t *pmb_cache;
34static unsigned long pmb_map;
35
36static struct pmb_entry pmb_init_map[] = {
37 /* vpn ppn flags (ub/sz/c/wt) */
38
39 /* P1 Section Mappings */
40 { 0x80000000, 0x00000000, PMB_SZ_64M | PMB_C, },
41 { 0x84000000, 0x04000000, PMB_SZ_64M | PMB_C, },
42 { 0x88000000, 0x08000000, PMB_SZ_128M | PMB_C, },
43 { 0x90000000, 0x10000000, PMB_SZ_64M | PMB_C, },
44 { 0x94000000, 0x14000000, PMB_SZ_64M | PMB_C, },
45 { 0x98000000, 0x18000000, PMB_SZ_64M | PMB_C, },
46
47 /* P2 Section Mappings */
48 { 0xa0000000, 0x00000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
49 { 0xa4000000, 0x04000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
50 { 0xa8000000, 0x08000000, PMB_UB | PMB_SZ_128M | PMB_WT, },
51 { 0xb0000000, 0x10000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
52 { 0xb4000000, 0x14000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
53 { 0xb8000000, 0x18000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
54};
55
56static inline unsigned long mk_pmb_entry(unsigned int entry)
57{
58 return (entry & PMB_E_MASK) << PMB_E_SHIFT;
59}
60
61static inline unsigned long mk_pmb_addr(unsigned int entry)
62{
63 return mk_pmb_entry(entry) | PMB_ADDR;
64}
65
66static inline unsigned long mk_pmb_data(unsigned int entry)
67{
68 return mk_pmb_entry(entry) | PMB_DATA;
69}
70
71struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn,
72 unsigned long flags)
73{
74 struct pmb_entry *pmbe;
75
76 pmbe = kmem_cache_alloc(pmb_cache, GFP_KERNEL);
77 if (!pmbe)
78 return ERR_PTR(-ENOMEM);
79
80 pmbe->vpn = vpn;
81 pmbe->ppn = ppn;
82 pmbe->flags = flags;
83
84 return pmbe;
85}
86
87void pmb_free(struct pmb_entry *pmbe)
88{
89 kmem_cache_free(pmb_cache, pmbe);
90}
91
92/*
93 * Must be in P2 for __set_pmb_entry()
94 */
95int __set_pmb_entry(unsigned long vpn, unsigned long ppn,
96 unsigned long flags, int *entry)
97{
98 unsigned int pos = *entry;
99
100 if (unlikely(pos == PMB_NO_ENTRY))
101 pos = find_first_zero_bit(&pmb_map, NR_PMB_ENTRIES);
102
103repeat:
104 if (unlikely(pos > NR_PMB_ENTRIES))
105 return -ENOSPC;
106
107 if (test_and_set_bit(pos, &pmb_map)) {
108 pos = find_first_zero_bit(&pmb_map, NR_PMB_ENTRIES);
109 goto repeat;
110 }
111
112 ctrl_outl(vpn | PMB_V, mk_pmb_addr(pos));
113
114#ifdef CONFIG_SH_WRITETHROUGH
115 /*
116 * When we are in 32-bit address extended mode, CCR.CB becomes
117 * invalid, so care must be taken to manually adjust cacheable
118 * translations.
119 */
120 if (likely(flags & PMB_C))
121 flags |= PMB_WT;
122#endif
123
124 ctrl_outl(ppn | flags | PMB_V, mk_pmb_data(pos));
125
126 *entry = pos;
127
128 return 0;
129}
130
131int set_pmb_entry(struct pmb_entry *pmbe)
132{
133 int ret;
134
135 jump_to_P2();
136 ret = __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, &pmbe->entry);
137 back_to_P1();
138
139 return ret;
140}
141
142void clear_pmb_entry(struct pmb_entry *pmbe)
143{
144 unsigned int entry = pmbe->entry;
145 unsigned long addr;
146
147 /*
148 * Don't allow clearing of wired init entries, P1 or P2 access
149 * without a corresponding mapping in the PMB will lead to reset
150 * by the TLB.
151 */
152 if (unlikely(entry < ARRAY_SIZE(pmb_init_map) ||
153 entry >= NR_PMB_ENTRIES))
154 return;
155
156 jump_to_P2();
157
158 /* Clear V-bit */
159 addr = mk_pmb_addr(entry);
160 ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr);
161
162 addr = mk_pmb_data(entry);
163 ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr);
164
165 back_to_P1();
166
167 clear_bit(entry, &pmb_map);
168}
169
170static DEFINE_SPINLOCK(pmb_list_lock);
171static struct pmb_entry *pmb_list;
172
173static inline void pmb_list_add(struct pmb_entry *pmbe)
174{
175 struct pmb_entry **p, *tmp;
176
177 p = &pmb_list;
178 while ((tmp = *p) != NULL)
179 p = &tmp->next;
180
181 pmbe->next = tmp;
182 *p = pmbe;
183}
184
185static inline void pmb_list_del(struct pmb_entry *pmbe)
186{
187 struct pmb_entry **p, *tmp;
188
189 for (p = &pmb_list; (tmp = *p); p = &tmp->next)
190 if (tmp == pmbe) {
191 *p = tmp->next;
192 return;
193 }
194}
195
196static struct {
197 unsigned long size;
198 int flag;
199} pmb_sizes[] = {
200 { .size = 0x20000000, .flag = PMB_SZ_512M, },
201 { .size = 0x08000000, .flag = PMB_SZ_128M, },
202 { .size = 0x04000000, .flag = PMB_SZ_64M, },
203 { .size = 0x01000000, .flag = PMB_SZ_16M, },
204};
205
206long pmb_remap(unsigned long vaddr, unsigned long phys,
207 unsigned long size, unsigned long flags)
208{
209 struct pmb_entry *pmbp;
210 unsigned long wanted;
211 int pmb_flags, i;
212
213 /* Convert typical pgprot value to the PMB equivalent */
214 if (flags & _PAGE_CACHABLE) {
215 if (flags & _PAGE_WT)
216 pmb_flags = PMB_WT;
217 else
218 pmb_flags = PMB_C;
219 } else
220 pmb_flags = PMB_WT | PMB_UB;
221
222 pmbp = NULL;
223 wanted = size;
224
225again:
226 for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) {
227 struct pmb_entry *pmbe;
228 int ret;
229
230 if (size < pmb_sizes[i].size)
231 continue;
232
233 pmbe = pmb_alloc(vaddr, phys, pmb_flags | pmb_sizes[i].flag);
234 if (IS_ERR(pmbe))
235 return PTR_ERR(pmbe);
236
237 ret = set_pmb_entry(pmbe);
238 if (ret != 0) {
239 pmb_free(pmbe);
240 return -EBUSY;
241 }
242
243 phys += pmb_sizes[i].size;
244 vaddr += pmb_sizes[i].size;
245 size -= pmb_sizes[i].size;
246
247 /*
248 * Link adjacent entries that span multiple PMB entries
249 * for easier tear-down.
250 */
251 if (likely(pmbp))
252 pmbp->link = pmbe;
253
254 pmbp = pmbe;
255 }
256
257 if (size >= 0x1000000)
258 goto again;
259
260 return wanted - size;
261}
262
263void pmb_unmap(unsigned long addr)
264{
265 struct pmb_entry **p, *pmbe;
266
267 for (p = &pmb_list; (pmbe = *p); p = &pmbe->next)
268 if (pmbe->vpn == addr)
269 break;
270
271 if (unlikely(!pmbe))
272 return;
273
274 WARN_ON(!test_bit(pmbe->entry, &pmb_map));
275
276 do {
277 struct pmb_entry *pmblink = pmbe;
278
279 clear_pmb_entry(pmbe);
280 pmbe = pmblink->link;
281
282 pmb_free(pmblink);
283 } while (pmbe);
284}
285
286static void pmb_cache_ctor(void *pmb, kmem_cache_t *cachep, unsigned long flags)
287{
288 struct pmb_entry *pmbe = pmb;
289
290 memset(pmb, 0, sizeof(struct pmb_entry));
291
292 spin_lock_irq(&pmb_list_lock);
293
294 pmbe->entry = PMB_NO_ENTRY;
295 pmb_list_add(pmbe);
296
297 spin_unlock_irq(&pmb_list_lock);
298}
299
300static void pmb_cache_dtor(void *pmb, kmem_cache_t *cachep, unsigned long flags)
301{
302 spin_lock_irq(&pmb_list_lock);
303 pmb_list_del(pmb);
304 spin_unlock_irq(&pmb_list_lock);
305}
306
307static int __init pmb_init(void)
308{
309 unsigned int nr_entries = ARRAY_SIZE(pmb_init_map);
310 unsigned int entry;
311
312 BUG_ON(unlikely(nr_entries >= NR_PMB_ENTRIES));
313
314 pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry),
315 0, 0, pmb_cache_ctor, pmb_cache_dtor);
316 BUG_ON(!pmb_cache);
317
318 jump_to_P2();
319
320 /*
321 * Ordering is important, P2 must be mapped in the PMB before we
322 * can set PMB.SE, and P1 must be mapped before we jump back to
323 * P1 space.
324 */
325 for (entry = 0; entry < nr_entries; entry++) {
326 struct pmb_entry *pmbe = pmb_init_map + entry;
327
328 __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, &entry);
329 }
330
331 ctrl_outl(0, PMB_IRMCR);
332
333 /* PMB.SE and UB[7] */
334 ctrl_outl((1 << 31) | (1 << 7), PMB_PASCR);
335
336 back_to_P1();
337
338 return 0;
339}
340arch_initcall(pmb_init);
341
342static int pmb_seq_show(struct seq_file *file, void *iter)
343{
344 int i;
345
346 seq_printf(file, "V: Valid, C: Cacheable, WT: Write-Through\n"
347 "CB: Copy-Back, B: Buffered, UB: Unbuffered\n");
348 seq_printf(file, "ety vpn ppn size flags\n");
349
350 for (i = 0; i < NR_PMB_ENTRIES; i++) {
351 unsigned long addr, data;
352 unsigned int size;
353 char *sz_str = NULL;
354
355 addr = ctrl_inl(mk_pmb_addr(i));
356 data = ctrl_inl(mk_pmb_data(i));
357
358 size = data & PMB_SZ_MASK;
359 sz_str = (size == PMB_SZ_16M) ? " 16MB":
360 (size == PMB_SZ_64M) ? " 64MB":
361 (size == PMB_SZ_128M) ? "128MB":
362 "512MB";
363
364 /* 02: V 0x88 0x08 128MB C CB B */
365 seq_printf(file, "%02d: %c 0x%02lx 0x%02lx %s %c %s %s\n",
366 i, ((addr & PMB_V) && (data & PMB_V)) ? 'V' : ' ',
367 (addr >> 24) & 0xff, (data >> 24) & 0xff,
368 sz_str, (data & PMB_C) ? 'C' : ' ',
369 (data & PMB_WT) ? "WT" : "CB",
370 (data & PMB_UB) ? "UB" : " B");
371 }
372
373 return 0;
374}
375
376static int pmb_debugfs_open(struct inode *inode, struct file *file)
377{
378 return single_open(file, pmb_seq_show, NULL);
379}
380
381static struct file_operations pmb_debugfs_fops = {
382 .owner = THIS_MODULE,
383 .open = pmb_debugfs_open,
384 .read = seq_read,
385 .llseek = seq_lseek,
386 .release = seq_release,
387};
388
389static int __init pmb_debugfs_init(void)
390{
391 struct dentry *dentry;
392
393 dentry = debugfs_create_file("pmb", S_IFREG | S_IRUGO,
394 NULL, NULL, &pmb_debugfs_fops);
395 if (IS_ERR(dentry))
396 return PTR_ERR(dentry);
397
398 return 0;
399}
400postcore_initcall(pmb_debugfs_init);
diff --git a/arch/sh/mm/tlb-flush.c b/arch/sh/mm/tlb-flush.c
new file mode 100644
index 000000000000..73ec7f6084fa
--- /dev/null
+++ b/arch/sh/mm/tlb-flush.c
@@ -0,0 +1,134 @@
1/*
2 * TLB flushing operations for SH with an MMU.
3 *
4 * Copyright (C) 1999 Niibe Yutaka
5 * Copyright (C) 2003 Paul Mundt
6 *
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
9 * for more details.
10 */
11#include <linux/mm.h>
12#include <asm/mmu_context.h>
13#include <asm/tlbflush.h>
14
15void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
16{
17 if (vma->vm_mm && vma->vm_mm->context.id != NO_CONTEXT) {
18 unsigned long flags;
19 unsigned long asid;
20 unsigned long saved_asid = MMU_NO_ASID;
21
22 asid = vma->vm_mm->context.id & MMU_CONTEXT_ASID_MASK;
23 page &= PAGE_MASK;
24
25 local_irq_save(flags);
26 if (vma->vm_mm != current->mm) {
27 saved_asid = get_asid();
28 set_asid(asid);
29 }
30 __flush_tlb_page(asid, page);
31 if (saved_asid != MMU_NO_ASID)
32 set_asid(saved_asid);
33 local_irq_restore(flags);
34 }
35}
36
37void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
38 unsigned long end)
39{
40 struct mm_struct *mm = vma->vm_mm;
41
42 if (mm->context.id != NO_CONTEXT) {
43 unsigned long flags;
44 int size;
45
46 local_irq_save(flags);
47 size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
48 if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
49 mm->context.id = NO_CONTEXT;
50 if (mm == current->mm)
51 activate_context(mm);
52 } else {
53 unsigned long asid;
54 unsigned long saved_asid = MMU_NO_ASID;
55
56 asid = mm->context.id & MMU_CONTEXT_ASID_MASK;
57 start &= PAGE_MASK;
58 end += (PAGE_SIZE - 1);
59 end &= PAGE_MASK;
60 if (mm != current->mm) {
61 saved_asid = get_asid();
62 set_asid(asid);
63 }
64 while (start < end) {
65 __flush_tlb_page(asid, start);
66 start += PAGE_SIZE;
67 }
68 if (saved_asid != MMU_NO_ASID)
69 set_asid(saved_asid);
70 }
71 local_irq_restore(flags);
72 }
73}
74
75void flush_tlb_kernel_range(unsigned long start, unsigned long end)
76{
77 unsigned long flags;
78 int size;
79
80 local_irq_save(flags);
81 size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
82 if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
83 flush_tlb_all();
84 } else {
85 unsigned long asid;
86 unsigned long saved_asid = get_asid();
87
88 asid = init_mm.context.id & MMU_CONTEXT_ASID_MASK;
89 start &= PAGE_MASK;
90 end += (PAGE_SIZE - 1);
91 end &= PAGE_MASK;
92 set_asid(asid);
93 while (start < end) {
94 __flush_tlb_page(asid, start);
95 start += PAGE_SIZE;
96 }
97 set_asid(saved_asid);
98 }
99 local_irq_restore(flags);
100}
101
102void flush_tlb_mm(struct mm_struct *mm)
103{
104 /* Invalidate all TLB of this process. */
105 /* Instead of invalidating each TLB, we get new MMU context. */
106 if (mm->context.id != NO_CONTEXT) {
107 unsigned long flags;
108
109 local_irq_save(flags);
110 mm->context.id = NO_CONTEXT;
111 if (mm == current->mm)
112 activate_context(mm);
113 local_irq_restore(flags);
114 }
115}
116
117void flush_tlb_all(void)
118{
119 unsigned long flags, status;
120
121 /*
122 * Flush all the TLB.
123 *
124 * Write to the MMU control register's bit:
125 * TF-bit for SH-3, TI-bit for SH-4.
126 * It's same position, bit #2.
127 */
128 local_irq_save(flags);
129 status = ctrl_inl(MMUCR);
130 status |= 0x04;
131 ctrl_outl(status, MMUCR);
132 ctrl_barrier();
133 local_irq_restore(flags);
134}
diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c
index 115b1b6be40b..812b2d567de2 100644
--- a/arch/sh/mm/tlb-sh4.c
+++ b/arch/sh/mm/tlb-sh4.c
@@ -36,7 +36,6 @@ void update_mmu_cache(struct vm_area_struct * vma,
36 unsigned long vpn; 36 unsigned long vpn;
37 struct page *page; 37 struct page *page;
38 unsigned long pfn; 38 unsigned long pfn;
39 unsigned long ptea;
40 39
41 /* Ptrace may call this routine. */ 40 /* Ptrace may call this routine. */
42 if (vma && current->active_mm != vma->vm_mm) 41 if (vma && current->active_mm != vma->vm_mm)
@@ -59,10 +58,11 @@ void update_mmu_cache(struct vm_area_struct * vma,
59 ctrl_outl(vpn, MMU_PTEH); 58 ctrl_outl(vpn, MMU_PTEH);
60 59
61 pteval = pte_val(pte); 60 pteval = pte_val(pte);
61
62 /* Set PTEA register */ 62 /* Set PTEA register */
63 /* TODO: make this look less hacky */ 63 if (cpu_data->flags & CPU_HAS_PTEA)
64 ptea = ((pteval >> 28) & 0xe) | (pteval & 0x1); 64 /* TODO: make this look less hacky */
65 ctrl_outl(ptea, MMU_PTEA); 65 ctrl_outl(((pteval >> 28) & 0xe) | (pteval & 0x1), MMU_PTEA);
66 66
67 /* Set PTEL register */ 67 /* Set PTEL register */
68 pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ 68 pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */