diff options
author | Stuart Menefy <stuart.menefy@st.com> | 2007-11-30 03:06:36 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2008-01-27 23:18:59 -0500 |
commit | cbaa118ecfd99fc5ed7adbd9c34a30e1c05e3c93 (patch) | |
tree | e60db5c0f3573558c97f39cfab78732220a72e6d /arch/sh | |
parent | 325df7f20467da07901c4f2b006d3457bba0adec (diff) |
sh: Preparation for uncached jumps through PMB.
Presently most of the 29-bit physical parts do P1/P2 segmentation
with a 1:1 cached/uncached mapping, jumping between the two to
control the caching behaviour. This provides the basic infrastructure
to maintain this behaviour on 32-bit physical parts that don't map
P1/P2 at all, using a shiny new linker section and corresponding
fixmap entry.
Signed-off-by: Stuart Menefy <stuart.menefy@st.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh')
-rw-r--r-- | arch/sh/kernel/cpu/init.c | 6 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh3/probe.c | 6 | ||||
-rw-r--r-- | arch/sh/kernel/vmlinux_32.lds.S | 9 | ||||
-rw-r--r-- | arch/sh/mm/cache-debugfs.c | 9 | ||||
-rw-r--r-- | arch/sh/mm/cache-sh4.c | 14 | ||||
-rw-r--r-- | arch/sh/mm/cache-sh7705.c | 12 | ||||
-rw-r--r-- | arch/sh/mm/init.c | 16 | ||||
-rw-r--r-- | arch/sh/mm/pmb.c | 18 | ||||
-rw-r--r-- | arch/sh/mm/tlb-sh4.c | 7 |
9 files changed, 61 insertions, 36 deletions
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c index fd1688e6c61c..0f0c76a842e4 100644 --- a/arch/sh/kernel/cpu/init.c +++ b/arch/sh/kernel/cpu/init.c | |||
@@ -64,11 +64,11 @@ static void __init speculative_execution_init(void) | |||
64 | * Generic first-level cache init | 64 | * Generic first-level cache init |
65 | */ | 65 | */ |
66 | #ifdef CONFIG_SUPERH32 | 66 | #ifdef CONFIG_SUPERH32 |
67 | static void __init cache_init(void) | 67 | static void __uses_jump_to_uncached cache_init(void) |
68 | { | 68 | { |
69 | unsigned long ccr, flags; | 69 | unsigned long ccr, flags; |
70 | 70 | ||
71 | jump_to_P2(); | 71 | jump_to_uncached(); |
72 | ccr = ctrl_inl(CCR); | 72 | ccr = ctrl_inl(CCR); |
73 | 73 | ||
74 | /* | 74 | /* |
@@ -145,7 +145,7 @@ static void __init cache_init(void) | |||
145 | #endif | 145 | #endif |
146 | 146 | ||
147 | ctrl_outl(flags, CCR); | 147 | ctrl_outl(flags, CCR); |
148 | back_to_P1(); | 148 | back_to_cached(); |
149 | } | 149 | } |
150 | #else | 150 | #else |
151 | #define cache_init() do { } while (0) | 151 | #define cache_init() do { } while (0) |
diff --git a/arch/sh/kernel/cpu/sh3/probe.c b/arch/sh/kernel/cpu/sh3/probe.c index bf579e061e09..22070e43e34d 100644 --- a/arch/sh/kernel/cpu/sh3/probe.c +++ b/arch/sh/kernel/cpu/sh3/probe.c | |||
@@ -16,11 +16,11 @@ | |||
16 | #include <asm/cache.h> | 16 | #include <asm/cache.h> |
17 | #include <asm/io.h> | 17 | #include <asm/io.h> |
18 | 18 | ||
19 | int __init detect_cpu_and_cache_system(void) | 19 | int __uses_jump_to_uncached detect_cpu_and_cache_system(void) |
20 | { | 20 | { |
21 | unsigned long addr0, addr1, data0, data1, data2, data3; | 21 | unsigned long addr0, addr1, data0, data1, data2, data3; |
22 | 22 | ||
23 | jump_to_P2(); | 23 | jump_to_uncached(); |
24 | /* | 24 | /* |
25 | * Check if the entry shadows or not. | 25 | * Check if the entry shadows or not. |
26 | * When shadowed, it's 128-entry system. | 26 | * When shadowed, it's 128-entry system. |
@@ -48,7 +48,7 @@ int __init detect_cpu_and_cache_system(void) | |||
48 | ctrl_outl(data0&~SH_CACHE_VALID, addr0); | 48 | ctrl_outl(data0&~SH_CACHE_VALID, addr0); |
49 | ctrl_outl(data2&~SH_CACHE_VALID, addr1); | 49 | ctrl_outl(data2&~SH_CACHE_VALID, addr1); |
50 | 50 | ||
51 | back_to_P1(); | 51 | back_to_cached(); |
52 | 52 | ||
53 | boot_cpu_data.dcache.ways = 4; | 53 | boot_cpu_data.dcache.ways = 4; |
54 | boot_cpu_data.dcache.entry_shift = 4; | 54 | boot_cpu_data.dcache.entry_shift = 4; |
diff --git a/arch/sh/kernel/vmlinux_32.lds.S b/arch/sh/kernel/vmlinux_32.lds.S index 0956fb3681a3..50c69c18dced 100644 --- a/arch/sh/kernel/vmlinux_32.lds.S +++ b/arch/sh/kernel/vmlinux_32.lds.S | |||
@@ -43,6 +43,15 @@ SECTIONS | |||
43 | NOTES | 43 | NOTES |
44 | RO_DATA(PAGE_SIZE) | 44 | RO_DATA(PAGE_SIZE) |
45 | 45 | ||
46 | /* | ||
47 | * Code which must be executed uncached and the associated data | ||
48 | */ | ||
49 | . = ALIGN(PAGE_SIZE); | ||
50 | __uncached_start = .; | ||
51 | .uncached.text : { *(.uncached.text) } | ||
52 | .uncached.data : { *(.uncached.data) } | ||
53 | __uncached_end = .; | ||
54 | |||
46 | . = ALIGN(THREAD_SIZE); | 55 | . = ALIGN(THREAD_SIZE); |
47 | .data : { /* Data */ | 56 | .data : { /* Data */ |
48 | *(.data.init_task) | 57 | *(.data.init_task) |
diff --git a/arch/sh/mm/cache-debugfs.c b/arch/sh/mm/cache-debugfs.c index de6d2c9aa477..db6d950b6f5e 100644 --- a/arch/sh/mm/cache-debugfs.c +++ b/arch/sh/mm/cache-debugfs.c | |||
@@ -22,7 +22,8 @@ enum cache_type { | |||
22 | CACHE_TYPE_UNIFIED, | 22 | CACHE_TYPE_UNIFIED, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | static int cache_seq_show(struct seq_file *file, void *iter) | 25 | static int __uses_jump_to_uncached cache_seq_show(struct seq_file *file, |
26 | void *iter) | ||
26 | { | 27 | { |
27 | unsigned int cache_type = (unsigned int)file->private; | 28 | unsigned int cache_type = (unsigned int)file->private; |
28 | struct cache_info *cache; | 29 | struct cache_info *cache; |
@@ -34,11 +35,11 @@ static int cache_seq_show(struct seq_file *file, void *iter) | |||
34 | * Go uncached immediately so we don't skew the results any | 35 | * Go uncached immediately so we don't skew the results any |
35 | * more than we already are.. | 36 | * more than we already are.. |
36 | */ | 37 | */ |
37 | jump_to_P2(); | 38 | jump_to_uncached(); |
38 | 39 | ||
39 | ccr = ctrl_inl(CCR); | 40 | ccr = ctrl_inl(CCR); |
40 | if ((ccr & CCR_CACHE_ENABLE) == 0) { | 41 | if ((ccr & CCR_CACHE_ENABLE) == 0) { |
41 | back_to_P1(); | 42 | back_to_cached(); |
42 | 43 | ||
43 | seq_printf(file, "disabled\n"); | 44 | seq_printf(file, "disabled\n"); |
44 | return 0; | 45 | return 0; |
@@ -104,7 +105,7 @@ static int cache_seq_show(struct seq_file *file, void *iter) | |||
104 | addrstart += cache->way_incr; | 105 | addrstart += cache->way_incr; |
105 | } | 106 | } |
106 | 107 | ||
107 | back_to_P1(); | 108 | back_to_cached(); |
108 | 109 | ||
109 | return 0; | 110 | return 0; |
110 | } | 111 | } |
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 226b190c5b9c..43d7ff6b6ec7 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c | |||
@@ -190,7 +190,7 @@ void flush_icache_range(unsigned long start, unsigned long end) | |||
190 | * .. which happens to be the same behavior as flush_icache_range(). | 190 | * .. which happens to be the same behavior as flush_icache_range(). |
191 | * So, we simply flush out a line. | 191 | * So, we simply flush out a line. |
192 | */ | 192 | */ |
193 | void flush_cache_sigtramp(unsigned long addr) | 193 | void __uses_jump_to_uncached flush_cache_sigtramp(unsigned long addr) |
194 | { | 194 | { |
195 | unsigned long v, index; | 195 | unsigned long v, index; |
196 | unsigned long flags; | 196 | unsigned long flags; |
@@ -205,13 +205,13 @@ void flush_cache_sigtramp(unsigned long addr) | |||
205 | (v & boot_cpu_data.icache.entry_mask); | 205 | (v & boot_cpu_data.icache.entry_mask); |
206 | 206 | ||
207 | local_irq_save(flags); | 207 | local_irq_save(flags); |
208 | jump_to_P2(); | 208 | jump_to_uncached(); |
209 | 209 | ||
210 | for (i = 0; i < boot_cpu_data.icache.ways; | 210 | for (i = 0; i < boot_cpu_data.icache.ways; |
211 | i++, index += boot_cpu_data.icache.way_incr) | 211 | i++, index += boot_cpu_data.icache.way_incr) |
212 | ctrl_outl(0, index); /* Clear out Valid-bit */ | 212 | ctrl_outl(0, index); /* Clear out Valid-bit */ |
213 | 213 | ||
214 | back_to_P1(); | 214 | back_to_cached(); |
215 | wmb(); | 215 | wmb(); |
216 | local_irq_restore(flags); | 216 | local_irq_restore(flags); |
217 | } | 217 | } |
@@ -256,12 +256,12 @@ void flush_dcache_page(struct page *page) | |||
256 | } | 256 | } |
257 | 257 | ||
258 | /* TODO: Selective icache invalidation through IC address array.. */ | 258 | /* TODO: Selective icache invalidation through IC address array.. */ |
259 | static inline void flush_icache_all(void) | 259 | static inline void __uses_jump_to_uncached flush_icache_all(void) |
260 | { | 260 | { |
261 | unsigned long flags, ccr; | 261 | unsigned long flags, ccr; |
262 | 262 | ||
263 | local_irq_save(flags); | 263 | local_irq_save(flags); |
264 | jump_to_P2(); | 264 | jump_to_uncached(); |
265 | 265 | ||
266 | /* Flush I-cache */ | 266 | /* Flush I-cache */ |
267 | ccr = ctrl_inl(CCR); | 267 | ccr = ctrl_inl(CCR); |
@@ -269,11 +269,11 @@ static inline void flush_icache_all(void) | |||
269 | ctrl_outl(ccr, CCR); | 269 | ctrl_outl(ccr, CCR); |
270 | 270 | ||
271 | /* | 271 | /* |
272 | * back_to_P1() will take care of the barrier for us, don't add | 272 | * back_to_cached() will take care of the barrier for us, don't add |
273 | * another one! | 273 | * another one! |
274 | */ | 274 | */ |
275 | 275 | ||
276 | back_to_P1(); | 276 | back_to_cached(); |
277 | local_irq_restore(flags); | 277 | local_irq_restore(flags); |
278 | } | 278 | } |
279 | 279 | ||
diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c index 4896d7376926..22dacc778823 100644 --- a/arch/sh/mm/cache-sh7705.c +++ b/arch/sh/mm/cache-sh7705.c | |||
@@ -71,7 +71,7 @@ void flush_icache_range(unsigned long start, unsigned long end) | |||
71 | /* | 71 | /* |
72 | * Writeback&Invalidate the D-cache of the page | 72 | * Writeback&Invalidate the D-cache of the page |
73 | */ | 73 | */ |
74 | static void __flush_dcache_page(unsigned long phys) | 74 | static void __uses_jump_to_uncached __flush_dcache_page(unsigned long phys) |
75 | { | 75 | { |
76 | unsigned long ways, waysize, addrstart; | 76 | unsigned long ways, waysize, addrstart; |
77 | unsigned long flags; | 77 | unsigned long flags; |
@@ -92,7 +92,7 @@ static void __flush_dcache_page(unsigned long phys) | |||
92 | * possible. | 92 | * possible. |
93 | */ | 93 | */ |
94 | local_irq_save(flags); | 94 | local_irq_save(flags); |
95 | jump_to_P2(); | 95 | jump_to_uncached(); |
96 | 96 | ||
97 | ways = current_cpu_data.dcache.ways; | 97 | ways = current_cpu_data.dcache.ways; |
98 | waysize = current_cpu_data.dcache.sets; | 98 | waysize = current_cpu_data.dcache.sets; |
@@ -118,7 +118,7 @@ static void __flush_dcache_page(unsigned long phys) | |||
118 | addrstart += current_cpu_data.dcache.way_incr; | 118 | addrstart += current_cpu_data.dcache.way_incr; |
119 | } while (--ways); | 119 | } while (--ways); |
120 | 120 | ||
121 | back_to_P1(); | 121 | back_to_cached(); |
122 | local_irq_restore(flags); | 122 | local_irq_restore(flags); |
123 | } | 123 | } |
124 | 124 | ||
@@ -132,15 +132,15 @@ void flush_dcache_page(struct page *page) | |||
132 | __flush_dcache_page(PHYSADDR(page_address(page))); | 132 | __flush_dcache_page(PHYSADDR(page_address(page))); |
133 | } | 133 | } |
134 | 134 | ||
135 | void flush_cache_all(void) | 135 | void __uses_jump_to_uncached flush_cache_all(void) |
136 | { | 136 | { |
137 | unsigned long flags; | 137 | unsigned long flags; |
138 | 138 | ||
139 | local_irq_save(flags); | 139 | local_irq_save(flags); |
140 | jump_to_P2(); | 140 | jump_to_uncached(); |
141 | 141 | ||
142 | cache_wback_all(); | 142 | cache_wback_all(); |
143 | back_to_P1(); | 143 | back_to_cached(); |
144 | local_irq_restore(flags); | 144 | local_irq_restore(flags); |
145 | } | 145 | } |
146 | 146 | ||
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 79c309780f95..094225e0d722 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c | |||
@@ -23,6 +23,7 @@ | |||
23 | 23 | ||
24 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); | 24 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); |
25 | pgd_t swapper_pg_dir[PTRS_PER_PGD]; | 25 | pgd_t swapper_pg_dir[PTRS_PER_PGD]; |
26 | unsigned long cached_to_uncached = 0; | ||
26 | 27 | ||
27 | void show_mem(void) | 28 | void show_mem(void) |
28 | { | 29 | { |
@@ -99,7 +100,8 @@ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot) | |||
99 | 100 | ||
100 | set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, prot)); | 101 | set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, prot)); |
101 | 102 | ||
102 | flush_tlb_one(get_asid(), addr); | 103 | if (cached_to_uncached) |
104 | flush_tlb_one(get_asid(), addr); | ||
103 | } | 105 | } |
104 | 106 | ||
105 | /* | 107 | /* |
@@ -164,6 +166,18 @@ void __init paging_init(void) | |||
164 | } | 166 | } |
165 | 167 | ||
166 | free_area_init_nodes(max_zone_pfns); | 168 | free_area_init_nodes(max_zone_pfns); |
169 | |||
170 | /* Set up the uncached fixmap */ | ||
171 | set_fixmap_nocache(FIX_UNCACHED, __pa(&__uncached_start)); | ||
172 | |||
173 | #ifdef CONFIG_29BIT | ||
174 | /* | ||
175 | * Handle trivial transitions between cached and uncached | ||
176 | * segments, making use of the 1:1 mapping relationship in | ||
177 | * 512MB lowmem. | ||
178 | */ | ||
179 | cached_to_uncached = P2SEG - P1SEG; | ||
180 | #endif | ||
167 | } | 181 | } |
168 | 182 | ||
169 | static struct kcore_list kcore_mem, kcore_vmalloc; | 183 | static struct kcore_list kcore_mem, kcore_vmalloc; |
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index ef6ab39eaf65..ab81c602295f 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c | |||
@@ -163,18 +163,18 @@ repeat: | |||
163 | return 0; | 163 | return 0; |
164 | } | 164 | } |
165 | 165 | ||
166 | int set_pmb_entry(struct pmb_entry *pmbe) | 166 | int __uses_jump_to_uncached set_pmb_entry(struct pmb_entry *pmbe) |
167 | { | 167 | { |
168 | int ret; | 168 | int ret; |
169 | 169 | ||
170 | jump_to_P2(); | 170 | jump_to_uncached(); |
171 | ret = __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, &pmbe->entry); | 171 | ret = __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, &pmbe->entry); |
172 | back_to_P1(); | 172 | back_to_cached(); |
173 | 173 | ||
174 | return ret; | 174 | return ret; |
175 | } | 175 | } |
176 | 176 | ||
177 | void clear_pmb_entry(struct pmb_entry *pmbe) | 177 | void __uses_jump_to_uncached clear_pmb_entry(struct pmb_entry *pmbe) |
178 | { | 178 | { |
179 | unsigned int entry = pmbe->entry; | 179 | unsigned int entry = pmbe->entry; |
180 | unsigned long addr; | 180 | unsigned long addr; |
@@ -188,7 +188,7 @@ void clear_pmb_entry(struct pmb_entry *pmbe) | |||
188 | entry >= NR_PMB_ENTRIES)) | 188 | entry >= NR_PMB_ENTRIES)) |
189 | return; | 189 | return; |
190 | 190 | ||
191 | jump_to_P2(); | 191 | jump_to_uncached(); |
192 | 192 | ||
193 | /* Clear V-bit */ | 193 | /* Clear V-bit */ |
194 | addr = mk_pmb_addr(entry); | 194 | addr = mk_pmb_addr(entry); |
@@ -197,7 +197,7 @@ void clear_pmb_entry(struct pmb_entry *pmbe) | |||
197 | addr = mk_pmb_data(entry); | 197 | addr = mk_pmb_data(entry); |
198 | ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr); | 198 | ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr); |
199 | 199 | ||
200 | back_to_P1(); | 200 | back_to_cached(); |
201 | 201 | ||
202 | clear_bit(entry, &pmb_map); | 202 | clear_bit(entry, &pmb_map); |
203 | } | 203 | } |
@@ -302,7 +302,7 @@ static void pmb_cache_ctor(struct kmem_cache *cachep, void *pmb) | |||
302 | pmbe->entry = PMB_NO_ENTRY; | 302 | pmbe->entry = PMB_NO_ENTRY; |
303 | } | 303 | } |
304 | 304 | ||
305 | static int __init pmb_init(void) | 305 | static int __uses_jump_to_uncached pmb_init(void) |
306 | { | 306 | { |
307 | unsigned int nr_entries = ARRAY_SIZE(pmb_init_map); | 307 | unsigned int nr_entries = ARRAY_SIZE(pmb_init_map); |
308 | unsigned int entry, i; | 308 | unsigned int entry, i; |
@@ -312,7 +312,7 @@ static int __init pmb_init(void) | |||
312 | pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry), 0, | 312 | pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry), 0, |
313 | SLAB_PANIC, pmb_cache_ctor); | 313 | SLAB_PANIC, pmb_cache_ctor); |
314 | 314 | ||
315 | jump_to_P2(); | 315 | jump_to_uncached(); |
316 | 316 | ||
317 | /* | 317 | /* |
318 | * Ordering is important, P2 must be mapped in the PMB before we | 318 | * Ordering is important, P2 must be mapped in the PMB before we |
@@ -335,7 +335,7 @@ static int __init pmb_init(void) | |||
335 | i |= MMUCR_TI; | 335 | i |= MMUCR_TI; |
336 | ctrl_outl(i, MMUCR); | 336 | ctrl_outl(i, MMUCR); |
337 | 337 | ||
338 | back_to_P1(); | 338 | back_to_cached(); |
339 | 339 | ||
340 | return 0; | 340 | return 0; |
341 | } | 341 | } |
diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c index 2d1dd6044307..f0c7b7397fa6 100644 --- a/arch/sh/mm/tlb-sh4.c +++ b/arch/sh/mm/tlb-sh4.c | |||
@@ -79,7 +79,8 @@ void update_mmu_cache(struct vm_area_struct * vma, | |||
79 | local_irq_restore(flags); | 79 | local_irq_restore(flags); |
80 | } | 80 | } |
81 | 81 | ||
82 | void local_flush_tlb_one(unsigned long asid, unsigned long page) | 82 | void __uses_jump_to_uncached local_flush_tlb_one(unsigned long asid, |
83 | unsigned long page) | ||
83 | { | 84 | { |
84 | unsigned long addr, data; | 85 | unsigned long addr, data; |
85 | 86 | ||
@@ -91,7 +92,7 @@ void local_flush_tlb_one(unsigned long asid, unsigned long page) | |||
91 | */ | 92 | */ |
92 | addr = MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT; | 93 | addr = MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT; |
93 | data = page | asid; /* VALID bit is off */ | 94 | data = page | asid; /* VALID bit is off */ |
94 | jump_to_P2(); | 95 | jump_to_uncached(); |
95 | ctrl_outl(data, addr); | 96 | ctrl_outl(data, addr); |
96 | back_to_P1(); | 97 | back_to_cached(); |
97 | } | 98 | } |