aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHongtao Jia <hongtao.jia@freescale.com>2013-04-28 01:20:08 -0400
committerScott Wood <scottwood@freescale.com>2013-07-30 16:50:07 -0400
commit4e0e3435b50285eafe5898124ce02f7577f6803a (patch)
tree1cb33868e383e1e94e339edfbcdf5206387f2667
parent9123c5ed45a583311d8373e99f5e3ee4c0b4306b (diff)
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@freescale.com> Signed-off-by: Li Yang <leoli@freescale.com> Signed-off-by: Liu Shuo <soniccat.liu@gmail.com> Signed-off-by: Jia Hongtao <hongtao.jia@freescale.com> Signed-off-by: Scott Wood <scottwood@freescale.com>
-rw-r--r--arch/powerpc/kernel/cpu_setup_fsl_booke.S2
-rw-r--r--arch/powerpc/kernel/traps.c3
-rw-r--r--arch/powerpc/sysdev/fsl_pci.c158
-rw-r--r--arch/powerpc/sysdev/fsl_pci.h6
4 files changed, 168 insertions, 1 deletions
diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
index 0b9af015bedc..bfb18c7290b7 100644
--- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
+++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
@@ -75,7 +75,7 @@ _GLOBAL(__setup_cpu_e500v2)
75 bl __e500_icache_setup 75 bl __e500_icache_setup
76 bl __e500_dcache_setup 76 bl __e500_dcache_setup
77 bl __setup_e500_ivors 77 bl __setup_e500_ivors
78#ifdef CONFIG_FSL_RIO 78#if defined(CONFIG_FSL_RIO) || defined(CONFIG_FSL_PCI)
79 /* Ensure that RFXE is set */ 79 /* Ensure that RFXE is set */
80 mfspr r3,SPRN_HID1 80 mfspr r3,SPRN_HID1
81 oris r3,r3,HID1_RFXE@h 81 oris r3,r3,HID1_RFXE@h
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index bf33c22e38a4..f58eaf23e8f1 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -62,6 +62,7 @@
62#include <asm/switch_to.h> 62#include <asm/switch_to.h>
63#include <asm/tm.h> 63#include <asm/tm.h>
64#include <asm/debug.h> 64#include <asm/debug.h>
65#include <sysdev/fsl_pci.h>
65 66
66#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) 67#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
67int (*__debugger)(struct pt_regs *regs) __read_mostly; 68int (*__debugger)(struct pt_regs *regs) __read_mostly;
@@ -567,6 +568,8 @@ int machine_check_e500(struct pt_regs *regs)
567 if (reason & MCSR_BUS_RBERR) { 568 if (reason & MCSR_BUS_RBERR) {
568 if (fsl_rio_mcheck_exception(regs)) 569 if (fsl_rio_mcheck_exception(regs))
569 return 1; 570 return 1;
571 if (fsl_pci_mcheck_exception(regs))
572 return 1;
570 } 573 }
571 574
572 printk("Machine check in kernel mode.\n"); 575 printk("Machine check in kernel mode.\n");
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 46ac1ddea683..3409758c78b2 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -26,11 +26,15 @@
26#include <linux/memblock.h> 26#include <linux/memblock.h>
27#include <linux/log2.h> 27#include <linux/log2.h>
28#include <linux/slab.h> 28#include <linux/slab.h>
29#include <linux/uaccess.h>
29 30
30#include <asm/io.h> 31#include <asm/io.h>
31#include <asm/prom.h> 32#include <asm/prom.h>
32#include <asm/pci-bridge.h> 33#include <asm/pci-bridge.h>
34#include <asm/ppc-pci.h>
33#include <asm/machdep.h> 35#include <asm/machdep.h>
36#include <asm/disassemble.h>
37#include <asm/ppc-opcode.h>
34#include <sysdev/fsl_soc.h> 38#include <sysdev/fsl_soc.h>
35#include <sysdev/fsl_pci.h> 39#include <sysdev/fsl_pci.h>
36 40
@@ -868,6 +872,160 @@ u64 fsl_pci_immrbar_base(struct pci_controller *hose)
868 return 0; 872 return 0;
869} 873}
870 874
875#ifdef CONFIG_E500
876static int mcheck_handle_load(struct pt_regs *regs, u32 inst)
877{
878 unsigned int rd, ra, rb, d;
879
880 rd = get_rt(inst);
881 ra = get_ra(inst);
882 rb = get_rb(inst);
883 d = get_d(inst);
884
885 switch (get_op(inst)) {
886 case 31:
887 switch (get_xop(inst)) {
888 case OP_31_XOP_LWZX:
889 case OP_31_XOP_LWBRX:
890 regs->gpr[rd] = 0xffffffff;
891 break;
892
893 case OP_31_XOP_LWZUX:
894 regs->gpr[rd] = 0xffffffff;
895 regs->gpr[ra] += regs->gpr[rb];
896 break;
897
898 case OP_31_XOP_LBZX:
899 regs->gpr[rd] = 0xff;
900 break;
901
902 case OP_31_XOP_LBZUX:
903 regs->gpr[rd] = 0xff;
904 regs->gpr[ra] += regs->gpr[rb];
905 break;
906
907 case OP_31_XOP_LHZX:
908 case OP_31_XOP_LHBRX:
909 regs->gpr[rd] = 0xffff;
910 break;
911
912 case OP_31_XOP_LHZUX:
913 regs->gpr[rd] = 0xffff;
914 regs->gpr[ra] += regs->gpr[rb];
915 break;
916
917 case OP_31_XOP_LHAX:
918 regs->gpr[rd] = ~0UL;
919 break;
920
921 case OP_31_XOP_LHAUX:
922 regs->gpr[rd] = ~0UL;
923 regs->gpr[ra] += regs->gpr[rb];
924 break;
925
926 default:
927 return 0;
928 }
929 break;
930
931 case OP_LWZ:
932 regs->gpr[rd] = 0xffffffff;
933 break;
934
935 case OP_LWZU:
936 regs->gpr[rd] = 0xffffffff;
937 regs->gpr[ra] += (s16)d;
938 break;
939
940 case OP_LBZ:
941 regs->gpr[rd] = 0xff;
942 break;
943
944 case OP_LBZU:
945 regs->gpr[rd] = 0xff;
946 regs->gpr[ra] += (s16)d;
947 break;
948
949 case OP_LHZ:
950 regs->gpr[rd] = 0xffff;
951 break;
952
953 case OP_LHZU:
954 regs->gpr[rd] = 0xffff;
955 regs->gpr[ra] += (s16)d;
956 break;
957
958 case OP_LHA:
959 regs->gpr[rd] = ~0UL;
960 break;
961
962 case OP_LHAU:
963 regs->gpr[rd] = ~0UL;
964 regs->gpr[ra] += (s16)d;
965 break;
966
967 default:
968 return 0;
969 }
970
971 return 1;
972}
973
974static int is_in_pci_mem_space(phys_addr_t addr)
975{
976 struct pci_controller *hose;
977 struct resource *res;
978 int i;
979
980 list_for_each_entry(hose, &hose_list, list_node) {
981 if (!(hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG))
982 continue;
983
984 for (i = 0; i < 3; i++) {
985 res = &hose->mem_resources[i];
986 if ((res->flags & IORESOURCE_MEM) &&
987 addr >= res->start && addr <= res->end)
988 return 1;
989 }
990 }
991 return 0;
992}
993
994int fsl_pci_mcheck_exception(struct pt_regs *regs)
995{
996 u32 inst;
997 int ret;
998 phys_addr_t addr = 0;
999
1000 /* Let KVM/QEMU deal with the exception */
1001 if (regs->msr & MSR_GS)
1002 return 0;
1003
1004#ifdef CONFIG_PHYS_64BIT
1005 addr = mfspr(SPRN_MCARU);
1006 addr <<= 32;
1007#endif
1008 addr += mfspr(SPRN_MCAR);
1009
1010 if (is_in_pci_mem_space(addr)) {
1011 if (user_mode(regs)) {
1012 pagefault_disable();
1013 ret = get_user(regs->nip, &inst);
1014 pagefault_enable();
1015 } else {
1016 ret = probe_kernel_address(regs->nip, inst);
1017 }
1018
1019 if (mcheck_handle_load(regs, inst)) {
1020 regs->nip += 4;
1021 return 1;
1022 }
1023 }
1024
1025 return 0;
1026}
1027#endif
1028
871#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx) 1029#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
872static const struct of_device_id pci_ids[] = { 1030static const struct of_device_id pci_ids[] = {
873 { .compatible = "fsl,mpc8540-pci", }, 1031 { .compatible = "fsl,mpc8540-pci", },
diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h
index 72b5625330e2..defc422a375f 100644
--- a/arch/powerpc/sysdev/fsl_pci.h
+++ b/arch/powerpc/sysdev/fsl_pci.h
@@ -126,5 +126,11 @@ static inline int mpc85xx_pci_err_probe(struct platform_device *op)
126} 126}
127#endif 127#endif
128 128
129#ifdef CONFIG_FSL_PCI
130extern int fsl_pci_mcheck_exception(struct pt_regs *);
131#else
132static inline int fsl_pci_mcheck_exception(struct pt_regs *regs) {return 0; }
133#endif
134
129#endif /* __POWERPC_FSL_PCI_H */ 135#endif /* __POWERPC_FSL_PCI_H */
130#endif /* __KERNEL__ */ 136#endif /* __KERNEL__ */