aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin
diff options
context:
space:
mode:
authorSonic Zhang <sonic.zhang@analog.com>2010-08-05 03:49:26 -0400
committerMike Frysinger <vapier@gentoo.org>2011-03-18 04:01:04 -0400
commitc6345ab1a3d17f4b6c80ac79d7fb0f006b32fdaa (patch)
tree8f3980f69cba2e3269aa9688426fca95be56d7a6 /arch/blackfin
parent6f546bc3ac9eedbf770bf3bcbc45ce2ea32c94ad (diff)
Blackfin: SMP: work around anomaly 05000491
In order to safely work around anomaly 05000491, we have to execute IFLUSH from L1 instruction sram. The trouble with multi-core systems is that all L1 sram is visible only to the active core. So we can't just place the functions into L1 and call it directly. We need to setup a jump table and place the entry point in external memory. This will call the right func based on the active core. In the process, convert from the manual relocation of a small bit of code into Core B's L1 to the more general framework we already have in place for loading arbitrary pieces of code into L1. Signed-off-by: Sonic Zhang <sonic.zhang@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'arch/blackfin')
-rw-r--r--arch/blackfin/Kconfig1
-rw-r--r--arch/blackfin/include/asm/smp.h7
-rw-r--r--arch/blackfin/kernel/setup.c37
-rw-r--r--arch/blackfin/kernel/vmlinux.lds.S1
-rw-r--r--arch/blackfin/mach-bf561/secondary.S7
-rw-r--r--arch/blackfin/mach-bf561/smp.c9
-rw-r--r--arch/blackfin/mach-common/cache.S20
-rw-r--r--arch/blackfin/mach-common/smp.c4
8 files changed, 74 insertions, 12 deletions
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index 0f34ec58bac3..c4cda6f52b61 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -850,7 +850,6 @@ config CPLB_SWITCH_TAB_L1
850config ICACHE_FLUSH_L1 850config ICACHE_FLUSH_L1
851 bool "Locate icache flush funcs in L1 Inst Memory" 851 bool "Locate icache flush funcs in L1 Inst Memory"
852 default y 852 default y
853 depends on !SMP
854 help 853 help
855 If enabled, the Blackfin icache flushing functions are linked 854 If enabled, the Blackfin icache flushing functions are linked
856 into L1 instruction memory. 855 into L1 instruction memory.
diff --git a/arch/blackfin/include/asm/smp.h b/arch/blackfin/include/asm/smp.h
index 9dd487375247..af6c0aa79bae 100644
--- a/arch/blackfin/include/asm/smp.h
+++ b/arch/blackfin/include/asm/smp.h
@@ -17,7 +17,12 @@
17 17
18#define raw_smp_processor_id() blackfin_core_id() 18#define raw_smp_processor_id() blackfin_core_id()
19 19
20extern char coreb_trampoline_start, coreb_trampoline_end; 20extern void bfin_relocate_coreb_l1_mem(void);
21
22#if defined(CONFIG_SMP) && defined(CONFIG_ICACHE_FLUSH_L1)
23asmlinkage void blackfin_icache_flush_range_l1(unsigned long *ptr);
24extern unsigned long blackfin_iflush_l1_entry[NR_CPUS];
25#endif
21 26
22struct corelock_slot { 27struct corelock_slot {
23 int lock; 28 int lock;
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
index ac71dc15cbdb..805c6132c779 100644
--- a/arch/blackfin/kernel/setup.c
+++ b/arch/blackfin/kernel/setup.c
@@ -215,11 +215,48 @@ void __init bfin_relocate_l1_mem(void)
215 215
216 early_dma_memcpy_done(); 216 early_dma_memcpy_done();
217 217
218#if defined(CONFIG_SMP) && defined(CONFIG_ICACHE_FLUSH_L1)
219 blackfin_iflush_l1_entry[0] = (unsigned long)blackfin_icache_flush_range_l1;
220#endif
221
218 /* if necessary, copy L2 text/data to L2 SRAM */ 222 /* if necessary, copy L2 text/data to L2 SRAM */
219 if (L2_LENGTH && l2_len) 223 if (L2_LENGTH && l2_len)
220 memcpy(_stext_l2, _l2_lma, l2_len); 224 memcpy(_stext_l2, _l2_lma, l2_len);
221} 225}
222 226
227#ifdef CONFIG_SMP
228void __init bfin_relocate_coreb_l1_mem(void)
229{
230 unsigned long text_l1_len = (unsigned long)_text_l1_len;
231 unsigned long data_l1_len = (unsigned long)_data_l1_len;
232 unsigned long data_b_l1_len = (unsigned long)_data_b_l1_len;
233
234 blackfin_dma_early_init();
235
236 /* if necessary, copy L1 text to L1 instruction SRAM */
237 if (L1_CODE_LENGTH && text_l1_len)
238 early_dma_memcpy((void *)COREB_L1_CODE_START, _text_l1_lma,
239 text_l1_len);
240
241 /* if necessary, copy L1 data to L1 data bank A SRAM */
242 if (L1_DATA_A_LENGTH && data_l1_len)
243 early_dma_memcpy((void *)COREB_L1_DATA_A_START, _data_l1_lma,
244 data_l1_len);
245
246 /* if necessary, copy L1 data B to L1 data bank B SRAM */
247 if (L1_DATA_B_LENGTH && data_b_l1_len)
248 early_dma_memcpy((void *)COREB_L1_DATA_B_START, _data_b_l1_lma,
249 data_b_l1_len);
250
251 early_dma_memcpy_done();
252
253#ifdef CONFIG_ICACHE_FLUSH_L1
254 blackfin_iflush_l1_entry[1] = (unsigned long)blackfin_icache_flush_range_l1 -
255 (unsigned long)_stext_l1 + COREB_L1_CODE_START;
256#endif
257}
258#endif
259
223#ifdef CONFIG_ROMKERNEL 260#ifdef CONFIG_ROMKERNEL
224void __init bfin_relocate_xip_data(void) 261void __init bfin_relocate_xip_data(void)
225{ 262{
diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S
index f5fd234e5773..854fa49f1c3e 100644
--- a/arch/blackfin/kernel/vmlinux.lds.S
+++ b/arch/blackfin/kernel/vmlinux.lds.S
@@ -176,6 +176,7 @@ SECTIONS
176 { 176 {
177 . = ALIGN(4); 177 . = ALIGN(4);
178 __stext_l1 = .; 178 __stext_l1 = .;
179 *(.l1.text.head)
179 *(.l1.text) 180 *(.l1.text)
180#ifdef CONFIG_SCHEDULE_L1 181#ifdef CONFIG_SCHEDULE_L1
181 SCHED_TEXT 182 SCHED_TEXT
diff --git a/arch/blackfin/mach-bf561/secondary.S b/arch/blackfin/mach-bf561/secondary.S
index 148e50764555..4c462838f4e1 100644
--- a/arch/blackfin/mach-bf561/secondary.S
+++ b/arch/blackfin/mach-bf561/secondary.S
@@ -13,7 +13,11 @@
13#include <asm/asm-offsets.h> 13#include <asm/asm-offsets.h>
14#include <asm/trace.h> 14#include <asm/trace.h>
15 15
16__INIT 16/*
17 * This code must come first as CoreB is hardcoded (in hardware)
18 * to start at the beginning of its L1 instruction memory.
19 */
20.section .l1.text.head
17 21
18/* Lay the initial stack into the L1 scratch area of Core B */ 22/* Lay the initial stack into the L1 scratch area of Core B */
19#define INITIAL_STACK (COREB_L1_SCRATCH_START + L1_SCRATCH_LENGTH - 12) 23#define INITIAL_STACK (COREB_L1_SCRATCH_START + L1_SCRATCH_LENGTH - 12)
@@ -160,7 +164,6 @@ ENTRY(_coreb_trampoline_start)
160.LWAIT_HERE: 164.LWAIT_HERE:
161 jump .LWAIT_HERE; 165 jump .LWAIT_HERE;
162ENDPROC(_coreb_trampoline_start) 166ENDPROC(_coreb_trampoline_start)
163ENTRY(_coreb_trampoline_end)
164 167
165#ifdef CONFIG_HOTPLUG_CPU 168#ifdef CONFIG_HOTPLUG_CPU
166.section ".text" 169.section ".text"
diff --git a/arch/blackfin/mach-bf561/smp.c b/arch/blackfin/mach-bf561/smp.c
index 1074a7ef81c7..82b94e137886 100644
--- a/arch/blackfin/mach-bf561/smp.c
+++ b/arch/blackfin/mach-bf561/smp.c
@@ -30,18 +30,11 @@ void __init platform_init_cpus(void)
30 30
31void __init platform_prepare_cpus(unsigned int max_cpus) 31void __init platform_prepare_cpus(unsigned int max_cpus)
32{ 32{
33 int len; 33 bfin_relocate_coreb_l1_mem();
34
35 len = &coreb_trampoline_end - &coreb_trampoline_start + 1;
36 BUG_ON(len > L1_CODE_LENGTH);
37
38 dma_memcpy((void *)COREB_L1_CODE_START, &coreb_trampoline_start, len);
39 34
40 /* Both cores ought to be present on a bf561! */ 35 /* Both cores ought to be present on a bf561! */
41 cpu_set(0, cpu_present_map); /* CoreA */ 36 cpu_set(0, cpu_present_map); /* CoreA */
42 cpu_set(1, cpu_present_map); /* CoreB */ 37 cpu_set(1, cpu_present_map); /* CoreB */
43
44 printk(KERN_INFO "CoreB bootstrap code to SRAM %p via DMA.\n", (void *)COREB_L1_CODE_START);
45} 38}
46 39
47int __init setup_profiling_timer(unsigned int multiplier) /* not supported */ 40int __init setup_profiling_timer(unsigned int multiplier) /* not supported */
diff --git a/arch/blackfin/mach-common/cache.S b/arch/blackfin/mach-common/cache.S
index 85aadeb76658..9f4dd35bfd74 100644
--- a/arch/blackfin/mach-common/cache.S
+++ b/arch/blackfin/mach-common/cache.S
@@ -69,10 +69,30 @@
69#endif 69#endif
70 70
71/* Invalidate all instruction cache lines assocoiated with this memory area */ 71/* Invalidate all instruction cache lines assocoiated with this memory area */
72#ifdef CONFIG_SMP
73# define _blackfin_icache_flush_range _blackfin_icache_flush_range_l1
74#endif
72ENTRY(_blackfin_icache_flush_range) 75ENTRY(_blackfin_icache_flush_range)
73 do_flush IFLUSH 76 do_flush IFLUSH
74ENDPROC(_blackfin_icache_flush_range) 77ENDPROC(_blackfin_icache_flush_range)
75 78
79#ifdef CONFIG_SMP
80.text
81# undef _blackfin_icache_flush_range
82ENTRY(_blackfin_icache_flush_range)
83 p0.L = LO(DSPID);
84 p0.H = HI(DSPID);
85 r3 = [p0];
86 r3 = r3.b (z);
87 p2 = r3;
88 p0.L = _blackfin_iflush_l1_entry;
89 p0.H = _blackfin_iflush_l1_entry;
90 p0 = p0 + (p2 << 2);
91 p1 = [p0];
92 jump (p1);
93ENDPROC(_blackfin_icache_flush_range)
94#endif
95
76#ifdef CONFIG_DCACHE_FLUSH_L1 96#ifdef CONFIG_DCACHE_FLUSH_L1
77.section .l1.text 97.section .l1.text
78#else 98#else
diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c
index 5f7617d66905..6e17a265c4d3 100644
--- a/arch/blackfin/mach-common/smp.c
+++ b/arch/blackfin/mach-common/smp.c
@@ -40,6 +40,10 @@
40 */ 40 */
41struct corelock_slot corelock __attribute__ ((__section__(".l2.bss"))); 41struct corelock_slot corelock __attribute__ ((__section__(".l2.bss")));
42 42
43#ifdef CONFIG_ICACHE_FLUSH_L1
44unsigned long blackfin_iflush_l1_entry[NR_CPUS];
45#endif
46
43void __cpuinitdata *init_retx_coreb, *init_saved_retx_coreb, 47void __cpuinitdata *init_retx_coreb, *init_saved_retx_coreb,
44 *init_saved_seqstat_coreb, *init_saved_icplb_fault_addr_coreb, 48 *init_saved_seqstat_coreb, *init_saved_icplb_fault_addr_coreb,
45 *init_saved_dcplb_fault_addr_coreb; 49 *init_saved_dcplb_fault_addr_coreb;