From: Kevin Hao <kexin....@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....@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@h ori r4,r4,start_kernel@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 _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto