On Apr 11, 2013, at 3:36 AM, Jia Hongtao wrote:

> 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 <b35...@freescale.com>
> Signed-off-by: Li Yang <le...@freescale.com>
> Signed-off-by: Liu Shuo <soniccat....@gmail.com>
> Signed-off-by: Jia Hongtao <hongtao....@freescale.com>
> ---
> V5:
> * Move OP and XOP defines to a new header file: asm/ppc-disassemble.h
> * Add X UX BRX variant of load instruction emulation
> * Remove A variant of load instruction emulation
> 
> 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/include/asm/ppc-disassemble.h |  31 +++++++
> arch/powerpc/kernel/cpu_setup_fsl_booke.S  |   2 +-
> arch/powerpc/kernel/traps.c                |   3 +
> arch/powerpc/sysdev/fsl_pci.c              | 140 +++++++++++++++++++++++++++++
> arch/powerpc/sysdev/fsl_pci.h              |   6 ++
> 5 files changed, 181 insertions(+), 1 deletion(-)
> create mode 100644 arch/powerpc/include/asm/ppc-disassemble.h
> 
> diff --git a/arch/powerpc/include/asm/ppc-disassemble.h 
> b/arch/powerpc/include/asm/ppc-disassemble.h
> new file mode 100644
> index 0000000..f9782b8
> --- /dev/null
> +++ b/arch/powerpc/include/asm/ppc-disassemble.h
> @@ -0,0 +1,31 @@
> +/*
> + * Copyright 2012-2013 Freescale Semiconductor, Inc.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + *
> + * provides opcode and xopcode images for use by emulating
> + * instructions
> + */
> +#ifndef _ASM_POWERPC_PPC_DISASSEMBLE_H
> +#define _ASM_POWERPC_PPC_DISASSEMBLE_H
> +

This should really just be in asm/ppc-opcode.h

> +#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_31_XOP_LWZX      23
> +#define OP_31_XOP_LWZUX     55
> +#define OP_31_XOP_LBZX      87
> +#define OP_31_XOP_LBZUX     119
> +#define OP_31_XOP_LHZX      279
> +#define OP_31_XOP_LHZUX     311
> +#define OP_31_XOP_LWBRX     534
> +#define OP_31_XOP_LHBRX     790
> +

Also, submit a patch to extract these from existing code so we stop duplicating 
them everywhere.

> +#endif
> 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@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..aaa54c5 100644
> --- a/arch/powerpc/sysdev/fsl_pci.c
> +++ b/arch/powerpc/sysdev/fsl_pci.c
> @@ -26,11 +26,15 @@
> #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>

what are you pulling in from ppc-pci.h?

> #include <asm/machdep.h>
> +#include <asm/disassemble.h>
> +#include <asm/ppc-disassemble.h>
> #include <sysdev/fsl_soc.h>
> #include <sysdev/fsl_pci.h>
> 
> @@ -826,6 +830,142 @@ u64 fsl_pci_immrbar_base(struct pci_controller *hose)
>       return 0;
> }
> 
> +#ifdef CONFIG_E500
> +static int mcheck_handle_load(struct pt_regs *regs, u32 inst)
> +{
> +     unsigned int rd, ra, rb, d;
> +
> +     rd = get_rt(inst);
> +     ra = get_ra(inst);
> +     rb = get_rb(inst);
> +     d = get_d(inst);
> +
> +     switch (get_op(inst)) {
> +     case 31:

What about 64-bit loads (LD...)?

> +             switch (get_xop(inst)) {
> +             case OP_31_XOP_LWZX:
> +             case OP_31_XOP_LWBRX:
> +                     regs->gpr[rd] = 0xffffffff;
> +                     break;
> +
> +             case OP_31_XOP_LWZUX:
> +                     regs->gpr[rd] = 0xffffffff;
> +                     regs->gpr[ra] += regs->gpr[rb];
> +                     break;
> +
> +             case OP_31_XOP_LBZX:
> +                     regs->gpr[rd] = 0xff;
> +                     break;
> +
> +             case OP_31_XOP_LBZUX:
> +                     regs->gpr[rd] = 0xff;
> +                     regs->gpr[ra] += regs->gpr[rb];
> +                     break;
> +
> +             case OP_31_XOP_LHZX:
> +             case OP_31_XOP_LHBRX:
> +                     regs->gpr[rd] = 0xffff;
> +                     break;
> +
> +             case OP_31_XOP_LHZUX:
> +                     regs->gpr[rd] = 0xffff;
> +                     regs->gpr[ra] += regs->gpr[rb];
> +                     break;
> +
> +             default:
> +                     return 0;
> +             }
> +             break;
> +
> +     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;
> +
> +     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
> 

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to