[linux-yocto] [PATCH 25/70] ppc/476: workaround for erratum #40 on dd2 core

Paul Butler butler.paul at gmail.com
Mon Jun 10 18:45:48 PDT 2013


From: Kevin Hao <kexin.hao at windriver.com>

Extracted from ibm.patch in lsi_acp_linux_3.8.1.28 tarball.

In a coherent multiprocessor system, one processor might initiate an
icbi to another processor. If at least one processor retries an msync
operation during this operation, it might cause a hang when a specific
alignment of operations occurs.

The workaround for this is to avoid I-cache miss after icbi and msync
sequence. We first trap the icbi instructions by using the instruction
opcode compare function of the processor, then the icbi is executed
from within the handler followed by an instruction cache touch of the
cache line containing the subsequent msync instruction.

Signed-off-by: Kevin Hao <kexin.hao at windriver.com>
---
 arch/powerpc/include/asm/ppc-opcode.h |  2 ++
 arch/powerpc/include/asm/reg_booke.h  | 13 +++++++++++++
 arch/powerpc/kernel/head_44x.S        | 24 ++++++++++++++++++++++++
 arch/powerpc/kernel/misc_32.S         | 30 ++++++++++++++++++++++++++++++
 arch/powerpc/kernel/traps.c           | 28 ++++++++++++++++++++++++++++
 5 files changed, 97 insertions(+)

diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index d81f994..dd43125 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -20,6 +20,8 @@
 #define PPC_INST_DCBA_MASK		0xfc0007fe
 #define PPC_INST_DCBAL			0x7c2005ec
 #define PPC_INST_DCBZL			0x7c2007ec
+#define PPC_INST_ICBI			0x7c0007ac
+#define PPC_INST_ICBI_MASK		0xfc0007fe
 #define PPC_INST_ISEL			0x7c00001e
 #define PPC_INST_ISEL_MASK		0xfc00003e
 #define PPC_INST_LDARX			0x7c0000a8
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index 8a97aa7..034d8c4 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -312,6 +312,8 @@
 #define ESR_IMCN	0x40000000	/* Instr. Machine Check - Non-config */
 #define ESR_IMCB	0x20000000	/* Instr. Machine Check - Bus error */
 #define ESR_IMCT	0x10000000	/* Instr. Machine Check - Timeout */
+#define ESR_POT1	0x20000000	/* 476 - IOCR1 trap */
+#define ESR_POT2	0x10000000	/* 476 - IOCR2 trap */
 #define ESR_PIL		0x08000000	/* Program Exception - Illegal */
 #define ESR_PPR		0x04000000	/* Program Exception - Privileged */
 #define ESR_PTR		0x02000000	/* Program Exception - Trap */
@@ -667,6 +669,17 @@
 #define MMUBE1_VBE3		0x00000004
 #define MMUBE1_VBE4		0x00000002
 #define MMUBE1_VBE5		0x00000001
+#define SPRN_IOCCR		860
+#define IOCCR_IOCR1EN		0x80000000
+#define IOCCR_IOCR1M		0x40000000
+#define IOCCR_IOCR2EN		0x20000000
+#define IOCCR_IOCR2M		0x10000000
+#define IOCCR_IOCR1ME		0x08000000
+#define IOCCR_IOCR2ME		0x08000000
+#define IOCCR_IOCR1U		0x02000000
+#define IOCCR_IOCR2U		0x01000000
+#define SPRN_IOCR1		861
+#define SPRN_IOCR2		862
 
 #endif /* __ASM_POWERPC_REG_BOOKE_H__ */
 #endif /* __KERNEL__ */
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
index 7dd2981..4aa3bd3 100644
--- a/arch/powerpc/kernel/head_44x.S
+++ b/arch/powerpc/kernel/head_44x.S
@@ -220,6 +220,10 @@ _ENTRY(_start);
 	li	r0,0
 	mtspr	SPRN_MCSR,r0
 
+#ifdef CONFIG_PPC_47x
+	bl	init_cpu_features
+#endif
+
 	/* Let's move on */
 	lis	r4,start_kernel at h
 	ori	r4,r4,start_kernel at l
@@ -1006,6 +1010,25 @@ skpinv:	addi	r4,r4,1				/* Increment */
 
 #ifdef CONFIG_PPC_47x
 
+/*
+ * per-processor initialization that depends on feature sections.
+ *
+ * We can't use the FTR_SECTION in init_cpu_state since early_init
+ * has not yet been called.
+ */
+_GLOBAL(init_cpu_features)
+BEGIN_FTR_SECTION
+	/* DD2 workaround, trap on icbi. Configure IOCR1 and enable
+	 * it in IOCCR.
+	 */
+	LOAD_REG_IMMEDIATE(r3, (31 << 26) | (982 << 16))	/* icbi */
+	lis r4,(IOCCR_IOCR1EN | IOCCR_IOCR1U)@h
+	mtspr	SPRN_IOCR1,r3
+	mtspr	SPRN_IOCCR,r4
+END_FTR_SECTION_IFSET(CPU_FTR_476_DD2)
+
+	blr
+
 #ifdef CONFIG_SMP
 
 /* Entry point for secondary 47x processors */
@@ -1013,6 +1036,7 @@ _GLOBAL(start_secondary_47x)
         mr      r24,r3          /* CPU number */
 
 	bl	init_cpu_state
+	bl	init_cpu_features
 
 	/* Now we need to bolt the rest of kernel memory which
 	 * is done in C code. We must be careful because our task
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 7cd07b4..e98d6b0 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -1008,3 +1008,33 @@ relocate_new_kernel_end:
 relocate_new_kernel_size:
 	.long relocate_new_kernel_end - relocate_new_kernel
 #endif
+
+#ifdef CONFIG_PPC_47x
+#define ICBT(CT,RA,RB)							\
+	.long	0x7c00002c | ((CT) << 21) | ((RA) << 16) | ((RB) << 11)
+
+_GLOBAL(__icbi)
+	mflr	r5
+1:	icbi	0,r3
+	bl 2f
+2:	mflr	r3
+	li	r4,32
+	ICBT(0,r3,r4)
+	add	r3,r3,r4
+	ICBT(0,r3,r4)
+	add	r3,r3,r4
+	ICBT(0,r3,r4)
+	sync
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	mtlr	r5
+	li	r3, 0
+	blr
+#endif /* CONFIG_PPC_47x */
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 3251840..016f67b 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -904,6 +904,19 @@ static int emulate_isel(struct pt_regs *regs, u32 instword)
 	return 0;
 }
 
+#ifdef CONFIG_PPC_47x
+extern int __icbi(unsigned long ea);
+
+static int emulate_icbi(struct pt_regs *regs, u32 instword)
+{
+	u8 rA = (instword >> 16) & 0x1f;
+	u8 rB = (instword >> 11) & 0x1f;
+	unsigned long ea = regs->gpr[rB] + ((rA == 0) ? 0 : regs->gpr[rA]);
+
+	return __icbi(ea);
+}
+#endif /* CONFIG_PPC_47x */
+
 static int emulate_instruction(struct pt_regs *regs)
 {
 	u32 instword;
@@ -980,6 +993,12 @@ static int emulate_instruction(struct pt_regs *regs)
 	}
 #endif
 
+#ifdef CONFIG_PPC_47x
+	/* Emulate icbi instruction */
+	if ((instword & PPC_INST_ICBI_MASK) == PPC_INST_ICBI)
+		return emulate_icbi(regs, instword);
+#endif
+
 	return -EINVAL;
 }
 
@@ -993,6 +1012,15 @@ void __kprobes program_check_exception(struct pt_regs *regs)
 	unsigned int reason = get_reason(regs);
 	extern int do_mathemu(struct pt_regs *regs);
 
+#ifdef CONFIG_PPC_47x
+	/* Make IOC instruction traps look like illegal instructions
+	 * so we hit the proper emulation code path
+	 */
+	if (mmu_has_feature(MMU_FTR_TYPE_47x) &&
+	    (reason & (ESR_POT1 | ESR_POT2)))
+		reason |= ESR_PIL;
+#endif /* CONFIG_PPC_47x */
+
 	/* We can now get here via a FP Unavailable exception if the core
 	 * has no FPU, in that case the reason flags will be 0 */
 
-- 
1.8.3




More information about the linux-yocto mailing list