brcm47xx: 2.6.28 was accidentally committed with the old (and conceptually broken...
[openwrt/svn-archive/archive.git] / target / linux / brcm47xx / patches-2.6.25 / 150-cpu_fixes.patch
1 --- a/arch/mips/kernel/genex.S
2 +++ b/arch/mips/kernel/genex.S
3 @@ -51,6 +51,10 @@ NESTED(except_vec1_generic, 0, sp)
4 NESTED(except_vec3_generic, 0, sp)
5 .set push
6 .set noat
7 +#ifdef CONFIG_BCM47XX
8 + nop
9 + nop
10 +#endif
11 #if R5432_CP0_INTERRUPT_WAR
12 mfc0 k0, CP0_INDEX
13 #endif
14 --- a/arch/mips/mm/c-r4k.c
15 +++ b/arch/mips/mm/c-r4k.c
16 @@ -33,6 +33,9 @@
17 #include <asm/cacheflush.h> /* for run_uncached() */
18
19
20 +/* For enabling BCM4710 cache workarounds */
21 +int bcm4710 = 0;
22 +
23 /*
24 * Special Variant of smp_call_function for use by cache functions:
25 *
26 @@ -97,6 +100,9 @@ static void __cpuinit r4k_blast_dcache_p
27 {
28 unsigned long dc_lsize = cpu_dcache_line_size();
29
30 + if (bcm4710)
31 + r4k_blast_dcache_page = blast_dcache_page;
32 + else
33 if (dc_lsize == 0)
34 r4k_blast_dcache_page = (void *)cache_noop;
35 else if (dc_lsize == 16)
36 @@ -111,6 +117,9 @@ static void __cpuinit r4k_blast_dcache_p
37 {
38 unsigned long dc_lsize = cpu_dcache_line_size();
39
40 + if (bcm4710)
41 + r4k_blast_dcache_page_indexed = blast_dcache_page_indexed;
42 + else
43 if (dc_lsize == 0)
44 r4k_blast_dcache_page_indexed = (void *)cache_noop;
45 else if (dc_lsize == 16)
46 @@ -125,6 +134,9 @@ static void __cpuinit r4k_blast_dcache_s
47 {
48 unsigned long dc_lsize = cpu_dcache_line_size();
49
50 + if (bcm4710)
51 + r4k_blast_dcache = blast_dcache;
52 + else
53 if (dc_lsize == 0)
54 r4k_blast_dcache = (void *)cache_noop;
55 else if (dc_lsize == 16)
56 @@ -630,6 +642,8 @@ static void local_r4k_flush_cache_sigtra
57 unsigned long addr = (unsigned long) arg;
58
59 R4600_HIT_CACHEOP_WAR_IMPL;
60 + BCM4710_PROTECTED_FILL_TLB(addr);
61 + BCM4710_PROTECTED_FILL_TLB(addr + 4);
62 if (dc_lsize)
63 protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
64 if (!cpu_icache_snoops_remote_store && scache_size)
65 @@ -1215,6 +1229,17 @@ static void __cpuinit coherency_setup(vo
66 * silly idea of putting something else there ...
67 */
68 switch (current_cpu_type()) {
69 + case CPU_BCM3302:
70 + {
71 + u32 cm;
72 + cm = read_c0_diag();
73 + /* Enable icache */
74 + cm |= (1 << 31);
75 + /* Enable dcache */
76 + cm |= (1 << 30);
77 + write_c0_diag(cm);
78 + }
79 + break;
80 case CPU_R4000PC:
81 case CPU_R4000SC:
82 case CPU_R4000MC:
83 @@ -1254,6 +1279,15 @@ void __cpuinit r4k_cache_init(void)
84 break;
85 }
86
87 + /* Check if special workarounds are required */
88 +#ifdef CONFIG_BCM47XX
89 + if (current_cpu_data.cputype == CPU_BCM4710 && (current_cpu_data.processor_id & 0xff) == 0) {
90 + printk("Enabling BCM4710A0 cache workarounds.\n");
91 + bcm4710 = 1;
92 + } else
93 +#endif
94 + bcm4710 = 0;
95 +
96 probe_pcache();
97 setup_scache();
98
99 @@ -1303,5 +1337,13 @@ void __cpuinit r4k_cache_init(void)
100 build_clear_page();
101 build_copy_page();
102 local_r4k___flush_cache_all(NULL);
103 +#ifdef CONFIG_BCM47XX
104 + {
105 + static void (*_coherency_setup)(void);
106 + _coherency_setup = (void (*)(void)) KSEG1ADDR(coherency_setup);
107 + _coherency_setup();
108 + }
109 +#else
110 coherency_setup();
111 +#endif
112 }
113 --- a/arch/mips/mm/tlbex.c
114 +++ b/arch/mips/mm/tlbex.c
115 @@ -677,6 +677,9 @@ static void __cpuinit build_r4000_tlb_re
116 /* No need for uasm_i_nop */
117 }
118
119 +#ifdef CONFIG_BCM47XX
120 + uasm_i_nop(&p);
121 +#endif
122 #ifdef CONFIG_64BIT
123 build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */
124 #else
125 @@ -1084,6 +1087,9 @@ build_r4000_tlbchange_handler_head(u32 *
126 struct uasm_reloc **r, unsigned int pte,
127 unsigned int ptr)
128 {
129 +#ifdef CONFIG_BCM47XX
130 + uasm_i_nop(p);
131 +#endif
132 #ifdef CONFIG_64BIT
133 build_get_pmde64(p, l, r, pte, ptr); /* get pmd in ptr */
134 #else
135 --- a/include/asm-mips/r4kcache.h
136 +++ b/include/asm-mips/r4kcache.h
137 @@ -17,6 +17,20 @@
138 #include <asm/cpu-features.h>
139 #include <asm/mipsmtregs.h>
140
141 +#ifdef CONFIG_BCM47XX
142 +#include <asm/paccess.h>
143 +#include <linux/ssb/ssb.h>
144 +#define BCM4710_DUMMY_RREG() ((void) *((u8 *) KSEG1ADDR(SSB_ENUM_BASE + SSB_IMSTATE)))
145 +
146 +#define BCM4710_FILL_TLB(addr) (*(volatile unsigned long *)(addr))
147 +#define BCM4710_PROTECTED_FILL_TLB(addr) ({ unsigned long x; get_dbe(x, (volatile unsigned long *)(addr)); })
148 +#else
149 +#define BCM4710_DUMMY_RREG()
150 +
151 +#define BCM4710_FILL_TLB(addr)
152 +#define BCM4710_PROTECTED_FILL_TLB(addr)
153 +#endif
154 +
155 /*
156 * This macro return a properly sign-extended address suitable as base address
157 * for indexed cache operations. Two issues here:
158 @@ -150,6 +164,7 @@ static inline void flush_icache_line_ind
159 static inline void flush_dcache_line_indexed(unsigned long addr)
160 {
161 __dflush_prologue
162 + BCM4710_DUMMY_RREG();
163 cache_op(Index_Writeback_Inv_D, addr);
164 __dflush_epilogue
165 }
166 @@ -169,6 +184,7 @@ static inline void flush_icache_line(uns
167 static inline void flush_dcache_line(unsigned long addr)
168 {
169 __dflush_prologue
170 + BCM4710_DUMMY_RREG();
171 cache_op(Hit_Writeback_Inv_D, addr);
172 __dflush_epilogue
173 }
174 @@ -176,6 +192,7 @@ static inline void flush_dcache_line(uns
175 static inline void invalidate_dcache_line(unsigned long addr)
176 {
177 __dflush_prologue
178 + BCM4710_DUMMY_RREG();
179 cache_op(Hit_Invalidate_D, addr);
180 __dflush_epilogue
181 }
182 @@ -208,6 +225,7 @@ static inline void flush_scache_line(uns
183 */
184 static inline void protected_flush_icache_line(unsigned long addr)
185 {
186 + BCM4710_DUMMY_RREG();
187 protected_cache_op(Hit_Invalidate_I, addr);
188 }
189
190 @@ -219,6 +237,7 @@ static inline void protected_flush_icach
191 */
192 static inline void protected_writeback_dcache_line(unsigned long addr)
193 {
194 + BCM4710_DUMMY_RREG();
195 protected_cache_op(Hit_Writeback_Inv_D, addr);
196 }
197
198 @@ -339,8 +358,52 @@ static inline void invalidate_tcache_pag
199 : "r" (base), \
200 "i" (op));
201
202 +static inline void blast_dcache(void)
203 +{
204 + unsigned long start = KSEG0;
205 + unsigned long dcache_size = current_cpu_data.dcache.waysize * current_cpu_data.dcache.ways;
206 + unsigned long end = (start + dcache_size);
207 +
208 + do {
209 + BCM4710_DUMMY_RREG();
210 + cache_op(Index_Writeback_Inv_D, start);
211 + start += current_cpu_data.dcache.linesz;
212 + } while(start < end);
213 +}
214 +
215 +static inline void blast_dcache_page(unsigned long page)
216 +{
217 + unsigned long start = page;
218 + unsigned long end = start + PAGE_SIZE;
219 +
220 + BCM4710_FILL_TLB(start);
221 + do {
222 + BCM4710_DUMMY_RREG();
223 + cache_op(Hit_Writeback_Inv_D, start);
224 + start += current_cpu_data.dcache.linesz;
225 + } while(start < end);
226 +}
227 +
228 +static inline void blast_dcache_page_indexed(unsigned long page)
229 +{
230 + unsigned long start = page;
231 + unsigned long end = start + PAGE_SIZE;
232 + unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit;
233 + unsigned long ws_end = current_cpu_data.dcache.ways <<
234 + current_cpu_data.dcache.waybit;
235 + unsigned long ws, addr;
236 + for (ws = 0; ws < ws_end; ws += ws_inc) {
237 + start = page + ws;
238 + for (addr = start; addr < end; addr += current_cpu_data.dcache.linesz) {
239 + BCM4710_DUMMY_RREG();
240 + cache_op(Index_Writeback_Inv_D, addr);
241 + }
242 + }
243 +}
244 +
245 +
246 /* build blast_xxx, blast_xxx_page, blast_xxx_page_indexed */
247 -#define __BUILD_BLAST_CACHE(pfx, desc, indexop, hitop, lsize) \
248 +#define __BUILD_BLAST_CACHE(pfx, desc, indexop, hitop, lsize, war) \
249 static inline void blast_##pfx##cache##lsize(void) \
250 { \
251 unsigned long start = INDEX_BASE; \
252 @@ -352,6 +415,7 @@ static inline void blast_##pfx##cache##l
253 \
254 __##pfx##flush_prologue \
255 \
256 + war \
257 for (ws = 0; ws < ws_end; ws += ws_inc) \
258 for (addr = start; addr < end; addr += lsize * 32) \
259 cache##lsize##_unroll32(addr|ws, indexop); \
260 @@ -366,6 +430,7 @@ static inline void blast_##pfx##cache##l
261 \
262 __##pfx##flush_prologue \
263 \
264 + war \
265 do { \
266 cache##lsize##_unroll32(start, hitop); \
267 start += lsize * 32; \
268 @@ -384,6 +449,8 @@ static inline void blast_##pfx##cache##l
269 current_cpu_data.desc.waybit; \
270 unsigned long ws, addr; \
271 \
272 + war \
273 + \
274 __##pfx##flush_prologue \
275 \
276 for (ws = 0; ws < ws_end; ws += ws_inc) \
277 @@ -393,35 +460,37 @@ static inline void blast_##pfx##cache##l
278 __##pfx##flush_epilogue \
279 }
280
281 -__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16)
282 -__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16)
283 -__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16)
284 -__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32)
285 -__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32)
286 -__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32)
287 -__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64)
288 -__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64)
289 -__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128)
290 -
291 -__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16)
292 -__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 32)
293 -__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 16)
294 -__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 32)
295 -__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 64)
296 -__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 128)
297 +__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16, )
298 +__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16, BCM4710_FILL_TLB(start);)
299 +__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16, )
300 +__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32, )
301 +__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32, BCM4710_FILL_TLB(start);)
302 +__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32, )
303 +__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64, BCM4710_FILL_TLB(start);)
304 +__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64, )
305 +__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128, )
306 +
307 +__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16, )
308 +__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 32, )
309 +__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 16, )
310 +__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 32, )
311 +__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 64, )
312 +__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 128, )
313
314 /* build blast_xxx_range, protected_blast_xxx_range */
315 -#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot) \
316 +#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot, war, war2) \
317 static inline void prot##blast_##pfx##cache##_range(unsigned long start, \
318 unsigned long end) \
319 { \
320 unsigned long lsize = cpu_##desc##_line_size(); \
321 unsigned long addr = start & ~(lsize - 1); \
322 unsigned long aend = (end - 1) & ~(lsize - 1); \
323 + war \
324 \
325 __##pfx##flush_prologue \
326 \
327 while (1) { \
328 + war2 \
329 prot##cache_op(hitop, addr); \
330 if (addr == aend) \
331 break; \
332 @@ -431,13 +500,13 @@ static inline void prot##blast_##pfx##ca
333 __##pfx##flush_epilogue \
334 }
335
336 -__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_)
337 -__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_)
338 -__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_)
339 -__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, )
340 -__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, )
341 +__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_, BCM4710_PROTECTED_FILL_TLB(addr); BCM4710_PROTECTED_FILL_TLB(aend);, BCM4710_DUMMY_RREG();)
342 +__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_,, )
343 +__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_,, )
344 +__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D,, BCM4710_FILL_TLB(addr); BCM4710_FILL_TLB(aend);, BCM4710_DUMMY_RREG();)
345 +__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD,,, )
346 /* blast_inv_dcache_range */
347 -__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, )
348 -__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD, )
349 +__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D,,,BCM4710_DUMMY_RREG();)
350 +__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD,,, )
351
352 #endif /* _ASM_R4KCACHE_H */
353 --- a/include/asm-mips/stackframe.h
354 +++ b/include/asm-mips/stackframe.h
355 @@ -359,6 +359,10 @@
356 .macro RESTORE_SP_AND_RET
357 LONG_L sp, PT_R29(sp)
358 .set mips3
359 +#ifdef CONFIG_BCM47XX
360 + nop
361 + nop
362 +#endif
363 eret
364 .set mips0
365 .endm