ipv6-support: Update iteration
[openwrt.git] / target / linux / brcm47xx / patches-3.3 / 150-cpu_fixes.patch
1 --- a/arch/mips/include/asm/r4kcache.h
2 +++ b/arch/mips/include/asm/r4kcache.h
3 @@ -17,6 +17,20 @@
4  #include <asm/cpu-features.h>
5  #include <asm/mipsmtregs.h>
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 @@ -150,6 +164,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 @@ -169,6 +184,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 @@ -176,6 +192,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 @@ -208,6 +225,7 @@ static inline void flush_scache_line(uns
49   */
50  static inline void protected_flush_icache_line(unsigned long addr)
51  {
52 +       BCM4710_DUMMY_RREG();
53         protected_cache_op(Hit_Invalidate_I, addr);
54  }
55  
56 @@ -219,6 +237,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         protected_cache_op(Hit_Writeback_Inv_D, addr);
62  }
63  
64 @@ -339,8 +358,52 @@ 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 +
112  /* build blast_xxx, blast_xxx_page, blast_xxx_page_indexed */
113 -#define __BUILD_BLAST_CACHE(pfx, desc, indexop, hitop, lsize) \
114 +#define __BUILD_BLAST_CACHE(pfx, desc, indexop, hitop, lsize, war) \
115  static inline void blast_##pfx##cache##lsize(void)                     \
116  {                                                                      \
117         unsigned long start = INDEX_BASE;                               \
118 @@ -352,6 +415,7 @@ static inline void blast_##pfx##cache##l
119                                                                         \
120         __##pfx##flush_prologue                                         \
121                                                                         \
122 +       war                                                             \
123         for (ws = 0; ws < ws_end; ws += ws_inc)                         \
124                 for (addr = start; addr < end; addr += lsize * 32)      \
125                         cache##lsize##_unroll32(addr|ws, indexop);      \
126 @@ -366,6 +430,7 @@ static inline void blast_##pfx##cache##l
127                                                                         \
128         __##pfx##flush_prologue                                         \
129                                                                         \
130 +       war                                                             \
131         do {                                                            \
132                 cache##lsize##_unroll32(start, hitop);                  \
133                 start += lsize * 32;                                    \
134 @@ -384,6 +449,8 @@ static inline void blast_##pfx##cache##l
135                                current_cpu_data.desc.waybit;            \
136         unsigned long ws, addr;                                         \
137                                                                         \
138 +       war                                                             \
139 +                                                                       \
140         __##pfx##flush_prologue                                         \
141                                                                         \
142         for (ws = 0; ws < ws_end; ws += ws_inc)                         \
143 @@ -393,36 +460,38 @@ static inline void blast_##pfx##cache##l
144         __##pfx##flush_epilogue                                         \
145  }
146  
147 -__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16)
148 -__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16)
149 -__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16)
150 -__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32)
151 -__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32)
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(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(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 64, )
171 +__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64, BCM4710_FILL_TLB(start);)
172 +__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64, )
173 +__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128, )
174 +
175 +__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16, )
176 +__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 32, )
177 +__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 16, )
178 +__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 32, )
179 +__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 64, )
180 +__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 128, )
181  
182  /* build blast_xxx_range, protected_blast_xxx_range */
183 -#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot) \
184 +#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot, war, war2) \
185  static inline void prot##blast_##pfx##cache##_range(unsigned long start, \
186                                                     unsigned long end)  \
187  {                                                                      \
188         unsigned long lsize = cpu_##desc##_line_size();                 \
189         unsigned long addr = start & ~(lsize - 1);                      \
190         unsigned long aend = (end - 1) & ~(lsize - 1);                  \
191 +       war                                                             \
192                                                                         \
193         __##pfx##flush_prologue                                         \
194                                                                         \
195         while (1) {                                                     \
196 +               war2                                            \
197                 prot##cache_op(hitop, addr);                            \
198                 if (addr == aend)                                       \
199                         break;                                          \
200 @@ -432,13 +501,13 @@ static inline void prot##blast_##pfx##ca
201         __##pfx##flush_epilogue                                         \
202  }
203  
204 -__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_)
205 -__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_)
206 -__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_)
207 -__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, )
208 -__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, )
209 +__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_, BCM4710_PROTECTED_FILL_TLB(addr); BCM4710_PROTECTED_FILL_TLB(aend);, BCM4710_DUMMY_RREG();)
210 +__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_,, )
211 +__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_,, )
212 +__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D,, BCM4710_FILL_TLB(addr); BCM4710_FILL_TLB(aend);, BCM4710_DUMMY_RREG();)
213 +__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD,,, )
214  /* blast_inv_dcache_range */
215 -__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, )
216 -__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD, )
217 +__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D,,,BCM4710_DUMMY_RREG();)
218 +__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD,,, )
219  
220  #endif /* _ASM_R4KCACHE_H */
221 --- a/arch/mips/include/asm/stackframe.h
222 +++ b/arch/mips/include/asm/stackframe.h
223 @@ -449,6 +449,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 --- a/arch/mips/kernel/genex.S
235 +++ b/arch/mips/kernel/genex.S
236 @@ -52,6 +52,10 @@ NESTED(except_vec1_generic, 0, sp)
237  NESTED(except_vec3_generic, 0, sp)
238         .set    push
239         .set    noat
240 +#ifdef CONFIG_BCM47XX
241 +       nop
242 +       nop
243 +#endif
244  #if R5432_CP0_INTERRUPT_WAR
245         mfc0    k0, CP0_INDEX
246  #endif
247 --- a/arch/mips/mm/c-r4k.c
248 +++ b/arch/mips/mm/c-r4k.c
249 @@ -35,6 +35,9 @@
250  #include <asm/cacheflush.h> /* for run_uncached() */
251  
252  
253 +/* For enabling BCM4710 cache workarounds */
254 +int bcm4710 = 0;
255 +
256  /*
257   * Special Variant of smp_call_function for use by cache functions:
258   *
259 @@ -111,6 +114,9 @@ static void __cpuinit r4k_blast_dcache_p
260  {
261         unsigned long  dc_lsize = cpu_dcache_line_size();
262  
263 +       if (bcm4710)
264 +               r4k_blast_dcache_page = blast_dcache_page;
265 +       else
266         if (dc_lsize == 0)
267                 r4k_blast_dcache_page = (void *)cache_noop;
268         else if (dc_lsize == 16)
269 @@ -127,6 +133,9 @@ static void __cpuinit r4k_blast_dcache_p
270  {
271         unsigned long dc_lsize = cpu_dcache_line_size();
272  
273 +       if (bcm4710)
274 +               r4k_blast_dcache_page_indexed = blast_dcache_page_indexed;
275 +       else
276         if (dc_lsize == 0)
277                 r4k_blast_dcache_page_indexed = (void *)cache_noop;
278         else if (dc_lsize == 16)
279 @@ -143,6 +152,9 @@ static void __cpuinit r4k_blast_dcache_s
280  {
281         unsigned long dc_lsize = cpu_dcache_line_size();
282  
283 +       if (bcm4710)
284 +               r4k_blast_dcache = blast_dcache;
285 +       else
286         if (dc_lsize == 0)
287                 r4k_blast_dcache = (void *)cache_noop;
288         else if (dc_lsize == 16)
289 @@ -683,6 +695,8 @@ static void local_r4k_flush_cache_sigtra
290         unsigned long addr = (unsigned long) arg;
291  
292         R4600_HIT_CACHEOP_WAR_IMPL;
293 +       BCM4710_PROTECTED_FILL_TLB(addr);
294 +       BCM4710_PROTECTED_FILL_TLB(addr + 4);
295         if (dc_lsize)
296                 protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
297         if (!cpu_icache_snoops_remote_store && scache_size)
298 @@ -1349,6 +1363,17 @@ static void __cpuinit coherency_setup(vo
299          * silly idea of putting something else there ...
300          */
301         switch (current_cpu_type()) {
302 +       case CPU_BMIPS3300:
303 +               {
304 +                       u32 cm;
305 +                       cm = read_c0_diag();
306 +                       /* Enable icache */
307 +                       cm |= (1 << 31);
308 +                       /* Enable dcache */
309 +                       cm |= (1 << 30);
310 +                       write_c0_diag(cm);
311 +               }
312 +               break;
313         case CPU_R4000PC:
314         case CPU_R4000SC:
315         case CPU_R4000MC:
316 @@ -1405,6 +1430,15 @@ void __cpuinit r4k_cache_init(void)
317                 break;
318         }
319  
320 +       /* Check if special workarounds are required */
321 +#ifdef CONFIG_BCM47XX
322 +       if (current_cpu_data.cputype == CPU_BMIPS32 && (current_cpu_data.processor_id & 0xff) == 0) {
323 +               printk("Enabling BCM4710A0 cache workarounds.\n");
324 +               bcm4710 = 1;
325 +       } else
326 +#endif
327 +               bcm4710 = 0;
328 +
329         probe_pcache();
330         setup_scache();
331  
332 @@ -1465,5 +1499,13 @@ void __cpuinit r4k_cache_init(void)
333  #if !defined(CONFIG_MIPS_CMP)
334         local_r4k___flush_cache_all(NULL);
335  #endif
336 +#ifdef CONFIG_BCM47XX
337 +       {
338 +               static void (*_coherency_setup)(void);
339 +               _coherency_setup = (void (*)(void)) KSEG1ADDR(coherency_setup);
340 +               _coherency_setup();
341 +       }
342 +#else
343         coherency_setup();
344 +#endif
345  }
346 --- a/arch/mips/mm/tlbex.c
347 +++ b/arch/mips/mm/tlbex.c
348 @@ -1264,6 +1264,9 @@ static void __cpuinit build_r4000_tlb_re
349                         /* No need for uasm_i_nop */
350                 }
351  
352 +#ifdef CONFIG_BCM47XX
353 +               uasm_i_nop(&p);
354 +#endif
355  #ifdef CONFIG_64BIT
356                 build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */
357  #else
358 @@ -1794,6 +1797,9 @@ build_r4000_tlbchange_handler_head(u32 *
359  {
360         struct work_registers wr = build_get_work_registers(p);
361  
362 +#ifdef CONFIG_BCM47XX
363 +       uasm_i_nop(p);
364 +#endif
365  #ifdef CONFIG_64BIT
366         build_get_pmde64(p, l, r, wr.r1, wr.r2); /* get pmd in ptr */
367  #else