Commit cce2d453e4940d3fccd42a6917d01027148e11c3
Committed by
Paul Mundt
1 parent
1af446edfe
Exists in
master
and in
7 other branches
SH2(A) cache update
Includes: - SH2 (7619) Writeback support. - SH2A cache handling fix. Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Showing 7 changed files with 213 additions and 16 deletions Side-by-side Diff
arch/sh/include/cpu-sh2/cpu/cache.h
... | ... | @@ -21,11 +21,11 @@ |
21 | 21 | #define CCR 0xffffffec |
22 | 22 | |
23 | 23 | #define CCR_CACHE_CE 0x01 /* Cache enable */ |
24 | -#define CCR_CACHE_WT 0x06 /* CCR[bit1=1,bit2=1] */ | |
24 | +#define CCR_CACHE_WT 0x02 /* CCR[bit1=1,bit2=1] */ | |
25 | 25 | /* 0x00000000-0x7fffffff: Write-through */ |
26 | 26 | /* 0x80000000-0x9fffffff: Write-back */ |
27 | 27 | /* 0xc0000000-0xdfffffff: Write-through */ |
28 | -#define CCR_CACHE_CB 0x00 /* CCR[bit1=0,bit2=0] */ | |
28 | +#define CCR_CACHE_CB 0x04 /* CCR[bit1=0,bit2=0] */ | |
29 | 29 | /* 0x00000000-0x7fffffff: Write-back */ |
30 | 30 | /* 0x80000000-0x9fffffff: Write-through */ |
31 | 31 | /* 0xc0000000-0xdfffffff: Write-back */ |
... | ... | @@ -36,6 +36,8 @@ |
36 | 36 | |
37 | 37 | #define CCR_CACHE_ENABLE CCR_CACHE_CE |
38 | 38 | #define CCR_CACHE_INVALIDATE CCR_CACHE_CF |
39 | +#define CACHE_PHYSADDR_MASK 0x1ffffc00 | |
40 | + | |
39 | 41 | #endif |
40 | 42 | |
41 | 43 | #endif /* __ASM_CPU_SH2_CACHE_H */ |
arch/sh/include/cpu-sh2a/cpu/cache.h
... | ... | @@ -36,6 +36,9 @@ |
36 | 36 | |
37 | 37 | #define CCR_CACHE_ENABLE (CCR_CACHE_OCE | CCR_CACHE_ICE) |
38 | 38 | #define CCR_CACHE_INVALIDATE (CCR_CACHE_OCI | CCR_CACHE_ICI) |
39 | +#define CCR_ICACHE_INVALIDATE CCR_CACHE_ICI | |
40 | +#define CCR_OCACHE_INVALIDATE CCR_CACHE_OCI | |
41 | +#define CACHE_PHYSADDR_MASK 0x1ffffc00 | |
39 | 42 | |
40 | 43 | #endif /* __ASM_CPU_SH2A_CACHE_H */ |
arch/sh/include/cpu-sh2a/cpu/cacheflush.h
1 | +#ifndef __ASM_CPU_SH2A_CACHEFLUSH_H | |
2 | +#define __ASM_CPU_SH2A_CACHEFLUSH_H | |
3 | + | |
4 | +/* | |
5 | + * Cache flushing: | |
6 | + * | |
7 | + * - flush_cache_all() flushes entire cache | |
8 | + * - flush_cache_mm(mm) flushes the specified mm context's cache lines | |
9 | + * - flush_cache_dup mm(mm) handles cache flushing when forking | |
10 | + * - flush_cache_page(mm, vmaddr, pfn) flushes a single page | |
11 | + * - flush_cache_range(vma, start, end) flushes a range of pages | |
12 | + * | |
13 | + * - flush_dcache_page(pg) flushes(wback&invalidates) a page for dcache | |
14 | + * - flush_icache_range(start, end) flushes(invalidates) a range for icache | |
15 | + * - flush_icache_page(vma, pg) flushes(invalidates) a page for icache | |
16 | + * | |
17 | + * Caches are indexed (effectively) by physical address on SH-2, so | |
18 | + * we don't need them. | |
19 | + */ | |
20 | +#define flush_cache_all() do { } while (0) | |
21 | +#define flush_cache_mm(mm) do { } while (0) | |
22 | +#define flush_cache_dup_mm(mm) do { } while (0) | |
23 | +#define flush_cache_range(vma, start, end) do { } while (0) | |
24 | +#define flush_cache_page(vma, vmaddr, pfn) do { } while (0) | |
25 | +#define flush_dcache_page(page) do { } while (0) | |
26 | +#define flush_dcache_mmap_lock(mapping) do { } while (0) | |
27 | +#define flush_dcache_mmap_unlock(mapping) do { } while (0) | |
28 | +void flush_icache_range(unsigned long start, unsigned long end); | |
29 | +#define flush_icache_page(vma,pg) do { } while (0) | |
30 | +#define flush_icache_user_range(vma,pg,adr,len) do { } while (0) | |
31 | +#define flush_cache_sigtramp(vaddr) do { } while (0) | |
32 | + | |
33 | +#define p3_cache_init() do { } while (0) | |
34 | +#endif /* __ASM_CPU_SH2A_CACHEFLUSH_H */ |
arch/sh/mm/Kconfig
arch/sh/mm/Makefile_32
... | ... | @@ -5,11 +5,14 @@ |
5 | 5 | obj-y := init.o extable_32.o consistent.o |
6 | 6 | |
7 | 7 | ifndef CONFIG_CACHE_OFF |
8 | -obj-$(CONFIG_CPU_SH2) += cache-sh2.o | |
9 | -obj-$(CONFIG_CPU_SH3) += cache-sh3.o | |
10 | -obj-$(CONFIG_CPU_SH4) += cache-sh4.o | |
11 | -obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o | |
8 | +cache-$(CONFIG_CPU_SH2) := cache-sh2.o | |
9 | +cache-$(CONFIG_CPU_SH2A) := cache-sh2a.o | |
10 | +cache-$(CONFIG_CPU_SH3) := cache-sh3.o | |
11 | +cache-$(CONFIG_CPU_SH4) := cache-sh4.o | |
12 | +cache-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o | |
12 | 13 | endif |
14 | + | |
15 | +obj-y += $(cache-y) | |
13 | 16 | |
14 | 17 | mmu-y := tlb-nommu.o pg-nommu.o |
15 | 18 | mmu-$(CONFIG_MMU) := fault_32.o tlbflush_32.o ioremap_32.o |
arch/sh/mm/cache-sh2.c
... | ... | @@ -2,6 +2,7 @@ |
2 | 2 | * arch/sh/mm/cache-sh2.c |
3 | 3 | * |
4 | 4 | * Copyright (C) 2002 Paul Mundt |
5 | + * Copyright (C) 2008 Yoshinori Sato | |
5 | 6 | * |
6 | 7 | * Released under the terms of the GNU GPL v2.0. |
7 | 8 | */ |
... | ... | @@ -24,8 +25,15 @@ |
24 | 25 | end = ((unsigned long)start + size + L1_CACHE_BYTES-1) |
25 | 26 | & ~(L1_CACHE_BYTES-1); |
26 | 27 | for (v = begin; v < end; v+=L1_CACHE_BYTES) { |
27 | - /* FIXME cache purge */ | |
28 | - ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008); | |
28 | + unsigned long addr = CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0); | |
29 | + int way; | |
30 | + for (way = 0; way < 4; way++) { | |
31 | + unsigned long data = ctrl_inl(addr | (way << 12)); | |
32 | + if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) { | |
33 | + data &= ~SH_CACHE_UPDATED; | |
34 | + ctrl_outl(data, addr | (way << 12)); | |
35 | + } | |
36 | + } | |
29 | 37 | } |
30 | 38 | } |
31 | 39 | |
32 | 40 | |
33 | 41 | |
... | ... | @@ -37,21 +45,41 @@ |
37 | 45 | begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); |
38 | 46 | end = ((unsigned long)start + size + L1_CACHE_BYTES-1) |
39 | 47 | & ~(L1_CACHE_BYTES-1); |
40 | - for (v = begin; v < end; v+=L1_CACHE_BYTES) { | |
41 | - ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008); | |
42 | - } | |
48 | + | |
49 | + for (v = begin; v < end; v+=L1_CACHE_BYTES) | |
50 | + ctrl_outl((v & CACHE_PHYSADDR_MASK), | |
51 | + CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0) | 0x00000008); | |
43 | 52 | } |
44 | 53 | |
45 | 54 | void __flush_invalidate_region(void *start, int size) |
46 | 55 | { |
56 | +#ifdef CONFIG_CACHE_WRITEBACK | |
57 | + /* | |
58 | + * SH-2 does not support individual line invalidation, only a | |
59 | + * global invalidate. | |
60 | + */ | |
61 | + unsigned long ccr; | |
62 | + unsigned long flags; | |
63 | + local_irq_save(flags); | |
64 | + jump_to_uncached(); | |
65 | + | |
66 | + ccr = ctrl_inl(CCR); | |
67 | + ccr |= CCR_CACHE_INVALIDATE; | |
68 | + ctrl_outl(ccr, CCR); | |
69 | + | |
70 | + back_to_cached(); | |
71 | + local_irq_restore(flags); | |
72 | +#else | |
47 | 73 | unsigned long v; |
48 | 74 | unsigned long begin, end; |
49 | 75 | |
50 | 76 | begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); |
51 | 77 | end = ((unsigned long)start + size + L1_CACHE_BYTES-1) |
52 | 78 | & ~(L1_CACHE_BYTES-1); |
53 | - for (v = begin; v < end; v+=L1_CACHE_BYTES) { | |
54 | - ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008); | |
55 | - } | |
79 | + | |
80 | + for (v = begin; v < end; v+=L1_CACHE_BYTES) | |
81 | + ctrl_outl((v & CACHE_PHYSADDR_MASK), | |
82 | + CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0) | 0x00000008); | |
83 | +#endif | |
56 | 84 | } |
arch/sh/mm/cache-sh2a.c
1 | +/* | |
2 | + * arch/sh/mm/cache-sh2a.c | |
3 | + * | |
4 | + * Copyright (C) 2008 Yoshinori Sato | |
5 | + * | |
6 | + * Released under the terms of the GNU GPL v2.0. | |
7 | + */ | |
8 | + | |
9 | +#include <linux/init.h> | |
10 | +#include <linux/mm.h> | |
11 | + | |
12 | +#include <asm/cache.h> | |
13 | +#include <asm/addrspace.h> | |
14 | +#include <asm/processor.h> | |
15 | +#include <asm/cacheflush.h> | |
16 | +#include <asm/io.h> | |
17 | + | |
18 | +void __flush_wback_region(void *start, int size) | |
19 | +{ | |
20 | + unsigned long v; | |
21 | + unsigned long begin, end; | |
22 | + unsigned long flags; | |
23 | + | |
24 | + begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); | |
25 | + end = ((unsigned long)start + size + L1_CACHE_BYTES-1) | |
26 | + & ~(L1_CACHE_BYTES-1); | |
27 | + | |
28 | + local_irq_save(flags); | |
29 | + jump_to_uncached(); | |
30 | + | |
31 | + for (v = begin; v < end; v+=L1_CACHE_BYTES) { | |
32 | + unsigned long addr = CACHE_OC_ADDRESS_ARRAY | (v & 0x000007f0); | |
33 | + int way; | |
34 | + for (way = 0; way < 4; way++) { | |
35 | + unsigned long data = ctrl_inl(addr | (way << 11)); | |
36 | + if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) { | |
37 | + data &= ~SH_CACHE_UPDATED; | |
38 | + ctrl_outl(data, addr | (way << 11)); | |
39 | + } | |
40 | + } | |
41 | + } | |
42 | + | |
43 | + back_to_cached(); | |
44 | + local_irq_restore(flags); | |
45 | +} | |
46 | + | |
47 | +void __flush_purge_region(void *start, int size) | |
48 | +{ | |
49 | + unsigned long v; | |
50 | + unsigned long begin, end; | |
51 | + unsigned long flags; | |
52 | + | |
53 | + begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); | |
54 | + end = ((unsigned long)start + size + L1_CACHE_BYTES-1) | |
55 | + & ~(L1_CACHE_BYTES-1); | |
56 | + | |
57 | + local_irq_save(flags); | |
58 | + jump_to_uncached(); | |
59 | + | |
60 | + for (v = begin; v < end; v+=L1_CACHE_BYTES) { | |
61 | + ctrl_outl((v & CACHE_PHYSADDR_MASK), | |
62 | + CACHE_OC_ADDRESS_ARRAY | (v & 0x000003f0) | 0x00000008); | |
63 | + } | |
64 | + back_to_cached(); | |
65 | + local_irq_restore(flags); | |
66 | +} | |
67 | + | |
68 | +void __flush_invalidate_region(void *start, int size) | |
69 | +{ | |
70 | + unsigned long v; | |
71 | + unsigned long begin, end; | |
72 | + unsigned long flags; | |
73 | + | |
74 | + begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); | |
75 | + end = ((unsigned long)start + size + L1_CACHE_BYTES-1) | |
76 | + & ~(L1_CACHE_BYTES-1); | |
77 | + local_irq_save(flags); | |
78 | + jump_to_uncached(); | |
79 | + | |
80 | +#ifdef CONFIG_CACHE_WRITEBACK | |
81 | + ctrl_outl(ctrl_inl(CCR) | CCR_OCACHE_INVALIDATE, CCR); | |
82 | + /* I-cache invalidate */ | |
83 | + for (v = begin; v < end; v+=L1_CACHE_BYTES) { | |
84 | + ctrl_outl((v & CACHE_PHYSADDR_MASK), | |
85 | + CACHE_IC_ADDRESS_ARRAY | (v & 0x000003f0) | 0x00000008); | |
86 | + } | |
87 | +#else | |
88 | + for (v = begin; v < end; v+=L1_CACHE_BYTES) { | |
89 | + ctrl_outl((v & CACHE_PHYSADDR_MASK), | |
90 | + CACHE_IC_ADDRESS_ARRAY | (v & 0x000003f0) | 0x00000008); | |
91 | + ctrl_outl((v & CACHE_PHYSADDR_MASK), | |
92 | + CACHE_OC_ADDRESS_ARRAY | (v & 0x000003f0) | 0x00000008); | |
93 | + } | |
94 | +#endif | |
95 | + back_to_cached(); | |
96 | + local_irq_restore(flags); | |
97 | +} | |
98 | + | |
99 | +/* WBack O-Cache and flush I-Cache */ | |
100 | +void flush_icache_range(unsigned long start, unsigned long end) | |
101 | +{ | |
102 | + unsigned long v; | |
103 | + unsigned long flags; | |
104 | + | |
105 | + start = start & ~(L1_CACHE_BYTES-1); | |
106 | + end = (end + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); | |
107 | + | |
108 | + local_irq_save(flags); | |
109 | + jump_to_uncached(); | |
110 | + | |
111 | + for (v = start; v < end; v+=L1_CACHE_BYTES) { | |
112 | + unsigned long addr = (v & 0x000007f0); | |
113 | + int way; | |
114 | + /* O-Cache writeback */ | |
115 | + for (way = 0; way < 4; way++) { | |
116 | + unsigned long data = ctrl_inl(CACHE_OC_ADDRESS_ARRAY | addr | (way << 11)); | |
117 | + if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) { | |
118 | + data &= ~SH_CACHE_UPDATED; | |
119 | + ctrl_outl(data, CACHE_OC_ADDRESS_ARRAY | addr | (way << 11)); | |
120 | + } | |
121 | + } | |
122 | + /* I-Cache invalidate */ | |
123 | + ctrl_outl(addr, | |
124 | + CACHE_IC_ADDRESS_ARRAY | addr | 0x00000008); | |
125 | + } | |
126 | + | |
127 | + back_to_cached(); | |
128 | + local_irq_restore(flags); | |
129 | +} |