aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/mm
diff options
context:
space:
mode:
authorRicardo Mendoza <ricmm@gentoo.org>2010-07-19 00:00:00 -0400
committerRalf Baechle <ralf@linux-mips.org>2010-08-05 08:26:06 -0400
commit745aef5df1e2277ee9e34d86491084c0d6106338 (patch)
tree3d20535d8b5d7f1ccc2867240cf70376eb23a574 /arch/mips/mm
parent58a6d45193a4f5af9d55f243779ea485656e3a22 (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.c151
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
28extern unsigned long icache_way_size, dcache_way_size; 32extern unsigned long icache_way_size, dcache_way_size;
33unsigned long tcache_size;
29 34
30#include <asm/r4kcache.h> 35#include <asm/r4kcache.h>
31 36
32static int rm7k_tcache_enabled; 37static 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
91static 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 */
107static __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
120static __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
158static 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
111static void rm7k_sc_disable(void) 168static 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
116static struct bcache_ops rm7k_sc_ops = { 176static 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 */
187static __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
123void __cpuinit rm7k_sc_init(void) 229void __cpuinit rm7k_sc_init(void)
124{ 230{
125 struct cpuinfo_mips *c = &current_cpu_data; 231 struct cpuinfo_mips *c = &current_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}