diff options
author | Ricardo Mendoza <ricmm@gentoo.org> | 2010-07-19 00:00:00 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2010-08-05 08:26:06 -0400 |
commit | 745aef5df1e2277ee9e34d86491084c0d6106338 (patch) | |
tree | 3d20535d8b5d7f1ccc2867240cf70376eb23a574 /arch/mips/mm | |
parent | 58a6d45193a4f5af9d55f243779ea485656e3a22 (diff) |
MIPS: RM7000: Add support for tertiary cache
Add support for the external T-cache interface. Allow for platform
independent size probing from 512KB to 8MB in powers of two.
Signed-off-by: Ricardo Mendoza <ricmm@gentoo.org>
To: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/1477/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/mm')
-rw-r--r-- | arch/mips/mm/sc-rm7k.c | 151 |
1 files changed, 128 insertions, 23 deletions
diff --git a/arch/mips/mm/sc-rm7k.c b/arch/mips/mm/sc-rm7k.c index 53634398a56d..1ef75cd80a0d 100644 --- a/arch/mips/mm/sc-rm7k.c +++ b/arch/mips/mm/sc-rm7k.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <asm/cacheops.h> | 16 | #include <asm/cacheops.h> |
17 | #include <asm/mipsregs.h> | 17 | #include <asm/mipsregs.h> |
18 | #include <asm/processor.h> | 18 | #include <asm/processor.h> |
19 | #include <asm/sections.h> | ||
19 | #include <asm/cacheflush.h> /* for run_uncached() */ | 20 | #include <asm/cacheflush.h> /* for run_uncached() */ |
20 | 21 | ||
21 | /* Primary cache parameters. */ | 22 | /* Primary cache parameters. */ |
@@ -25,11 +26,15 @@ | |||
25 | /* Secondary cache parameters. */ | 26 | /* Secondary cache parameters. */ |
26 | #define scache_size (256*1024) /* Fixed to 256KiB on RM7000 */ | 27 | #define scache_size (256*1024) /* Fixed to 256KiB on RM7000 */ |
27 | 28 | ||
29 | /* Tertiary cache parameters */ | ||
30 | #define tc_lsize 32 | ||
31 | |||
28 | extern unsigned long icache_way_size, dcache_way_size; | 32 | extern unsigned long icache_way_size, dcache_way_size; |
33 | unsigned long tcache_size; | ||
29 | 34 | ||
30 | #include <asm/r4kcache.h> | 35 | #include <asm/r4kcache.h> |
31 | 36 | ||
32 | static int rm7k_tcache_enabled; | 37 | static int rm7k_tcache_init; |
33 | 38 | ||
34 | /* | 39 | /* |
35 | * Writeback and invalidate the primary cache dcache before DMA. | 40 | * Writeback and invalidate the primary cache dcache before DMA. |
@@ -46,7 +51,7 @@ static void rm7k_sc_wback_inv(unsigned long addr, unsigned long size) | |||
46 | 51 | ||
47 | blast_scache_range(addr, addr + size); | 52 | blast_scache_range(addr, addr + size); |
48 | 53 | ||
49 | if (!rm7k_tcache_enabled) | 54 | if (!rm7k_tcache_init) |
50 | return; | 55 | return; |
51 | 56 | ||
52 | a = addr & ~(tc_pagesize - 1); | 57 | a = addr & ~(tc_pagesize - 1); |
@@ -70,7 +75,7 @@ static void rm7k_sc_inv(unsigned long addr, unsigned long size) | |||
70 | 75 | ||
71 | blast_inv_scache_range(addr, addr + size); | 76 | blast_inv_scache_range(addr, addr + size); |
72 | 77 | ||
73 | if (!rm7k_tcache_enabled) | 78 | if (!rm7k_tcache_init) |
74 | return; | 79 | return; |
75 | 80 | ||
76 | a = addr & ~(tc_pagesize - 1); | 81 | a = addr & ~(tc_pagesize - 1); |
@@ -83,6 +88,45 @@ static void rm7k_sc_inv(unsigned long addr, unsigned long size) | |||
83 | } | 88 | } |
84 | } | 89 | } |
85 | 90 | ||
91 | static void blast_rm7k_tcache(void) | ||
92 | { | ||
93 | unsigned long start = CKSEG0ADDR(0); | ||
94 | unsigned long end = start + tcache_size; | ||
95 | |||
96 | write_c0_taglo(0); | ||
97 | |||
98 | while (start < end) { | ||
99 | cache_op(Page_Invalidate_T, start); | ||
100 | start += tc_pagesize; | ||
101 | } | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * This function is executed in uncached address space. | ||
106 | */ | ||
107 | static __cpuinit void __rm7k_tc_enable(void) | ||
108 | { | ||
109 | int i; | ||
110 | |||
111 | set_c0_config(RM7K_CONF_TE); | ||
112 | |||
113 | write_c0_taglo(0); | ||
114 | write_c0_taghi(0); | ||
115 | |||
116 | for (i = 0; i < tcache_size; i += tc_lsize) | ||
117 | cache_op(Index_Store_Tag_T, CKSEG0ADDR(i)); | ||
118 | } | ||
119 | |||
120 | static __cpuinit void rm7k_tc_enable(void) | ||
121 | { | ||
122 | if (read_c0_config() & RM7K_CONF_TE) | ||
123 | return; | ||
124 | |||
125 | BUG_ON(tcache_size == 0); | ||
126 | |||
127 | run_uncached(__rm7k_tc_enable); | ||
128 | } | ||
129 | |||
86 | /* | 130 | /* |
87 | * This function is executed in uncached address space. | 131 | * This function is executed in uncached address space. |
88 | */ | 132 | */ |
@@ -104,13 +148,29 @@ static __cpuinit void rm7k_sc_enable(void) | |||
104 | if (read_c0_config() & RM7K_CONF_SE) | 148 | if (read_c0_config() & RM7K_CONF_SE) |
105 | return; | 149 | return; |
106 | 150 | ||
107 | printk(KERN_INFO "Enabling secondary cache...\n"); | 151 | pr_info("Enabling secondary cache...\n"); |
108 | run_uncached(__rm7k_sc_enable); | 152 | run_uncached(__rm7k_sc_enable); |
153 | |||
154 | if (rm7k_tcache_init) | ||
155 | rm7k_tc_enable(); | ||
156 | } | ||
157 | |||
158 | static void rm7k_tc_disable(void) | ||
159 | { | ||
160 | unsigned long flags; | ||
161 | |||
162 | local_irq_save(flags); | ||
163 | blast_rm7k_tcache(); | ||
164 | clear_c0_config(RM7K_CONF_TE); | ||
165 | local_irq_save(flags); | ||
109 | } | 166 | } |
110 | 167 | ||
111 | static void rm7k_sc_disable(void) | 168 | static void rm7k_sc_disable(void) |
112 | { | 169 | { |
113 | clear_c0_config(RM7K_CONF_SE); | 170 | clear_c0_config(RM7K_CONF_SE); |
171 | |||
172 | if (rm7k_tcache_init) | ||
173 | rm7k_tc_disable(); | ||
114 | } | 174 | } |
115 | 175 | ||
116 | static struct bcache_ops rm7k_sc_ops = { | 176 | static struct bcache_ops rm7k_sc_ops = { |
@@ -120,6 +180,52 @@ static struct bcache_ops rm7k_sc_ops = { | |||
120 | .bc_inv = rm7k_sc_inv | 180 | .bc_inv = rm7k_sc_inv |
121 | }; | 181 | }; |
122 | 182 | ||
183 | /* | ||
184 | * This is a probing function like the one found in c-r4k.c, we look for the | ||
185 | * wrap around point with different addresses. | ||
186 | */ | ||
187 | static __cpuinit void __probe_tcache(void) | ||
188 | { | ||
189 | unsigned long flags, addr, begin, end, pow2; | ||
190 | |||
191 | begin = (unsigned long) &_stext; | ||
192 | begin &= ~((8 * 1024 * 1024) - 1); | ||
193 | end = begin + (8 * 1024 * 1024); | ||
194 | |||
195 | local_irq_save(flags); | ||
196 | |||
197 | set_c0_config(RM7K_CONF_TE); | ||
198 | |||
199 | /* Fill size-multiple lines with a valid tag */ | ||
200 | pow2 = (256 * 1024); | ||
201 | for (addr = begin; addr <= end; addr = (begin + pow2)) { | ||
202 | unsigned long *p = (unsigned long *) addr; | ||
203 | __asm__ __volatile__("nop" : : "r" (*p)); | ||
204 | pow2 <<= 1; | ||
205 | } | ||
206 | |||
207 | /* Load first line with a 0 tag, to check after */ | ||
208 | write_c0_taglo(0); | ||
209 | write_c0_taghi(0); | ||
210 | cache_op(Index_Store_Tag_T, begin); | ||
211 | |||
212 | /* Look for the wrap-around */ | ||
213 | pow2 = (512 * 1024); | ||
214 | for (addr = begin + (512 * 1024); addr <= end; addr = begin + pow2) { | ||
215 | cache_op(Index_Load_Tag_T, addr); | ||
216 | if (!read_c0_taglo()) | ||
217 | break; | ||
218 | pow2 <<= 1; | ||
219 | } | ||
220 | |||
221 | addr -= begin; | ||
222 | tcache_size = addr; | ||
223 | |||
224 | clear_c0_config(RM7K_CONF_TE); | ||
225 | |||
226 | local_irq_restore(flags); | ||
227 | } | ||
228 | |||
123 | void __cpuinit rm7k_sc_init(void) | 229 | void __cpuinit rm7k_sc_init(void) |
124 | { | 230 | { |
125 | struct cpuinfo_mips *c = ¤t_cpu_data; | 231 | struct cpuinfo_mips *c = ¤t_cpu_data; |
@@ -139,27 +245,26 @@ void __cpuinit rm7k_sc_init(void) | |||
139 | if (!(config & RM7K_CONF_SE)) | 245 | if (!(config & RM7K_CONF_SE)) |
140 | rm7k_sc_enable(); | 246 | rm7k_sc_enable(); |
141 | 247 | ||
248 | bcops = &rm7k_sc_ops; | ||
249 | |||
142 | /* | 250 | /* |
143 | * While we're at it let's deal with the tertiary cache. | 251 | * While we're at it let's deal with the tertiary cache. |
144 | */ | 252 | */ |
145 | if (!(config & RM7K_CONF_TC)) { | ||
146 | |||
147 | /* | ||
148 | * We can't enable the L3 cache yet. There may be board-specific | ||
149 | * magic necessary to turn it on, and blindly asking the CPU to | ||
150 | * start using it would may give cache errors. | ||
151 | * | ||
152 | * Also, board-specific knowledge may allow us to use the | ||
153 | * CACHE Flash_Invalidate_T instruction if the tag RAM supports | ||
154 | * it, and may specify the size of the L3 cache so we don't have | ||
155 | * to probe it. | ||
156 | */ | ||
157 | printk(KERN_INFO "Tertiary cache present, %s enabled\n", | ||
158 | (config & RM7K_CONF_TE) ? "already" : "not (yet)"); | ||
159 | |||
160 | if ((config & RM7K_CONF_TE)) | ||
161 | rm7k_tcache_enabled = 1; | ||
162 | } | ||
163 | 253 | ||
164 | bcops = &rm7k_sc_ops; | 254 | rm7k_tcache_init = 0; |
255 | tcache_size = 0; | ||
256 | |||
257 | if (config & RM7K_CONF_TC) | ||
258 | return; | ||
259 | |||
260 | /* | ||
261 | * No efficient way to ask the hardware for the size of the tcache, | ||
262 | * so must probe for it. | ||
263 | */ | ||
264 | run_uncached(__probe_tcache); | ||
265 | rm7k_tc_enable(); | ||
266 | rm7k_tcache_init = 1; | ||
267 | c->tcache.linesz = tc_lsize; | ||
268 | c->tcache.ways = 1; | ||
269 | pr_info("Tertiary cache size %ldK.\n", (tcache_size >> 10)); | ||
165 | } | 270 | } |