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

Reply via email to