[PATCH V5] powerpc/85xx: Add machine check handler to fix PCIe erratum on mpc85xx
Jia Hongtao-B38951
B38951 at freescale.com
Wed Apr 10 12:27:32 EST 2013
Hi Scott,
I added load instruction handler for the skipped instruction.
For now most common load instructions are handled in this patch.
Any advice for this?
Thanks.
-Hongtao.
> -----Original Message-----
> From: Jia Hongtao-B38951
> Sent: Monday, April 08, 2013 4:27 PM
> To: linuxppc-dev at lists.ozlabs.org; galak at kernel.crashing.org
> Cc: Wood Scott-B07421; Li Yang-R58472; Jia Hongtao-B38951
> Subject: [PATCH V5] powerpc/85xx: Add machine check handler to fix PCIe
> erratum on mpc85xx
>
> A PCIe erratum of mpc85xx may causes a core hang when a link of PCIe goes
> down. when the link goes down, Non-posted transactions issued via the
> ATMU requiring completion result in an instruction stall.
> At the same time a machine-check exception is generated to the core to
> allow further processing by the handler. We implements the handler which
> skips the instruction caused the stall.
>
> This patch depends on patch:
> powerpc/85xx: Add platform_device declaration to fsl_pci.h
>
> Signed-off-by: Zhao Chenhui <b35336 at freescale.com>
> Signed-off-by: Li Yang <leoli at freescale.com>
> Signed-off-by: Liu Shuo <soniccat.liu at gmail.com>
> Signed-off-by: Jia Hongtao <hongtao.jia at freescale.com>
> ---
> Changes for V4:
> * Fill rd with all-Fs if the skipped instruction is load and emulate the
> instruction.
> * Let KVM/QEMU deal with the exception if the machine check comes from
> KVM.
>
> arch/powerpc/kernel/cpu_setup_fsl_booke.S | 2 +-
> arch/powerpc/kernel/traps.c | 3 +
> arch/powerpc/sysdev/fsl_pci.c | 121
> ++++++++++++++++++++++++++++++
> arch/powerpc/sysdev/fsl_pci.h | 6 ++
> 4 files changed, 131 insertions(+), 1 deletion(-)
>
> diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> index dcd8819..f1bde90 100644
> --- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> +++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> @@ -66,7 +66,7 @@ _GLOBAL(__setup_cpu_e500v2)
> bl __e500_icache_setup
> bl __e500_dcache_setup
> bl __setup_e500_ivors
> -#ifdef CONFIG_FSL_RIO
> +#if defined(CONFIG_FSL_RIO) || defined(CONFIG_FSL_PCI)
> /* Ensure that RFXE is set */
> mfspr r3,SPRN_HID1
> oris r3,r3,HID1_RFXE at h
> diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
> index a008cf5..dd275a4 100644
> --- a/arch/powerpc/kernel/traps.c
> +++ b/arch/powerpc/kernel/traps.c
> @@ -59,6 +59,7 @@
> #include <asm/fadump.h>
> #include <asm/switch_to.h>
> #include <asm/debug.h>
> +#include <sysdev/fsl_pci.h>
>
> #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) int
> (*__debugger)(struct pt_regs *regs) __read_mostly; @@ -556,6 +557,8 @@
> int machine_check_e500(struct pt_regs *regs)
> if (reason & MCSR_BUS_RBERR) {
> if (fsl_rio_mcheck_exception(regs))
> return 1;
> + if (fsl_pci_mcheck_exception(regs))
> + return 1;
> }
>
> printk("Machine check in kernel mode.\n"); diff --git
> a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index
> 682084d..48326cd 100644
> --- a/arch/powerpc/sysdev/fsl_pci.c
> +++ b/arch/powerpc/sysdev/fsl_pci.c
> @@ -26,11 +26,14 @@
> #include <linux/memblock.h>
> #include <linux/log2.h>
> #include <linux/slab.h>
> +#include <linux/uaccess.h>
>
> #include <asm/io.h>
> #include <asm/prom.h>
> #include <asm/pci-bridge.h>
> +#include <asm/ppc-pci.h>
> #include <asm/machdep.h>
> +#include <asm/disassemble.h>
> #include <sysdev/fsl_soc.h>
> #include <sysdev/fsl_pci.h>
>
> @@ -826,6 +829,124 @@ u64 fsl_pci_immrbar_base(struct pci_controller
> *hose)
> return 0;
> }
>
> +#ifdef CONFIG_E500
> +
> +#define OP_LWZ 32
> +#define OP_LWZU 33
> +#define OP_LBZ 34
> +#define OP_LBZU 35
> +#define OP_LHZ 40
> +#define OP_LHZU 41
> +#define OP_LHA 42
> +#define OP_LHAU 43
> +
> +static int mcheck_handle_load(struct pt_regs *regs, u32 inst) {
> + unsigned int rd, ra, d;
> +
> + rd = get_rt(inst);
> + ra = get_ra(inst);
> + d = get_d(inst);
> +
> + switch (get_op(inst)) {
> + case OP_LWZ:
> + regs->gpr[rd] = 0xffffffff;
> + break;
> +
> + case OP_LWZU:
> + regs->gpr[rd] = 0xffffffff;
> + regs->gpr[ra] += (s16)d;
> + break;
> +
> + case OP_LBZ:
> + regs->gpr[rd] = 0xff;
> + break;
> +
> + case OP_LBZU:
> + regs->gpr[rd] = 0xff;
> + regs->gpr[ra] += (s16)d;
> + break;
> +
> + case OP_LHZ:
> + regs->gpr[rd] = 0xffff;
> + break;
> +
> + case OP_LHZU:
> + regs->gpr[rd] = 0xffff;
> + regs->gpr[ra] += (s16)d;
> + break;
> +
> + case OP_LHA:
> + regs->gpr[rd] = 0xffff;
> + break;
> +
> + case OP_LHAU:
> + regs->gpr[rd] = 0xffff;
> + regs->gpr[ra] += (s16)d;
> + break;
> +
> + default:
> + return 0;
> + }
> +
> + return 1;
> +}
> +
> +static int is_in_pci_mem_space(phys_addr_t addr) {
> + struct pci_controller *hose;
> + struct resource *res;
> + int i;
> +
> + list_for_each_entry(hose, &hose_list, list_node) {
> + if (!early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP))
> + continue;
> +
> + for (i = 0; i < 3; i++) {
> + res = &hose->mem_resources[i];
> + if ((res->flags & IORESOURCE_MEM) &&
> + addr >= res->start && addr <= res->end)
> + return 1;
> + }
> + }
> + return 0;
> +}
> +
> +int fsl_pci_mcheck_exception(struct pt_regs *regs) {
> + u32 inst;
> + int ret;
> + phys_addr_t addr = 0;
> +
> + /* Let KVM/QEMU deal with the exception */
> + if (regs->msr & MSR_GS)
> + return 0;
> +
> +#ifdef CONFIG_PHYS_64BIT
> + addr = mfspr(SPRN_MCARU);
> + addr <<= 32;
> +#endif
> + addr += mfspr(SPRN_MCAR);
> +
> + if (is_in_pci_mem_space(addr)) {
> + if (user_mode(regs)) {
> + pagefault_disable();
> + ret = get_user(regs->nip, &inst);
> + pagefault_enable();
> + } else {
> + ret = probe_kernel_address(regs->nip, inst);
> + }
> +
> + if (mcheck_handle_load(regs, inst)) {
> + regs->nip += 4;
> + return 1;
> + }
> + }
> +
> + return 0;
> +}
> +#endif
> +
> #if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx) static
> const struct of_device_id pci_ids[] = {
> { .compatible = "fsl,mpc8540-pci", },
> diff --git a/arch/powerpc/sysdev/fsl_pci.h
> b/arch/powerpc/sysdev/fsl_pci.h index 851dd56..b0d01ea 100644
> --- a/arch/powerpc/sysdev/fsl_pci.h
> +++ b/arch/powerpc/sysdev/fsl_pci.h
> @@ -115,5 +115,11 @@ static inline int mpc85xx_pci_err_probe(struct
> platform_device *op) } #endif
>
> +#ifdef CONFIG_FSL_PCI
> +extern int fsl_pci_mcheck_exception(struct pt_regs *); #else static
> +inline int fsl_pci_mcheck_exception(struct pt_regs *regs) {return 0; }
> +#endif
> +
> #endif /* __POWERPC_FSL_PCI_H */
> #endif /* __KERNEL__ */
> --
> 1.8.0
More information about the Linuxppc-dev
mailing list