bcm4710: port a missing part of the cache fixes to linux 2.6
[openwrt.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