|
@@ -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>
|
|
|
#include <asm/machdep.h>
|
|
|
+#include <asm/disassemble.h>
|
|
|
+#include <asm/ppc-opcode.h>
|
|
|
#include <sysdev/fsl_soc.h>
|
|
|
#include <sysdev/fsl_pci.h>
|
|
|
|
|
@@ -868,6 +872,160 @@ 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:
|
|
|
+ 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;
|
|
|
+
|
|
|
+ case OP_31_XOP_LHAX:
|
|
|
+ regs->gpr[rd] = ~0UL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case OP_31_XOP_LHAUX:
|
|
|
+ regs->gpr[rd] = ~0UL;
|
|
|
+ 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;
|
|
|
+
|
|
|
+ case OP_LHA:
|
|
|
+ regs->gpr[rd] = ~0UL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case OP_LHAU:
|
|
|
+ regs->gpr[rd] = ~0UL;
|
|
|
+ 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 (!(hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG))
|
|
|
+ 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", },
|