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
5 #include <asm/cpu-features.h>
6 #include <asm/mipsmtregs.h>
9 +#include <asm/paccess.h>
10 +#include <linux/ssb/ssb.h>
11 +#define BCM4710_DUMMY_RREG() ((void) *((u8 *) KSEG1ADDR(SSB_ENUM_BASE + SSB_IMSTATE)))
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)); })
16 +#define BCM4710_DUMMY_RREG()
18 +#define BCM4710_FILL_TLB(addr)
19 +#define BCM4710_PROTECTED_FILL_TLB(addr)
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)
29 + BCM4710_DUMMY_RREG();
30 cache_op(Index_Writeback_Inv_D, addr);
33 @@ -169,6 +184,7 @@ static inline void flush_icache_line(unsigned long addr)
34 static inline void flush_dcache_line(unsigned long addr)
37 + BCM4710_DUMMY_RREG();
38 cache_op(Hit_Writeback_Inv_D, addr);
41 @@ -176,6 +192,7 @@ static inline void flush_dcache_line(unsigned long addr)
42 static inline void invalidate_dcache_line(unsigned long addr)
45 + BCM4710_DUMMY_RREG();
46 cache_op(Hit_Invalidate_D, addr);
49 @@ -208,6 +225,7 @@ static inline void flush_scache_line(unsigned long addr)
51 static inline void protected_flush_icache_line(unsigned long addr)
53 + BCM4710_DUMMY_RREG();
54 protected_cache_op(Hit_Invalidate_I, addr);
57 @@ -219,6 +237,7 @@ static inline void protected_flush_icache_line(unsigned long addr)
59 static inline void protected_writeback_dcache_line(unsigned long addr)
61 + BCM4710_DUMMY_RREG();
62 protected_cache_op(Hit_Writeback_Inv_D, addr);
65 @@ -339,8 +358,52 @@ static inline void invalidate_tcache_page(unsigned long addr)
69 +static inline void blast_dcache(void)
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);
76 + BCM4710_DUMMY_RREG();
77 + cache_op(Index_Writeback_Inv_D, start);
78 + start += current_cpu_data.dcache.linesz;
79 + } while(start < end);
82 +static inline void blast_dcache_page(unsigned long page)
84 + unsigned long start = page;
85 + unsigned long end = start + PAGE_SIZE;
87 + BCM4710_FILL_TLB(start);
89 + BCM4710_DUMMY_RREG();
90 + cache_op(Hit_Writeback_Inv_D, start);
91 + start += current_cpu_data.dcache.linesz;
92 + } while(start < end);
95 +static inline void blast_dcache_page_indexed(unsigned long page)
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) {
105 + for (addr = start; addr < end; addr += current_cpu_data.dcache.linesz) {
106 + BCM4710_DUMMY_RREG();
107 + cache_op(Index_Writeback_Inv_D, addr);
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) \
118 unsigned long start = INDEX_BASE; \
119 @@ -352,6 +415,7 @@ static inline void blast_##pfx##cache##lsize(void) \
121 __##pfx##flush_prologue \
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) \
129 __##pfx##flush_prologue \
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; \
141 __##pfx##flush_prologue \
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 \
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)
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, )
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, )
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, \
187 unsigned long lsize = cpu_##desc##_line_size(); \
188 unsigned long addr = start & ~(lsize - 1); \
189 unsigned long aend = (end - 1) & ~(lsize - 1); \
192 __##pfx##flush_prologue \
196 prot##cache_op(hitop, addr); \
199 @@ -431,13 +500,13 @@ static inline void prot##blast_##pfx##cache##_range(unsigned long start, \
200 __##pfx##flush_epilogue \
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,,, )
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
224 .macro RESTORE_SP_AND_RET
225 LONG_L sp, PT_R29(sp)
227 +#ifdef CONFIG_BCM47XX
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)
241 +#ifdef CONFIG_BCM47XX
245 #if R5432_CP0_INTERRUPT_WAR
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
252 #include <asm/cacheflush.h> /* for run_uncached() */
255 +/* For enabling BCM4710 cache workarounds */
259 * Special Variant of smp_call_function for use by cache functions:
261 @@ -104,6 +107,9 @@ static void __cpuinit r4k_blast_dcache_page_setup(void)
263 unsigned long dc_lsize = cpu_dcache_line_size();
266 + r4k_blast_dcache_page = blast_dcache_page;
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)
273 unsigned long dc_lsize = cpu_dcache_line_size();
276 + r4k_blast_dcache_page_indexed = blast_dcache_page_indexed;
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)
283 unsigned long dc_lsize = cpu_dcache_line_size();
286 + r4k_blast_dcache = blast_dcache;
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;
294 R4600_HIT_CACHEOP_WAR_IMPL;
295 + BCM4710_PROTECTED_FILL_TLB(addr);
296 + BCM4710_PROTECTED_FILL_TLB(addr + 4);
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 ...
303 switch (current_cpu_type()) {
307 + cm = read_c0_diag();
308 + /* Enable icache */
310 + /* Enable dcache */
318 @@ -1328,6 +1353,15 @@ void __cpuinit r4k_cache_init(void)
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");
334 @@ -1386,5 +1420,13 @@ void __cpuinit r4k_cache_init(void)
335 #if !defined(CONFIG_MIPS_CMP)
336 local_r4k___flush_cache_all(NULL);
338 +#ifdef CONFIG_BCM47XX
340 + static void (*_coherency_setup)(void);
341 + _coherency_setup = (void (*)(void)) KSEG1ADDR(coherency_setup);
342 + _coherency_setup();
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 */
355 +#ifdef CONFIG_BCM47XX
359 build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */
361 @@ -1085,6 +1088,9 @@ build_r4000_tlbchange_handler_head(u32 **p, struct uasm_label **l,
362 struct uasm_reloc **r, unsigned int pte,
365 +#ifdef CONFIG_BCM47XX
369 build_get_pmde64(p, l, r, pte, ptr); /* get pmd in ptr */