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