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