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