d0487fb92648fb4d73432a0885c858e2158fb510
[openwrt/svn-archive/archive.git] / target / linux / brcm-2.6 / patches / 003-bcm4710_cache_fixes.patch
1 diff -ur linux.old/arch/mips/kernel/genex.S linux.dev/arch/mips/kernel/genex.S
2 --- linux.old/arch/mips/kernel/genex.S 2006-10-16 19:09:36.000000000 +0200
3 +++ linux.dev/arch/mips/kernel/genex.S 2006-10-16 19:06:50.000000000 +0200
4 @@ -73,6 +73,10 @@
5 .set push
6 .set mips3
7 .set noat
8 +#ifdef CONFIG_BCM947XX
9 + nop
10 + nop
11 +#endif
12 mfc0 k1, CP0_CAUSE
13 li k0, 31<<2
14 andi k1, k1, 0x7c
15 diff -ur linux.old/arch/mips/mm/c-r4k.c linux.dev/arch/mips/mm/c-r4k.c
16 --- linux.old/arch/mips/mm/c-r4k.c 2006-10-16 19:09:36.000000000 +0200
17 +++ linux.dev/arch/mips/mm/c-r4k.c 2006-10-16 19:08:46.000000000 +0200
18 @@ -14,6 +14,15 @@
19 #include <linux/mm.h>
20 #include <linux/bitops.h>
21
22 +#ifdef CONFIG_BCM947XX
23 +#include "../bcm947xx/include/typedefs.h"
24 +#include "../bcm947xx/include/sbconfig.h"
25 +#include "../bcm947xx/include/mipsinc.h"
26 +#undef MTC0
27 +#undef MFC0
28 +#undef cache_op
29 +#include <asm/paccess.h>
30 +#endif
31 #include <asm/bcache.h>
32 #include <asm/bootinfo.h>
33 #include <asm/cache.h>
34 @@ -30,6 +39,9 @@
35 #include <asm/cacheflush.h> /* for run_uncached() */
36
37
38 +/* For enabling BCM4710 cache workarounds */
39 +int bcm4710 = 0;
40 +
41 /*
42 * Special Variant of smp_call_function for use by cache functions:
43 *
44 @@ -94,7 +106,9 @@
45 {
46 unsigned long dc_lsize = cpu_dcache_line_size();
47
48 - if (dc_lsize == 16)
49 + if (bcm4710)
50 + r4k_blast_dcache_page = blast_dcache_page;
51 + else if (dc_lsize == 16)
52 r4k_blast_dcache_page = blast_dcache16_page;
53 else if (dc_lsize == 32)
54 r4k_blast_dcache_page = r4k_blast_dcache_page_dc32;
55 @@ -106,7 +120,9 @@
56 {
57 unsigned long dc_lsize = cpu_dcache_line_size();
58
59 - if (dc_lsize == 16)
60 + if (bcm4710)
61 + r4k_blast_dcache_page_indexed = blast_dcache_page_indexed;
62 + else if (dc_lsize == 16)
63 r4k_blast_dcache_page_indexed = blast_dcache16_page_indexed;
64 else if (dc_lsize == 32)
65 r4k_blast_dcache_page_indexed = blast_dcache32_page_indexed;
66 @@ -118,7 +134,9 @@
67 {
68 unsigned long dc_lsize = cpu_dcache_line_size();
69
70 - if (dc_lsize == 16)
71 + if (bcm4710)
72 + r4k_blast_dcache = blast_dcache;
73 + else if (dc_lsize == 16)
74 r4k_blast_dcache = blast_dcache16;
75 else if (dc_lsize == 32)
76 r4k_blast_dcache = blast_dcache32;
77 @@ -527,6 +545,9 @@
78 r4k_blast_icache();
79 else
80 protected_blast_icache_range(start, end);
81 +
82 + if (bcm4710)
83 + r4k_flush_cache_all();
84 }
85
86 static void r4k_flush_icache_range(unsigned long start, unsigned long end)
87 @@ -683,6 +704,8 @@
88 unsigned long addr = (unsigned long) arg;
89
90 R4600_HIT_CACHEOP_WAR_IMPL;
91 + BCM4710_PROTECTED_FILL_TLB(addr);
92 + BCM4710_PROTECTED_FILL_TLB(addr + 4);
93 protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
94 if (!cpu_icache_snoops_remote_store && scache_size)
95 protected_writeback_scache_line(addr & ~(sc_lsize - 1));
96 @@ -1189,6 +1212,16 @@
97 static inline void coherency_setup(void)
98 {
99 change_c0_config(CONF_CM_CMASK, CONF_CM_DEFAULT);
100 +#ifdef CONFIG_BCM947XX
101 + if (BCM330X(current_cpu_data.processor_id)) {
102 + __u32 cm = read_c0_diag();
103 + /* Enable icache */
104 + cm |= (1 << 31);
105 + /* Enable dcache */
106 + cm |= (1 << 30);
107 + write_c0_diag(cm);
108 + }
109 +#endif
110
111 /*
112 * c0_status.cu=0 specifies that updates by the sc instruction use
113 @@ -1227,6 +1260,15 @@
114
115 /* Default cache error handler for R4000 and R5000 family */
116 set_uncached_handler (0x100, &except_vec2_generic, 0x80);
117 +
118 + /* Check if special workarounds are required */
119 +#ifdef CONFIG_BCM947XX
120 + if (current_cpu_data.cputype == CPU_BCM4710 && (current_cpu_data.processor_id & 0xff) == 0) {
121 + printk("Enabling BCM4710A0 cache workarounds.\n");
122 + bcm4710 = 1;
123 + } else
124 +#endif
125 + bcm4710 = 0;
126
127 probe_pcache();
128 setup_scache();
129 diff -ur linux.old/arch/mips/mm/tlbex.c linux.dev/arch/mips/mm/tlbex.c
130 --- linux.old/arch/mips/mm/tlbex.c 2006-10-16 19:09:36.000000000 +0200
131 +++ linux.dev/arch/mips/mm/tlbex.c 2006-10-16 19:06:50.000000000 +0200
132 @@ -38,6 +38,10 @@
133
134 /* #define DEBUG_TLB */
135
136 +#ifdef CONFIG_BCM947XX
137 +extern int bcm4710;
138 +#endif
139 +
140 static __init int __attribute__((unused)) r45k_bvahwbug(void)
141 {
142 /* XXX: We should probe for the presence of this bug, but we don't. */
143 @@ -1184,6 +1188,12 @@
144 memset(relocs, 0, sizeof(relocs));
145 memset(final_handler, 0, sizeof(final_handler));
146
147 +#ifdef CONFIG_BCM947XX
148 + if (bcm4710) {
149 + i_nop(&p);
150 + }
151 +#endif
152 +
153 /*
154 * create the plain linear handler
155 */
156 diff -ur linux.old/include/asm-mips/r4kcache.h linux.dev/include/asm-mips/r4kcache.h
157 --- linux.old/include/asm-mips/r4kcache.h 2006-10-16 19:09:36.000000000 +0200
158 +++ linux.dev/include/asm-mips/r4kcache.h 2006-10-16 19:09:11.000000000 +0200
159 @@ -17,6 +17,18 @@
160 #include <asm/cpu-features.h>
161 #include <asm/mipsmtregs.h>
162
163 +#ifdef CONFIG_BCM947XX
164 +#define BCM4710_DUMMY_RREG() (((sbconfig_t *)(KSEG1ADDR(SB_ENUM_BASE + SBCONFIGOFF)))->sbimstate)
165 +
166 +#define BCM4710_FILL_TLB(addr) (*(volatile unsigned long *)(addr))
167 +#define BCM4710_PROTECTED_FILL_TLB(addr) ({ unsigned long x; get_dbe(x, (volatile unsigned long *)(addr)); })
168 +#else
169 +#define BCM4710_DUMMY_RREG()
170 +
171 +#define BCM4710_FILL_TLB(addr)
172 +#define BCM4710_PROTECTED_FILL_TLB(addr)
173 +#endif
174 +
175 /*
176 * This macro return a properly sign-extended address suitable as base address
177 * for indexed cache operations. Two issues here:
178 @@ -150,6 +162,7 @@
179 static inline void flush_dcache_line_indexed(unsigned long addr)
180 {
181 __dflush_prologue
182 + BCM4710_DUMMY_RREG();
183 cache_op(Index_Writeback_Inv_D, addr);
184 __dflush_epilogue
185 }
186 @@ -169,6 +182,7 @@
187 static inline void flush_dcache_line(unsigned long addr)
188 {
189 __dflush_prologue
190 + BCM4710_DUMMY_RREG();
191 cache_op(Hit_Writeback_Inv_D, addr);
192 __dflush_epilogue
193 }
194 @@ -176,6 +190,7 @@
195 static inline void invalidate_dcache_line(unsigned long addr)
196 {
197 __dflush_prologue
198 + BCM4710_DUMMY_RREG();
199 cache_op(Hit_Invalidate_D, addr);
200 __dflush_epilogue
201 }
202 @@ -208,6 +223,7 @@
203 */
204 static inline void protected_flush_icache_line(unsigned long addr)
205 {
206 + BCM4710_DUMMY_RREG();
207 protected_cache_op(Hit_Invalidate_I, addr);
208 }
209
210 @@ -219,6 +235,7 @@
211 */
212 static inline void protected_writeback_dcache_line(unsigned long addr)
213 {
214 + BCM4710_DUMMY_RREG();
215 protected_cache_op(Hit_Writeback_Inv_D, addr);
216 }
217
218 @@ -339,8 +356,52 @@
219 : "r" (base), \
220 "i" (op));
221
222 +static inline void blast_dcache(void)
223 +{
224 + unsigned long start = KSEG0;
225 + unsigned long dcache_size = current_cpu_data.dcache.waysize * current_cpu_data.dcache.ways;
226 + unsigned long end = (start + dcache_size);
227 +
228 + do {
229 + BCM4710_DUMMY_RREG();
230 + cache_op(Index_Writeback_Inv_D, start);
231 + start += current_cpu_data.dcache.linesz;
232 + } while(start < end);
233 +}
234 +
235 +static inline void blast_dcache_page(unsigned long page)
236 +{
237 + unsigned long start = page;
238 + unsigned long end = start + PAGE_SIZE;
239 +
240 + BCM4710_FILL_TLB(start);
241 + do {
242 + BCM4710_DUMMY_RREG();
243 + cache_op(Hit_Writeback_Inv_D, start);
244 + start += current_cpu_data.dcache.linesz;
245 + } while(start < end);
246 +}
247 +
248 +static inline void blast_dcache_page_indexed(unsigned long page)
249 +{
250 + unsigned long start = page;
251 + unsigned long end = start + PAGE_SIZE;
252 + unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit;
253 + unsigned long ws_end = current_cpu_data.dcache.ways <<
254 + current_cpu_data.dcache.waybit;
255 + unsigned long ws, addr;
256 + for (ws = 0; ws < ws_end; ws += ws_inc) {
257 + start = page + ws;
258 + for (addr = start; addr < end; addr += current_cpu_data.dcache.linesz) {
259 + BCM4710_DUMMY_RREG();
260 + cache_op(Index_Writeback_Inv_D, addr);
261 + }
262 + }
263 +}
264 +
265 +
266 /* build blast_xxx, blast_xxx_page, blast_xxx_page_indexed */
267 -#define __BUILD_BLAST_CACHE(pfx, desc, indexop, hitop, lsize) \
268 +#define __BUILD_BLAST_CACHE(pfx, desc, indexop, hitop, lsize, war) \
269 static inline void blast_##pfx##cache##lsize(void) \
270 { \
271 unsigned long start = INDEX_BASE; \
272 @@ -352,6 +413,7 @@
273 \
274 __##pfx##flush_prologue \
275 \
276 + war \
277 for (ws = 0; ws < ws_end; ws += ws_inc) \
278 for (addr = start; addr < end; addr += lsize * 32) \
279 cache##lsize##_unroll32(addr|ws,indexop); \
280 @@ -366,6 +428,7 @@
281 \
282 __##pfx##flush_prologue \
283 \
284 + war \
285 do { \
286 cache##lsize##_unroll32(start,hitop); \
287 start += lsize * 32; \
288 @@ -384,6 +447,8 @@
289 current_cpu_data.desc.waybit; \
290 unsigned long ws, addr; \
291 \
292 + war \
293 + \
294 __##pfx##flush_prologue \
295 \
296 for (ws = 0; ws < ws_end; ws += ws_inc) \
297 @@ -393,28 +458,30 @@
298 __##pfx##flush_epilogue \
299 }
300
301 -__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16)
302 -__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16)
303 -__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16)
304 -__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32)
305 -__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32)
306 -__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32)
307 -__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64)
308 -__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64)
309 -__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128)
310 +__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16, )
311 +__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16, BCM4710_FILL_TLB(start);)
312 +__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16, )
313 +__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32, )
314 +__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32, BCM4710_FILL_TLB(start);)
315 +__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32, )
316 +__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64, BCM4710_FILL_TLB(start);)
317 +__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64, )
318 +__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128, )
319
320 /* build blast_xxx_range, protected_blast_xxx_range */
321 -#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot) \
322 +#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot, war, war2) \
323 static inline void prot##blast_##pfx##cache##_range(unsigned long start, \
324 unsigned long end) \
325 { \
326 unsigned long lsize = cpu_##desc##_line_size(); \
327 unsigned long addr = start & ~(lsize - 1); \
328 unsigned long aend = (end - 1) & ~(lsize - 1); \
329 + war \
330 \
331 __##pfx##flush_prologue \
332 \
333 while (1) { \
334 + war2 \
335 prot##cache_op(hitop, addr); \
336 if (addr == aend) \
337 break; \
338 @@ -424,13 +491,13 @@
339 __##pfx##flush_epilogue \
340 }
341
342 -__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_)
343 -__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_)
344 -__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_)
345 -__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, )
346 -__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, )
347 +__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_, BCM4710_PROTECTED_FILL_TLB(addr); BCM4710_PROTECTED_FILL_TLB(aend);, BCM4710_DUMMY_RREG();)
348 +__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_,, )
349 +__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_,, )
350 +__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D,, BCM4710_FILL_TLB(addr); BCM4710_FILL_TLB(aend);, BCM4710_DUMMY_RREG();)
351 +__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD,,, )
352 /* blast_inv_dcache_range */
353 -__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, )
354 -__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD, )
355 +__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D,,,BCM4710_DUMMY_RREG();)
356 +__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD,,, )
357
358 #endif /* _ASM_R4KCACHE_H */
359 diff -ur linux.old/include/asm-mips/stackframe.h linux.dev/include/asm-mips/stackframe.h
360 --- linux.old/include/asm-mips/stackframe.h 2006-10-16 19:09:36.000000000 +0200
361 +++ linux.dev/include/asm-mips/stackframe.h 2006-10-16 19:06:50.000000000 +0200
362 @@ -361,6 +361,10 @@
363 .macro RESTORE_SP_AND_RET
364 LONG_L sp, PT_R29(sp)
365 .set mips3
366 +#ifdef CONFIG_BCM947XX
367 + nop
368 + nop
369 +#endif
370 eret
371 .set mips0
372 .endm