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