Title: [9052] trunk/arch/blackfin: Fix bug[#6055] Walk around anomaly 05000491 in SMP kernel for bf561
Revision
9052
Author
sonicz
Date
2010-08-05 03:49:26 -0400 (Thu, 05 Aug 2010)

Log Message

Fix bug[#6055] Walk around anomaly 05000491 in SMP kernel for bf561


The only reliable walk around for anomaly 05000491 is to execute iflush
from L1 SRAM. In bf561 SMP kernel, L1 SRAM space on different core
occupy difference memory region. Call to invalidate icache should jump
to the same icache flush code at different L1 address on different core.
This patch implement this logic if anomaly 0500491 is applicable when
building SMP kernel.

Modified Paths

Added Paths

Diff

Modified: trunk/arch/blackfin/include/asm/kgdb.h (9051 => 9052)


--- trunk/arch/blackfin/include/asm/kgdb.h	2010-08-05 07:34:28 UTC (rev 9051)
+++ trunk/arch/blackfin/include/asm/kgdb.h	2010-08-05 07:49:26 UTC (rev 9052)
@@ -103,7 +103,11 @@
 	asm("EXCPT 2;");
 }
 #define BREAK_INSTR_SIZE	2
-#define CACHE_FLUSH_IS_SAFE	1
+#ifdef CONFIG_SMP
+# define CACHE_FLUSH_IS_SAFE	0
+#else
+# define CACHE_FLUSH_IS_SAFE	1
+#endif
 #define GDB_ADJUSTS_BREAK_OFFSET
 #define GDB_SKIP_HW_WATCH_TEST
 #define HW_INST_WATCHPOINT_NUM	6

Modified: trunk/arch/blackfin/include/asm/smp.h (9051 => 9052)


--- trunk/arch/blackfin/include/asm/smp.h	2010-08-05 07:34:28 UTC (rev 9051)
+++ trunk/arch/blackfin/include/asm/smp.h	2010-08-05 07:49:26 UTC (rev 9052)
@@ -18,7 +18,14 @@
 #define raw_smp_processor_id()  blackfin_core_id()
 
 extern char coreb_trampoline_start, coreb_trampoline_end;
+extern void bfin_relocate_coreb_l1_mem(void);
 
+#if ANOMALY_05000491
+asmlinkage void blackfin_icache_flush_range_l1(unsigned long *ptr);
+extern unsigned long blackfin_iflush_l1_entry[NR_CPUS];
+#endif
+
+
 struct corelock_slot {
 	int lock;
 };

Modified: trunk/arch/blackfin/kernel/setup.c (9051 => 9052)


--- trunk/arch/blackfin/kernel/setup.c	2010-08-05 07:34:28 UTC (rev 9051)
+++ trunk/arch/blackfin/kernel/setup.c	2010-08-05 07:49:26 UTC (rev 9052)
@@ -215,11 +215,43 @@
 
 	early_dma_memcpy_done();
 
+#if defined(CONFIG_SMP) && ANOMALY_05000491
+	blackfin_iflush_l1_entry[0] = (unsigned long)blackfin_icache_flush_range_l1;
+#endif
 	/* if necessary, copy L2 text/data to L2 SRAM */
 	if (L2_LENGTH && l2_len)
 		memcpy(_stext_l2, _l2_lma, l2_len);
 }
 
+#ifdef CONFIG_SMP
+void __init bfin_relocate_coreb_l1_mem(void)
+{
+	unsigned long text_l1_len = (unsigned long)_text_l1_len;
+	unsigned long data_l1_len = (unsigned long)_data_l1_len;
+	unsigned long data_b_l1_len = (unsigned long)_data_b_l1_len;
+
+	/* if necessary, copy L1 text to L1 instruction SRAM */
+	if (L1_CODE_LENGTH && text_l1_len)
+		early_dma_memcpy((void *)COREB_L1_CODE_START, _text_l1_lma,
+				text_l1_len);
+
+	/* if necessary, copy L1 data to L1 data bank A SRAM */
+	if (L1_DATA_A_LENGTH && data_l1_len)
+		early_dma_memcpy((void *)COREB_L1_DATA_A_START, _data_l1_lma,
+				data_l1_len);
+
+	/* if necessary, copy L1 data B to L1 data bank B SRAM */
+	if (L1_DATA_B_LENGTH && data_b_l1_len)
+		early_dma_memcpy((void *)COREB_L1_DATA_B_START, _data_b_l1_lma,
+				data_b_l1_len);
+
+#if ANOMALY_05000491
+	blackfin_iflush_l1_entry[1] = (unsigned long)blackfin_icache_flush_range_l1 -
+			(unsigned long)_stext_l1 + COREB_L1_CODE_START;
+#endif
+#endif
+}
+
 #ifdef CONFIG_ROMKERNEL
 void __init bfin_relocate_xip_data(void)
 {

Modified: trunk/arch/blackfin/mach-bf561/smp.c (9051 => 9052)


--- trunk/arch/blackfin/mach-bf561/smp.c	2010-08-05 07:34:28 UTC (rev 9051)
+++ trunk/arch/blackfin/mach-bf561/smp.c	2010-08-05 07:49:26 UTC (rev 9052)
@@ -106,6 +106,9 @@
 	if (cpu_online(cpu)) {
 		/* release the lock and let coreb run */
 		spin_unlock(&boot_lock);
+
+		bfin_relocate_coreb_l1_mem();
+
 		return 0;
 	} else
 		panic("CPU%u: processor failed to boot\n", cpu);

Modified: trunk/arch/blackfin/mach-common/Makefile (9051 => 9052)


--- trunk/arch/blackfin/mach-common/Makefile	2010-08-05 07:34:28 UTC (rev 9051)
+++ trunk/arch/blackfin/mach-common/Makefile	2010-08-05 07:49:26 UTC (rev 9052)
@@ -9,6 +9,6 @@
 obj-$(CONFIG_PM)          += pm.o dpmc_modes.o
 obj-$(CONFIG_CPU_FREQ)    += cpufreq.o
 obj-$(CONFIG_CPU_VOLTAGE) += dpmc.o
-obj-$(CONFIG_SMP)         += smp.o
+obj-$(CONFIG_SMP)         += smp.o smp_iflush_l1.o
 obj-$(CONFIG_BFIN_KERNEL_CLOCK) += clocks-init.o
 obj-$(CONFIG_DEBUG_ICACHE_CHECK) += irqpanic.o

Modified: trunk/arch/blackfin/mach-common/arch_checks.c (9051 => 9052)


--- trunk/arch/blackfin/mach-common/arch_checks.c	2010-08-05 07:34:28 UTC (rev 9051)
+++ trunk/arch/blackfin/mach-common/arch_checks.c	2010-08-05 07:49:26 UTC (rev 9052)
@@ -60,7 +60,3 @@
 	(defined(CONFIG_BFIN_EXTMEM_WRITEBACK) || defined(CONFIG_BFIN_L2_WRITEBACK))
 # error "Anomaly 05000220 does not allow you to use Write Back cache with L2 or External Memory"
 #endif
-
-#if ANOMALY_05000491 && !defined(CONFIG_CACHE_FLUSH_L1)
-# error You need IFLUSH in L1 inst while Anomaly 05000491 applies
-#endif

Modified: trunk/arch/blackfin/mach-common/cache.S (9051 => 9052)


--- trunk/arch/blackfin/mach-common/cache.S	2010-08-05 07:34:28 UTC (rev 9051)
+++ trunk/arch/blackfin/mach-common/cache.S	2010-08-05 07:49:26 UTC (rev 9052)
@@ -11,7 +11,8 @@
 #include <asm/cache.h>
 #include <asm/page.h>
 
-#ifdef CONFIG_CACHE_FLUSH_L1
+/* 05000491 - IFLUSH needs to reside in L1 memory */
+#if defined(CONFIG_CACHE_FLUSH_L1) || (!defined(CONFIG_SMP) && ANOMALY_05000491)
 .section .l1.text
 #else
 .text
@@ -68,7 +69,22 @@
 
 /* Invalidate all instruction cache lines assocoiated with this memory area */
 ENTRY(_blackfin_icache_flush_range)
+#if defined(CONFIG_SMP) && ANOMALY_05000491
+	p0.L = LO(DSPID);
+	p0.H = HI(DSPID);
+	r2 = 0xff;
+	r3 = [p0];
+	r3 = r3 & r2;
+	r3 <<= 2;
+	p1 = r3;
+	p0.L = _blackfin_iflush_l1_entry;
+	p0.H = _blackfin_iflush_l1_entry;
+	p0 = p0 + p1;
+	p1 = [p0];
+	jump (p1);
+#else
 	do_flush IFLUSH
+#endif
 ENDPROC(_blackfin_icache_flush_range)
 
 /* Throw away all D-cached data in specified region without any obligation to

Modified: trunk/arch/blackfin/mach-common/smp.c (9051 => 9052)


--- trunk/arch/blackfin/mach-common/smp.c	2010-08-05 07:34:28 UTC (rev 9051)
+++ trunk/arch/blackfin/mach-common/smp.c	2010-08-05 07:49:26 UTC (rev 9052)
@@ -40,6 +40,10 @@
  */
 struct corelock_slot corelock __attribute__ ((__section__(".l2.bss")));
 
+#if ANOMALY_05000491
+unsigned long blackfin_iflush_l1_entry[NR_CPUS];
+#endif
+
 void __cpuinitdata *init_retx_coreb, *init_saved_retx_coreb,
 	*init_saved_seqstat_coreb, *init_saved_icplb_fault_addr_coreb,
 	*init_saved_dcplb_fault_addr_coreb;

Added: trunk/arch/blackfin/mach-common/smp_iflush_l1.S (0 => 9052)


--- trunk/arch/blackfin/mach-common/smp_iflush_l1.S	                        (rev 0)
+++ trunk/arch/blackfin/mach-common/smp_iflush_l1.S	2010-08-05 07:49:26 UTC (rev 9052)
@@ -0,0 +1,53 @@
+/*
+ * Blackfin SMP kernel icache flush anomaly walk around code in L1 SRAM
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+#include <asm/cache.h>
+#include <asm/page.h>
+
+/* 05000491 - IFLUSH needs to reside in L1 memory */
+#if ANOMALY_05000491
+
+.section .l1.text
+
+/* Invalidate all instruction cache lines assocoiated with this memory area */
+ENTRY(_blackfin_icache_flush_range_l1)
+	P0 = R0;
+
+	R2 = -L1_CACHE_BYTES;
+
+	/* start = (start & -L1_CACHE_BYTES) */
+	R0 = R0 & R2;
+
+	/* end = ((end - 1) & -L1_CACHE_BYTES) + L1_CACHE_BYTES; */
+	R1 += -1;
+	R1 = R1 & R2;
+	R1 += L1_CACHE_BYTES;
+
+	/* count = (end - start) >> L1_CACHE_SHIFT */
+	R2 = R1 - R0;
+	R2 >>= L1_CACHE_SHIFT;
+	P1 = R2;
+
+	P0 = R0;
+
+	LSETUP (1f, 2f) LC1 = P1;
+1:
+/* 05000443 - IFLUSH cannot be last instruction in hardware loop */
+#if ANOMALY_05000443
+	IFLUSH [P0++];
+2:	nop;
+#else
+2:	IFLUSH [P0++];
+#endif
+
+	RTS;
+ENDPROC(_blackfin_icache_flush_range_l1)
+
+#endif
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to