diff options
author | Paul Mundt <lethal@linux-sh.org> | 2007-07-31 04:07:28 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2007-09-20 22:57:46 -0400 |
commit | e7bd34a15b85655f24d1b45edbe3bdfebf9d027e (patch) | |
tree | 051647273266582fe95dcc5cf008534c264be5ae | |
parent | ac919986d7dfc5d1d9f5585521307f222a8ebeaf (diff) |
sh: Support explicit L1 cache disabling.
This reworks the cache mode configuration in Kconfig, and allows for
explicit selection of write-back/write-through/off configurations.
All of the cache flushing routines are optimized away for the off
case.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r-- | arch/sh/kernel/cpu/init.c | 11 | ||||
-rw-r--r-- | arch/sh/kernel/sh_ksyms.c | 7 | ||||
-rw-r--r-- | arch/sh/mm/Kconfig | 19 | ||||
-rw-r--r-- | arch/sh/mm/Makefile | 11 | ||||
-rw-r--r-- | arch/sh/mm/pmb.c | 2 | ||||
-rw-r--r-- | arch/sh/mm/tlb-sh4.c | 25 | ||||
-rw-r--r-- | include/asm-sh/cacheflush.h | 33 | ||||
-rw-r--r-- | include/asm-sh/page.h | 6 | ||||
-rw-r--r-- | include/asm-sh/pgtable.h | 3 |
9 files changed, 86 insertions, 31 deletions
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c index 9172e97dc26a..fdc245b7b043 100644 --- a/arch/sh/kernel/cpu/init.c +++ b/arch/sh/kernel/cpu/init.c | |||
@@ -143,12 +143,15 @@ static void __init cache_init(void) | |||
143 | flags &= ~CCR_CACHE_EMODE; | 143 | flags &= ~CCR_CACHE_EMODE; |
144 | #endif | 144 | #endif |
145 | 145 | ||
146 | #ifdef CONFIG_SH_WRITETHROUGH | 146 | #if defined(CONFIG_CACHE_WRITETHROUGH) |
147 | /* Turn on Write-through caching */ | 147 | /* Write-through */ |
148 | flags |= CCR_CACHE_WT; | 148 | flags |= CCR_CACHE_WT; |
149 | #else | 149 | #elif defined(CONFIG_CACHE_WRITEBACK) |
150 | /* .. or default to Write-back */ | 150 | /* Write-back */ |
151 | flags |= CCR_CACHE_CB; | 151 | flags |= CCR_CACHE_CB; |
152 | #else | ||
153 | /* Off */ | ||
154 | flags &= ~CCR_CACHE_ENABLE; | ||
152 | #endif | 155 | #endif |
153 | 156 | ||
154 | ctrl_outl(flags, CCR); | 157 | ctrl_outl(flags, CCR); |
diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c index 37aef0a85197..de250705c35e 100644 --- a/arch/sh/kernel/sh_ksyms.c +++ b/arch/sh/kernel/sh_ksyms.c | |||
@@ -128,7 +128,8 @@ DECLARE_EXPORT(__movstrSI12_i4); | |||
128 | #endif /* __GNUC__ == 4 */ | 128 | #endif /* __GNUC__ == 4 */ |
129 | #endif | 129 | #endif |
130 | 130 | ||
131 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) | 131 | #if !defined(CONFIG_CACHE_OFF) && (defined(CONFIG_CPU_SH4) || \ |
132 | defined(CONFIG_SH7705_CACHE_32KB)) | ||
132 | /* needed by some modules */ | 133 | /* needed by some modules */ |
133 | EXPORT_SYMBOL(flush_cache_all); | 134 | EXPORT_SYMBOL(flush_cache_all); |
134 | EXPORT_SYMBOL(flush_cache_range); | 135 | EXPORT_SYMBOL(flush_cache_range); |
@@ -136,8 +137,8 @@ EXPORT_SYMBOL(flush_dcache_page); | |||
136 | EXPORT_SYMBOL(__flush_purge_region); | 137 | EXPORT_SYMBOL(__flush_purge_region); |
137 | #endif | 138 | #endif |
138 | 139 | ||
139 | #if defined(CONFIG_MMU) && (defined(CONFIG_CPU_SH4) || \ | 140 | #if !defined(CONFIG_CACHE_OFF) && defined(CONFIG_MMU) && \ |
140 | defined(CONFIG_SH7705_CACHE_32KB)) | 141 | (defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)) |
141 | EXPORT_SYMBOL(clear_user_page); | 142 | EXPORT_SYMBOL(clear_user_page); |
142 | #endif | 143 | #endif |
143 | 144 | ||
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index 093d491424fd..c2777555003e 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig | |||
@@ -2,7 +2,6 @@ | |||
2 | # Processor families | 2 | # Processor families |
3 | # | 3 | # |
4 | config CPU_SH2 | 4 | config CPU_SH2 |
5 | select SH_WRITETHROUGH if !CPU_SH2A | ||
6 | bool | 5 | bool |
7 | 6 | ||
8 | config CPU_SH2A | 7 | config CPU_SH2A |
@@ -414,8 +413,17 @@ config SH_DIRECT_MAPPED | |||
414 | Turn this option off for platforms that do not have a direct-mapped | 413 | Turn this option off for platforms that do not have a direct-mapped |
415 | cache, and you have no need to run the caches in such a configuration. | 414 | cache, and you have no need to run the caches in such a configuration. |
416 | 415 | ||
417 | config SH_WRITETHROUGH | 416 | choice |
418 | bool "Use write-through caching" | 417 | prompt "Cache mode" |
418 | default CACHE_WRITEBACK if CPU_SH2A || CPU_SH3 || CPU_SH4 | ||
419 | default CACHE_WRITETHROUGH if (CPU_SH2 && !CPU_SH2A) | ||
420 | |||
421 | config CACHE_WRITEBACK | ||
422 | bool "Write-back" | ||
423 | depends on CPU_SH2A || CPU_SH3 || CPU_SH4 | ||
424 | |||
425 | config CACHE_WRITETHROUGH | ||
426 | bool "Write-through" | ||
419 | help | 427 | help |
420 | Selecting this option will configure the caches in write-through | 428 | Selecting this option will configure the caches in write-through |
421 | mode, as opposed to the default write-back configuration. | 429 | mode, as opposed to the default write-back configuration. |
@@ -426,4 +434,9 @@ config SH_WRITETHROUGH | |||
426 | 434 | ||
427 | If unsure, say N. | 435 | If unsure, say N. |
428 | 436 | ||
437 | config CACHE_OFF | ||
438 | bool "Off" | ||
439 | |||
440 | endchoice | ||
441 | |||
429 | endmenu | 442 | endmenu |
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile index 4061e89d84d0..e73d7f970ce0 100644 --- a/arch/sh/mm/Makefile +++ b/arch/sh/mm/Makefile | |||
@@ -4,9 +4,10 @@ | |||
4 | 4 | ||
5 | obj-y := init.o extable.o consistent.o | 5 | obj-y := init.o extable.o consistent.o |
6 | 6 | ||
7 | obj-$(CONFIG_CPU_SH2) += cache-sh2.o | 7 | cache-$(CONFIG_CPU_SH2) := cache-sh2.o |
8 | obj-$(CONFIG_CPU_SH3) += cache-sh3.o | 8 | cache-$(CONFIG_CPU_SH3) := cache-sh3.o |
9 | obj-$(CONFIG_CPU_SH4) += cache-sh4.o | 9 | cache-$(CONFIG_CPU_SH4) := cache-sh4.o pg-sh4.o |
10 | cache-$(CONFIG_CACHE_OFF) := | ||
10 | 11 | ||
11 | mmu-y := tlb-nommu.o pg-nommu.o | 12 | mmu-y := tlb-nommu.o pg-nommu.o |
12 | mmu-$(CONFIG_CPU_SH3) += fault-nommu.o | 13 | mmu-$(CONFIG_CPU_SH3) += fault-nommu.o |
@@ -14,7 +15,7 @@ mmu-$(CONFIG_CPU_SH4) += fault-nommu.o | |||
14 | mmu-$(CONFIG_MMU) := fault.o clear_page.o copy_page.o tlb-flush.o \ | 15 | mmu-$(CONFIG_MMU) := fault.o clear_page.o copy_page.o tlb-flush.o \ |
15 | ioremap.o | 16 | ioremap.o |
16 | 17 | ||
17 | obj-y += $(mmu-y) | 18 | obj-y += $(cache-y) $(mmu-y) |
18 | 19 | ||
19 | ifdef CONFIG_DEBUG_FS | 20 | ifdef CONFIG_DEBUG_FS |
20 | obj-$(CONFIG_CPU_SH4) += cache-debugfs.o | 21 | obj-$(CONFIG_CPU_SH4) += cache-debugfs.o |
@@ -22,7 +23,7 @@ endif | |||
22 | 23 | ||
23 | ifdef CONFIG_MMU | 24 | ifdef CONFIG_MMU |
24 | obj-$(CONFIG_CPU_SH3) += tlb-sh3.o | 25 | obj-$(CONFIG_CPU_SH3) += tlb-sh3.o |
25 | obj-$(CONFIG_CPU_SH4) += tlb-sh4.o pg-sh4.o | 26 | obj-$(CONFIG_CPU_SH4) += tlb-sh4.o |
26 | obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o | 27 | obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o |
27 | endif | 28 | endif |
28 | 29 | ||
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index a08a4a958add..7d43758dc244 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c | |||
@@ -145,7 +145,7 @@ repeat: | |||
145 | 145 | ||
146 | ctrl_outl(vpn | PMB_V, mk_pmb_addr(pos)); | 146 | ctrl_outl(vpn | PMB_V, mk_pmb_addr(pos)); |
147 | 147 | ||
148 | #ifdef CONFIG_SH_WRITETHROUGH | 148 | #ifdef CONFIG_CACHE_WRITETHROUGH |
149 | /* | 149 | /* |
150 | * When we are in 32-bit address extended mode, CCR.CB becomes | 150 | * When we are in 32-bit address extended mode, CCR.CB becomes |
151 | * invalid, so care must be taken to manually adjust cacheable | 151 | * invalid, so care must be taken to manually adjust cacheable |
diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c index f74cf667c8fa..13fde8cc7179 100644 --- a/arch/sh/mm/tlb-sh4.c +++ b/arch/sh/mm/tlb-sh4.c | |||
@@ -34,22 +34,27 @@ void update_mmu_cache(struct vm_area_struct * vma, | |||
34 | unsigned long flags; | 34 | unsigned long flags; |
35 | unsigned long pteval; | 35 | unsigned long pteval; |
36 | unsigned long vpn; | 36 | unsigned long vpn; |
37 | struct page *page; | ||
38 | unsigned long pfn; | ||
39 | 37 | ||
40 | /* Ptrace may call this routine. */ | 38 | /* Ptrace may call this routine. */ |
41 | if (vma && current->active_mm != vma->vm_mm) | 39 | if (vma && current->active_mm != vma->vm_mm) |
42 | return; | 40 | return; |
43 | 41 | ||
44 | pfn = pte_pfn(pte); | 42 | #ifndef CONFIG_CACHE_OFF |
45 | if (pfn_valid(pfn)) { | 43 | { |
46 | page = pfn_to_page(pfn); | 44 | unsigned long pfn = pte_pfn(pte); |
47 | if (!test_bit(PG_mapped, &page->flags)) { | 45 | |
48 | unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; | 46 | if (pfn_valid(pfn)) { |
49 | __flush_wback_region((void *)P1SEGADDR(phys), PAGE_SIZE); | 47 | struct page *page = pfn_to_page(pfn); |
50 | __set_bit(PG_mapped, &page->flags); | 48 | |
49 | if (!test_bit(PG_mapped, &page->flags)) { | ||
50 | unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; | ||
51 | __flush_wback_region((void *)P1SEGADDR(phys), | ||
52 | PAGE_SIZE); | ||
53 | __set_bit(PG_mapped, &page->flags); | ||
54 | } | ||
51 | } | 55 | } |
52 | } | 56 | } |
57 | #endif | ||
53 | 58 | ||
54 | local_irq_save(flags); | 59 | local_irq_save(flags); |
55 | 60 | ||
@@ -66,7 +71,7 @@ void update_mmu_cache(struct vm_area_struct * vma, | |||
66 | 71 | ||
67 | /* Set PTEL register */ | 72 | /* Set PTEL register */ |
68 | pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ | 73 | pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ |
69 | #ifdef CONFIG_SH_WRITETHROUGH | 74 | #ifdef CONFIG_CACHE_WRITETHROUGH |
70 | pteval |= _PAGE_WT; | 75 | pteval |= _PAGE_WT; |
71 | #endif | 76 | #endif |
72 | /* conveniently, we want all the software flags to be 0 anyway */ | 77 | /* conveniently, we want all the software flags to be 0 anyway */ |
diff --git a/include/asm-sh/cacheflush.h b/include/asm-sh/cacheflush.h index 07f62ec9ff0c..aa558da08471 100644 --- a/include/asm-sh/cacheflush.h +++ b/include/asm-sh/cacheflush.h | |||
@@ -1,16 +1,47 @@ | |||
1 | #ifndef __ASM_SH_CACHEFLUSH_H | 1 | #ifndef __ASM_SH_CACHEFLUSH_H |
2 | #define __ASM_SH_CACHEFLUSH_H | 2 | #define __ASM_SH_CACHEFLUSH_H |
3 | |||
3 | #ifdef __KERNEL__ | 4 | #ifdef __KERNEL__ |
4 | 5 | ||
5 | #include <linux/mm.h> | 6 | #ifdef CONFIG_CACHE_OFF |
7 | /* | ||
8 | * Nothing to do when the cache is disabled, initial flush and explicit | ||
9 | * disabling is handled at CPU init time. | ||
10 | * | ||
11 | * See arch/sh/kernel/cpu/init.c:cache_init(). | ||
12 | */ | ||
13 | #define p3_cache_init() do { } while (0) | ||
14 | #define flush_cache_all() do { } while (0) | ||
15 | #define flush_cache_mm(mm) do { } while (0) | ||
16 | #define flush_cache_dup_mm(mm) do { } while (0) | ||
17 | #define flush_cache_range(vma, start, end) do { } while (0) | ||
18 | #define flush_cache_page(vma, vmaddr, pfn) do { } while (0) | ||
19 | #define flush_dcache_page(page) do { } while (0) | ||
20 | #define flush_icache_range(start, end) do { } while (0) | ||
21 | #define flush_icache_page(vma,pg) do { } while (0) | ||
22 | #define flush_dcache_mmap_lock(mapping) do { } while (0) | ||
23 | #define flush_dcache_mmap_unlock(mapping) do { } while (0) | ||
24 | #define flush_cache_sigtramp(vaddr) do { } while (0) | ||
25 | #define flush_icache_user_range(vma,pg,adr,len) do { } while (0) | ||
26 | #define __flush_wback_region(start, size) do { (void)(start); } while (0) | ||
27 | #define __flush_purge_region(start, size) do { (void)(start); } while (0) | ||
28 | #define __flush_invalidate_region(start, size) do { (void)(start); } while (0) | ||
29 | #else | ||
6 | #include <asm/cpu/cacheflush.h> | 30 | #include <asm/cpu/cacheflush.h> |
7 | 31 | ||
32 | /* | ||
33 | * Consistent DMA requires that the __flush_xxx() primitives must be set | ||
34 | * for any of the enabled non-coherent caches (most of the UP CPUs), | ||
35 | * regardless of PIPT or VIPT cache configurations. | ||
36 | */ | ||
37 | |||
8 | /* Flush (write-back only) a region (smaller than a page) */ | 38 | /* Flush (write-back only) a region (smaller than a page) */ |
9 | extern void __flush_wback_region(void *start, int size); | 39 | extern void __flush_wback_region(void *start, int size); |
10 | /* Flush (write-back & invalidate) a region (smaller than a page) */ | 40 | /* Flush (write-back & invalidate) a region (smaller than a page) */ |
11 | extern void __flush_purge_region(void *start, int size); | 41 | extern void __flush_purge_region(void *start, int size); |
12 | /* Flush (invalidate only) a region (smaller than a page) */ | 42 | /* Flush (invalidate only) a region (smaller than a page) */ |
13 | extern void __flush_invalidate_region(void *start, int size); | 43 | extern void __flush_invalidate_region(void *start, int size); |
44 | #endif | ||
14 | 45 | ||
15 | #define flush_cache_vmap(start, end) flush_cache_all() | 46 | #define flush_cache_vmap(start, end) flush_cache_all() |
16 | #define flush_cache_vunmap(start, end) flush_cache_all() | 47 | #define flush_cache_vunmap(start, end) flush_cache_all() |
diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h index 6bc9bba10105..48b718e7455c 100644 --- a/include/asm-sh/page.h +++ b/include/asm-sh/page.h | |||
@@ -70,14 +70,14 @@ extern void clear_page_nommu(void *to); | |||
70 | extern void copy_page_nommu(void *to, void *from); | 70 | extern void copy_page_nommu(void *to, void *from); |
71 | #endif | 71 | #endif |
72 | 72 | ||
73 | #if defined(CONFIG_MMU) && (defined(CONFIG_CPU_SH4) || \ | 73 | #if !defined(CONFIG_CACHE_OFF) && defined(CONFIG_MMU) && \ |
74 | defined(CONFIG_SH7705_CACHE_32KB)) | 74 | (defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)) |
75 | struct page; | 75 | struct page; |
76 | extern void clear_user_page(void *to, unsigned long address, struct page *pg); | 76 | extern void clear_user_page(void *to, unsigned long address, struct page *pg); |
77 | extern void copy_user_page(void *to, void *from, unsigned long address, struct page *pg); | 77 | extern void copy_user_page(void *to, void *from, unsigned long address, struct page *pg); |
78 | extern void __clear_user_page(void *to, void *orig_to); | 78 | extern void __clear_user_page(void *to, void *orig_to); |
79 | extern void __copy_user_page(void *to, void *from, void *orig_to); | 79 | extern void __copy_user_page(void *to, void *from, void *orig_to); |
80 | #elif defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH3) || !defined(CONFIG_MMU) | 80 | #else |
81 | #define clear_user_page(page, vaddr, pg) clear_page(page) | 81 | #define clear_user_page(page, vaddr, pg) clear_page(page) |
82 | #define copy_user_page(to, from, vaddr, pg) copy_page(to, from) | 82 | #define copy_user_page(to, from, vaddr, pg) copy_page(to, from) |
83 | #endif | 83 | #endif |
diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h index e3fae12c0e49..54ad5037fe40 100644 --- a/include/asm-sh/pgtable.h +++ b/include/asm-sh/pgtable.h | |||
@@ -563,7 +563,8 @@ struct mm_struct; | |||
563 | extern unsigned int kobjsize(const void *objp); | 563 | extern unsigned int kobjsize(const void *objp); |
564 | #endif /* !CONFIG_MMU */ | 564 | #endif /* !CONFIG_MMU */ |
565 | 565 | ||
566 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) | 566 | #if !defined(CONFIG_CACHE_OFF) && (defined(CONFIG_CPU_SH4) || \ |
567 | defined(CONFIG_SH7705_CACHE_32KB)) | ||
567 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR | 568 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR |
568 | extern pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep); | 569 | extern pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep); |
569 | #endif | 570 | #endif |